mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-10-12 11:09:40 +00:00
Merge pull request #62 from JosJuice/merge-upstream
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
0f94aa9ef2
970 changed files with 100021 additions and 88645 deletions
|
@ -6,7 +6,7 @@
|
||||||
#
|
#
|
||||||
# vim: expandtab sw=4 ts=4 sts=4:
|
# vim: expandtab sw=4 ts=4 sts=4:
|
||||||
|
|
||||||
include(FindPkgConfig)
|
find_package(PkgConfig QUIET)
|
||||||
pkg_check_modules (BlueZ_PKG QUIET bluez)
|
pkg_check_modules (BlueZ_PKG QUIET bluez)
|
||||||
|
|
||||||
find_path(BlueZ_INCLUDE_DIR NAMES bluetooth/bluetooth.h
|
find_path(BlueZ_INCLUDE_DIR NAMES bluetooth/bluetooth.h
|
||||||
|
|
|
@ -27,7 +27,7 @@ set(LIBEVDEV_LIBRARIES ${LIBEVDEV_LIBRARY} )
|
||||||
set(LIBEVDEV_INCLUDE_DIRS ${LIBEVDEV_INCLUDE_DIR} )
|
set(LIBEVDEV_INCLUDE_DIRS ${LIBEVDEV_INCLUDE_DIR} )
|
||||||
|
|
||||||
include(FindPackageHandleStandardArgs)
|
include(FindPackageHandleStandardArgs)
|
||||||
find_package_handle_standard_args(libevdev DEFAULT_MSG
|
find_package_handle_standard_args(LIBEVDEV DEFAULT_MSG
|
||||||
LIBEVDEV_LIBRARY LIBEVDEV_INCLUDE_DIR)
|
LIBEVDEV_LIBRARY LIBEVDEV_INCLUDE_DIR)
|
||||||
|
|
||||||
mark_as_advanced(LIBEVDEV_INCLUDE_DIR LIBEVDEV_LIBRARY )
|
mark_as_advanced(LIBEVDEV_INCLUDE_DIR LIBEVDEV_LIBRARY )
|
|
@ -6,7 +6,7 @@
|
||||||
#
|
#
|
||||||
# vim: expandtab sw=4 ts=4 sts=4:
|
# vim: expandtab sw=4 ts=4 sts=4:
|
||||||
|
|
||||||
include(FindPkgConfig)
|
find_package(PkgConfig QUIET)
|
||||||
pkg_check_modules (PulseAudio_PKG QUIET libpulse)
|
pkg_check_modules (PulseAudio_PKG QUIET libpulse)
|
||||||
|
|
||||||
find_path(PulseAudio_INCLUDE_DIR NAMES pulse/pulseaudio.h
|
find_path(PulseAudio_INCLUDE_DIR NAMES pulse/pulseaudio.h
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
include(FindPkgConfig)
|
find_package(PkgConfig QUIET)
|
||||||
pkg_check_modules(PC_SYSTEMD QUIET "libsystemd")
|
pkg_check_modules(PC_SYSTEMD QUIET "libsystemd")
|
||||||
|
|
||||||
if (PC_SYSTEMD_FOUND)
|
if (PC_SYSTEMD_FOUND)
|
||||||
add_definitions(${PC_SYSTEMD_CFLAGS} ${PC_SYSTEMD_CFLAGS_OTHER})
|
add_definitions(${PC_SYSTEMD_CFLAGS} ${PC_SYSTEMD_CFLAGS_OTHER})
|
||||||
endif(PC_SYSTEMD_FOUND)
|
endif(PC_SYSTEMD_FOUND)
|
|
@ -35,6 +35,7 @@ option(ENABLE_ALSA "Enables ALSA sound backend" ON)
|
||||||
option(ENABLE_PULSEAUDIO "Enables PulseAudio sound backend" ON)
|
option(ENABLE_PULSEAUDIO "Enables PulseAudio sound backend" ON)
|
||||||
option(ENABLE_LLVM "Enables LLVM support, for disassembly" ON)
|
option(ENABLE_LLVM "Enables LLVM support, for disassembly" ON)
|
||||||
option(ENABLE_TESTS "Enables building the unit tests" ON)
|
option(ENABLE_TESTS "Enables building the unit tests" ON)
|
||||||
|
option(ENABLE_VULKAN "Enables vulkan video backend" ON)
|
||||||
option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence, show the current game on Discord" ON)
|
option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence, show the current game on Discord" ON)
|
||||||
|
|
||||||
# Maintainers: if you consider blanket disabling this for your users, please
|
# Maintainers: if you consider blanket disabling this for your users, please
|
||||||
|
@ -117,8 +118,8 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/Binaries)
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/Binary)
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/Binary)
|
||||||
|
|
||||||
if (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
|
if (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
|
||||||
string(APPEND CMAKE_RUNTIME_OUTPUT_DIRECTORY /ARM64)
|
string(APPEND CMAKE_RUNTIME_OUTPUT_DIRECTORY /ARM64)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
|
||||||
|
@ -246,27 +247,17 @@ if(CMAKE_C_COMPILER_ID MATCHES "MSVC")
|
||||||
add_compile_options(/volatile:iso)
|
add_compile_options(/volatile:iso)
|
||||||
# Fix non-conformant lambda behavior (constexpr variables shouldn't need capturing)
|
# Fix non-conformant lambda behavior (constexpr variables shouldn't need capturing)
|
||||||
add_compile_options(/experimental:newLambdaProcessor)
|
add_compile_options(/experimental:newLambdaProcessor)
|
||||||
|
# Fix various other non-conformant behaviors
|
||||||
|
add_compile_options(/Zc:externConstexpr,lambda,preprocessor)
|
||||||
|
|
||||||
|
# Temporarily disable warnings to enable /Zc:preprocessor compatibility with WinSDK headers.
|
||||||
|
add_compile_options(
|
||||||
|
/wd5105 # macro expansion producing 'defined' has undefined behavior
|
||||||
|
)
|
||||||
|
|
||||||
string(APPEND CMAKE_EXE_LINKER_FLAGS " /NXCOMPAT")
|
string(APPEND CMAKE_EXE_LINKER_FLAGS " /NXCOMPAT")
|
||||||
else()
|
else()
|
||||||
add_definitions(-D_DEFAULT_SOURCE)
|
add_definitions(-D_DEFAULT_SOURCE)
|
||||||
check_and_add_flag(HAVE_WALL -Wall)
|
|
||||||
# TODO: would like these but they produce overwhelming amounts of warnings
|
|
||||||
#check_and_add_flag(EXTRA -Wextra)
|
|
||||||
#check_and_add_flag(MISSING_FIELD_INITIALIZERS -Wmissing-field-initializers)
|
|
||||||
#check_and_add_flag(SWITCH_DEFAULT -Wswitch-default)
|
|
||||||
#check_and_add_flag(FLOAT_EQUAL -Wfloat-equal)
|
|
||||||
#check_and_add_flag(CONVERSION -Wconversion)
|
|
||||||
#check_and_add_flag(ZERO_AS_NULL_POINTER_CONSTANT -Wzero-as-null-pointer-constant)
|
|
||||||
check_and_add_flag(TYPE_LIMITS -Wtype-limits)
|
|
||||||
check_and_add_flag(SIGN_COMPARE -Wsign-compare)
|
|
||||||
check_and_add_flag(IGNORED_QUALIFIERS -Wignored-qualifiers)
|
|
||||||
check_and_add_flag(UNINITIALIZED -Wuninitialized)
|
|
||||||
check_and_add_flag(LOGICAL_OP -Wlogical-op)
|
|
||||||
check_and_add_flag(SHADOW -Wshadow)
|
|
||||||
check_and_add_flag(INIT_SELF -Winit-self)
|
|
||||||
check_and_add_flag(MISSING_DECLARATIONS -Wmissing-declarations)
|
|
||||||
check_and_add_flag(MISSING_VARIABLE_DECLARATIONS -Wmissing-variable-declarations)
|
|
||||||
|
|
||||||
# gcc uses some optimizations which might break stuff without this flag
|
# gcc uses some optimizations which might break stuff without this flag
|
||||||
check_and_add_flag(NO_STRICT_ALIASING -fno-strict-aliasing)
|
check_and_add_flag(NO_STRICT_ALIASING -fno-strict-aliasing)
|
||||||
|
@ -311,6 +302,14 @@ if(CMAKE_SYSTEM_NAME MATCHES "Darwin")
|
||||||
# Drop unreachable code and data.
|
# Drop unreachable code and data.
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-dead_strip,-dead_strip_dylibs")
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-dead_strip,-dead_strip_dylibs")
|
||||||
|
|
||||||
|
# Set -fno-objc-exceptions, for consistency with -fno-exceptions earlier.
|
||||||
|
# If we set only -fno-exceptions, fmt fails to compile when included from
|
||||||
|
# Objective-C++ because fmt tries try to use throw because __EXCEPTIONS is defined.
|
||||||
|
#
|
||||||
|
# TODO: Only enable this for Objective-C(++).
|
||||||
|
# We get warnings if we enable this when building regular C(++) code.
|
||||||
|
check_and_add_flag(NO_OBJC_EXCEPTIONS -fno-objc-exceptions)
|
||||||
|
|
||||||
find_library(APPKIT_LIBRARY AppKit)
|
find_library(APPKIT_LIBRARY AppKit)
|
||||||
find_library(APPSERV_LIBRARY ApplicationServices)
|
find_library(APPSERV_LIBRARY ApplicationServices)
|
||||||
find_library(CARBON_LIBRARY Carbon)
|
find_library(CARBON_LIBRARY Carbon)
|
||||||
|
@ -488,8 +487,8 @@ if(OPROFILING)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(ENABLE_EVDEV)
|
if(ENABLE_EVDEV)
|
||||||
find_package(Libudev REQUIRED)
|
find_package(LIBUDEV REQUIRED)
|
||||||
find_package(Libevdev REQUIRED)
|
find_package(LIBEVDEV REQUIRED)
|
||||||
if(LIBUDEV_FOUND AND LIBEVDEV_FOUND)
|
if(LIBUDEV_FOUND AND LIBEVDEV_FOUND)
|
||||||
message(STATUS "libevdev/libudev found, enabling evdev controller backend")
|
message(STATUS "libevdev/libudev found, enabling evdev controller backend")
|
||||||
add_definitions(-DHAVE_LIBUDEV=1)
|
add_definitions(-DHAVE_LIBUDEV=1)
|
||||||
|
@ -543,7 +542,8 @@ if (_M_X86)
|
||||||
add_subdirectory(Externals/Bochs_disasm)
|
add_subdirectory(Externals/Bochs_disasm)
|
||||||
endif()
|
endif()
|
||||||
add_subdirectory(Externals/cpp-optparse)
|
add_subdirectory(Externals/cpp-optparse)
|
||||||
find_package(fmt 6.0)
|
|
||||||
|
find_package(fmt 7.1)
|
||||||
if(fmt_FOUND)
|
if(fmt_FOUND)
|
||||||
message(STATUS "Using shared fmt ${fmt_VERSION}")
|
message(STATUS "Using shared fmt ${fmt_VERSION}")
|
||||||
else()
|
else()
|
||||||
|
@ -551,8 +551,8 @@ else()
|
||||||
message(STATUS "Using static fmt from Externals")
|
message(STATUS "Using static fmt from Externals")
|
||||||
add_subdirectory(Externals/fmt EXCLUDE_FROM_ALL)
|
add_subdirectory(Externals/fmt EXCLUDE_FROM_ALL)
|
||||||
endif()
|
endif()
|
||||||
add_subdirectory(Externals/glslang)
|
|
||||||
add_subdirectory(Externals/imgui)
|
add_subdirectory(Externals/imgui)
|
||||||
|
add_subdirectory(Externals/glslang)
|
||||||
add_subdirectory(Externals/SlippiLib)
|
add_subdirectory(Externals/SlippiLib)
|
||||||
include_directories(Externals/SlippiLib)
|
include_directories(Externals/SlippiLib)
|
||||||
include_directories(Externals/nlohmann)
|
include_directories(Externals/nlohmann)
|
||||||
|
@ -561,6 +561,15 @@ include_directories(Externals/semver/include)
|
||||||
add_subdirectory(Externals/open-vcdiff)
|
add_subdirectory(Externals/open-vcdiff)
|
||||||
include_directories(Externals)
|
include_directories(Externals)
|
||||||
|
|
||||||
|
if(ENABLE_VULKAN)
|
||||||
|
add_definitions(-DHAS_VULKAN)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(NOT WIN32 OR (NOT (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")))
|
||||||
|
# OpenGL is available on all platforms except windows-arm64
|
||||||
|
add_definitions(-DHAS_OPENGL)
|
||||||
|
endif()
|
||||||
|
|
||||||
find_package(pugixml)
|
find_package(pugixml)
|
||||||
if(NOT pugixml_FOUND)
|
if(NOT pugixml_FOUND)
|
||||||
check_vendoring_approved(pugixml)
|
check_vendoring_approved(pugixml)
|
||||||
|
@ -625,9 +634,9 @@ else()
|
||||||
add_subdirectory(Externals/liblzma)
|
add_subdirectory(Externals/liblzma)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
pkg_search_module(ZSTD QUIET libzstd)
|
pkg_check_modules(ZSTD QUIET libzstd>=1.4.0)
|
||||||
if(ZSTD_FOUND AND NOT APPLE)
|
if(ZSTD_FOUND AND NOT APPLE)
|
||||||
message(STATUS "Using shared zstd")
|
message(STATUS "Using shared zstd version: " ${ZSTD_VERSION})
|
||||||
else()
|
else()
|
||||||
check_vendoring_approved(zstd)
|
check_vendoring_approved(zstd)
|
||||||
message(STATUS "Shared zstd not found, falling back to the static library")
|
message(STATUS "Shared zstd not found, falling back to the static library")
|
||||||
|
@ -694,7 +703,7 @@ endif()
|
||||||
add_subdirectory(Externals/soundtouch)
|
add_subdirectory(Externals/soundtouch)
|
||||||
include_directories(Externals/soundtouch)
|
include_directories(Externals/soundtouch)
|
||||||
|
|
||||||
find_package(Cubeb)
|
find_package(CUBEB)
|
||||||
if(CUBEB_FOUND)
|
if(CUBEB_FOUND)
|
||||||
message(STATUS "Using the system cubeb")
|
message(STATUS "Using the system cubeb")
|
||||||
else()
|
else()
|
||||||
|
@ -736,7 +745,7 @@ endif()
|
||||||
|
|
||||||
if(USE_UPNP)
|
if(USE_UPNP)
|
||||||
if(NOT APPLE)
|
if(NOT APPLE)
|
||||||
find_package(Miniupnpc)
|
find_package(MINIUPNPC)
|
||||||
endif()
|
endif()
|
||||||
if(MINIUPNPC_FOUND AND MINIUPNPC_API_VERSION GREATER 8)
|
if(MINIUPNPC_FOUND AND MINIUPNPC_API_VERSION GREATER 8)
|
||||||
message(STATUS "Using shared miniupnpc")
|
message(STATUS "Using shared miniupnpc")
|
||||||
|
@ -749,7 +758,7 @@ if(USE_UPNP)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT APPLE)
|
if(NOT APPLE)
|
||||||
find_package(MbedTLS)
|
find_package(MBEDTLS)
|
||||||
endif()
|
endif()
|
||||||
if(MBEDTLS_FOUND)
|
if(MBEDTLS_FOUND)
|
||||||
message(STATUS "Using shared mbed TLS")
|
message(STATUS "Using shared mbed TLS")
|
||||||
|
@ -804,7 +813,7 @@ if(USE_DISCORD_PRESENCE)
|
||||||
include_directories(Externals/discord-rpc/include)
|
include_directories(Externals/discord-rpc/include)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(Libsystemd)
|
find_package(SYSTEMD)
|
||||||
if(SYSTEMD_FOUND)
|
if(SYSTEMD_FOUND)
|
||||||
message(STATUS "libsystemd found, enabling traversal server watchdog support")
|
message(STATUS "libsystemd found, enabling traversal server watchdog support")
|
||||||
add_definitions(-DHAVE_LIBSYSTEMD)
|
add_definitions(-DHAVE_LIBSYSTEMD)
|
||||||
|
@ -818,6 +827,8 @@ endif()
|
||||||
|
|
||||||
include_directories(Externals/picojson)
|
include_directories(Externals/picojson)
|
||||||
|
|
||||||
|
add_subdirectory(Externals/rangeset)
|
||||||
|
|
||||||
########################################
|
########################################
|
||||||
# Pre-build events: Define configuration variables and write SCM info header
|
# Pre-build events: Define configuration variables and write SCM info header
|
||||||
#
|
#
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
"variables": [
|
"variables": [
|
||||||
{
|
{
|
||||||
"name": "Qt5_DIR",
|
"name": "Qt5_DIR",
|
||||||
"value": "${workspaceRoot}\\Externals\\Qt\\Qt5.14.1\\msvc2019_64\\lib\\cmake\\Qt5",
|
"value": "${workspaceRoot}\\Externals\\Qt\\Qt5.15.0\\msvc2019_64\\lib\\cmake\\Qt5",
|
||||||
"type": "STRING"
|
"type": "STRING"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
"variables": [
|
"variables": [
|
||||||
{
|
{
|
||||||
"name": "Qt5_DIR",
|
"name": "Qt5_DIR",
|
||||||
"value": "${workspaceRoot}\\Externals\\Qt\\Qt5.14.1\\msvc2019_64\\lib\\cmake\\Qt5",
|
"value": "${workspaceRoot}\\Externals\\Qt\\Qt5.15.0\\msvc2019_64\\lib\\cmake\\Qt5",
|
||||||
"type": "STRING"
|
"type": "STRING"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -43,7 +43,7 @@
|
||||||
"variables": [
|
"variables": [
|
||||||
{
|
{
|
||||||
"name": "Qt5_DIR",
|
"name": "Qt5_DIR",
|
||||||
"value": "${workspaceRoot}\\Externals\\Qt\\Qt5.14.1\\msvc2019_arm64\\lib\\cmake\\Qt5",
|
"value": "${workspaceRoot}\\Externals\\Qt\\Qt5.15.0\\msvc2019_arm64\\lib\\cmake\\Qt5",
|
||||||
"type": "STRING"
|
"type": "STRING"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -69,7 +69,7 @@
|
||||||
"variables": [
|
"variables": [
|
||||||
{
|
{
|
||||||
"name": "Qt5_DIR",
|
"name": "Qt5_DIR",
|
||||||
"value": "${workspaceRoot}\\Externals\\Qt\\Qt5.14.1\\msvc2019_arm64\\lib\\cmake\\Qt5",
|
"value": "${workspaceRoot}\\Externals\\Qt\\Qt5.15.0\\msvc2019_arm64\\lib\\cmake\\Qt5",
|
||||||
"type": "STRING"
|
"type": "STRING"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
[Profile]
|
||||||
|
Device = Bluetooth/0/Wii Remote
|
||||||
|
Buttons/A = `A`
|
||||||
|
Buttons/B = `B`
|
||||||
|
Buttons/1 = `1`
|
||||||
|
Buttons/2 = `2`
|
||||||
|
Buttons/- = `-`
|
||||||
|
Buttons/+ = `+`
|
||||||
|
Buttons/Home = `HOME`
|
||||||
|
IMUAccelerometer/Up = `Accel Up`
|
||||||
|
IMUAccelerometer/Down = `Accel Down`
|
||||||
|
IMUAccelerometer/Left = `Accel Left`
|
||||||
|
IMUAccelerometer/Right = `Accel Right`
|
||||||
|
IMUAccelerometer/Forward = `Accel Forward`
|
||||||
|
IMUAccelerometer/Backward = `Accel Backward`
|
||||||
|
IMUGyroscope/Dead Zone = 3
|
||||||
|
IMUGyroscope/Pitch Up = `Gyro Pitch Up`
|
||||||
|
IMUGyroscope/Pitch Down = `Gyro Pitch Down`
|
||||||
|
IMUGyroscope/Roll Left = `Gyro Roll Left`
|
||||||
|
IMUGyroscope/Roll Right = `Gyro Roll Right`
|
||||||
|
IMUGyroscope/Yaw Left = `Gyro Yaw Left`
|
||||||
|
IMUGyroscope/Yaw Right = `Gyro Yaw Right`
|
||||||
|
IMUIR/Enabled = True
|
||||||
|
Extension/Attach MotionPlus = `Attached MotionPlus`
|
||||||
|
Extension = `Attached Extension`
|
||||||
|
Nunchuk/Buttons/C = `Nunchuk C`
|
||||||
|
Nunchuk/Buttons/Z = `Nunchuk Z`
|
||||||
|
Nunchuk/Stick/Up = `Nunchuk Y+`
|
||||||
|
Nunchuk/Stick/Down = `Nunchuk Y-`
|
||||||
|
Nunchuk/Stick/Left = `Nunchuk X-`
|
||||||
|
Nunchuk/Stick/Right = `Nunchuk X+`
|
||||||
|
Nunchuk/Stick/Calibration = 100 100 100 100 100 100 100 100
|
||||||
|
Nunchuk/IMUAccelerometer/Up = `Nunchuk Accel Up`
|
||||||
|
Nunchuk/IMUAccelerometer/Down = `Nunchuk Accel Down`
|
||||||
|
Nunchuk/IMUAccelerometer/Left = `Nunchuk Accel Left`
|
||||||
|
Nunchuk/IMUAccelerometer/Right = `Nunchuk Accel Right`
|
||||||
|
Nunchuk/IMUAccelerometer/Forward = `Nunchuk Accel Forward`
|
||||||
|
Nunchuk/IMUAccelerometer/Backward = `Nunchuk Accel Backward`
|
||||||
|
Classic/Buttons/A = `Classic A`
|
||||||
|
Classic/Buttons/B = `Classic B`
|
||||||
|
Classic/Buttons/X = `Classic X`
|
||||||
|
Classic/Buttons/Y = `Classic Y`
|
||||||
|
Classic/Buttons/ZL = `Classic ZL`
|
||||||
|
Classic/Buttons/ZR = `Classic ZR`
|
||||||
|
Classic/Buttons/- = `Classic -`
|
||||||
|
Classic/Buttons/+ = `Classic +`
|
||||||
|
Classic/Buttons/Home = `Classic HOME`
|
||||||
|
Classic/Left Stick/Up = `Classic Left Y+`
|
||||||
|
Classic/Left Stick/Down = `Classic Left Y-`
|
||||||
|
Classic/Left Stick/Left = `Classic Left X-`
|
||||||
|
Classic/Left Stick/Right = `Classic Left X+`
|
||||||
|
Classic/Left Stick/Calibration = 100 100 100 100 100 100 100 100
|
||||||
|
Classic/Right Stick/Up = `Classic Right Y+`
|
||||||
|
Classic/Right Stick/Down = `Classic Right Y-`
|
||||||
|
Classic/Right Stick/Left = `Classic Right X-`
|
||||||
|
Classic/Right Stick/Right = `Classic Right X+`
|
||||||
|
Classic/Right Stick/Calibration = 100 100 100 100 100 100 100 100
|
||||||
|
Classic/Triggers/L = `Classic L`
|
||||||
|
Classic/Triggers/R = `Classic R`
|
||||||
|
Classic/Triggers/L-Analog = `Classic L-Analog`
|
||||||
|
Classic/Triggers/R-Analog = `Classic R-Analog`
|
||||||
|
Classic/D-Pad/Up = `Classic Up`
|
||||||
|
Classic/D-Pad/Down = `Classic Down`
|
||||||
|
Classic/D-Pad/Left = `Classic Left`
|
||||||
|
Classic/D-Pad/Right = `Classic Right`
|
||||||
|
Rumble/Motor = `Motor`
|
||||||
|
D-Pad/Up = `Up`
|
||||||
|
D-Pad/Down = `Down`
|
||||||
|
D-Pad/Left = `Left`
|
||||||
|
D-Pad/Right = `Right`
|
||||||
|
Options/Battery = `Battery`
|
|
@ -1,91 +0,0 @@
|
||||||
const int char_width = 8;
|
|
||||||
const int char_height = 13;
|
|
||||||
const int char_count = 95;
|
|
||||||
const int char_pixels = char_width*char_height;
|
|
||||||
const float2 char_dim = float2(char_width, char_height);
|
|
||||||
const float2 font_scale = float2(1.0/float(char_width)/float(char_count), 1.0/float(char_height));
|
|
||||||
|
|
||||||
void main()
|
|
||||||
{
|
|
||||||
float2 char_pos = floor(GetCoordinates()*GetResolution()/char_dim);
|
|
||||||
float2 pixel_offset = floor(GetCoordinates()*GetResolution()) - char_pos*char_dim;
|
|
||||||
|
|
||||||
// just a big number
|
|
||||||
float mindiff = float(char_width*char_height) * 100.0;
|
|
||||||
|
|
||||||
float minc = 0.0;
|
|
||||||
float4 mina = float4(0.0, 0.0, 0.0, 0.0);
|
|
||||||
float4 minb = float4(0.0, 0.0, 0.0, 0.0);
|
|
||||||
|
|
||||||
for (int i=0; i<char_count; i++)
|
|
||||||
{
|
|
||||||
float4 ff = float4(0.0, 0.0, 0.0, 0.0);
|
|
||||||
float4 f = float4(0.0, 0.0, 0.0, 0.0);
|
|
||||||
float4 ft = float4(0.0, 0.0, 0.0, 0.0);
|
|
||||||
float4 t = float4(0.0, 0.0, 0.0, 0.0);
|
|
||||||
float4 tt = float4(0.0, 0.0, 0.0, 0.0);
|
|
||||||
|
|
||||||
for (int x=0; x<char_width; x++)
|
|
||||||
{
|
|
||||||
for (int y=0; y<char_height; y++)
|
|
||||||
{
|
|
||||||
float2 tex_pos = char_pos*char_dim + float2(x,y) + 0.5;
|
|
||||||
float4 tex = SampleLocation(tex_pos * GetInvResolution());
|
|
||||||
|
|
||||||
float2 font_pos = float2(x+i*char_width, y) + 0.5;
|
|
||||||
float4 font = SampleFontLocation(font_pos * font_scale);
|
|
||||||
|
|
||||||
// generates sum of texture and font and their squares
|
|
||||||
ff += font*font;
|
|
||||||
f += font;
|
|
||||||
ft += font*tex;
|
|
||||||
t += tex;
|
|
||||||
tt += tex*tex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// The next lines are a bit harder, hf :-)
|
|
||||||
|
|
||||||
// The idea is to find the perfect char with the perfect background color and the perfect font color.
|
|
||||||
// As this is an equation with three unknowns, we can't just try all chars and color combinations.
|
|
||||||
|
|
||||||
// As criterion how "perfect" the selection is, we compare the "mean squared error" of the resulted colors of all chars.
|
|
||||||
// So, now the big issue: how to calculate the MSE without knowing the two colors ...
|
|
||||||
|
|
||||||
// In the next steps, "a" is the font color, "b" is the background color, "f" is the font value at this pixel, "t" is the texture value
|
|
||||||
|
|
||||||
// So the square error of one pixel is:
|
|
||||||
// e = ( t - a⋅f - b⋅(1-f) ) ^ 2
|
|
||||||
|
|
||||||
// In longer:
|
|
||||||
// e = a^2⋅f^2 - 2⋅a⋅b⋅f^2 + 2⋅a⋅b⋅f - 2⋅a⋅f⋅t + b^2⋅f^2 - 2⋅b^2⋅f + b^2 + 2⋅b⋅f⋅t - 2⋅b⋅t + t^2
|
|
||||||
|
|
||||||
// The sum of all errors is: (as shortcut, ff,f,ft,t,tt are now the sums like declared above, sum(1) is the count of pixels)
|
|
||||||
// sum(e) = a^2⋅ff - 2⋅a^2⋅ff + 2⋅a⋅b⋅f - 2⋅a⋅ft + b^2⋅ff - 2⋅b^2⋅f + b^2⋅sum(1) + 2⋅b⋅ft - 2⋅b⋅t + tt
|
|
||||||
|
|
||||||
// To find the minimum, we have to derive this by "a" and "b":
|
|
||||||
// d/da sum(e) = 2⋅a⋅ff + 2⋅b⋅f - 2⋅b⋅ff - 2⋅ft
|
|
||||||
// d/db sum(e) = 2⋅a⋅f - 2⋅a⋅ff - 4⋅b⋅f + 2⋅b⋅ff + 2⋅b⋅sum(1) + 2⋅ft - 2⋅t
|
|
||||||
|
|
||||||
// So, both equations must be zero at minimum and there is only one solution.
|
|
||||||
|
|
||||||
float4 a = (f*ft - ff*t + f*t - ft*float(char_pixels)) / (f*f - ff*float(char_pixels));
|
|
||||||
float4 b = (f*ft - ff*t) / (f*f - ff*float(char_pixels));
|
|
||||||
|
|
||||||
float4 diff = a*a*ff + 2.0*a*b*f - 2.0*a*b*ff - 2.0*a*ft + b*b *(-2.0*f + ff + float(char_pixels)) + 2.0*b*ft - 2.0*b*t + tt;
|
|
||||||
float diff_f = dot(diff, float4(1.0, 1.0, 1.0, 1.0));
|
|
||||||
|
|
||||||
if (diff_f < mindiff)
|
|
||||||
{
|
|
||||||
mindiff = diff_f;
|
|
||||||
minc = float(i);
|
|
||||||
mina = a;
|
|
||||||
minb = b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float2 font_pos_res = float2(minc * float(char_width), 0.0) + pixel_offset + 0.5;
|
|
||||||
|
|
||||||
float4 col = SampleFontLocation(font_pos_res * font_scale);
|
|
||||||
SetOutput(mina * col + minb * (float4(1.0,1.0,1.0,1.0) - col));
|
|
||||||
}
|
|
BIN
Externals/MoltenVK/libvulkan.dylib
vendored
BIN
Externals/MoltenVK/libvulkan.dylib
vendored
Binary file not shown.
4
Externals/MoltenVK/version.txt
vendored
4
Externals/MoltenVK/version.txt
vendored
|
@ -1,3 +1 @@
|
||||||
MoltenVK/macOS/dynamic/libMoltenVK.dylib from vulkansdk-macos-1.2.131.2, renamed to libvulkan.dylib
|
MoltenVK from https://github.com/KhronosGroup/MoltenVK, commit b9b78def172074872bfbb1015ccf75eeec554ae2
|
||||||
|
|
||||||
Downloaded from: https://sdk.lunarg.com/sdk/download/1.2.131.2/mac/vulkansdk-macos-1.2.131.2.tar.gz
|
|
||||||
|
|
2
Externals/Qt
vendored
2
Externals/Qt
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit a14e340be1ad66e0cb1d8180485896a9134800e0
|
Subproject commit 5ab31b5fdf1cdc59b9e8c82a0f7c12d5fe878cd8
|
6
Externals/curl/lib/CMakeLists.txt
vendored
6
Externals/curl/lib/CMakeLists.txt
vendored
|
@ -1,7 +1,7 @@
|
||||||
if(NOT CMAKE_SYSTEM_NAME MATCHES "Windows")
|
if(CMAKE_SYSTEM_NAME MATCHES "Windows")
|
||||||
add_definitions(-DHAVE_CONFIG_H)
|
add_definitions(-DUSE_SCHANNEL -DUSE_WINDOWS_SSPI)
|
||||||
else()
|
else()
|
||||||
add_definitions(-DUSE_SCHANNEL -DUSE_WINDOWS_SSPI)
|
add_definitions(-DHAVE_CONFIG_H)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
include_directories(.)
|
include_directories(.)
|
||||||
|
|
34
Externals/fmt/.gitignore
vendored
34
Externals/fmt/.gitignore
vendored
|
@ -1,34 +0,0 @@
|
||||||
.vscode/
|
|
||||||
|
|
||||||
*.iml
|
|
||||||
.idea/
|
|
||||||
.externalNativeBuild/
|
|
||||||
.gradle/
|
|
||||||
gradle/
|
|
||||||
gradlew*
|
|
||||||
local.properties
|
|
||||||
build/
|
|
||||||
|
|
||||||
bin/
|
|
||||||
/_CPack_Packages
|
|
||||||
/CMakeScripts
|
|
||||||
/doc/doxyxml
|
|
||||||
/doc/html
|
|
||||||
virtualenv
|
|
||||||
/Testing
|
|
||||||
/install_manifest.txt
|
|
||||||
*~
|
|
||||||
*.a
|
|
||||||
*.so*
|
|
||||||
*.xcodeproj
|
|
||||||
*.zip
|
|
||||||
cmake_install.cmake
|
|
||||||
CPack*.cmake
|
|
||||||
fmt-*.cmake
|
|
||||||
CTestTestfile.cmake
|
|
||||||
CMakeCache.txt
|
|
||||||
CMakeFiles
|
|
||||||
FMT.build
|
|
||||||
Makefile
|
|
||||||
run-msbuild.bat
|
|
||||||
fmt.pc
|
|
146
Externals/fmt/CMakeLists.txt
vendored
146
Externals/fmt/CMakeLists.txt
vendored
|
@ -1,10 +1,8 @@
|
||||||
cmake_minimum_required(VERSION 3.1.0)
|
cmake_minimum_required(VERSION 3.1...3.18)
|
||||||
|
|
||||||
# Use newer policies if available, up to most recent tested version of CMake.
|
# Fallback for using newer policies on CMake <3.12.
|
||||||
if(${CMAKE_VERSION} VERSION_LESS 3.11)
|
if(${CMAKE_VERSION} VERSION_LESS 3.12)
|
||||||
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
|
||||||
else()
|
|
||||||
cmake_policy(VERSION 3.11)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Determine if fmt is built as a subproject (using add_subdirectory)
|
# Determine if fmt is built as a subproject (using add_subdirectory)
|
||||||
|
@ -24,15 +22,40 @@ function(join result_var)
|
||||||
set(${result_var} "${result}" PARENT_SCOPE)
|
set(${result_var} "${result}" PARENT_SCOPE)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
|
include(CMakeParseArguments)
|
||||||
|
|
||||||
|
# Sets a cache variable with a docstring joined from multiple arguments:
|
||||||
|
# set(<variable> <value>... CACHE <type> <docstring>...)
|
||||||
|
# This allows splitting a long docstring for readability.
|
||||||
|
function(set_verbose)
|
||||||
|
# cmake_parse_arguments is broken in CMake 3.4 (cannot parse CACHE) so use
|
||||||
|
# list instead.
|
||||||
|
list(GET ARGN 0 var)
|
||||||
|
list(REMOVE_AT ARGN 0)
|
||||||
|
list(GET ARGN 0 val)
|
||||||
|
list(REMOVE_AT ARGN 0)
|
||||||
|
list(REMOVE_AT ARGN 0)
|
||||||
|
list(GET ARGN 0 type)
|
||||||
|
list(REMOVE_AT ARGN 0)
|
||||||
|
join(doc ${ARGN})
|
||||||
|
set(${var} ${val} CACHE ${type} ${doc})
|
||||||
|
endfunction()
|
||||||
|
|
||||||
# Set the default CMAKE_BUILD_TYPE to Release.
|
# Set the default CMAKE_BUILD_TYPE to Release.
|
||||||
# This should be done before the project command since the latter can set
|
# This should be done before the project command since the latter can set
|
||||||
# CMAKE_BUILD_TYPE itself (it does so for nmake).
|
# CMAKE_BUILD_TYPE itself (it does so for nmake).
|
||||||
if (MASTER_PROJECT AND NOT CMAKE_BUILD_TYPE)
|
if (MASTER_PROJECT AND NOT CMAKE_BUILD_TYPE)
|
||||||
join(doc "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or "
|
set_verbose(CMAKE_BUILD_TYPE Release CACHE STRING
|
||||||
"CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.")
|
"Choose the type of build, options are: None(CMAKE_CXX_FLAGS or "
|
||||||
set(CMAKE_BUILD_TYPE Release CACHE STRING ${doc})
|
"CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
project(FMT CXX)
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
set_verbose(FMT_INC_DIR ${CMAKE_INSTALL_INCLUDEDIR} CACHE STRING
|
||||||
|
"Installation directory for include files, a relative path that "
|
||||||
|
"will be joined with ${CMAKE_INSTALL_PREFIX} or an absolute path.")
|
||||||
|
|
||||||
option(FMT_PEDANTIC "Enable extra warnings and expensive tests." OFF)
|
option(FMT_PEDANTIC "Enable extra warnings and expensive tests." OFF)
|
||||||
option(FMT_WERROR "Halt the compilation with an error on compiler warnings."
|
option(FMT_WERROR "Halt the compilation with an error on compiler warnings."
|
||||||
OFF)
|
OFF)
|
||||||
|
@ -43,8 +66,7 @@ option(FMT_INSTALL "Generate the install target." ${MASTER_PROJECT})
|
||||||
option(FMT_TEST "Generate the test target." ${MASTER_PROJECT})
|
option(FMT_TEST "Generate the test target." ${MASTER_PROJECT})
|
||||||
option(FMT_FUZZ "Generate the fuzz target." OFF)
|
option(FMT_FUZZ "Generate the fuzz target." OFF)
|
||||||
option(FMT_CUDA_TEST "Generate the cuda-test target." OFF)
|
option(FMT_CUDA_TEST "Generate the cuda-test target." OFF)
|
||||||
|
option(FMT_OS "Include core requiring OS (Windows/Posix) " ON)
|
||||||
project(FMT CXX)
|
|
||||||
|
|
||||||
# Get version from core.h
|
# Get version from core.h
|
||||||
file(READ include/fmt/core.h core_h)
|
file(READ include/fmt/core.h core_h)
|
||||||
|
@ -61,26 +83,35 @@ message(STATUS "Version: ${FMT_VERSION}")
|
||||||
|
|
||||||
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
|
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
|
||||||
|
|
||||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
if (NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY)
|
||||||
|
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||||
|
endif ()
|
||||||
|
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
|
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(CheckCXXCompilerFlag)
|
||||||
|
include(JoinPaths)
|
||||||
|
|
||||||
set(FMT_REQUIRED_FEATURES cxx_auto_type cxx_variadic_templates)
|
list(FIND CMAKE_CXX_COMPILE_FEATURES "cxx_variadic_templates" index)
|
||||||
|
if (${index} GREATER -1)
|
||||||
|
# Use cxx_variadic_templates instead of more appropriate cxx_std_11 for
|
||||||
|
# compatibility with older CMake versions.
|
||||||
|
set(FMT_REQUIRED_FEATURES cxx_variadic_templates)
|
||||||
|
endif ()
|
||||||
|
message(STATUS "Required features: ${FMT_REQUIRED_FEATURES}")
|
||||||
|
|
||||||
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||||
set(PEDANTIC_COMPILE_FLAGS -pedantic-errors -Wall -Wextra -pedantic
|
set(PEDANTIC_COMPILE_FLAGS -pedantic-errors -Wall -Wextra -pedantic
|
||||||
-Wold-style-cast -Wundef
|
-Wold-style-cast -Wundef
|
||||||
-Wredundant-decls -Wwrite-strings -Wpointer-arith
|
-Wredundant-decls -Wwrite-strings -Wpointer-arith
|
||||||
-Wcast-qual -Wformat=2 -Wmissing-include-dirs
|
-Wcast-qual -Wformat=2 -Wmissing-include-dirs
|
||||||
-Wcast-align -Wnon-virtual-dtor
|
-Wcast-align
|
||||||
-Wctor-dtor-privacy -Wdisabled-optimization
|
-Wctor-dtor-privacy -Wdisabled-optimization
|
||||||
-Winvalid-pch -Woverloaded-virtual
|
-Winvalid-pch -Woverloaded-virtual
|
||||||
-Wconversion -Wswitch-enum
|
-Wconversion -Wswitch-enum -Wundef
|
||||||
-Wno-ctor-dtor-privacy -Wno-format-nonliteral -Wno-shadow)
|
-Wno-ctor-dtor-privacy -Wno-format-nonliteral)
|
||||||
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6)
|
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6)
|
||||||
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wnoexcept
|
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wnoexcept
|
||||||
-Wno-dangling-else -Wno-unused-local-typedefs)
|
-Wno-dangling-else -Wno-unused-local-typedefs)
|
||||||
|
@ -98,8 +129,8 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||||
set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -pedantic -Wconversion
|
set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -pedantic -Wconversion -Wundef
|
||||||
-Wno-sign-conversion -Wdeprecated -Wweak-vtables)
|
-Wdeprecated -Wweak-vtables)
|
||||||
check_cxx_compiler_flag(-Wzero-as-null-pointer-constant HAS_NULLPTR_WARNING)
|
check_cxx_compiler_flag(-Wzero-as-null-pointer-constant HAS_NULLPTR_WARNING)
|
||||||
if (HAS_NULLPTR_WARNING)
|
if (HAS_NULLPTR_WARNING)
|
||||||
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS}
|
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS}
|
||||||
|
@ -123,7 +154,9 @@ if (MASTER_PROJECT AND CMAKE_GENERATOR MATCHES "Visual Studio")
|
||||||
set(MSBUILD_SETUP "call \"${WINSDK_SETENV}\"")
|
set(MSBUILD_SETUP "call \"${WINSDK_SETENV}\"")
|
||||||
endif ()
|
endif ()
|
||||||
# Set FrameworkPathOverride to get rid of MSB3644 warnings.
|
# Set FrameworkPathOverride to get rid of MSB3644 warnings.
|
||||||
set(netfxpath "C:\\Program Files\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.0")
|
join(netfxpath
|
||||||
|
"C:\\Program Files\\Reference Assemblies\\Microsoft\\Framework\\"
|
||||||
|
".NETFramework\\v4.0")
|
||||||
file(WRITE run-msbuild.bat "
|
file(WRITE run-msbuild.bat "
|
||||||
${MSBUILD_SETUP}
|
${MSBUILD_SETUP}
|
||||||
${CMAKE_MAKE_PROGRAM} -p:FrameworkPathOverride=\"${netfxpath}\" %*")
|
${CMAKE_MAKE_PROGRAM} -p:FrameworkPathOverride=\"${netfxpath}\" %*")
|
||||||
|
@ -151,8 +184,12 @@ 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 chrono.h color.h compile.h core.h format.h format-inl.h
|
add_headers(FMT_HEADERS chrono.h color.h compile.h core.h format.h format-inl.h
|
||||||
locale.h ostream.h posix.h printf.h ranges.h)
|
locale.h os.h ostream.h posix.h printf.h ranges.h)
|
||||||
set(FMT_SOURCES src/format.cc src/posix.cc)
|
if (FMT_OS)
|
||||||
|
set(FMT_SOURCES src/format.cc src/os.cc)
|
||||||
|
else()
|
||||||
|
set(FMT_SOURCES src/format.cc)
|
||||||
|
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)
|
||||||
|
@ -161,6 +198,13 @@ if (HAVE_STRTOD_L)
|
||||||
target_compile_definitions(fmt PUBLIC FMT_LOCALE)
|
target_compile_definitions(fmt PUBLIC FMT_LOCALE)
|
||||||
endif ()
|
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 ()
|
||||||
|
@ -172,14 +216,24 @@ target_compile_features(fmt INTERFACE ${FMT_REQUIRED_FEATURES})
|
||||||
|
|
||||||
target_include_directories(fmt PUBLIC
|
target_include_directories(fmt PUBLIC
|
||||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
|
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
|
||||||
$<INSTALL_INTERFACE:include>)
|
$<INSTALL_INTERFACE:${FMT_INC_DIR}>)
|
||||||
|
|
||||||
|
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}
|
||||||
DEBUG_POSTFIX d)
|
DEBUG_POSTFIX "${FMT_DEBUG_POSTFIX}")
|
||||||
|
|
||||||
|
# Set FMT_LIB_NAME for pkg-config fmt.pc. We cannot use the OUTPUT_NAME target
|
||||||
|
# property because it's not set by default.
|
||||||
|
set(FMT_LIB_NAME fmt)
|
||||||
|
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||||
|
set(FMT_LIB_NAME ${FMT_LIB_NAME}${FMT_DEBUG_POSTFIX})
|
||||||
|
endif ()
|
||||||
|
|
||||||
if (BUILD_SHARED_LIBS)
|
if (BUILD_SHARED_LIBS)
|
||||||
if (UNIX AND NOT APPLE AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
|
if (UNIX AND NOT APPLE AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "SunOS" AND
|
||||||
|
NOT EMSCRIPTEN)
|
||||||
# Fix rpmlint warning:
|
# Fix rpmlint warning:
|
||||||
# unused-direct-shlib-dependency /usr/lib/libformat.so.1.1.0 /lib/libm.so.6.
|
# unused-direct-shlib-dependency /usr/lib/libformat.so.1.1.0 /lib/libm.so.6.
|
||||||
target_link_libraries(fmt -Wl,--as-needed)
|
target_link_libraries(fmt -Wl,--as-needed)
|
||||||
|
@ -194,43 +248,42 @@ add_library(fmt-header-only INTERFACE)
|
||||||
add_library(fmt::fmt-header-only ALIAS fmt-header-only)
|
add_library(fmt::fmt-header-only ALIAS fmt-header-only)
|
||||||
|
|
||||||
target_compile_definitions(fmt-header-only INTERFACE FMT_HEADER_ONLY=1)
|
target_compile_definitions(fmt-header-only INTERFACE FMT_HEADER_ONLY=1)
|
||||||
|
|
||||||
target_compile_features(fmt-header-only INTERFACE ${FMT_REQUIRED_FEATURES})
|
target_compile_features(fmt-header-only INTERFACE ${FMT_REQUIRED_FEATURES})
|
||||||
|
|
||||||
target_include_directories(fmt-header-only INTERFACE
|
target_include_directories(fmt-header-only INTERFACE
|
||||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
|
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
|
||||||
$<INSTALL_INTERFACE:include>)
|
$<INSTALL_INTERFACE:${FMT_INC_DIR}>)
|
||||||
|
|
||||||
# Install targets.
|
# Install targets.
|
||||||
if (FMT_INSTALL)
|
if (FMT_INSTALL)
|
||||||
include(GNUInstallDirs)
|
|
||||||
include(CMakePackageConfigHelpers)
|
include(CMakePackageConfigHelpers)
|
||||||
set(FMT_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/fmt CACHE STRING
|
set_verbose(FMT_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/fmt CACHE STRING
|
||||||
"Installation directory for cmake files, relative to ${CMAKE_INSTALL_PREFIX}.")
|
"Installation directory for cmake files, a relative path that "
|
||||||
|
"will be joined with ${CMAKE_INSTALL_PREFIX} or an absolute "
|
||||||
|
"path.")
|
||||||
set(version_config ${PROJECT_BINARY_DIR}/fmt-config-version.cmake)
|
set(version_config ${PROJECT_BINARY_DIR}/fmt-config-version.cmake)
|
||||||
set(project_config ${PROJECT_BINARY_DIR}/fmt-config.cmake)
|
set(project_config ${PROJECT_BINARY_DIR}/fmt-config.cmake)
|
||||||
set(pkgconfig ${PROJECT_BINARY_DIR}/fmt.pc)
|
set(pkgconfig ${PROJECT_BINARY_DIR}/fmt.pc)
|
||||||
set(targets_export_name fmt-targets)
|
set(targets_export_name fmt-targets)
|
||||||
|
|
||||||
set (INSTALL_TARGETS fmt)
|
set_verbose(FMT_LIB_DIR ${CMAKE_INSTALL_LIBDIR} CACHE STRING
|
||||||
if (TARGET fmt-header-only)
|
"Installation directory for libraries, a relative path that "
|
||||||
set(INSTALL_TARGETS ${INSTALL_TARGETS} fmt-header-only)
|
"will be joined to ${CMAKE_INSTALL_PREFIX} or an absolute path.")
|
||||||
endif ()
|
|
||||||
|
|
||||||
set(FMT_LIB_DIR ${CMAKE_INSTALL_LIBDIR} CACHE STRING
|
set_verbose(FMT_PKGCONFIG_DIR ${CMAKE_INSTALL_LIBDIR}/pkgconfig CACHE PATH
|
||||||
"Installation directory for libraries, relative to ${CMAKE_INSTALL_PREFIX}.")
|
"Installation directory for pkgconfig (.pc) files, a relative "
|
||||||
|
"path that will be joined with ${CMAKE_INSTALL_PREFIX} or an "
|
||||||
set(FMT_INC_DIR ${CMAKE_INSTALL_INCLUDEDIR}/fmt CACHE STRING
|
"absolute path.")
|
||||||
"Installation directory for include files, relative to ${CMAKE_INSTALL_PREFIX}.")
|
|
||||||
|
|
||||||
set(FMT_PKGCONFIG_DIR ${CMAKE_INSTALL_LIBDIR}/pkgconfig CACHE PATH
|
|
||||||
"Installation directory for pkgconfig (.pc) files, relative to ${CMAKE_INSTALL_PREFIX}.")
|
|
||||||
|
|
||||||
# Generate the version, config and target files into the build directory.
|
# Generate the version, config and target files into the build directory.
|
||||||
write_basic_package_version_file(
|
write_basic_package_version_file(
|
||||||
${version_config}
|
${version_config}
|
||||||
VERSION ${FMT_VERSION}
|
VERSION ${FMT_VERSION}
|
||||||
COMPATIBILITY AnyNewerVersion)
|
COMPATIBILITY AnyNewerVersion)
|
||||||
|
|
||||||
|
join_paths(libdir_for_pc_file "\${exec_prefix}" "${FMT_LIB_DIR}")
|
||||||
|
join_paths(includedir_for_pc_file "\${prefix}" "${FMT_INC_DIR}")
|
||||||
|
|
||||||
configure_file(
|
configure_file(
|
||||||
"${PROJECT_SOURCE_DIR}/support/cmake/fmt.pc.in"
|
"${PROJECT_SOURCE_DIR}/support/cmake/fmt.pc.in"
|
||||||
"${pkgconfig}"
|
"${pkgconfig}"
|
||||||
|
@ -239,6 +292,8 @@ if (FMT_INSTALL)
|
||||||
${PROJECT_SOURCE_DIR}/support/cmake/fmt-config.cmake.in
|
${PROJECT_SOURCE_DIR}/support/cmake/fmt-config.cmake.in
|
||||||
${project_config}
|
${project_config}
|
||||||
INSTALL_DESTINATION ${FMT_CMAKE_DIR})
|
INSTALL_DESTINATION ${FMT_CMAKE_DIR})
|
||||||
|
|
||||||
|
set(INSTALL_TARGETS fmt fmt-header-only)
|
||||||
# Use a namespace because CMake provides better diagnostics for namespaced
|
# Use a namespace because CMake provides better diagnostics for namespaced
|
||||||
# imported targets.
|
# imported targets.
|
||||||
export(TARGETS ${INSTALL_TARGETS} NAMESPACE fmt::
|
export(TARGETS ${INSTALL_TARGETS} NAMESPACE fmt::
|
||||||
|
@ -259,7 +314,7 @@ 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})
|
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 ()
|
||||||
|
|
||||||
|
@ -275,13 +330,20 @@ endif ()
|
||||||
# Control fuzzing independent of the unit tests.
|
# Control fuzzing independent of the unit tests.
|
||||||
if (FMT_FUZZ)
|
if (FMT_FUZZ)
|
||||||
add_subdirectory(test/fuzzing)
|
add_subdirectory(test/fuzzing)
|
||||||
|
|
||||||
|
# The FMT_FUZZ macro is used to prevent resource exhaustion in fuzzing
|
||||||
|
# mode and make fuzzing practically possible. It is similar to
|
||||||
|
# FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION but uses a different name to
|
||||||
|
# avoid interfering with fuzzing of projects that use {fmt}.
|
||||||
|
# See also https://llvm.org/docs/LibFuzzer.html#fuzzer-friendly-build-mode.
|
||||||
|
target_compile_definitions(fmt PUBLIC FMT_FUZZ)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
set(gitignore ${PROJECT_SOURCE_DIR}/.gitignore)
|
set(gitignore ${PROJECT_SOURCE_DIR}/.gitignore)
|
||||||
if (MASTER_PROJECT AND EXISTS ${gitignore})
|
if (MASTER_PROJECT AND EXISTS ${gitignore})
|
||||||
# Get the list of ignored files from .gitignore.
|
# Get the list of ignored files from .gitignore.
|
||||||
file (STRINGS ${gitignore} lines)
|
file (STRINGS ${gitignore} lines)
|
||||||
LIST(REMOVE_ITEM lines /doc/html)
|
list(REMOVE_ITEM lines /doc/html)
|
||||||
foreach (line ${lines})
|
foreach (line ${lines})
|
||||||
string(REPLACE "." "[.]" line "${line}")
|
string(REPLACE "." "[.]" line "${line}")
|
||||||
string(REPLACE "*" ".*" line "${line}")
|
string(REPLACE "*" ".*" line "${line}")
|
||||||
|
|
3
Externals/fmt/CONTRIBUTING.md
vendored
3
Externals/fmt/CONTRIBUTING.md
vendored
|
@ -14,4 +14,7 @@ exceptions:
|
||||||
* snake_case should be used instead of UpperCamelCase for function and type
|
* snake_case should be used instead of UpperCamelCase for function and type
|
||||||
names
|
names
|
||||||
|
|
||||||
|
All documentation must adhere to the [Google Developer Documentation Style
|
||||||
|
Guide](https://developers.google.com/style).
|
||||||
|
|
||||||
Thanks for contributing!
|
Thanks for contributing!
|
||||||
|
|
960
Externals/fmt/ChangeLog.rst
vendored
960
Externals/fmt/ChangeLog.rst
vendored
File diff suppressed because it is too large
Load diff
441
Externals/fmt/README.rst
vendored
441
Externals/fmt/README.rst
vendored
|
@ -7,153 +7,174 @@
|
||||||
.. image:: https://ci.appveyor.com/api/projects/status/ehjkiefde6gucy1v
|
.. image:: https://ci.appveyor.com/api/projects/status/ehjkiefde6gucy1v
|
||||||
:target: https://ci.appveyor.com/project/vitaut/fmt
|
:target: https://ci.appveyor.com/project/vitaut/fmt
|
||||||
|
|
||||||
.. image:: https://oss-fuzz-build-logs.storage.googleapis.com/badges/libfmt.svg
|
.. image:: https://oss-fuzz-build-logs.storage.googleapis.com/badges/fmt.svg
|
||||||
:alt: fmt is continuously fuzzed att oss-fuzz
|
:alt: fmt is continuously fuzzed at oss-fuzz
|
||||||
:target: https://bugs.chromium.org/p/oss-fuzz/issues/list?colspec=ID%20Type%20Component%20Status%20Proj%20Reported%20Owner%20Summary&q=proj%3Dlibfmt&can=1
|
:target: https://bugs.chromium.org/p/oss-fuzz/issues/list?\
|
||||||
|
colspec=ID%20Type%20Component%20Status%20Proj%20Reported%20Owner%20\
|
||||||
|
Summary&q=proj%3Dfmt&can=1
|
||||||
|
|
||||||
.. image:: https://img.shields.io/badge/stackoverflow-fmt-blue.svg
|
.. image:: https://img.shields.io/badge/stackoverflow-fmt-blue.svg
|
||||||
:alt: Ask questions at StackOverflow with the tag fmt
|
:alt: Ask questions at StackOverflow with the tag fmt
|
||||||
:target: http://stackoverflow.com/questions/tagged/fmt
|
:target: https://stackoverflow.com/questions/tagged/fmt
|
||||||
|
|
||||||
**{fmt}** is an open-source formatting library for C++.
|
**{fmt}** is an open-source formatting library providing a fast and safe
|
||||||
It can be used as a safe and fast alternative to (s)printf and iostreams.
|
alternative to C stdio and C++ iostreams.
|
||||||
|
|
||||||
`Documentation <https://fmt.dev/latest/>`__
|
If you like this project, please consider donating to BYSOL,
|
||||||
|
an initiative to help victims of political repressions in Belarus:
|
||||||
|
https://www.facebook.com/donate/759400044849707/108388587646909/.
|
||||||
|
|
||||||
Q&A: ask questions on `StackOverflow with the tag fmt <http://stackoverflow.com/questions/tagged/fmt>`_.
|
`Documentation <https://fmt.dev>`__
|
||||||
|
|
||||||
|
Q&A: ask questions on `StackOverflow with the tag fmt
|
||||||
|
<https://stackoverflow.com/questions/tagged/fmt>`_.
|
||||||
|
|
||||||
|
Try {fmt} in `Compiler Explorer <https://godbolt.org/z/Eq5763>`_.
|
||||||
|
|
||||||
Features
|
Features
|
||||||
--------
|
--------
|
||||||
|
|
||||||
* Replacement-based `format API <https://fmt.dev/dev/api.html>`_ with
|
* Simple `format API <https://fmt.dev/latest/api.html>`_ with positional arguments
|
||||||
positional arguments for localization.
|
for localization
|
||||||
* `Format string syntax <https://fmt.dev/dev/syntax.html>`_ similar to the one
|
* Implementation of `C++20 std::format
|
||||||
of `str.format <https://docs.python.org/3/library/stdtypes.html#str.format>`_
|
<https://en.cppreference.com/w/cpp/utility/format>`__
|
||||||
in Python.
|
* `Format string syntax <https://fmt.dev/latest/syntax.html>`_ similar to Python's
|
||||||
|
`format <https://docs.python.org/3/library/stdtypes.html#str.format>`_
|
||||||
|
* Fast IEEE 754 floating-point formatter with correct rounding, shortness and
|
||||||
|
round-trip guarantees
|
||||||
* Safe `printf implementation
|
* Safe `printf implementation
|
||||||
<https://fmt.dev/latest/api.html#printf-formatting>`_ including
|
<https://fmt.dev/latest/api.html#printf-formatting>`_ including the POSIX
|
||||||
the POSIX extension for positional arguments.
|
extension for positional arguments
|
||||||
* Implementation of `C++20 std::format <https://fmt.dev/Text%20Formatting.html>`__.
|
* Extensibility: `support for user-defined types
|
||||||
* Support for user-defined types.
|
<https://fmt.dev/latest/api.html#formatting-user-defined-types>`_
|
||||||
* High performance: faster than common standard library implementations of
|
* High performance: faster than common standard library implementations of
|
||||||
`printf <http://en.cppreference.com/w/cpp/io/c/fprintf>`_ and
|
``(s)printf``, iostreams, ``to_string`` and ``to_chars``, see `Speed tests`_
|
||||||
iostreams. See `Speed tests`_ and `Fast integer to string conversion in C++
|
and `Converting a hundred million integers to strings per second
|
||||||
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_.
|
<http://www.zverovich.net/2020/06/13/fast-int-to-string-revisited.html>`_
|
||||||
* Small code size both in terms of source code (the minimum configuration
|
* Small code size both in terms of source code with the minimum configuration
|
||||||
consists of just three header files, ``core.h``, ``format.h`` and
|
consisting of just three files, ``core.h``, ``format.h`` and ``format-inl.h``,
|
||||||
``format-inl.h``) and compiled code. See `Compile time and code bloat`_.
|
and compiled code; see `Compile time and code bloat`_
|
||||||
* Reliability: the library has an extensive set of `unit tests
|
* Reliability: the library has an extensive set of `tests
|
||||||
<https://github.com/fmtlib/fmt/tree/master/test>`_ and is continuously fuzzed.
|
<https://github.com/fmtlib/fmt/tree/master/test>`_ and is `continuously fuzzed
|
||||||
|
<https://bugs.chromium.org/p/oss-fuzz/issues/list?colspec=ID%20Type%20
|
||||||
|
Component%20Status%20Proj%20Reported%20Owner%20Summary&q=proj%3Dfmt&can=1>`_
|
||||||
* Safety: the library is fully type safe, errors in format strings can be
|
* Safety: the library is fully type safe, errors in format strings can be
|
||||||
reported at compile time, automatic memory management prevents buffer overflow
|
reported at compile time, automatic memory management prevents buffer overflow
|
||||||
errors.
|
errors
|
||||||
* Ease of use: small self-contained code base, no external dependencies,
|
* Ease of use: small self-contained code base, no external dependencies,
|
||||||
permissive MIT `license
|
permissive MIT `license
|
||||||
<https://github.com/fmtlib/fmt/blob/master/LICENSE.rst>`_
|
<https://github.com/fmtlib/fmt/blob/master/LICENSE.rst>`_
|
||||||
* `Portability <https://fmt.dev/latest/index.html#portability>`_ with
|
* `Portability <https://fmt.dev/latest/index.html#portability>`_ with
|
||||||
consistent output across platforms and support for older compilers.
|
consistent output across platforms and support for older compilers
|
||||||
* Clean warning-free codebase even on high warning levels
|
* Clean warning-free codebase even on high warning levels such as
|
||||||
(``-Wall -Wextra -pedantic``).
|
``-Wall -Wextra -pedantic``
|
||||||
* Support for wide strings.
|
* Locale-independence by default
|
||||||
* Optional header-only configuration enabled with the ``FMT_HEADER_ONLY`` macro.
|
* Optional header-only configuration enabled with the ``FMT_HEADER_ONLY`` macro
|
||||||
|
|
||||||
See the `documentation <https://fmt.dev/latest/>`_ for more details.
|
See the `documentation <https://fmt.dev>`_ for more details.
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
|
|
||||||
Print ``Hello, world!`` to ``stdout``:
|
**Print to stdout** (`run <https://godbolt.org/z/Tevcjh>`_)
|
||||||
|
|
||||||
.. code:: c++
|
.. code:: c++
|
||||||
|
|
||||||
fmt::print("Hello, {}!", "world"); // Python-like format string syntax
|
#include <fmt/core.h>
|
||||||
fmt::printf("Hello, %s!", "world"); // printf format string syntax
|
|
||||||
|
int main() {
|
||||||
|
fmt::print("Hello, world!\n");
|
||||||
|
}
|
||||||
|
|
||||||
Format a string and use positional arguments:
|
**Format a string** (`run <https://godbolt.org/z/oK8h33>`_)
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
std::string s = fmt::format("The answer is {}.", 42);
|
||||||
|
// s == "The answer is 42."
|
||||||
|
|
||||||
|
**Format a string using positional arguments** (`run <https://godbolt.org/z/Yn7Txe>`_)
|
||||||
|
|
||||||
.. code:: c++
|
.. code:: c++
|
||||||
|
|
||||||
std::string s = fmt::format("I'd rather be {1} than {0}.", "right", "happy");
|
std::string s = fmt::format("I'd rather be {1} than {0}.", "right", "happy");
|
||||||
// s == "I'd rather be happy than right."
|
// s == "I'd rather be happy than right."
|
||||||
|
|
||||||
Check a format string at compile time:
|
**Print chrono durations** (`run <https://godbolt.org/z/K8s4Mc>`_)
|
||||||
|
|
||||||
.. code:: c++
|
.. code:: c++
|
||||||
|
|
||||||
// test.cc
|
#include <fmt/chrono.h>
|
||||||
#include <fmt/format.h>
|
|
||||||
std::string s = format(FMT_STRING("{2}"), 42);
|
|
||||||
|
|
||||||
.. code::
|
int main() {
|
||||||
|
using namespace std::literals::chrono_literals;
|
||||||
$ c++ -Iinclude -std=c++14 test.cc
|
fmt::print("Default format: {} {}\n", 42s, 100ms);
|
||||||
...
|
fmt::print("strftime-like format: {:%H:%M:%S}\n", 3h + 15min + 30s);
|
||||||
test.cc:4:17: note: in instantiation of function template specialization 'fmt::v5::format<S, int>' requested here
|
|
||||||
std::string s = format(FMT_STRING("{2}"), 42);
|
|
||||||
^
|
|
||||||
include/fmt/core.h:778:19: note: non-constexpr function 'on_error' cannot be used in a constant expression
|
|
||||||
ErrorHandler::on_error(message);
|
|
||||||
^
|
|
||||||
include/fmt/format.h:2226:16: note: in call to '&checker.context_->on_error(&"argument index out of range"[0])'
|
|
||||||
context_.on_error("argument index out of range");
|
|
||||||
^
|
|
||||||
|
|
||||||
Use {fmt} as a safe portable replacement for ``itoa``
|
|
||||||
(`godbolt <https://godbolt.org/g/NXmpU4>`_):
|
|
||||||
|
|
||||||
.. code:: c++
|
|
||||||
|
|
||||||
fmt::memory_buffer buf;
|
|
||||||
format_to(buf, "{}", 42); // replaces itoa(42, buffer, 10)
|
|
||||||
format_to(buf, "{:x}", 42); // replaces itoa(42, buffer, 16)
|
|
||||||
// access the string with to_string(buf) or buf.data()
|
|
||||||
|
|
||||||
Format objects of user-defined types via a simple `extension API
|
|
||||||
<https://fmt.dev/latest/api.html#formatting-user-defined-types>`_:
|
|
||||||
|
|
||||||
.. code:: c++
|
|
||||||
|
|
||||||
#include "fmt/format.h"
|
|
||||||
|
|
||||||
struct date {
|
|
||||||
int year, month, day;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct fmt::formatter<date> {
|
|
||||||
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
|
|
||||||
|
|
||||||
template <typename FormatContext>
|
|
||||||
auto format(const date& d, FormatContext& ctx) {
|
|
||||||
return format_to(ctx.out(), "{}-{}-{}", d.year, d.month, d.day);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::string s = fmt::format("The date is {}", date{2012, 12, 9});
|
|
||||||
// s == "The date is 2012-12-9"
|
|
||||||
|
|
||||||
Create your own functions similar to `format
|
|
||||||
<https://fmt.dev/latest/api.html#format>`_ and
|
|
||||||
`print <https://fmt.dev/latest/api.html#print>`_
|
|
||||||
which take arbitrary arguments (`godbolt <https://godbolt.org/g/MHjHVf>`_):
|
|
||||||
|
|
||||||
.. code:: c++
|
|
||||||
|
|
||||||
// Prints formatted error message.
|
|
||||||
void vreport_error(const char* format, fmt::format_args args) {
|
|
||||||
fmt::print("Error: ");
|
|
||||||
fmt::vprint(format, args);
|
|
||||||
}
|
|
||||||
template <typename... Args>
|
|
||||||
void report_error(const char* format, const Args & ... args) {
|
|
||||||
vreport_error(format, fmt::make_format_args(args...));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
report_error("file not found: {}", path);
|
Output::
|
||||||
|
|
||||||
Note that ``vreport_error`` is not parameterized on argument types which can
|
Default format: 42s 100ms
|
||||||
improve compile times and reduce code size compared to a fully parameterized
|
strftime-like format: 03:15:30
|
||||||
version.
|
|
||||||
|
**Print a container** (`run <https://godbolt.org/z/MjsY7c>`_)
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <fmt/ranges.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
std::vector<int> v = {1, 2, 3};
|
||||||
|
fmt::print("{}\n", v);
|
||||||
|
}
|
||||||
|
|
||||||
|
Output::
|
||||||
|
|
||||||
|
{1, 2, 3}
|
||||||
|
|
||||||
|
**Check a format string at compile time**
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
std::string s = fmt::format(FMT_STRING("{:d}"), "don't panic");
|
||||||
|
|
||||||
|
This gives a compile-time error because ``d`` is an invalid format specifier for
|
||||||
|
a string.
|
||||||
|
|
||||||
|
**Write a file from a single thread**
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
#include <fmt/os.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
auto out = fmt::output_file("guide.txt");
|
||||||
|
out.print("Don't {}", "Panic");
|
||||||
|
}
|
||||||
|
|
||||||
|
This can be `5 to 9 times faster than fprintf
|
||||||
|
<http://www.zverovich.net/2020/08/04/optimal-file-buffer-size.html>`_.
|
||||||
|
|
||||||
|
**Print with colors and text styles**
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
#include <fmt/color.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
fmt::print(fg(fmt::color::crimson) | fmt::emphasis::bold,
|
||||||
|
"Hello, {}!\n", "world");
|
||||||
|
fmt::print(fg(fmt::color::floral_white) | bg(fmt::color::slate_gray) |
|
||||||
|
fmt::emphasis::underline, "Hello, {}!\n", "мир");
|
||||||
|
fmt::print(fg(fmt::color::steel_blue) | fmt::emphasis::italic,
|
||||||
|
"Hello, {}!\n", "世界");
|
||||||
|
}
|
||||||
|
|
||||||
|
Output on a modern terminal:
|
||||||
|
|
||||||
|
.. image:: https://user-images.githubusercontent.com/
|
||||||
|
576385/88485597-d312f600-cf2b-11ea-9cbe-61f535a86e28.png
|
||||||
|
|
||||||
Benchmarks
|
Benchmarks
|
||||||
----------
|
----------
|
||||||
|
@ -174,18 +195,20 @@ Folly Format folly::format 2.23
|
||||||
{fmt} is the fastest of the benchmarked methods, ~35% faster than ``printf``.
|
{fmt} is the fastest of the benchmarked methods, ~35% faster than ``printf``.
|
||||||
|
|
||||||
The above results were generated by building ``tinyformat_test.cpp`` on macOS
|
The above results were generated by building ``tinyformat_test.cpp`` on macOS
|
||||||
10.14.6 with ``clang++ -O3 -DSPEED_TEST -DHAVE_FORMAT``, and taking the best of
|
10.14.6 with ``clang++ -O3 -DNDEBUG -DSPEED_TEST -DHAVE_FORMAT``, and taking the
|
||||||
three runs. In the test, the format string ``"%0.10f:%04d:%+g:%s:%p:%c:%%\n"``
|
best of three runs. In the test, the format string ``"%0.10f:%04d:%+g:%s:%p:%c:%%\n"``
|
||||||
or equivalent is filled 2,000,000 times with output sent to ``/dev/null``; for
|
or equivalent is filled 2,000,000 times with output sent to ``/dev/null``; for
|
||||||
further details refer to the `source
|
further details refer to the `source
|
||||||
<https://github.com/fmtlib/format-benchmark/blob/master/tinyformat_test.cpp>`_.
|
<https://github.com/fmtlib/format-benchmark/blob/master/tinyformat_test.cpp>`_.
|
||||||
|
|
||||||
{fmt} is 10x faster than ``std::ostringstream`` and ``sprintf`` on floating-point
|
{fmt} is up to 20-30x faster than ``std::ostringstream`` and ``sprintf`` on
|
||||||
formatting (`dtoa-benchmark <https://github.com/fmtlib/dtoa-benchmark>`_)
|
floating-point formatting (`dtoa-benchmark <https://github.com/fmtlib/dtoa-benchmark>`_)
|
||||||
and as fast as `double-conversion <https://github.com/google/double-conversion>`_:
|
and faster than `double-conversion <https://github.com/google/double-conversion>`_ and
|
||||||
|
`ryu <https://github.com/ulfjack/ryu>`_:
|
||||||
|
|
||||||
.. image:: https://user-images.githubusercontent.com/576385/69767160-cdaca400-112f-11ea-9fc5-347c9f83caad.png
|
.. image:: https://user-images.githubusercontent.com/576385/
|
||||||
:target: https://fmt.dev/unknown_mac64_clang10.0.html
|
95684665-11719600-0ba8-11eb-8e5b-972ff4e49428.png
|
||||||
|
:target: https://fmt.dev/unknown_mac64_clang12.0.html
|
||||||
|
|
||||||
Compile time and code bloat
|
Compile time and code bloat
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -264,36 +287,33 @@ or the bloat test::
|
||||||
Projects using this library
|
Projects using this library
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
||||||
* `0 A.D. <http://play0ad.com/>`_: A free, open-source, cross-platform real-time
|
* `0 A.D. <https://play0ad.com/>`_: a free, open-source, cross-platform
|
||||||
strategy game
|
real-time strategy game
|
||||||
|
|
||||||
* `AMPL/MP <https://github.com/ampl/mp>`_:
|
* `AMPL/MP <https://github.com/ampl/mp>`_:
|
||||||
An open-source library for mathematical programming
|
an open-source library for mathematical programming
|
||||||
|
|
||||||
* `AvioBook <https://www.aviobook.aero/en>`_: A comprehensive aircraft
|
* `Aseprite <https://github.com/aseprite/aseprite>`_:
|
||||||
|
animated sprite editor & pixel art tool
|
||||||
|
|
||||||
|
* `AvioBook <https://www.aviobook.aero/en>`_: a comprehensive aircraft
|
||||||
operations suite
|
operations suite
|
||||||
|
|
||||||
* `Celestia <https://celestia.space/>`_: Real-time 3D visualization of space
|
* `Blizzard Battle.net <https://battle.net/>`_: an online gaming platform
|
||||||
|
|
||||||
|
* `Celestia <https://celestia.space/>`_: real-time 3D visualization of space
|
||||||
|
|
||||||
* `Ceph <https://ceph.com/>`_: A scalable distributed storage system
|
* `Ceph <https://ceph.com/>`_: a scalable distributed storage system
|
||||||
|
|
||||||
* `ccache <https://ccache.dev/>`_: A compiler cache
|
* `ccache <https://ccache.dev/>`_: a compiler cache
|
||||||
|
|
||||||
|
* `ClickHouse <https://github.com/ClickHouse/ClickHouse>`_: analytical database
|
||||||
|
management system
|
||||||
|
|
||||||
* `CUAUV <http://cuauv.org/>`_: Cornell University's autonomous underwater
|
* `CUAUV <http://cuauv.org/>`_: Cornell University's autonomous underwater
|
||||||
vehicle
|
vehicle
|
||||||
|
|
||||||
* `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_:
|
* `Drake <https://drake.mit.edu/>`_: a planning, control, and analysis toolbox
|
||||||
Player vs Player Gaming Network with tweaks
|
|
||||||
|
|
||||||
* `KBEngine <http://kbengine.org/>`_: An open-source MMOG server engine
|
|
||||||
|
|
||||||
* `Keypirinha <http://keypirinha.com/>`_: A semantic launcher for Windows
|
|
||||||
|
|
||||||
* `Kodi <https://kodi.tv/>`_ (formerly xbmc): Home theater software
|
|
||||||
|
|
||||||
* `Lifeline <https://github.com/peter-clark/lifeline>`_: A 2D game
|
|
||||||
|
|
||||||
* `Drake <http://drake.mit.edu/>`_: A planning, control, and analysis toolbox
|
|
||||||
for nonlinear dynamical systems (MIT)
|
for nonlinear dynamical systems (MIT)
|
||||||
|
|
||||||
* `Envoy <https://lyft.github.io/envoy/>`_: C++ L7 proxy and communication bus
|
* `Envoy <https://lyft.github.io/envoy/>`_: C++ L7 proxy and communication bus
|
||||||
|
@ -301,49 +321,76 @@ Projects using this library
|
||||||
|
|
||||||
* `FiveM <https://fivem.net/>`_: a modification framework for GTA V
|
* `FiveM <https://fivem.net/>`_: a modification framework for GTA V
|
||||||
|
|
||||||
* `MongoDB <https://mongodb.com/>`_: Distributed document database
|
* `Folly <https://github.com/facebook/folly>`_: Facebook open-source library
|
||||||
|
|
||||||
* `MongoDB Smasher <https://github.com/duckie/mongo_smasher>`_: A small tool to
|
* `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_:
|
||||||
|
Player vs Player Gaming Network with tweaks
|
||||||
|
|
||||||
|
* `KBEngine <https://github.com/kbengine/kbengine>`_: an open-source MMOG server
|
||||||
|
engine
|
||||||
|
|
||||||
|
* `Keypirinha <https://keypirinha.com/>`_: a semantic launcher for Windows
|
||||||
|
|
||||||
|
* `Kodi <https://kodi.tv/>`_ (formerly xbmc): home theater software
|
||||||
|
|
||||||
|
* `Knuth <https://kth.cash/>`_: high-performance Bitcoin full-node
|
||||||
|
|
||||||
|
* `Microsoft Verona <https://github.com/microsoft/verona>`_:
|
||||||
|
research programming language for concurrent ownership
|
||||||
|
|
||||||
|
* `MongoDB <https://mongodb.com/>`_: distributed document database
|
||||||
|
|
||||||
|
* `MongoDB Smasher <https://github.com/duckie/mongo_smasher>`_: a small tool to
|
||||||
generate randomized datasets
|
generate randomized datasets
|
||||||
|
|
||||||
* `OpenSpace <http://openspaceproject.com/>`_: An open-source astrovisualization
|
* `OpenSpace <https://openspaceproject.com/>`_: an open-source
|
||||||
framework
|
astrovisualization framework
|
||||||
|
|
||||||
* `PenUltima Online (POL) <http://www.polserver.com/>`_:
|
* `PenUltima Online (POL) <https://www.polserver.com/>`_:
|
||||||
An MMO server, compatible with most Ultima Online clients
|
an MMO server, compatible with most Ultima Online clients
|
||||||
|
|
||||||
* `quasardb <https://www.quasardb.net/>`_: A distributed, high-performance,
|
* `PyTorch <https://github.com/pytorch/pytorch>`_: an open-source machine
|
||||||
|
learning library
|
||||||
|
|
||||||
|
* `quasardb <https://www.quasardb.net/>`_: a distributed, high-performance,
|
||||||
associative database
|
associative database
|
||||||
|
|
||||||
|
* `Quill <https://github.com/odygrd/quill>`_: asynchronous low-latency logging library
|
||||||
|
|
||||||
* `readpe <https://bitbucket.org/sys_dev/readpe>`_: Read Portable Executable
|
* `QKW <https://github.com/ravijanjam/qkw>`_: generalizing aliasing to simplify
|
||||||
|
navigation, and executing complex multi-line terminal command sequences
|
||||||
|
|
||||||
* `redis-cerberus <https://github.com/HunanTV/redis-cerberus>`_: A Redis cluster
|
* `redis-cerberus <https://github.com/HunanTV/redis-cerberus>`_: a Redis cluster
|
||||||
proxy
|
proxy
|
||||||
|
|
||||||
* `rpclib <http://rpclib.net/>`_: A modern C++ msgpack-RPC server and client
|
* `redpanda <https://vectorized.io/redpanda>`_: a 10x faster Kafka® replacement
|
||||||
|
for mission critical systems written in C++
|
||||||
|
|
||||||
|
* `rpclib <http://rpclib.net/>`_: a modern C++ msgpack-RPC server and client
|
||||||
library
|
library
|
||||||
|
|
||||||
* `Saddy <https://github.com/mamontov-cpp/saddy-graphics-engine-2d>`_:
|
* `Salesforce Analytics Cloud
|
||||||
Small crossplatform 2D graphic engine
|
<https://www.salesforce.com/analytics-cloud/overview/>`_:
|
||||||
|
business intelligence software
|
||||||
|
|
||||||
* `Salesforce Analytics Cloud <http://www.salesforce.com/analytics-cloud/overview/>`_:
|
* `Scylla <https://www.scylladb.com/>`_: a Cassandra-compatible NoSQL data store
|
||||||
Business intelligence software
|
|
||||||
|
|
||||||
* `Scylla <http://www.scylladb.com/>`_: A Cassandra-compatible NoSQL data store
|
|
||||||
that can handle 1 million transactions per second on a single server
|
that can handle 1 million transactions per second on a single server
|
||||||
|
|
||||||
* `Seastar <http://www.seastar-project.org/>`_: An advanced, open-source C++
|
* `Seastar <http://www.seastar-project.org/>`_: an advanced, open-source C++
|
||||||
framework for high-performance server applications on modern hardware
|
framework for high-performance server applications on modern hardware
|
||||||
|
|
||||||
* `spdlog <https://github.com/gabime/spdlog>`_: Super fast C++ logging library
|
* `spdlog <https://github.com/gabime/spdlog>`_: super fast C++ logging library
|
||||||
|
|
||||||
* `Stellar <https://www.stellar.org/>`_: Financial platform
|
* `Stellar <https://www.stellar.org/>`_: financial platform
|
||||||
|
|
||||||
* `Touch Surgery <https://www.touchsurgery.com/>`_: Surgery simulator
|
* `Touch Surgery <https://www.touchsurgery.com/>`_: surgery simulator
|
||||||
|
|
||||||
* `TrinityCore <https://github.com/TrinityCore/TrinityCore>`_: Open-source
|
* `TrinityCore <https://github.com/TrinityCore/TrinityCore>`_: open-source
|
||||||
MMORPG framework
|
MMORPG framework
|
||||||
|
|
||||||
|
* `Windows Terminal <https://github.com/microsoft/terminal>`_: the new Windows
|
||||||
|
terminal
|
||||||
|
|
||||||
`More... <https://github.com/search?q=fmtlib&type=Code>`_
|
`More... <https://github.com/search?q=fmtlib&type=Code>`_
|
||||||
|
|
||||||
If you are aware of other projects using this library, please let me know
|
If you are aware of other projects using this library, please let me know
|
||||||
|
@ -368,7 +415,7 @@ The good thing about ``printf`` is that it is pretty fast and readily available
|
||||||
being a part of the C standard library. The main drawback is that it
|
being a part of the C standard library. The main drawback is that it
|
||||||
doesn't support user-defined types. ``printf`` also has safety issues although
|
doesn't support user-defined types. ``printf`` also has safety issues although
|
||||||
they are somewhat mitigated with `__attribute__ ((format (printf, ...))
|
they are somewhat mitigated with `__attribute__ ((format (printf, ...))
|
||||||
<http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>`_ in GCC.
|
<https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>`_ in GCC.
|
||||||
There is a POSIX extension that adds positional arguments required for
|
There is a POSIX extension that adds positional arguments required for
|
||||||
`i18n <https://en.wikipedia.org/wiki/Internationalization_and_localization>`_
|
`i18n <https://en.wikipedia.org/wiki/Internationalization_and_localization>`_
|
||||||
to ``printf`` but it is not a part of C99 and may not be available on some
|
to ``printf`` but it is not a part of C99 and may not be available on some
|
||||||
|
@ -400,15 +447,15 @@ Boost Format
|
||||||
|
|
||||||
This is a very powerful library which supports both ``printf``-like format
|
This is a very powerful library which supports both ``printf``-like format
|
||||||
strings and positional arguments. Its main drawback is performance. According to
|
strings and positional arguments. Its main drawback is performance. According to
|
||||||
various benchmarks it is much slower than other methods considered here. Boost
|
various, benchmarks it is much slower than other methods considered here. Boost
|
||||||
Format also has excessive build times and severe code bloat issues (see
|
Format also has excessive build times and severe code bloat issues (see
|
||||||
`Benchmarks`_).
|
`Benchmarks`_).
|
||||||
|
|
||||||
FastFormat
|
FastFormat
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
|
||||||
This is an interesting library which is fast, safe and has positional
|
This is an interesting library which is fast, safe and has positional arguments.
|
||||||
arguments. However it has significant limitations, citing its author:
|
However, it has significant limitations, citing its author:
|
||||||
|
|
||||||
Three features that have no hope of being accommodated within the
|
Three features that have no hope of being accommodated within the
|
||||||
current design are:
|
current design are:
|
||||||
|
@ -417,8 +464,8 @@ arguments. However it has significant limitations, citing its author:
|
||||||
* Octal/hexadecimal encoding
|
* Octal/hexadecimal encoding
|
||||||
* Runtime width/alignment specification
|
* Runtime width/alignment specification
|
||||||
|
|
||||||
It is also quite big and has a heavy dependency, STLSoft, which might be
|
It is also quite big and has a heavy dependency, STLSoft, which might be too
|
||||||
too restrictive for using it in some projects.
|
restrictive for using it in some projects.
|
||||||
|
|
||||||
Boost Spirit.Karma
|
Boost Spirit.Karma
|
||||||
~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
@ -426,32 +473,9 @@ Boost Spirit.Karma
|
||||||
This is not really a formatting library but I decided to include it here for
|
This is not really a formatting library but I decided to include it here for
|
||||||
completeness. As iostreams, it suffers from the problem of mixing verbatim text
|
completeness. As iostreams, it suffers from the problem of mixing verbatim text
|
||||||
with arguments. The library is pretty fast, but slower on integer formatting
|
with arguments. The library is pretty fast, but slower on integer formatting
|
||||||
than ``fmt::format_int`` on Karma's own benchmark,
|
than ``fmt::format_to`` with format string compilation on Karma's own benchmark,
|
||||||
see `Fast integer to string conversion in C++
|
see `Converting a hundred million integers to strings per second
|
||||||
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_.
|
<http://www.zverovich.net/2020/06/13/fast-int-to-string-revisited.html>`_.
|
||||||
|
|
||||||
FAQ
|
|
||||||
---
|
|
||||||
|
|
||||||
Q: how can I capture formatting arguments and format them later?
|
|
||||||
|
|
||||||
A: use ``std::tuple``:
|
|
||||||
|
|
||||||
.. code:: c++
|
|
||||||
|
|
||||||
template <typename... Args>
|
|
||||||
auto capture(const Args&... args) {
|
|
||||||
return std::make_tuple(args...);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto print_message = [](const auto&... args) {
|
|
||||||
fmt::print(args...);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Capture and store arguments:
|
|
||||||
auto args = capture("{} {}", 42, "foo");
|
|
||||||
// Do formatting:
|
|
||||||
std::apply(print_message, args);
|
|
||||||
|
|
||||||
License
|
License
|
||||||
-------
|
-------
|
||||||
|
@ -459,18 +483,19 @@ License
|
||||||
{fmt} is distributed under the MIT `license
|
{fmt} is distributed under the MIT `license
|
||||||
<https://github.com/fmtlib/fmt/blob/master/LICENSE.rst>`_.
|
<https://github.com/fmtlib/fmt/blob/master/LICENSE.rst>`_.
|
||||||
|
|
||||||
The `Format String Syntax
|
Documentation License
|
||||||
<https://fmt.dev/latest/syntax.html>`_
|
---------------------
|
||||||
section in the documentation is based on the one from Python `string module
|
|
||||||
documentation <https://docs.python.org/3/library/string.html#module-string>`_
|
|
||||||
adapted for the current library. For this reason the documentation is
|
|
||||||
distributed under the Python Software Foundation license available in
|
|
||||||
`doc/python-license.txt
|
|
||||||
<https://raw.github.com/fmtlib/fmt/master/doc/python-license.txt>`_.
|
|
||||||
It only applies if you distribute the documentation of fmt.
|
|
||||||
|
|
||||||
Acknowledgments
|
The `Format String Syntax <https://fmt.dev/latest/syntax.html>`_
|
||||||
---------------
|
section in the documentation is based on the one from Python `string module
|
||||||
|
documentation <https://docs.python.org/3/library/string.html#module-string>`_.
|
||||||
|
For this reason the documentation is distributed under the Python Software
|
||||||
|
Foundation license available in `doc/python-license.txt
|
||||||
|
<https://raw.github.com/fmtlib/fmt/master/doc/python-license.txt>`_.
|
||||||
|
It only applies if you distribute the documentation of {fmt}.
|
||||||
|
|
||||||
|
Maintainers
|
||||||
|
-----------
|
||||||
|
|
||||||
The {fmt} library is maintained by Victor Zverovich (`vitaut
|
The {fmt} library is maintained by Victor Zverovich (`vitaut
|
||||||
<https://github.com/vitaut>`_) and Jonathan Müller (`foonathan
|
<https://github.com/vitaut>`_) and Jonathan Müller (`foonathan
|
||||||
|
@ -479,23 +504,3 @@ See `Contributors <https://github.com/fmtlib/fmt/graphs/contributors>`_ and
|
||||||
`Releases <https://github.com/fmtlib/fmt/releases>`_ for some of the names.
|
`Releases <https://github.com/fmtlib/fmt/releases>`_ for some of the names.
|
||||||
Let us know if your contribution is not listed or mentioned incorrectly and
|
Let us know if your contribution is not listed or mentioned incorrectly and
|
||||||
we'll make it right.
|
we'll make it right.
|
||||||
|
|
||||||
The benchmark section of this readme file and the performance tests are taken
|
|
||||||
from the excellent `tinyformat <https://github.com/c42f/tinyformat>`_ library
|
|
||||||
written by Chris Foster. Boost Format library is acknowledged transitively
|
|
||||||
since it had some influence on tinyformat.
|
|
||||||
Some ideas used in the implementation are borrowed from `Loki
|
|
||||||
<http://loki-lib.sourceforge.net/>`_ SafeFormat and `Diagnostic API
|
|
||||||
<http://clang.llvm.org/doxygen/classclang_1_1Diagnostic.html>`_ in
|
|
||||||
`Clang <http://clang.llvm.org/>`_.
|
|
||||||
Format string syntax and the documentation are based on Python's `str.format
|
|
||||||
<https://docs.python.org/3/library/stdtypes.html#str.format>`_.
|
|
||||||
Thanks `Doug Turnbull <https://github.com/softwaredoug>`_ for his valuable
|
|
||||||
comments and contribution to the design of the type-safe API and
|
|
||||||
`Gregory Czajkowski <https://github.com/gcflymoto>`_ for implementing binary
|
|
||||||
formatting. Thanks `Ruslan Baratov <https://github.com/ruslo>`_ for comprehensive
|
|
||||||
`comparison of integer formatting algorithms <https://github.com/ruslo/int-dec-format-tests>`_
|
|
||||||
and useful comments regarding performance, `Boris Kaul <https://github.com/localvoid>`_ for
|
|
||||||
`C++ counting digits benchmark <https://github.com/localvoid/cxx-benchmark-count-digits>`_.
|
|
||||||
Thanks to `CarterLi <https://github.com/CarterLi>`_ for contributing various
|
|
||||||
improvements to the code.
|
|
||||||
|
|
250
Externals/fmt/include/fmt/chrono.h
vendored
250
Externals/fmt/include/fmt/chrono.h
vendored
|
@ -8,14 +8,14 @@
|
||||||
#ifndef FMT_CHRONO_H_
|
#ifndef FMT_CHRONO_H_
|
||||||
#define FMT_CHRONO_H_
|
#define FMT_CHRONO_H_
|
||||||
|
|
||||||
#include "format.h"
|
|
||||||
#include "locale.h"
|
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <locale>
|
#include <locale>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "format.h"
|
||||||
|
#include "locale.h"
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// Enable safe chrono durations, unless explicitly disabled.
|
// Enable safe chrono durations, unless explicitly disabled.
|
||||||
|
@ -48,7 +48,7 @@ FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
|
||||||
// From fits in To without any problem.
|
// From fits in To without any problem.
|
||||||
} else {
|
} else {
|
||||||
// From does not always fit in To, resort to a dynamic check.
|
// From does not always fit in To, resort to a dynamic check.
|
||||||
if (from < T::min() || from > T::max()) {
|
if (from < (T::min)() || from > (T::max)()) {
|
||||||
// outside range.
|
// outside range.
|
||||||
ec = 1;
|
ec = 1;
|
||||||
return {};
|
return {};
|
||||||
|
@ -72,43 +72,27 @@ FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
|
||||||
static_assert(F::is_integer, "From must be integral");
|
static_assert(F::is_integer, "From must be integral");
|
||||||
static_assert(T::is_integer, "To must be integral");
|
static_assert(T::is_integer, "To must be integral");
|
||||||
|
|
||||||
if (F::is_signed && !T::is_signed) {
|
if (detail::const_check(F::is_signed && !T::is_signed)) {
|
||||||
// From may be negative, not allowed!
|
// From may be negative, not allowed!
|
||||||
if (fmt::internal::is_negative(from)) {
|
if (fmt::detail::is_negative(from)) {
|
||||||
ec = 1;
|
ec = 1;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// From is positive. Can it always fit in To?
|
// From is positive. Can it always fit in To?
|
||||||
if (F::digits <= T::digits) {
|
if (F::digits > T::digits &&
|
||||||
// yes, From always fits in To.
|
from > static_cast<From>(detail::max_value<To>())) {
|
||||||
} else {
|
ec = 1;
|
||||||
// from may not fit in To, we have to do a dynamic check
|
return {};
|
||||||
if (from > static_cast<From>(T::max())) {
|
|
||||||
ec = 1;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!F::is_signed && T::is_signed) {
|
if (!F::is_signed && T::is_signed && F::digits >= T::digits &&
|
||||||
// can from be held in To?
|
from > static_cast<From>(detail::max_value<To>())) {
|
||||||
if (F::digits < T::digits) {
|
ec = 1;
|
||||||
// yes, From always fits in To.
|
return {};
|
||||||
} else {
|
|
||||||
// from may not fit in To, we have to do a dynamic check
|
|
||||||
if (from > static_cast<From>(T::max())) {
|
|
||||||
// outside range.
|
|
||||||
ec = 1;
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return static_cast<To>(from); // Lossless conversion.
|
||||||
// reaching here means all is ok for lossless conversion.
|
}
|
||||||
return static_cast<To>(from);
|
|
||||||
|
|
||||||
} // function
|
|
||||||
|
|
||||||
template <typename To, typename From,
|
template <typename To, typename From,
|
||||||
FMT_ENABLE_IF(std::is_same<From, To>::value)>
|
FMT_ENABLE_IF(std::is_same<From, To>::value)>
|
||||||
|
@ -141,7 +125,7 @@ FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec) {
|
||||||
|
|
||||||
// catch the only happy case
|
// catch the only happy case
|
||||||
if (std::isfinite(from)) {
|
if (std::isfinite(from)) {
|
||||||
if (from >= T::lowest() && from <= T::max()) {
|
if (from >= T::lowest() && from <= (T::max)()) {
|
||||||
return static_cast<To>(from);
|
return static_cast<To>(from);
|
||||||
}
|
}
|
||||||
// not within range.
|
// not within range.
|
||||||
|
@ -190,17 +174,16 @@ To safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
|
||||||
// safe conversion to IntermediateRep
|
// safe conversion to IntermediateRep
|
||||||
IntermediateRep count =
|
IntermediateRep count =
|
||||||
lossless_integral_conversion<IntermediateRep>(from.count(), ec);
|
lossless_integral_conversion<IntermediateRep>(from.count(), ec);
|
||||||
if (ec) {
|
if (ec) return {};
|
||||||
return {};
|
|
||||||
}
|
|
||||||
// multiply with Factor::num without overflow or underflow
|
// multiply with Factor::num without overflow or underflow
|
||||||
if (Factor::num != 1) {
|
if (detail::const_check(Factor::num != 1)) {
|
||||||
const auto max1 = internal::max_value<IntermediateRep>() / Factor::num;
|
const auto max1 = detail::max_value<IntermediateRep>() / Factor::num;
|
||||||
if (count > max1) {
|
if (count > max1) {
|
||||||
ec = 1;
|
ec = 1;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
const auto min1 = std::numeric_limits<IntermediateRep>::min() / Factor::num;
|
const auto min1 =
|
||||||
|
(std::numeric_limits<IntermediateRep>::min)() / Factor::num;
|
||||||
if (count < min1) {
|
if (count < min1) {
|
||||||
ec = 1;
|
ec = 1;
|
||||||
return {};
|
return {};
|
||||||
|
@ -208,17 +191,9 @@ To safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
|
||||||
count *= Factor::num;
|
count *= Factor::num;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this can't go wrong, right? den>0 is checked earlier.
|
if (detail::const_check(Factor::den != 1)) count /= Factor::den;
|
||||||
if (Factor::den != 1) {
|
auto tocount = lossless_integral_conversion<typename To::rep>(count, ec);
|
||||||
count /= Factor::den;
|
return ec ? To() : To(tocount);
|
||||||
}
|
|
||||||
// convert to the to type, safely
|
|
||||||
using ToRep = typename To::rep;
|
|
||||||
const ToRep tocount = lossless_integral_conversion<ToRep>(count, ec);
|
|
||||||
if (ec) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
return To{tocount};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -269,7 +244,7 @@ To safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
|
||||||
|
|
||||||
// multiply with Factor::num without overflow or underflow
|
// multiply with Factor::num without overflow or underflow
|
||||||
if (Factor::num != 1) {
|
if (Factor::num != 1) {
|
||||||
constexpr auto max1 = internal::max_value<IntermediateRep>() /
|
constexpr auto max1 = detail::max_value<IntermediateRep>() /
|
||||||
static_cast<IntermediateRep>(Factor::num);
|
static_cast<IntermediateRep>(Factor::num);
|
||||||
if (count > max1) {
|
if (count > max1) {
|
||||||
ec = 1;
|
ec = 1;
|
||||||
|
@ -306,12 +281,12 @@ To safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
|
||||||
// Usage: f FMT_NOMACRO()
|
// Usage: f FMT_NOMACRO()
|
||||||
#define FMT_NOMACRO
|
#define FMT_NOMACRO
|
||||||
|
|
||||||
namespace internal {
|
namespace detail {
|
||||||
inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); }
|
inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); }
|
||||||
inline null<> localtime_s(...) { return null<>(); }
|
inline null<> localtime_s(...) { return null<>(); }
|
||||||
inline null<> gmtime_r(...) { return null<>(); }
|
inline null<> gmtime_r(...) { return null<>(); }
|
||||||
inline null<> gmtime_s(...) { return null<>(); }
|
inline null<> gmtime_s(...) { return null<>(); }
|
||||||
} // namespace internal
|
} // namespace detail
|
||||||
|
|
||||||
// Thread-safe replacement for std::localtime
|
// Thread-safe replacement for std::localtime
|
||||||
inline std::tm localtime(std::time_t time) {
|
inline std::tm localtime(std::time_t time) {
|
||||||
|
@ -322,22 +297,22 @@ inline std::tm localtime(std::time_t time) {
|
||||||
dispatcher(std::time_t t) : time_(t) {}
|
dispatcher(std::time_t t) : time_(t) {}
|
||||||
|
|
||||||
bool run() {
|
bool run() {
|
||||||
using namespace fmt::internal;
|
using namespace fmt::detail;
|
||||||
return handle(localtime_r(&time_, &tm_));
|
return handle(localtime_r(&time_, &tm_));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool handle(std::tm* tm) { return tm != nullptr; }
|
bool handle(std::tm* tm) { return tm != nullptr; }
|
||||||
|
|
||||||
bool handle(internal::null<>) {
|
bool handle(detail::null<>) {
|
||||||
using namespace fmt::internal;
|
using namespace fmt::detail;
|
||||||
return fallback(localtime_s(&tm_, &time_));
|
return fallback(localtime_s(&tm_, &time_));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fallback(int res) { return res == 0; }
|
bool fallback(int res) { return res == 0; }
|
||||||
|
|
||||||
#if !FMT_MSC_VER
|
#if !FMT_MSC_VER
|
||||||
bool fallback(internal::null<>) {
|
bool fallback(detail::null<>) {
|
||||||
using namespace fmt::internal;
|
using namespace fmt::detail;
|
||||||
std::tm* tm = std::localtime(&time_);
|
std::tm* tm = std::localtime(&time_);
|
||||||
if (tm) tm_ = *tm;
|
if (tm) tm_ = *tm;
|
||||||
return tm != nullptr;
|
return tm != nullptr;
|
||||||
|
@ -350,6 +325,11 @@ inline std::tm localtime(std::time_t time) {
|
||||||
return lt.tm_;
|
return lt.tm_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::tm localtime(
|
||||||
|
std::chrono::time_point<std::chrono::system_clock> time_point) {
|
||||||
|
return localtime(std::chrono::system_clock::to_time_t(time_point));
|
||||||
|
}
|
||||||
|
|
||||||
// Thread-safe replacement for std::gmtime
|
// Thread-safe replacement for std::gmtime
|
||||||
inline std::tm gmtime(std::time_t time) {
|
inline std::tm gmtime(std::time_t time) {
|
||||||
struct dispatcher {
|
struct dispatcher {
|
||||||
|
@ -359,21 +339,21 @@ inline std::tm gmtime(std::time_t time) {
|
||||||
dispatcher(std::time_t t) : time_(t) {}
|
dispatcher(std::time_t t) : time_(t) {}
|
||||||
|
|
||||||
bool run() {
|
bool run() {
|
||||||
using namespace fmt::internal;
|
using namespace fmt::detail;
|
||||||
return handle(gmtime_r(&time_, &tm_));
|
return handle(gmtime_r(&time_, &tm_));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool handle(std::tm* tm) { return tm != nullptr; }
|
bool handle(std::tm* tm) { return tm != nullptr; }
|
||||||
|
|
||||||
bool handle(internal::null<>) {
|
bool handle(detail::null<>) {
|
||||||
using namespace fmt::internal;
|
using namespace fmt::detail;
|
||||||
return fallback(gmtime_s(&tm_, &time_));
|
return fallback(gmtime_s(&tm_, &time_));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool fallback(int res) { return res == 0; }
|
bool fallback(int res) { return res == 0; }
|
||||||
|
|
||||||
#if !FMT_MSC_VER
|
#if !FMT_MSC_VER
|
||||||
bool fallback(internal::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;
|
||||||
return tm != nullptr;
|
return tm != nullptr;
|
||||||
|
@ -386,17 +366,33 @@ inline std::tm gmtime(std::time_t time) {
|
||||||
return gt.tm_;
|
return gt.tm_;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace internal {
|
inline std::tm gmtime(
|
||||||
inline std::size_t strftime(char* str, std::size_t count, const char* format,
|
std::chrono::time_point<std::chrono::system_clock> time_point) {
|
||||||
const std::tm* time) {
|
return gmtime(std::chrono::system_clock::to_time_t(time_point));
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
inline size_t strftime(char* str, size_t count, const char* format,
|
||||||
|
const std::tm* time) {
|
||||||
return std::strftime(str, count, format, time);
|
return std::strftime(str, count, format, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::size_t strftime(wchar_t* str, std::size_t count,
|
inline size_t strftime(wchar_t* str, size_t count, const wchar_t* format,
|
||||||
const wchar_t* format, const std::tm* time) {
|
const std::tm* time) {
|
||||||
return std::wcsftime(str, count, format, time);
|
return std::wcsftime(str, count, format, time);
|
||||||
}
|
}
|
||||||
} // namespace internal
|
} // namespace detail
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
struct formatter<std::chrono::time_point<std::chrono::system_clock>, Char>
|
||||||
|
: formatter<std::tm, Char> {
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(std::chrono::time_point<std::chrono::system_clock> val,
|
||||||
|
FormatContext& ctx) -> decltype(ctx.out()) {
|
||||||
|
std::tm time = localtime(val);
|
||||||
|
return formatter<std::tm, Char>::format(time, ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <typename Char> struct formatter<std::tm, Char> {
|
template <typename Char> struct formatter<std::tm, Char> {
|
||||||
template <typename ParseContext>
|
template <typename ParseContext>
|
||||||
|
@ -405,7 +401,7 @@ template <typename Char> struct formatter<std::tm, Char> {
|
||||||
if (it != ctx.end() && *it == ':') ++it;
|
if (it != ctx.end() && *it == ':') ++it;
|
||||||
auto end = it;
|
auto end = it;
|
||||||
while (end != ctx.end() && *end != '}') ++end;
|
while (end != ctx.end() && *end != '}') ++end;
|
||||||
tm_format.reserve(internal::to_unsigned(end - it + 1));
|
tm_format.reserve(detail::to_unsigned(end - it + 1));
|
||||||
tm_format.append(it, end);
|
tm_format.append(it, end);
|
||||||
tm_format.push_back('\0');
|
tm_format.push_back('\0');
|
||||||
return end;
|
return end;
|
||||||
|
@ -414,11 +410,10 @@ template <typename Char> struct formatter<std::tm, Char> {
|
||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
auto format(const std::tm& tm, FormatContext& ctx) -> decltype(ctx.out()) {
|
auto format(const std::tm& tm, FormatContext& ctx) -> decltype(ctx.out()) {
|
||||||
basic_memory_buffer<Char> buf;
|
basic_memory_buffer<Char> buf;
|
||||||
std::size_t start = buf.size();
|
size_t start = buf.size();
|
||||||
for (;;) {
|
for (;;) {
|
||||||
std::size_t size = buf.capacity() - start;
|
size_t size = buf.capacity() - start;
|
||||||
std::size_t count =
|
size_t count = detail::strftime(&buf[start], size, &tm_format[0], &tm);
|
||||||
internal::strftime(&buf[start], size, &tm_format[0], &tm);
|
|
||||||
if (count != 0) {
|
if (count != 0) {
|
||||||
buf.resize(start + count);
|
buf.resize(start + count);
|
||||||
break;
|
break;
|
||||||
|
@ -430,7 +425,7 @@ template <typename Char> struct formatter<std::tm, Char> {
|
||||||
// https://github.com/fmtlib/fmt/issues/367
|
// https://github.com/fmtlib/fmt/issues/367
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
const std::size_t MIN_GROWTH = 10;
|
const size_t MIN_GROWTH = 10;
|
||||||
buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
|
buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
|
||||||
}
|
}
|
||||||
return std::copy(buf.begin(), buf.end(), ctx.out());
|
return std::copy(buf.begin(), buf.end(), ctx.out());
|
||||||
|
@ -439,7 +434,7 @@ template <typename Char> struct formatter<std::tm, Char> {
|
||||||
basic_memory_buffer<Char> tm_format;
|
basic_memory_buffer<Char> tm_format;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace internal {
|
namespace detail {
|
||||||
template <typename Period> FMT_CONSTEXPR const char* get_units() {
|
template <typename Period> FMT_CONSTEXPR const char* get_units() {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -495,12 +490,12 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin,
|
||||||
handler.on_text(ptr - 1, ptr);
|
handler.on_text(ptr - 1, ptr);
|
||||||
break;
|
break;
|
||||||
case 'n': {
|
case 'n': {
|
||||||
const char newline[] = "\n";
|
const Char newline[] = {'\n'};
|
||||||
handler.on_text(newline, newline + 1);
|
handler.on_text(newline, newline + 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 't': {
|
case 't': {
|
||||||
const char tab[] = "\t";
|
const Char tab[] = {'\t'};
|
||||||
handler.on_text(tab, tab + 1);
|
handler.on_text(tab, tab + 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -759,18 +754,36 @@ inline std::chrono::duration<Rep, std::milli> get_milliseconds(
|
||||||
return std::chrono::duration<Rep, std::milli>(static_cast<Rep>(ms));
|
return std::chrono::duration<Rep, std::milli>(static_cast<Rep>(ms));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Rep, typename OutputIt>
|
template <typename Char, typename Rep, typename OutputIt>
|
||||||
OutputIt format_chrono_duration_value(OutputIt out, Rep val, int precision) {
|
OutputIt format_duration_value(OutputIt out, Rep val, int precision) {
|
||||||
if (precision >= 0) return format_to(out, "{:.{}f}", val, precision);
|
const Char pr_f[] = {'{', ':', '.', '{', '}', 'f', '}', 0};
|
||||||
return format_to(out, std::is_floating_point<Rep>::value ? "{:g}" : "{}",
|
if (precision >= 0) return format_to(out, pr_f, val, precision);
|
||||||
|
const Char fp_f[] = {'{', ':', 'g', '}', 0};
|
||||||
|
const Char format[] = {'{', '}', 0};
|
||||||
|
return format_to(out, std::is_floating_point<Rep>::value ? fp_f : format,
|
||||||
val);
|
val);
|
||||||
}
|
}
|
||||||
|
template <typename Char, typename OutputIt>
|
||||||
|
OutputIt copy_unit(string_view unit, OutputIt out, Char) {
|
||||||
|
return std::copy(unit.begin(), unit.end(), out);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Period, typename OutputIt>
|
template <typename OutputIt>
|
||||||
static OutputIt format_chrono_duration_unit(OutputIt out) {
|
OutputIt copy_unit(string_view unit, OutputIt out, wchar_t) {
|
||||||
if (const char* unit = get_units<Period>()) return format_to(out, "{}", unit);
|
// This works when wchar_t is UTF-32 because units only contain characters
|
||||||
if (Period::den == 1) return format_to(out, "[{}]s", Period::num);
|
// that have the same representation in UTF-16 and UTF-32.
|
||||||
return format_to(out, "[{}/{}]s", Period::num, Period::den);
|
utf8_to_utf16 u(unit);
|
||||||
|
return std::copy(u.c_str(), u.c_str() + u.size(), out);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Char, typename Period, typename OutputIt>
|
||||||
|
OutputIt format_duration_unit(OutputIt out) {
|
||||||
|
if (const char* unit = get_units<Period>())
|
||||||
|
return copy_unit(string_view(unit), out, Char());
|
||||||
|
const Char num_f[] = {'[', '{', '}', ']', 's', 0};
|
||||||
|
if (const_check(Period::den == 1)) return format_to(out, num_f, Period::num);
|
||||||
|
const Char num_def_f[] = {'[', '{', '}', '/', '{', '}', ']', 's', 0};
|
||||||
|
return format_to(out, num_def_f, Period::num, Period::den);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FormatContext, typename OutputIt, typename Rep,
|
template <typename FormatContext, typename OutputIt, typename Rep,
|
||||||
|
@ -862,22 +875,22 @@ struct chrono_formatter {
|
||||||
if (isnan(value)) return write_nan();
|
if (isnan(value)) return write_nan();
|
||||||
uint32_or_64_or_128_t<int> n =
|
uint32_or_64_or_128_t<int> n =
|
||||||
to_unsigned(to_nonnegative_int(value, max_value<int>()));
|
to_unsigned(to_nonnegative_int(value, max_value<int>()));
|
||||||
int num_digits = internal::count_digits(n);
|
int num_digits = detail::count_digits(n);
|
||||||
if (width > num_digits) out = std::fill_n(out, width - num_digits, '0');
|
if (width > num_digits) out = std::fill_n(out, width - num_digits, '0');
|
||||||
out = format_decimal<char_type>(out, n, num_digits);
|
out = format_decimal<char_type>(out, n, num_digits).end;
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_nan() { std::copy_n("nan", 3, out); }
|
void write_nan() { std::copy_n("nan", 3, out); }
|
||||||
void write_pinf() { std::copy_n("inf", 3, out); }
|
void write_pinf() { std::copy_n("inf", 3, out); }
|
||||||
void write_ninf() { std::copy_n("-inf", 4, out); }
|
void write_ninf() { std::copy_n("-inf", 4, out); }
|
||||||
|
|
||||||
void format_localized(const tm& time, const char* format) {
|
void format_localized(const tm& time, char format, char modifier = 0) {
|
||||||
if (isnan(val)) return write_nan();
|
if (isnan(val)) return write_nan();
|
||||||
auto locale = context.locale().template get<std::locale>();
|
auto locale = context.locale().template get<std::locale>();
|
||||||
auto& facet = std::use_facet<std::time_put<char_type>>(locale);
|
auto& facet = std::use_facet<std::time_put<char_type>>(locale);
|
||||||
std::basic_ostringstream<char_type> os;
|
std::basic_ostringstream<char_type> os;
|
||||||
os.imbue(locale);
|
os.imbue(locale);
|
||||||
facet.put(os, os, ' ', &time, format, format + std::strlen(format));
|
facet.put(os, os, ' ', &time, format, modifier);
|
||||||
auto str = os.str();
|
auto str = os.str();
|
||||||
std::copy(str.begin(), str.end(), out);
|
std::copy(str.begin(), str.end(), out);
|
||||||
}
|
}
|
||||||
|
@ -907,7 +920,7 @@ struct chrono_formatter {
|
||||||
if (ns == numeric_system::standard) return write(hour(), 2);
|
if (ns == numeric_system::standard) return write(hour(), 2);
|
||||||
auto time = tm();
|
auto time = tm();
|
||||||
time.tm_hour = to_nonnegative_int(hour(), 24);
|
time.tm_hour = to_nonnegative_int(hour(), 24);
|
||||||
format_localized(time, "%OH");
|
format_localized(time, 'H', 'O');
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_12_hour(numeric_system ns) {
|
void on_12_hour(numeric_system ns) {
|
||||||
|
@ -916,7 +929,7 @@ struct chrono_formatter {
|
||||||
if (ns == numeric_system::standard) return write(hour12(), 2);
|
if (ns == numeric_system::standard) return write(hour12(), 2);
|
||||||
auto time = tm();
|
auto time = tm();
|
||||||
time.tm_hour = to_nonnegative_int(hour12(), 12);
|
time.tm_hour = to_nonnegative_int(hour12(), 12);
|
||||||
format_localized(time, "%OI");
|
format_localized(time, 'I', 'O');
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_minute(numeric_system ns) {
|
void on_minute(numeric_system ns) {
|
||||||
|
@ -925,7 +938,7 @@ struct chrono_formatter {
|
||||||
if (ns == numeric_system::standard) return write(minute(), 2);
|
if (ns == numeric_system::standard) return write(minute(), 2);
|
||||||
auto time = tm();
|
auto time = tm();
|
||||||
time.tm_min = to_nonnegative_int(minute(), 60);
|
time.tm_min = to_nonnegative_int(minute(), 60);
|
||||||
format_localized(time, "%OM");
|
format_localized(time, 'M', 'O');
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_second(numeric_system ns) {
|
void on_second(numeric_system ns) {
|
||||||
|
@ -950,13 +963,12 @@ struct chrono_formatter {
|
||||||
}
|
}
|
||||||
auto time = tm();
|
auto time = tm();
|
||||||
time.tm_sec = to_nonnegative_int(second(), 60);
|
time.tm_sec = to_nonnegative_int(second(), 60);
|
||||||
format_localized(time, "%OS");
|
format_localized(time, 'S', 'O');
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_12_hour_time() {
|
void on_12_hour_time() {
|
||||||
if (handle_nan_inf()) return;
|
if (handle_nan_inf()) return;
|
||||||
|
format_localized(time(), 'r');
|
||||||
format_localized(time(), "%r");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_24_hour_time() {
|
void on_24_hour_time() {
|
||||||
|
@ -980,25 +992,27 @@ struct chrono_formatter {
|
||||||
|
|
||||||
void on_am_pm() {
|
void on_am_pm() {
|
||||||
if (handle_nan_inf()) return;
|
if (handle_nan_inf()) return;
|
||||||
format_localized(time(), "%p");
|
format_localized(time(), 'p');
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_duration_value() {
|
void on_duration_value() {
|
||||||
if (handle_nan_inf()) return;
|
if (handle_nan_inf()) return;
|
||||||
write_sign();
|
write_sign();
|
||||||
out = format_chrono_duration_value(out, val, precision);
|
out = format_duration_value<char_type>(out, val, precision);
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_duration_unit() { out = format_chrono_duration_unit<Period>(out); }
|
void on_duration_unit() {
|
||||||
|
out = format_duration_unit<char_type, Period>(out);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
} // namespace internal
|
} // namespace detail
|
||||||
|
|
||||||
template <typename Rep, typename Period, typename Char>
|
template <typename Rep, typename Period, typename Char>
|
||||||
struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
||||||
private:
|
private:
|
||||||
basic_format_specs<Char> specs;
|
basic_format_specs<Char> specs;
|
||||||
int precision;
|
int precision;
|
||||||
using arg_ref_type = internal::arg_ref<Char>;
|
using arg_ref_type = detail::arg_ref<Char>;
|
||||||
arg_ref_type width_ref;
|
arg_ref_type width_ref;
|
||||||
arg_ref_type precision_ref;
|
arg_ref_type precision_ref;
|
||||||
mutable basic_string_view<Char> format_str;
|
mutable basic_string_view<Char> format_str;
|
||||||
|
@ -1019,12 +1033,12 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
||||||
return arg_ref_type(arg_id);
|
return arg_ref_type(arg_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR arg_ref_type make_arg_ref(internal::auto_id) {
|
FMT_CONSTEXPR arg_ref_type make_arg_ref(detail::auto_id) {
|
||||||
return arg_ref_type(context.next_arg_id());
|
return arg_ref_type(context.next_arg_id());
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_error(const char* msg) { FMT_THROW(format_error(msg)); }
|
void on_error(const char* msg) { FMT_THROW(format_error(msg)); }
|
||||||
void on_fill(Char fill) { f.specs.fill[0] = fill; }
|
void on_fill(basic_string_view<Char> fill) { f.specs.fill = fill; }
|
||||||
void on_align(align_t align) { f.specs.align = align; }
|
void on_align(align_t align) { f.specs.align = align; }
|
||||||
void on_width(int width) { f.specs.width = width; }
|
void on_width(int width) { f.specs.width = width; }
|
||||||
void on_precision(int _precision) { f.precision = _precision; }
|
void on_precision(int _precision) { f.precision = _precision; }
|
||||||
|
@ -1049,17 +1063,17 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
||||||
auto begin = ctx.begin(), end = ctx.end();
|
auto begin = ctx.begin(), end = ctx.end();
|
||||||
if (begin == end || *begin == '}') return {begin, begin};
|
if (begin == end || *begin == '}') return {begin, begin};
|
||||||
spec_handler handler{*this, ctx, format_str};
|
spec_handler handler{*this, ctx, format_str};
|
||||||
begin = internal::parse_align(begin, end, handler);
|
begin = detail::parse_align(begin, end, handler);
|
||||||
if (begin == end) return {begin, begin};
|
if (begin == end) return {begin, begin};
|
||||||
begin = internal::parse_width(begin, end, handler);
|
begin = detail::parse_width(begin, end, handler);
|
||||||
if (begin == end) return {begin, begin};
|
if (begin == end) return {begin, begin};
|
||||||
if (*begin == '.') {
|
if (*begin == '.') {
|
||||||
if (std::is_floating_point<Rep>::value)
|
if (std::is_floating_point<Rep>::value)
|
||||||
begin = internal::parse_precision(begin, end, handler);
|
begin = detail::parse_precision(begin, end, handler);
|
||||||
else
|
else
|
||||||
handler.on_error("precision not allowed for this argument type");
|
handler.on_error("precision not allowed for this argument type");
|
||||||
}
|
}
|
||||||
end = parse_chrono_format(begin, end, internal::chrono_format_checker());
|
end = parse_chrono_format(begin, end, detail::chrono_format_checker());
|
||||||
return {begin, end};
|
return {begin, end};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1070,7 +1084,7 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
||||||
-> decltype(ctx.begin()) {
|
-> decltype(ctx.begin()) {
|
||||||
auto range = do_parse(ctx);
|
auto range = do_parse(ctx);
|
||||||
format_str = basic_string_view<Char>(
|
format_str = basic_string_view<Char>(
|
||||||
&*range.begin, internal::to_unsigned(range.end - range.begin));
|
&*range.begin, detail::to_unsigned(range.end - range.begin));
|
||||||
return range.end;
|
return range.end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1081,23 +1095,21 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
||||||
// is not specified.
|
// is not specified.
|
||||||
basic_memory_buffer<Char> buf;
|
basic_memory_buffer<Char> buf;
|
||||||
auto out = std::back_inserter(buf);
|
auto out = std::back_inserter(buf);
|
||||||
using range = internal::output_range<decltype(ctx.out()), Char>;
|
detail::handle_dynamic_spec<detail::width_checker>(specs.width, width_ref,
|
||||||
internal::basic_writer<range> w(range(ctx.out()));
|
ctx);
|
||||||
internal::handle_dynamic_spec<internal::width_checker>(specs.width,
|
detail::handle_dynamic_spec<detail::precision_checker>(precision,
|
||||||
width_ref, ctx);
|
precision_ref, ctx);
|
||||||
internal::handle_dynamic_spec<internal::precision_checker>(
|
|
||||||
precision, precision_ref, ctx);
|
|
||||||
if (begin == end || *begin == '}') {
|
if (begin == end || *begin == '}') {
|
||||||
out = internal::format_chrono_duration_value(out, d.count(), precision);
|
out = detail::format_duration_value<Char>(out, d.count(), precision);
|
||||||
internal::format_chrono_duration_unit<Period>(out);
|
detail::format_duration_unit<Char, Period>(out);
|
||||||
} else {
|
} else {
|
||||||
internal::chrono_formatter<FormatContext, decltype(out), Rep, Period> f(
|
detail::chrono_formatter<FormatContext, decltype(out), Rep, Period> f(
|
||||||
ctx, out, d);
|
ctx, out, d);
|
||||||
f.precision = precision;
|
f.precision = precision;
|
||||||
parse_chrono_format(begin, end, f);
|
parse_chrono_format(begin, end, f);
|
||||||
}
|
}
|
||||||
w.write(buf.data(), buf.size(), specs);
|
return detail::write(
|
||||||
return w.out();
|
ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
130
Externals/fmt/include/fmt/color.h
vendored
130
Externals/fmt/include/fmt/color.h
vendored
|
@ -198,7 +198,7 @@ struct rgb {
|
||||||
uint8_t b;
|
uint8_t b;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace internal {
|
namespace detail {
|
||||||
|
|
||||||
// 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 {
|
||||||
|
@ -221,7 +221,7 @@ struct color_type {
|
||||||
uint32_t rgb_color;
|
uint32_t rgb_color;
|
||||||
} value;
|
} value;
|
||||||
};
|
};
|
||||||
} // namespace internal
|
} // namespace detail
|
||||||
|
|
||||||
// Experimental text formatting support.
|
// Experimental text formatting support.
|
||||||
class text_style {
|
class text_style {
|
||||||
|
@ -298,11 +298,11 @@ class text_style {
|
||||||
FMT_CONSTEXPR bool has_emphasis() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR bool has_emphasis() const FMT_NOEXCEPT {
|
||||||
return static_cast<uint8_t>(ems) != 0;
|
return static_cast<uint8_t>(ems) != 0;
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR internal::color_type get_foreground() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR detail::color_type get_foreground() const FMT_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 internal::color_type get_background() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR detail::color_type get_background() const FMT_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;
|
||||||
}
|
}
|
||||||
|
@ -313,7 +313,7 @@ class text_style {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FMT_CONSTEXPR text_style(bool is_foreground,
|
FMT_CONSTEXPR text_style(bool is_foreground,
|
||||||
internal::color_type text_color) FMT_NOEXCEPT
|
detail::color_type text_color) FMT_NOEXCEPT
|
||||||
: set_foreground_color(),
|
: set_foreground_color(),
|
||||||
set_background_color(),
|
set_background_color(),
|
||||||
ems() {
|
ems() {
|
||||||
|
@ -326,23 +326,23 @@ class text_style {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
friend FMT_CONSTEXPR_DECL text_style fg(internal::color_type foreground)
|
friend FMT_CONSTEXPR_DECL text_style fg(detail::color_type foreground)
|
||||||
FMT_NOEXCEPT;
|
FMT_NOEXCEPT;
|
||||||
friend FMT_CONSTEXPR_DECL text_style bg(internal::color_type background)
|
friend FMT_CONSTEXPR_DECL text_style bg(detail::color_type background)
|
||||||
FMT_NOEXCEPT;
|
FMT_NOEXCEPT;
|
||||||
|
|
||||||
internal::color_type foreground_color;
|
detail::color_type foreground_color;
|
||||||
internal::color_type background_color;
|
detail::color_type background_color;
|
||||||
bool set_foreground_color;
|
bool set_foreground_color;
|
||||||
bool set_background_color;
|
bool set_background_color;
|
||||||
emphasis ems;
|
emphasis ems;
|
||||||
};
|
};
|
||||||
|
|
||||||
FMT_CONSTEXPR text_style fg(internal::color_type foreground) FMT_NOEXCEPT {
|
FMT_CONSTEXPR text_style fg(detail::color_type foreground) FMT_NOEXCEPT {
|
||||||
return text_style(/*is_foreground=*/true, foreground);
|
return text_style(/*is_foreground=*/true, foreground);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR text_style bg(internal::color_type background) FMT_NOEXCEPT {
|
FMT_CONSTEXPR text_style bg(detail::color_type background) FMT_NOEXCEPT {
|
||||||
return text_style(/*is_foreground=*/false, background);
|
return text_style(/*is_foreground=*/false, background);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -350,21 +350,21 @@ FMT_CONSTEXPR text_style operator|(emphasis lhs, emphasis rhs) FMT_NOEXCEPT {
|
||||||
return text_style(lhs) | rhs;
|
return text_style(lhs) | rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace internal {
|
namespace detail {
|
||||||
|
|
||||||
template <typename Char> struct ansi_color_escape {
|
template <typename Char> struct ansi_color_escape {
|
||||||
FMT_CONSTEXPR ansi_color_escape(internal::color_type text_color,
|
FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color,
|
||||||
const char* esc) FMT_NOEXCEPT {
|
const char* esc) FMT_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) {
|
||||||
bool is_background = esc == internal::data::background_color;
|
bool is_background = esc == detail::data::background_color;
|
||||||
uint32_t value = text_color.value.term_color;
|
uint32_t value = text_color.value.term_color;
|
||||||
// Background ASCII codes are the same as the foreground ones but with
|
// Background ASCII codes are the same as the foreground ones but with
|
||||||
// 10 more.
|
// 10 more.
|
||||||
if (is_background) value += 10u;
|
if (is_background) value += 10u;
|
||||||
|
|
||||||
std::size_t index = 0;
|
size_t index = 0;
|
||||||
buffer[index++] = static_cast<Char>('\x1b');
|
buffer[index++] = static_cast<Char>('\x1b');
|
||||||
buffer[index++] = static_cast<Char>('[');
|
buffer[index++] = static_cast<Char>('[');
|
||||||
|
|
||||||
|
@ -398,7 +398,7 @@ template <typename Char> struct ansi_color_escape {
|
||||||
if (em_bits & static_cast<uint8_t>(emphasis::strikethrough))
|
if (em_bits & static_cast<uint8_t>(emphasis::strikethrough))
|
||||||
em_codes[3] = 9;
|
em_codes[3] = 9;
|
||||||
|
|
||||||
std::size_t index = 0;
|
size_t index = 0;
|
||||||
for (int i = 0; i < 4; ++i) {
|
for (int i = 0; i < 4; ++i) {
|
||||||
if (!em_codes[i]) continue;
|
if (!em_codes[i]) continue;
|
||||||
buffer[index++] = static_cast<Char>('\x1b');
|
buffer[index++] = static_cast<Char>('\x1b');
|
||||||
|
@ -412,7 +412,7 @@ template <typename Char> struct ansi_color_escape {
|
||||||
|
|
||||||
FMT_CONSTEXPR const Char* begin() const FMT_NOEXCEPT { return buffer; }
|
FMT_CONSTEXPR const Char* begin() const FMT_NOEXCEPT { return buffer; }
|
||||||
FMT_CONSTEXPR const Char* end() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR const Char* end() const FMT_NOEXCEPT {
|
||||||
return buffer + std::strlen(buffer);
|
return buffer + std::char_traits<Char>::length(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -429,14 +429,14 @@ template <typename Char> struct ansi_color_escape {
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
FMT_CONSTEXPR ansi_color_escape<Char> make_foreground_color(
|
FMT_CONSTEXPR ansi_color_escape<Char> make_foreground_color(
|
||||||
internal::color_type foreground) FMT_NOEXCEPT {
|
detail::color_type foreground) FMT_NOEXCEPT {
|
||||||
return ansi_color_escape<Char>(foreground, internal::data::foreground_color);
|
return ansi_color_escape<Char>(foreground, detail::data::foreground_color);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
FMT_CONSTEXPR ansi_color_escape<Char> make_background_color(
|
FMT_CONSTEXPR ansi_color_escape<Char> make_background_color(
|
||||||
internal::color_type background) FMT_NOEXCEPT {
|
detail::color_type background) FMT_NOEXCEPT {
|
||||||
return ansi_color_escape<Char>(background, internal::data::background_color);
|
return ansi_color_escape<Char>(background, detail::data::background_color);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
|
@ -455,73 +455,71 @@ inline void fputs<wchar_t>(const wchar_t* chars, FILE* stream) FMT_NOEXCEPT {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char> inline void reset_color(FILE* stream) FMT_NOEXCEPT {
|
template <typename Char> inline void reset_color(FILE* stream) FMT_NOEXCEPT {
|
||||||
fputs(internal::data::reset_color, stream);
|
fputs(detail::data::reset_color, stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <> inline void reset_color<wchar_t>(FILE* stream) FMT_NOEXCEPT {
|
template <> inline void reset_color<wchar_t>(FILE* stream) FMT_NOEXCEPT {
|
||||||
fputs(internal::data::wreset_color, stream);
|
fputs(detail::data::wreset_color, stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
inline void reset_color(basic_memory_buffer<Char>& buffer) FMT_NOEXCEPT {
|
inline void reset_color(buffer<Char>& buffer) FMT_NOEXCEPT {
|
||||||
const char* begin = data::reset_color;
|
const char* begin = data::reset_color;
|
||||||
const char* end = begin + sizeof(data::reset_color) - 1;
|
const char* end = begin + sizeof(data::reset_color) - 1;
|
||||||
buffer.append(begin, end);
|
buffer.append(begin, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
void vformat_to(basic_memory_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,
|
||||||
basic_format_args<buffer_context<Char>> args) {
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
bool has_style = false;
|
bool has_style = false;
|
||||||
if (ts.has_emphasis()) {
|
if (ts.has_emphasis()) {
|
||||||
has_style = true;
|
has_style = true;
|
||||||
auto emphasis = internal::make_emphasis<Char>(ts.get_emphasis());
|
auto emphasis = detail::make_emphasis<Char>(ts.get_emphasis());
|
||||||
buf.append(emphasis.begin(), emphasis.end());
|
buf.append(emphasis.begin(), emphasis.end());
|
||||||
}
|
}
|
||||||
if (ts.has_foreground()) {
|
if (ts.has_foreground()) {
|
||||||
has_style = true;
|
has_style = true;
|
||||||
auto foreground =
|
auto foreground = detail::make_foreground_color<Char>(ts.get_foreground());
|
||||||
internal::make_foreground_color<Char>(ts.get_foreground());
|
|
||||||
buf.append(foreground.begin(), foreground.end());
|
buf.append(foreground.begin(), foreground.end());
|
||||||
}
|
}
|
||||||
if (ts.has_background()) {
|
if (ts.has_background()) {
|
||||||
has_style = true;
|
has_style = true;
|
||||||
auto background =
|
auto background = detail::make_background_color<Char>(ts.get_background());
|
||||||
internal::make_background_color<Char>(ts.get_background());
|
|
||||||
buf.append(background.begin(), background.end());
|
buf.append(background.begin(), background.end());
|
||||||
}
|
}
|
||||||
vformat_to(buf, format_str, args);
|
detail::vformat_to(buf, format_str, args);
|
||||||
if (has_style) {
|
if (has_style) detail::reset_color<Char>(buf);
|
||||||
internal::reset_color<Char>(buf);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} // namespace internal
|
} // namespace detail
|
||||||
|
|
||||||
template <typename S, typename Char = char_t<S>>
|
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<Char>> args) {
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
basic_memory_buffer<Char> buf;
|
basic_memory_buffer<Char> buf;
|
||||||
internal::vformat_to(buf, ts, to_string_view(format), args);
|
detail::vformat_to(buf, ts, to_string_view(format), args);
|
||||||
buf.push_back(Char(0));
|
buf.push_back(Char(0));
|
||||||
internal::fputs(buf.data(), f);
|
detail::fputs(buf.data(), f);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
\rst
|
||||||
Formats a string and prints it to the specified file stream using ANSI
|
Formats a string and prints it to the specified file stream using ANSI
|
||||||
escape sequences to specify text formatting.
|
escape sequences to specify text formatting.
|
||||||
Example:
|
|
||||||
|
**Example**::
|
||||||
|
|
||||||
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
|
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
|
||||||
"Elapsed time: {0:.2f} seconds", 1.23);
|
"Elapsed time: {0:.2f} seconds", 1.23);
|
||||||
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename S, typename... Args,
|
template <typename S, typename... Args,
|
||||||
FMT_ENABLE_IF(internal::is_string<S>::value)>
|
FMT_ENABLE_IF(detail::is_string<S>::value)>
|
||||||
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) {
|
||||||
internal::check_format_string<Args...>(format_str);
|
vprint(f, ts, format_str,
|
||||||
using context = buffer_context<char_t<S>>;
|
fmt::make_args_checked<Args...>(format_str, args...));
|
||||||
format_arg_store<context, Args...> as{args...};
|
|
||||||
vprint(f, ts, format_str, basic_format_args<context>(as));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -532,7 +530,7 @@ void print(std::FILE* f, const text_style& ts, const S& format_str,
|
||||||
"Elapsed time: {0:.2f} seconds", 1.23);
|
"Elapsed time: {0:.2f} seconds", 1.23);
|
||||||
*/
|
*/
|
||||||
template <typename S, typename... Args,
|
template <typename S, typename... Args,
|
||||||
FMT_ENABLE_IF(internal::is_string<S>::value)>
|
FMT_ENABLE_IF(detail::is_string<S>::value)>
|
||||||
void print(const text_style& ts, const S& format_str, const Args&... args) {
|
void print(const text_style& ts, const S& format_str, const Args&... args) {
|
||||||
return print(stdout, ts, format_str, args...);
|
return print(stdout, ts, format_str, args...);
|
||||||
}
|
}
|
||||||
|
@ -540,9 +538,9 @@ void print(const text_style& ts, const S& format_str, const Args&... args) {
|
||||||
template <typename S, typename Char = char_t<S>>
|
template <typename S, typename Char = char_t<S>>
|
||||||
inline std::basic_string<Char> vformat(
|
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<Char>> args) {
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
basic_memory_buffer<Char> buf;
|
basic_memory_buffer<Char> buf;
|
||||||
internal::vformat_to(buf, ts, to_string_view(format_str), args);
|
detail::vformat_to(buf, ts, to_string_view(format_str), args);
|
||||||
return fmt::to_string(buf);
|
return fmt::to_string(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -562,7 +560,41 @@ 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 vformat(ts, to_string_view(format_str),
|
return vformat(ts, to_string_view(format_str),
|
||||||
{internal::make_args_checked<Args...>(format_str, args...)});
|
fmt::make_args_checked<Args...>(format_str, args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Formats a string with the given text_style and writes the output to ``out``.
|
||||||
|
*/
|
||||||
|
template <typename OutputIt, typename Char,
|
||||||
|
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value)>
|
||||||
|
OutputIt vformat_to(
|
||||||
|
OutputIt out, const text_style& ts, basic_string_view<Char> format_str,
|
||||||
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
|
decltype(detail::get_buffer<Char>(out)) buf(detail::get_buffer_init(out));
|
||||||
|
detail::vformat_to(buf, ts, format_str, args);
|
||||||
|
return detail::get_iterator(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
Formats arguments with the given text_style, writes the result to the output
|
||||||
|
iterator ``out`` and returns the iterator past the end of the output range.
|
||||||
|
|
||||||
|
**Example**::
|
||||||
|
|
||||||
|
std::vector<char> out;
|
||||||
|
fmt::format_to(std::back_inserter(out),
|
||||||
|
fmt::emphasis::bold | fg(fmt::color::red), "{}", 42);
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
template <typename OutputIt, typename S, typename... Args,
|
||||||
|
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, char_t<S>>::value&&
|
||||||
|
detail::is_string<S>::value)>
|
||||||
|
inline OutputIt format_to(OutputIt out, const text_style& ts,
|
||||||
|
const S& format_str, Args&&... args) {
|
||||||
|
return vformat_to(out, ts, to_string_view(format_str),
|
||||||
|
fmt::make_args_checked<Args...>(format_str, args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
339
Externals/fmt/include/fmt/compile.h
vendored
339
Externals/fmt/include/fmt/compile.h
vendored
|
@ -9,10 +9,37 @@
|
||||||
#define FMT_COMPILE_H_
|
#define FMT_COMPILE_H_
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
namespace internal {
|
namespace detail {
|
||||||
|
|
||||||
|
// A compile-time string which is compiled into fast formatting code.
|
||||||
|
class compiled_string {};
|
||||||
|
|
||||||
|
template <typename S>
|
||||||
|
struct is_compiled_string : std::is_base_of<compiled_string, S> {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
Converts a string literal *s* into a format string that will be parsed at
|
||||||
|
compile time and converted into efficient formatting code. Requires C++17
|
||||||
|
``constexpr if`` compiler support.
|
||||||
|
|
||||||
|
**Example**::
|
||||||
|
|
||||||
|
// Converts 42 into std::string using the most efficient method and no
|
||||||
|
// runtime format string processing.
|
||||||
|
std::string s = fmt::format(FMT_COMPILE("{}"), 42);
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
#define FMT_COMPILE(s) FMT_STRING_IMPL(s, fmt::detail::compiled_string)
|
||||||
|
|
||||||
|
template <typename T, typename... Tail>
|
||||||
|
const T& first(const T& value, const Tail&...) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
// Part of a compiled format string. It can be either literal text or a
|
// Part of a compiled format string. It can be either literal text or a
|
||||||
// replacement field.
|
// replacement field.
|
||||||
|
@ -61,13 +88,15 @@ template <typename Char> struct part_counter {
|
||||||
if (begin != end) ++num_parts;
|
if (begin != end) ++num_parts;
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR void on_arg_id() { ++num_parts; }
|
FMT_CONSTEXPR int on_arg_id() { return ++num_parts, 0; }
|
||||||
FMT_CONSTEXPR void on_arg_id(int) { ++num_parts; }
|
FMT_CONSTEXPR int on_arg_id(int) { return ++num_parts, 0; }
|
||||||
FMT_CONSTEXPR void on_arg_id(basic_string_view<Char>) { ++num_parts; }
|
FMT_CONSTEXPR int on_arg_id(basic_string_view<Char>) {
|
||||||
|
return ++num_parts, 0;
|
||||||
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR void on_replacement_field(const Char*) {}
|
FMT_CONSTEXPR void on_replacement_field(int, const Char*) {}
|
||||||
|
|
||||||
FMT_CONSTEXPR const Char* on_format_specs(const Char* begin,
|
FMT_CONSTEXPR const Char* on_format_specs(int, const Char* begin,
|
||||||
const Char* end) {
|
const Char* end) {
|
||||||
// Find the matching brace.
|
// Find the matching brace.
|
||||||
unsigned brace_counter = 0;
|
unsigned brace_counter = 0;
|
||||||
|
@ -115,25 +144,28 @@ class format_string_compiler : public error_handler {
|
||||||
handler_(part::make_text({begin, to_unsigned(end - begin)}));
|
handler_(part::make_text({begin, to_unsigned(end - begin)}));
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR void on_arg_id() {
|
FMT_CONSTEXPR int on_arg_id() {
|
||||||
part_ = part::make_arg_index(parse_context_.next_arg_id());
|
part_ = part::make_arg_index(parse_context_.next_arg_id());
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR void on_arg_id(int id) {
|
FMT_CONSTEXPR int on_arg_id(int id) {
|
||||||
parse_context_.check_arg_id(id);
|
parse_context_.check_arg_id(id);
|
||||||
part_ = part::make_arg_index(id);
|
part_ = part::make_arg_index(id);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR void on_arg_id(basic_string_view<Char> id) {
|
FMT_CONSTEXPR int on_arg_id(basic_string_view<Char> id) {
|
||||||
part_ = part::make_arg_name(id);
|
part_ = part::make_arg_name(id);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR void on_replacement_field(const Char* ptr) {
|
FMT_CONSTEXPR void on_replacement_field(int, const Char* ptr) {
|
||||||
part_.arg_id_end = ptr;
|
part_.arg_id_end = ptr;
|
||||||
handler_(part_);
|
handler_(part_);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR const Char* on_format_specs(const Char* begin,
|
FMT_CONSTEXPR const Char* on_format_specs(int, const Char* begin,
|
||||||
const Char* end) {
|
const Char* end) {
|
||||||
auto repl = typename part::replacement();
|
auto repl = typename part::replacement();
|
||||||
dynamic_specs_handler<basic_format_parse_context<Char>> handler(
|
dynamic_specs_handler<basic_format_parse_context<Char>> handler(
|
||||||
|
@ -159,23 +191,24 @@ FMT_CONSTEXPR void compile_format_string(basic_string_view<Char> format_str,
|
||||||
format_string_compiler<Char, PartHandler>(format_str, handler));
|
format_string_compiler<Char, PartHandler>(format_str, handler));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Range, typename Context, typename Id>
|
template <typename OutputIt, typename Context, typename Id>
|
||||||
void format_arg(
|
void format_arg(
|
||||||
basic_format_parse_context<typename Range::value_type>& parse_ctx,
|
basic_format_parse_context<typename Context::char_type>& parse_ctx,
|
||||||
Context& ctx, Id arg_id) {
|
Context& ctx, Id arg_id) {
|
||||||
ctx.advance_to(
|
ctx.advance_to(visit_format_arg(
|
||||||
visit_format_arg(arg_formatter<Range>(ctx, &parse_ctx), ctx.arg(arg_id)));
|
arg_formatter<OutputIt, typename Context::char_type>(ctx, &parse_ctx),
|
||||||
|
ctx.arg(arg_id)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// vformat_to is defined in a subnamespace to prevent ADL.
|
// vformat_to is defined in a subnamespace to prevent ADL.
|
||||||
namespace cf {
|
namespace cf {
|
||||||
template <typename Context, typename Range, typename CompiledFormat>
|
template <typename Context, typename OutputIt, typename CompiledFormat>
|
||||||
auto vformat_to(Range out, CompiledFormat& cf, basic_format_args<Context> args)
|
auto vformat_to(OutputIt out, CompiledFormat& cf,
|
||||||
-> typename Context::iterator {
|
basic_format_args<Context> args) -> typename Context::iterator {
|
||||||
using char_type = typename Context::char_type;
|
using char_type = typename Context::char_type;
|
||||||
basic_format_parse_context<char_type> parse_ctx(
|
basic_format_parse_context<char_type> parse_ctx(
|
||||||
to_string_view(cf.format_str_));
|
to_string_view(cf.format_str_));
|
||||||
Context ctx(out.begin(), args);
|
Context ctx(out, args);
|
||||||
|
|
||||||
const auto& parts = cf.parts();
|
const auto& parts = cf.parts();
|
||||||
for (auto part_it = std::begin(parts); part_it != std::end(parts);
|
for (auto part_it = std::begin(parts); part_it != std::end(parts);
|
||||||
|
@ -196,12 +229,12 @@ auto vformat_to(Range out, CompiledFormat& cf, basic_format_args<Context> args)
|
||||||
|
|
||||||
case format_part_t::kind::arg_index:
|
case format_part_t::kind::arg_index:
|
||||||
advance_to(parse_ctx, part.arg_id_end);
|
advance_to(parse_ctx, part.arg_id_end);
|
||||||
internal::format_arg<Range>(parse_ctx, ctx, value.arg_index);
|
detail::format_arg<OutputIt>(parse_ctx, ctx, value.arg_index);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case format_part_t::kind::arg_name:
|
case format_part_t::kind::arg_name:
|
||||||
advance_to(parse_ctx, part.arg_id_end);
|
advance_to(parse_ctx, part.arg_id_end);
|
||||||
internal::format_arg<Range>(parse_ctx, ctx, value.str);
|
detail::format_arg<OutputIt>(parse_ctx, ctx, value.str);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case format_part_t::kind::replacement: {
|
case format_part_t::kind::replacement: {
|
||||||
|
@ -225,7 +258,9 @@ auto vformat_to(Range out, CompiledFormat& cf, basic_format_args<Context> args)
|
||||||
|
|
||||||
advance_to(parse_ctx, part.arg_id_end);
|
advance_to(parse_ctx, part.arg_id_end);
|
||||||
ctx.advance_to(
|
ctx.advance_to(
|
||||||
visit_format_arg(arg_formatter<Range>(ctx, nullptr, &specs), arg));
|
visit_format_arg(arg_formatter<OutputIt, typename Context::char_type>(
|
||||||
|
ctx, nullptr, &specs),
|
||||||
|
arg));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -239,7 +274,7 @@ struct basic_compiled_format {};
|
||||||
template <typename S, typename = void>
|
template <typename S, typename = void>
|
||||||
struct compiled_format_base : basic_compiled_format {
|
struct compiled_format_base : basic_compiled_format {
|
||||||
using char_type = char_t<S>;
|
using char_type = char_t<S>;
|
||||||
using parts_container = std::vector<internal::format_part<char_type>>;
|
using parts_container = std::vector<detail::format_part<char_type>>;
|
||||||
|
|
||||||
parts_container compiled_parts;
|
parts_container compiled_parts;
|
||||||
|
|
||||||
|
@ -304,7 +339,7 @@ struct compiled_format_base<S, enable_if_t<is_compile_string<S>::value>>
|
||||||
const parts_container& parts() const {
|
const parts_container& parts() const {
|
||||||
static FMT_CONSTEXPR_DECL const auto compiled_parts =
|
static FMT_CONSTEXPR_DECL const auto compiled_parts =
|
||||||
compile_to_parts<char_type, num_format_parts>(
|
compile_to_parts<char_type, num_format_parts>(
|
||||||
internal::to_string_view(S()));
|
detail::to_string_view(S()));
|
||||||
return compiled_parts.data;
|
return compiled_parts.data;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -317,8 +352,8 @@ class compiled_format : private compiled_format_base<S> {
|
||||||
private:
|
private:
|
||||||
basic_string_view<char_type> format_str_;
|
basic_string_view<char_type> format_str_;
|
||||||
|
|
||||||
template <typename Context, typename Range, typename CompiledFormat>
|
template <typename Context, typename OutputIt, typename CompiledFormat>
|
||||||
friend auto cf::vformat_to(Range out, CompiledFormat& cf,
|
friend auto cf::vformat_to(OutputIt out, CompiledFormat& cf,
|
||||||
basic_format_args<Context> args) ->
|
basic_format_args<Context> args) ->
|
||||||
typename Context::iterator;
|
typename Context::iterator;
|
||||||
|
|
||||||
|
@ -333,7 +368,8 @@ template <typename... Args> struct type_list {};
|
||||||
|
|
||||||
// Returns a reference to the argument at index N from [first, rest...].
|
// Returns a reference to the argument at index N from [first, rest...].
|
||||||
template <int N, typename T, typename... Args>
|
template <int N, typename T, typename... Args>
|
||||||
constexpr const auto& get(const T& first, const Args&... rest) {
|
constexpr const auto& get([[maybe_unused]] const T& first,
|
||||||
|
[[maybe_unused]] const Args&... rest) {
|
||||||
static_assert(N < 1 + sizeof...(Args), "index is out of bounds");
|
static_assert(N < 1 + sizeof...(Args), "index is out of bounds");
|
||||||
if constexpr (N == 0)
|
if constexpr (N == 0)
|
||||||
return first;
|
return first;
|
||||||
|
@ -350,49 +386,39 @@ template <int N, typename... Args> struct get_type_impl<N, type_list<Args...>> {
|
||||||
template <int N, typename T>
|
template <int N, typename T>
|
||||||
using get_type = typename get_type_impl<N, T>::type;
|
using get_type = typename get_type_impl<N, T>::type;
|
||||||
|
|
||||||
|
template <typename T> struct is_compiled_format : std::false_type {};
|
||||||
|
|
||||||
template <typename Char> struct text {
|
template <typename Char> struct text {
|
||||||
basic_string_view<Char> data;
|
basic_string_view<Char> data;
|
||||||
using char_type = Char;
|
using char_type = Char;
|
||||||
|
|
||||||
template <typename OutputIt, typename... Args>
|
template <typename OutputIt, typename... Args>
|
||||||
OutputIt format(OutputIt out, const Args&...) const {
|
OutputIt format(OutputIt out, const Args&...) const {
|
||||||
// TODO: reserve
|
return write<Char>(out, data);
|
||||||
return copy_str<Char>(data.begin(), data.end(), out);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
struct is_compiled_format<text<Char>> : std::true_type {};
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
constexpr text<Char> make_text(basic_string_view<Char> s, size_t pos,
|
constexpr text<Char> make_text(basic_string_view<Char> s, size_t pos,
|
||||||
size_t size) {
|
size_t size) {
|
||||||
return {{&s[pos], size}};
|
return {{&s[pos], size}};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename OutputIt, typename T,
|
template <typename Char> struct code_unit {
|
||||||
std::enable_if_t<std::is_integral_v<T>, int> = 0>
|
Char value;
|
||||||
OutputIt format_default(OutputIt out, T value) {
|
using char_type = Char;
|
||||||
// TODO: reserve
|
|
||||||
format_int fi(value);
|
|
||||||
return std::copy(fi.data(), fi.data() + fi.size(), out);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Char, typename OutputIt>
|
template <typename OutputIt, typename... Args>
|
||||||
OutputIt format_default(OutputIt out, double value) {
|
OutputIt format(OutputIt out, const Args&...) const {
|
||||||
writer w(out);
|
return write<Char>(out, value);
|
||||||
w.write(value);
|
}
|
||||||
return w.out();
|
};
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Char, typename OutputIt>
|
template <typename Char>
|
||||||
OutputIt format_default(OutputIt out, Char value) {
|
struct is_compiled_format<code_unit<Char>> : std::true_type {};
|
||||||
*out++ = value;
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Char, typename OutputIt>
|
|
||||||
OutputIt format_default(OutputIt out, const Char* value) {
|
|
||||||
auto length = std::char_traits<Char>::length(value);
|
|
||||||
return copy_str<Char>(value, value + length, out);
|
|
||||||
}
|
|
||||||
|
|
||||||
// A replacement field that refers to argument N.
|
// A replacement field that refers to argument N.
|
||||||
template <typename Char, typename T, int N> struct field {
|
template <typename Char, typename T, int N> struct field {
|
||||||
|
@ -402,10 +428,32 @@ template <typename Char, typename T, int N> struct field {
|
||||||
OutputIt format(OutputIt out, const Args&... args) const {
|
OutputIt format(OutputIt out, const Args&... args) const {
|
||||||
// This ensures that the argument type is convertile to `const T&`.
|
// This ensures that the argument type is convertile to `const T&`.
|
||||||
const T& arg = get<N>(args...);
|
const T& arg = get<N>(args...);
|
||||||
return format_default<Char>(out, arg);
|
return write<Char>(out, arg);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename Char, typename T, int N>
|
||||||
|
struct is_compiled_format<field<Char, T, N>> : std::true_type {};
|
||||||
|
|
||||||
|
// A replacement field that refers to argument N and has format specifiers.
|
||||||
|
template <typename Char, typename T, int N> struct spec_field {
|
||||||
|
using char_type = Char;
|
||||||
|
mutable formatter<T, Char> fmt;
|
||||||
|
|
||||||
|
template <typename OutputIt, typename... Args>
|
||||||
|
OutputIt format(OutputIt out, const Args&... args) const {
|
||||||
|
// This ensures that the argument type is convertile to `const T&`.
|
||||||
|
const T& arg = get<N>(args...);
|
||||||
|
const auto& vargs =
|
||||||
|
make_format_args<basic_format_context<OutputIt, Char>>(args...);
|
||||||
|
basic_format_context<OutputIt, Char> ctx(out, vargs);
|
||||||
|
return fmt.format(arg, ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char, typename T, int N>
|
||||||
|
struct is_compiled_format<spec_field<Char, T, N>> : std::true_type {};
|
||||||
|
|
||||||
template <typename L, typename R> struct concat {
|
template <typename L, typename R> struct concat {
|
||||||
L lhs;
|
L lhs;
|
||||||
R rhs;
|
R rhs;
|
||||||
|
@ -418,6 +466,9 @@ template <typename L, typename R> struct concat {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename L, typename R>
|
||||||
|
struct is_compiled_format<concat<L, R>> : std::true_type {};
|
||||||
|
|
||||||
template <typename L, typename R>
|
template <typename L, typename R>
|
||||||
constexpr concat<L, R> make_concat(L lhs, R rhs) {
|
constexpr concat<L, R> make_concat(L lhs, R rhs) {
|
||||||
return {lhs, rhs};
|
return {lhs, rhs};
|
||||||
|
@ -438,7 +489,8 @@ constexpr auto compile_format_string(S format_str);
|
||||||
|
|
||||||
template <typename Args, size_t POS, int ID, typename T, typename S>
|
template <typename Args, size_t POS, int ID, typename T, typename S>
|
||||||
constexpr auto parse_tail(T head, S format_str) {
|
constexpr auto parse_tail(T head, S format_str) {
|
||||||
if constexpr (POS != to_string_view(format_str).size()) {
|
if constexpr (POS !=
|
||||||
|
basic_string_view<typename S::char_type>(format_str).size()) {
|
||||||
constexpr auto tail = compile_format_string<Args, POS, ID>(format_str);
|
constexpr auto tail = compile_format_string<Args, POS, ID>(format_str);
|
||||||
if constexpr (std::is_same<remove_cvref_t<decltype(tail)>,
|
if constexpr (std::is_same<remove_cvref_t<decltype(tail)>,
|
||||||
unknown_format>())
|
unknown_format>())
|
||||||
|
@ -450,6 +502,22 @@ constexpr auto parse_tail(T head, S format_str) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T, typename Char> struct parse_specs_result {
|
||||||
|
formatter<T, Char> fmt;
|
||||||
|
size_t end;
|
||||||
|
int next_arg_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename Char>
|
||||||
|
constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str,
|
||||||
|
size_t pos, int arg_id) {
|
||||||
|
str.remove_prefix(pos);
|
||||||
|
auto ctx = basic_format_parse_context<Char>(str, {}, arg_id + 1);
|
||||||
|
auto f = formatter<T, Char>();
|
||||||
|
auto end = f.parse(ctx);
|
||||||
|
return {f, pos + (end - str.data()) + 1, ctx.next_arg_id()};
|
||||||
|
}
|
||||||
|
|
||||||
// Compiles a non-empty format string and returns the compiled representation
|
// Compiles a non-empty format string and returns the compiled representation
|
||||||
// or unknown_format() on unrecognized input.
|
// or unknown_format() on unrecognized input.
|
||||||
template <typename Args, size_t POS, int ID, typename S>
|
template <typename Args, size_t POS, int ID, typename S>
|
||||||
|
@ -463,12 +531,13 @@ constexpr auto compile_format_string(S format_str) {
|
||||||
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
|
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
|
||||||
} else if constexpr (str[POS + 1] == '}') {
|
} else if constexpr (str[POS + 1] == '}') {
|
||||||
using type = get_type<ID, Args>;
|
using type = get_type<ID, Args>;
|
||||||
if constexpr (std::is_same<type, int>::value) {
|
return parse_tail<Args, POS + 2, ID + 1>(field<char_type, type, ID>(),
|
||||||
return parse_tail<Args, POS + 2, ID + 1>(field<char_type, type, ID>(),
|
format_str);
|
||||||
format_str);
|
} else if constexpr (str[POS + 1] == ':') {
|
||||||
} else {
|
using type = get_type<ID, Args>;
|
||||||
return unknown_format();
|
constexpr auto result = parse_specs<type>(str, POS + 2, ID);
|
||||||
}
|
return parse_tail<Args, result.end, result.next_arg_id>(
|
||||||
|
spec_field<char_type, type, ID>{result.fmt}, format_str);
|
||||||
} else {
|
} else {
|
||||||
return unknown_format();
|
return unknown_format();
|
||||||
}
|
}
|
||||||
|
@ -478,106 +547,152 @@ constexpr auto compile_format_string(S format_str) {
|
||||||
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
|
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
|
||||||
} else {
|
} else {
|
||||||
constexpr auto end = parse_text(str, POS + 1);
|
constexpr auto end = parse_text(str, POS + 1);
|
||||||
return parse_tail<Args, end, ID>(make_text(str, POS, end - POS),
|
if constexpr (end - POS > 1) {
|
||||||
format_str);
|
return parse_tail<Args, end, ID>(make_text(str, POS, end - POS),
|
||||||
|
format_str);
|
||||||
|
} else {
|
||||||
|
return parse_tail<Args, end, ID>(code_unit<char_type>{str[POS]},
|
||||||
|
format_str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // __cpp_if_constexpr
|
|
||||||
} // namespace internal
|
|
||||||
|
|
||||||
#if FMT_USE_CONSTEXPR
|
|
||||||
# ifdef __cpp_if_constexpr
|
|
||||||
template <typename... Args, typename S,
|
template <typename... Args, typename S,
|
||||||
FMT_ENABLE_IF(is_compile_string<S>::value)>
|
FMT_ENABLE_IF(is_compile_string<S>::value ||
|
||||||
|
detail::is_compiled_string<S>::value)>
|
||||||
constexpr auto compile(S format_str) {
|
constexpr auto compile(S format_str) {
|
||||||
constexpr basic_string_view<typename S::char_type> str = format_str;
|
constexpr basic_string_view<typename S::char_type> str = format_str;
|
||||||
if constexpr (str.size() == 0) {
|
if constexpr (str.size() == 0) {
|
||||||
return internal::make_text(str, 0, 0);
|
return detail::make_text(str, 0, 0);
|
||||||
} else {
|
} else {
|
||||||
constexpr auto result =
|
constexpr auto result =
|
||||||
internal::compile_format_string<internal::type_list<Args...>, 0, 0>(
|
detail::compile_format_string<detail::type_list<Args...>, 0, 0>(
|
||||||
format_str);
|
format_str);
|
||||||
if constexpr (std::is_same<remove_cvref_t<decltype(result)>,
|
if constexpr (std::is_same<remove_cvref_t<decltype(result)>,
|
||||||
internal::unknown_format>()) {
|
detail::unknown_format>()) {
|
||||||
return internal::compiled_format<S, Args...>(to_string_view(format_str));
|
return detail::compiled_format<S, Args...>(to_string_view(format_str));
|
||||||
} else {
|
} else {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
template <typename CompiledFormat, typename... Args,
|
|
||||||
typename Char = typename CompiledFormat::char_type,
|
|
||||||
FMT_ENABLE_IF(!std::is_base_of<internal::basic_compiled_format,
|
|
||||||
CompiledFormat>::value)>
|
|
||||||
std::basic_string<Char> format(const CompiledFormat& cf, const Args&... args) {
|
|
||||||
basic_memory_buffer<Char> buffer;
|
|
||||||
cf.format(std::back_inserter(buffer), args...);
|
|
||||||
return to_string(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename OutputIt, typename CompiledFormat, typename... Args,
|
|
||||||
FMT_ENABLE_IF(!std::is_base_of<internal::basic_compiled_format,
|
|
||||||
CompiledFormat>::value)>
|
|
||||||
OutputIt format_to(OutputIt out, const CompiledFormat& cf,
|
|
||||||
const Args&... args) {
|
|
||||||
return cf.format(out, args...);
|
|
||||||
}
|
|
||||||
# else
|
|
||||||
template <typename... Args, typename S,
|
template <typename... Args, typename S,
|
||||||
FMT_ENABLE_IF(is_compile_string<S>::value)>
|
FMT_ENABLE_IF(is_compile_string<S>::value)>
|
||||||
constexpr auto compile(S format_str) -> internal::compiled_format<S, Args...> {
|
constexpr auto compile(S format_str) -> detail::compiled_format<S, Args...> {
|
||||||
return internal::compiled_format<S, Args...>(to_string_view(format_str));
|
return detail::compiled_format<S, Args...>(to_string_view(format_str));
|
||||||
}
|
}
|
||||||
# endif // __cpp_if_constexpr
|
#endif // __cpp_if_constexpr
|
||||||
#endif // FMT_USE_CONSTEXPR
|
|
||||||
|
|
||||||
// Compiles the format string which must be a string literal.
|
// Compiles the format string which must be a string literal.
|
||||||
template <typename... Args, typename Char, size_t N>
|
template <typename... Args, typename Char, size_t N>
|
||||||
auto compile(const Char (&format_str)[N])
|
auto compile(const Char (&format_str)[N])
|
||||||
-> internal::compiled_format<const Char*, Args...> {
|
-> detail::compiled_format<const Char*, Args...> {
|
||||||
return internal::compiled_format<const Char*, Args...>(
|
return detail::compiled_format<const Char*, Args...>(
|
||||||
basic_string_view<Char>(format_str, N - 1));
|
basic_string_view<Char>(format_str, N - 1));
|
||||||
}
|
}
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
// DEPRECATED! use FMT_COMPILE instead.
|
||||||
|
template <typename... Args>
|
||||||
|
FMT_DEPRECATED auto compile(const Args&... args)
|
||||||
|
-> decltype(detail::compile(args...)) {
|
||||||
|
return detail::compile(args...);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if FMT_USE_CONSTEXPR
|
||||||
|
# ifdef __cpp_if_constexpr
|
||||||
|
|
||||||
template <typename CompiledFormat, typename... Args,
|
template <typename CompiledFormat, typename... Args,
|
||||||
typename Char = typename CompiledFormat::char_type,
|
typename Char = typename CompiledFormat::char_type,
|
||||||
FMT_ENABLE_IF(std::is_base_of<internal::basic_compiled_format,
|
FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
|
||||||
CompiledFormat>::value)>
|
FMT_INLINE std::basic_string<Char> format(const CompiledFormat& cf,
|
||||||
std::basic_string<Char> format(const CompiledFormat& cf, const Args&... args) {
|
const Args&... args) {
|
||||||
basic_memory_buffer<Char> buffer;
|
basic_memory_buffer<Char> buffer;
|
||||||
using range = buffer_range<Char>;
|
cf.format(detail::buffer_appender<Char>(buffer), args...);
|
||||||
using context = buffer_context<Char>;
|
|
||||||
internal::cf::vformat_to<context>(range(buffer), cf,
|
|
||||||
{make_format_args<context>(args...)});
|
|
||||||
return to_string(buffer);
|
return to_string(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIt, typename CompiledFormat, typename... Args,
|
template <typename OutputIt, typename CompiledFormat, typename... Args,
|
||||||
FMT_ENABLE_IF(std::is_base_of<internal::basic_compiled_format,
|
FMT_ENABLE_IF(detail::is_compiled_format<CompiledFormat>::value)>
|
||||||
|
OutputIt format_to(OutputIt out, const CompiledFormat& cf,
|
||||||
|
const Args&... args) {
|
||||||
|
return cf.format(out, args...);
|
||||||
|
}
|
||||||
|
# endif // __cpp_if_constexpr
|
||||||
|
#endif // FMT_USE_CONSTEXPR
|
||||||
|
|
||||||
|
template <typename CompiledFormat, typename... Args,
|
||||||
|
typename Char = typename CompiledFormat::char_type,
|
||||||
|
FMT_ENABLE_IF(std::is_base_of<detail::basic_compiled_format,
|
||||||
|
CompiledFormat>::value)>
|
||||||
|
std::basic_string<Char> format(const CompiledFormat& cf, const Args&... args) {
|
||||||
|
basic_memory_buffer<Char> buffer;
|
||||||
|
using context = buffer_context<Char>;
|
||||||
|
detail::cf::vformat_to<context>(detail::buffer_appender<Char>(buffer), cf,
|
||||||
|
make_format_args<context>(args...));
|
||||||
|
return to_string(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename S, typename... Args,
|
||||||
|
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||||
|
FMT_INLINE std::basic_string<typename S::char_type> format(const S&,
|
||||||
|
Args&&... args) {
|
||||||
|
#ifdef __cpp_if_constexpr
|
||||||
|
if constexpr (std::is_same<typename S::char_type, char>::value) {
|
||||||
|
constexpr basic_string_view<typename S::char_type> str = S();
|
||||||
|
if (str.size() == 2 && str[0] == '{' && str[1] == '}')
|
||||||
|
return fmt::to_string(detail::first(args...));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
constexpr auto compiled = detail::compile<Args...>(S());
|
||||||
|
return format(compiled, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputIt, typename CompiledFormat, typename... Args,
|
||||||
|
FMT_ENABLE_IF(std::is_base_of<detail::basic_compiled_format,
|
||||||
CompiledFormat>::value)>
|
CompiledFormat>::value)>
|
||||||
OutputIt format_to(OutputIt out, const CompiledFormat& cf,
|
OutputIt format_to(OutputIt out, const CompiledFormat& cf,
|
||||||
const Args&... args) {
|
const Args&... args) {
|
||||||
using char_type = typename CompiledFormat::char_type;
|
using char_type = typename CompiledFormat::char_type;
|
||||||
using range = internal::output_range<OutputIt, char_type>;
|
|
||||||
using context = format_context_t<OutputIt, char_type>;
|
using context = format_context_t<OutputIt, char_type>;
|
||||||
return internal::cf::vformat_to<context>(
|
return detail::cf::vformat_to<context>(out, cf,
|
||||||
range(out), cf, {make_format_args<context>(args...)});
|
make_format_args<context>(args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputIt, typename S, typename... Args,
|
||||||
|
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||||
|
OutputIt format_to(OutputIt out, const S&, const Args&... args) {
|
||||||
|
constexpr auto compiled = detail::compile<Args...>(S());
|
||||||
|
return format_to(out, compiled, args...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIt, typename CompiledFormat, typename... Args,
|
template <typename OutputIt, typename CompiledFormat, typename... Args,
|
||||||
FMT_ENABLE_IF(internal::is_output_iterator<OutputIt>::value)>
|
FMT_ENABLE_IF(detail::is_output_iterator<
|
||||||
|
OutputIt, typename CompiledFormat::char_type>::value&&
|
||||||
|
std::is_base_of<detail::basic_compiled_format,
|
||||||
|
CompiledFormat>::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 CompiledFormat& cf,
|
const CompiledFormat& cf,
|
||||||
const Args&... args) {
|
const Args&... args) {
|
||||||
auto it =
|
auto it =
|
||||||
format_to(internal::truncating_iterator<OutputIt>(out, n), cf, args...);
|
format_to(detail::truncating_iterator<OutputIt>(out, n), cf, args...);
|
||||||
|
return {it.base(), it.count()};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputIt, typename S, typename... Args,
|
||||||
|
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||||
|
format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n, const S&,
|
||||||
|
const Args&... args) {
|
||||||
|
constexpr auto compiled = detail::compile<Args...>(S());
|
||||||
|
auto it = format_to(detail::truncating_iterator<OutputIt>(out, n), compiled,
|
||||||
|
args...);
|
||||||
return {it.base(), it.count()};
|
return {it.base(), it.count()};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename CompiledFormat, typename... Args>
|
template <typename CompiledFormat, typename... Args>
|
||||||
std::size_t formatted_size(const CompiledFormat& cf, const Args&... args) {
|
size_t formatted_size(const CompiledFormat& cf, const Args&... args) {
|
||||||
return format_to(internal::counting_iterator(), cf, args...).count();
|
return format_to(detail::counting_iterator(), cf, args...).count();
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
1647
Externals/fmt/include/fmt/core.h
vendored
1647
Externals/fmt/include/fmt/core.h
vendored
File diff suppressed because it is too large
Load diff
2255
Externals/fmt/include/fmt/format-inl.h
vendored
2255
Externals/fmt/include/fmt/format-inl.h
vendored
File diff suppressed because it is too large
Load diff
3371
Externals/fmt/include/fmt/format.h
vendored
3371
Externals/fmt/include/fmt/format.h
vendored
File diff suppressed because it is too large
Load diff
59
Externals/fmt/include/fmt/locale.h
vendored
59
Externals/fmt/include/fmt/locale.h
vendored
|
@ -9,67 +9,54 @@
|
||||||
#define FMT_LOCALE_H_
|
#define FMT_LOCALE_H_
|
||||||
|
|
||||||
#include <locale>
|
#include <locale>
|
||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
namespace internal {
|
namespace detail {
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
typename buffer_context<Char>::iterator vformat_to(
|
std::basic_string<Char> vformat(
|
||||||
const std::locale& loc, buffer<Char>& buf,
|
const std::locale& loc, basic_string_view<Char> format_str,
|
||||||
basic_string_view<Char> format_str,
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
basic_format_args<buffer_context<Char>> args) {
|
|
||||||
using range = buffer_range<Char>;
|
|
||||||
return vformat_to<arg_formatter<range>>(buf, to_string_view(format_str), args,
|
|
||||||
internal::locale_ref(loc));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Char>
|
|
||||||
std::basic_string<Char> vformat(const std::locale& loc,
|
|
||||||
basic_string_view<Char> format_str,
|
|
||||||
basic_format_args<buffer_context<Char>> args) {
|
|
||||||
basic_memory_buffer<Char> buffer;
|
basic_memory_buffer<Char> buffer;
|
||||||
internal::vformat_to(loc, buffer, format_str, args);
|
detail::vformat_to(buffer, format_str, args, detail::locale_ref(loc));
|
||||||
return fmt::to_string(buffer);
|
return fmt::to_string(buffer);
|
||||||
}
|
}
|
||||||
} // namespace internal
|
} // namespace detail
|
||||||
|
|
||||||
template <typename S, typename Char = char_t<S>>
|
template <typename S, typename Char = char_t<S>>
|
||||||
inline std::basic_string<Char> vformat(
|
inline std::basic_string<Char> vformat(
|
||||||
const std::locale& loc, const S& format_str,
|
const std::locale& loc, const S& format_str,
|
||||||
basic_format_args<buffer_context<Char>> args) {
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
return internal::vformat(loc, to_string_view(format_str), args);
|
return detail::vformat(loc, to_string_view(format_str), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
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 std::locale& loc,
|
inline std::basic_string<Char> format(const std::locale& loc,
|
||||||
const S& format_str, Args&&... args) {
|
const S& format_str, Args&&... args) {
|
||||||
return internal::vformat(
|
return detail::vformat(loc, to_string_view(format_str),
|
||||||
loc, to_string_view(format_str),
|
fmt::make_args_checked<Args...>(format_str, args...));
|
||||||
{internal::make_args_checked<Args...>(format_str, args...)});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S, typename OutputIt, typename... Args,
|
template <typename S, typename OutputIt, typename... Args,
|
||||||
typename Char = enable_if_t<
|
typename Char = char_t<S>,
|
||||||
internal::is_output_iterator<OutputIt>::value, char_t<S>>>
|
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value)>
|
||||||
inline OutputIt vformat_to(OutputIt out, const std::locale& loc,
|
inline OutputIt vformat_to(
|
||||||
const S& format_str,
|
OutputIt out, const std::locale& loc, const S& format_str,
|
||||||
format_args_t<OutputIt, Char> args) {
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
using range = internal::output_range<OutputIt, Char>;
|
decltype(detail::get_buffer<Char>(out)) buf(detail::get_buffer_init(out));
|
||||||
return vformat_to<arg_formatter<range>>(
|
vformat_to(buf, to_string_view(format_str), args, detail::locale_ref(loc));
|
||||||
range(out), to_string_view(format_str), args, internal::locale_ref(loc));
|
return detail::get_iterator(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIt, typename S, typename... Args,
|
template <typename OutputIt, typename S, typename... Args,
|
||||||
FMT_ENABLE_IF(internal::is_output_iterator<OutputIt>::value&&
|
typename Char = char_t<S>,
|
||||||
internal::is_string<S>::value)>
|
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value)>
|
||||||
inline OutputIt format_to(OutputIt out, const std::locale& loc,
|
inline OutputIt format_to(OutputIt out, const std::locale& loc,
|
||||||
const S& format_str, Args&&... args) {
|
const S& format_str, Args&&... args) {
|
||||||
internal::check_format_string<Args...>(format_str);
|
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
||||||
using context = format_context_t<OutputIt, char_t<S>>;
|
return vformat_to(out, loc, to_string_view(format_str), vargs);
|
||||||
format_arg_store<context, Args...> as{args...};
|
|
||||||
return vformat_to(out, loc, to_string_view(format_str),
|
|
||||||
basic_format_args<context>(as));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
480
Externals/fmt/include/fmt/os.h
vendored
Normal file
480
Externals/fmt/include/fmt/os.h
vendored
Normal file
|
@ -0,0 +1,480 @@
|
||||||
|
// Formatting library for C++ - optional OS-specific functionality
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
|
#ifndef FMT_OS_H_
|
||||||
|
#define FMT_OS_H_
|
||||||
|
|
||||||
|
#if defined(__MINGW32__) || defined(__CYGWIN__)
|
||||||
|
// Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/.
|
||||||
|
# undef __STRICT_ANSI__
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <cerrno>
|
||||||
|
#include <clocale> // for locale_t
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib> // for strtod_l
|
||||||
|
|
||||||
|
#if defined __APPLE__ || defined(__FreeBSD__)
|
||||||
|
# include <xlocale.h> // for LC_NUMERIC_MASK on OS X
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "format.h"
|
||||||
|
|
||||||
|
// UWP doesn't provide _pipe.
|
||||||
|
#if FMT_HAS_INCLUDE("winapifamily.h")
|
||||||
|
# include <winapifamily.h>
|
||||||
|
#endif
|
||||||
|
#if (FMT_HAS_INCLUDE(<fcntl.h>) || defined(__APPLE__) || \
|
||||||
|
defined(__linux__)) && \
|
||||||
|
(!defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
|
||||||
|
# include <fcntl.h> // for O_RDONLY
|
||||||
|
# define FMT_USE_FCNTL 1
|
||||||
|
#else
|
||||||
|
# define FMT_USE_FCNTL 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FMT_POSIX
|
||||||
|
# if defined(_WIN32) && !defined(__MINGW32__)
|
||||||
|
// Fix warnings about deprecated symbols.
|
||||||
|
# define FMT_POSIX(call) _##call
|
||||||
|
# else
|
||||||
|
# define FMT_POSIX(call) call
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Calls to system functions are wrapped in FMT_SYSTEM for testability.
|
||||||
|
#ifdef FMT_SYSTEM
|
||||||
|
# define FMT_POSIX_CALL(call) FMT_SYSTEM(call)
|
||||||
|
#else
|
||||||
|
# define FMT_SYSTEM(call) ::call
|
||||||
|
# ifdef _WIN32
|
||||||
|
// Fix warnings about deprecated symbols.
|
||||||
|
# define FMT_POSIX_CALL(call) ::_##call
|
||||||
|
# else
|
||||||
|
# define FMT_POSIX_CALL(call) ::call
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Retries the expression while it evaluates to error_result and errno
|
||||||
|
// equals to EINTR.
|
||||||
|
#ifndef _WIN32
|
||||||
|
# define FMT_RETRY_VAL(result, expression, error_result) \
|
||||||
|
do { \
|
||||||
|
(result) = (expression); \
|
||||||
|
} while ((result) == (error_result) && errno == EINTR)
|
||||||
|
#else
|
||||||
|
# define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
|
||||||
|
|
||||||
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
A reference to a null-terminated string. It can be constructed from a C
|
||||||
|
string or ``std::string``.
|
||||||
|
|
||||||
|
You can use one of the following type aliases for common character types:
|
||||||
|
|
||||||
|
+---------------+-----------------------------+
|
||||||
|
| Type | Definition |
|
||||||
|
+===============+=============================+
|
||||||
|
| cstring_view | basic_cstring_view<char> |
|
||||||
|
+---------------+-----------------------------+
|
||||||
|
| wcstring_view | basic_cstring_view<wchar_t> |
|
||||||
|
+---------------+-----------------------------+
|
||||||
|
|
||||||
|
This class is most useful as a parameter type to allow passing
|
||||||
|
different types of strings to a function, for example::
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
std::string format(cstring_view format_str, const Args & ... args);
|
||||||
|
|
||||||
|
format("{}", 42);
|
||||||
|
format(std::string("{}"), 42);
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
template <typename Char> class basic_cstring_view {
|
||||||
|
private:
|
||||||
|
const Char* data_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** Constructs a string reference object from a C string. */
|
||||||
|
basic_cstring_view(const Char* s) : data_(s) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
Constructs a string reference from an ``std::string`` object.
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
basic_cstring_view(const std::basic_string<Char>& s) : data_(s.c_str()) {}
|
||||||
|
|
||||||
|
/** Returns the pointer to a C string. */
|
||||||
|
const Char* c_str() const { return data_; }
|
||||||
|
};
|
||||||
|
|
||||||
|
using cstring_view = basic_cstring_view<char>;
|
||||||
|
using wcstring_view = basic_cstring_view<wchar_t>;
|
||||||
|
|
||||||
|
// An error code.
|
||||||
|
class error_code {
|
||||||
|
private:
|
||||||
|
int value_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit error_code(int value = 0) FMT_NOEXCEPT : value_(value) {}
|
||||||
|
|
||||||
|
int get() const FMT_NOEXCEPT { return value_; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
namespace detail {
|
||||||
|
// A converter from UTF-16 to UTF-8.
|
||||||
|
// It is only provided for Windows since other systems support UTF-8 natively.
|
||||||
|
class utf16_to_utf8 {
|
||||||
|
private:
|
||||||
|
memory_buffer buffer_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
utf16_to_utf8() {}
|
||||||
|
FMT_API explicit utf16_to_utf8(wstring_view s);
|
||||||
|
operator string_view() const { return string_view(&buffer_[0], size()); }
|
||||||
|
size_t size() const { return buffer_.size() - 1; }
|
||||||
|
const char* c_str() const { return &buffer_[0]; }
|
||||||
|
std::string str() const { return std::string(&buffer_[0], size()); }
|
||||||
|
|
||||||
|
// Performs conversion returning a system error code instead of
|
||||||
|
// throwing exception on conversion error. This method may still throw
|
||||||
|
// in case of memory allocation error.
|
||||||
|
FMT_API int convert(wstring_view s);
|
||||||
|
};
|
||||||
|
|
||||||
|
FMT_API void format_windows_error(buffer<char>& out, int error_code,
|
||||||
|
string_view message) FMT_NOEXCEPT;
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
/** A Windows error. */
|
||||||
|
class windows_error : public system_error {
|
||||||
|
private:
|
||||||
|
FMT_API void init(int error_code, string_view format_str, format_args args);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
Constructs a :class:`fmt::windows_error` object with the description
|
||||||
|
of the form
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
*<message>*: *<system-message>*
|
||||||
|
|
||||||
|
where *<message>* is the formatted message and *<system-message>* is the
|
||||||
|
system message corresponding to the error code.
|
||||||
|
*error_code* is a Windows error code as given by ``GetLastError``.
|
||||||
|
If *error_code* is not a valid error code such as -1, the system message
|
||||||
|
will look like "error -1".
|
||||||
|
|
||||||
|
**Example**::
|
||||||
|
|
||||||
|
// This throws a windows_error with the description
|
||||||
|
// cannot open file 'madeup': The system cannot find the file specified.
|
||||||
|
// or similar (system message may vary).
|
||||||
|
const char *filename = "madeup";
|
||||||
|
LPOFSTRUCT of = LPOFSTRUCT();
|
||||||
|
HFILE file = OpenFile(filename, &of, OF_READ);
|
||||||
|
if (file == HFILE_ERROR) {
|
||||||
|
throw fmt::windows_error(GetLastError(),
|
||||||
|
"cannot open file '{}'", filename);
|
||||||
|
}
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
template <typename... Args>
|
||||||
|
windows_error(int error_code, string_view message, const Args&... args) {
|
||||||
|
init(error_code, message, make_format_args(args...));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Reports a Windows error without throwing an exception.
|
||||||
|
// Can be used to report errors from destructors.
|
||||||
|
FMT_API void report_windows_error(int error_code,
|
||||||
|
string_view message) FMT_NOEXCEPT;
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
// A buffered file.
|
||||||
|
class buffered_file {
|
||||||
|
private:
|
||||||
|
FILE* file_;
|
||||||
|
|
||||||
|
friend class file;
|
||||||
|
|
||||||
|
explicit buffered_file(FILE* f) : file_(f) {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
buffered_file(const buffered_file&) = delete;
|
||||||
|
void operator=(const buffered_file&) = delete;
|
||||||
|
|
||||||
|
// Constructs a buffered_file object which doesn't represent any file.
|
||||||
|
buffered_file() FMT_NOEXCEPT : file_(nullptr) {}
|
||||||
|
|
||||||
|
// Destroys the object closing the file it represents if any.
|
||||||
|
FMT_API ~buffered_file() FMT_NOEXCEPT;
|
||||||
|
|
||||||
|
public:
|
||||||
|
buffered_file(buffered_file&& other) FMT_NOEXCEPT : file_(other.file_) {
|
||||||
|
other.file_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffered_file& operator=(buffered_file&& other) {
|
||||||
|
close();
|
||||||
|
file_ = other.file_;
|
||||||
|
other.file_ = nullptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Opens a file.
|
||||||
|
FMT_API buffered_file(cstring_view filename, cstring_view mode);
|
||||||
|
|
||||||
|
// Closes the file.
|
||||||
|
FMT_API void close();
|
||||||
|
|
||||||
|
// Returns the pointer to a FILE object representing this file.
|
||||||
|
FILE* get() const FMT_NOEXCEPT { return file_; }
|
||||||
|
|
||||||
|
// We place parentheses around fileno to workaround a bug in some versions
|
||||||
|
// of MinGW that define fileno as a macro.
|
||||||
|
FMT_API int(fileno)() const;
|
||||||
|
|
||||||
|
void vprint(string_view format_str, format_args args) {
|
||||||
|
fmt::vprint(file_, format_str, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
inline void print(string_view format_str, const Args&... args) {
|
||||||
|
vprint(format_str, make_format_args(args...));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#if FMT_USE_FCNTL
|
||||||
|
// A file. Closed file is represented by a file object with descriptor -1.
|
||||||
|
// Methods that are not declared with FMT_NOEXCEPT may throw
|
||||||
|
// 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
|
||||||
|
// than an exception. You can get standard behavior by overriding the
|
||||||
|
// invalid parameter handler with _set_invalid_parameter_handler.
|
||||||
|
class file {
|
||||||
|
private:
|
||||||
|
int fd_; // File descriptor.
|
||||||
|
|
||||||
|
// Constructs a file object with a given descriptor.
|
||||||
|
explicit file(int fd) : fd_(fd) {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Possible values for the oflag argument to the constructor.
|
||||||
|
enum {
|
||||||
|
RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
|
||||||
|
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
|
||||||
|
RDWR = FMT_POSIX(O_RDWR), // Open for reading and writing.
|
||||||
|
CREATE = FMT_POSIX(O_CREAT), // Create if the file doesn't exist.
|
||||||
|
APPEND = FMT_POSIX(O_APPEND) // Open in append mode.
|
||||||
|
};
|
||||||
|
|
||||||
|
// Constructs a file object which doesn't represent any file.
|
||||||
|
file() FMT_NOEXCEPT : fd_(-1) {}
|
||||||
|
|
||||||
|
// Opens a file and constructs a file object representing this file.
|
||||||
|
FMT_API file(cstring_view path, int oflag);
|
||||||
|
|
||||||
|
public:
|
||||||
|
file(const file&) = delete;
|
||||||
|
void operator=(const file&) = delete;
|
||||||
|
|
||||||
|
file(file&& other) FMT_NOEXCEPT : fd_(other.fd_) { other.fd_ = -1; }
|
||||||
|
|
||||||
|
file& operator=(file&& other) FMT_NOEXCEPT {
|
||||||
|
close();
|
||||||
|
fd_ = other.fd_;
|
||||||
|
other.fd_ = -1;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroys the object closing the file it represents if any.
|
||||||
|
FMT_API ~file() FMT_NOEXCEPT;
|
||||||
|
|
||||||
|
// Returns the file descriptor.
|
||||||
|
int descriptor() const FMT_NOEXCEPT { return fd_; }
|
||||||
|
|
||||||
|
// Closes the file.
|
||||||
|
FMT_API void close();
|
||||||
|
|
||||||
|
// Returns the file size. The size has signed type for consistency with
|
||||||
|
// stat::st_size.
|
||||||
|
FMT_API long long size() const;
|
||||||
|
|
||||||
|
// Attempts to read count bytes from the file into the specified buffer.
|
||||||
|
FMT_API size_t read(void* buffer, size_t count);
|
||||||
|
|
||||||
|
// Attempts to write count bytes from the specified buffer to the file.
|
||||||
|
FMT_API size_t write(const void* buffer, size_t count);
|
||||||
|
|
||||||
|
// Duplicates a file descriptor with the dup function and returns
|
||||||
|
// the duplicate as a file object.
|
||||||
|
FMT_API static file dup(int fd);
|
||||||
|
|
||||||
|
// Makes fd be the copy of this file descriptor, closing fd first if
|
||||||
|
// necessary.
|
||||||
|
FMT_API void dup2(int fd);
|
||||||
|
|
||||||
|
// Makes fd be the copy of this file descriptor, closing fd first if
|
||||||
|
// necessary.
|
||||||
|
FMT_API void dup2(int fd, error_code& ec) FMT_NOEXCEPT;
|
||||||
|
|
||||||
|
// Creates a pipe setting up read_end and write_end file objects for reading
|
||||||
|
// and writing respectively.
|
||||||
|
FMT_API static void pipe(file& read_end, file& write_end);
|
||||||
|
|
||||||
|
// Creates a buffered_file object associated with this file and detaches
|
||||||
|
// this file object from the file.
|
||||||
|
FMT_API buffered_file fdopen(const char* mode);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns the memory page size.
|
||||||
|
long getpagesize();
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
struct buffer_size {
|
||||||
|
size_t value = 0;
|
||||||
|
buffer_size operator=(size_t val) const {
|
||||||
|
auto bs = buffer_size();
|
||||||
|
bs.value = val;
|
||||||
|
return bs;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ostream_params {
|
||||||
|
int oflag = file::WRONLY | file::CREATE;
|
||||||
|
size_t buffer_size = BUFSIZ > 32768 ? BUFSIZ : 32768;
|
||||||
|
|
||||||
|
ostream_params() {}
|
||||||
|
|
||||||
|
template <typename... T>
|
||||||
|
ostream_params(T... params, int oflag) : ostream_params(params...) {
|
||||||
|
this->oflag = oflag;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... T>
|
||||||
|
ostream_params(T... params, detail::buffer_size bs)
|
||||||
|
: ostream_params(params...) {
|
||||||
|
this->buffer_size = bs.value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
static constexpr detail::buffer_size buffer_size;
|
||||||
|
|
||||||
|
// A fast output stream which is not thread-safe.
|
||||||
|
class ostream final : private detail::buffer<char> {
|
||||||
|
private:
|
||||||
|
file file_;
|
||||||
|
|
||||||
|
void flush() {
|
||||||
|
if (size() == 0) return;
|
||||||
|
file_.write(data(), size());
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void grow(size_t) final;
|
||||||
|
|
||||||
|
ostream(cstring_view path, const detail::ostream_params& params)
|
||||||
|
: file_(path, params.oflag) {
|
||||||
|
set(new char[params.buffer_size], params.buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
ostream(ostream&& other)
|
||||||
|
: detail::buffer<char>(other.data(), other.size(), other.capacity()),
|
||||||
|
file_(std::move(other.file_)) {
|
||||||
|
other.set(nullptr, 0);
|
||||||
|
}
|
||||||
|
~ostream() {
|
||||||
|
flush();
|
||||||
|
delete[] data();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... T>
|
||||||
|
friend ostream output_file(cstring_view path, T... params);
|
||||||
|
|
||||||
|
void close() {
|
||||||
|
flush();
|
||||||
|
file_.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename S, typename... Args>
|
||||||
|
void print(const S& format_str, const Args&... args) {
|
||||||
|
format_to(detail::buffer_appender<char>(*this), format_str, args...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Opens a file for writing. Supported parameters passed in `params`:
|
||||||
|
* ``<integer>``: Output flags (``file::WRONLY | file::CREATE`` by default)
|
||||||
|
* ``buffer_size=<integer>``: Output buffer size
|
||||||
|
*/
|
||||||
|
template <typename... T>
|
||||||
|
inline ostream output_file(cstring_view path, T... params) {
|
||||||
|
return {path, detail::ostream_params(params...)};
|
||||||
|
}
|
||||||
|
#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.
|
||||||
|
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_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif // FMT_OS_H_
|
76
Externals/fmt/include/fmt/ostream.h
vendored
76
Externals/fmt/include/fmt/ostream.h
vendored
|
@ -9,10 +9,15 @@
|
||||||
#define FMT_OSTREAM_H_
|
#define FMT_OSTREAM_H_
|
||||||
|
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
namespace internal {
|
|
||||||
|
template <typename Char> class basic_printf_parse_context;
|
||||||
|
template <typename OutputIt, typename Char> class basic_printf_context;
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
template <class Char> class formatbuf : public std::basic_streambuf<Char> {
|
template <class Char> class formatbuf : public std::basic_streambuf<Char> {
|
||||||
private:
|
private:
|
||||||
|
@ -44,17 +49,27 @@ template <class Char> class formatbuf : public std::basic_streambuf<Char> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct converter {
|
||||||
|
template <typename T, FMT_ENABLE_IF(is_integral<T>::value)> converter(T);
|
||||||
|
};
|
||||||
|
|
||||||
template <typename Char> struct test_stream : std::basic_ostream<Char> {
|
template <typename Char> struct test_stream : std::basic_ostream<Char> {
|
||||||
private:
|
private:
|
||||||
// Hide all operator<< from std::basic_ostream<Char>.
|
void_t<> operator<<(converter);
|
||||||
void_t<> operator<<(null<>);
|
|
||||||
void_t<> operator<<(const Char*);
|
|
||||||
|
|
||||||
template <typename T, FMT_ENABLE_IF(std::is_convertible<T, int>::value &&
|
|
||||||
!std::is_enum<T>::value)>
|
|
||||||
void_t<> operator<<(T);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Hide insertion operators for built-in types.
|
||||||
|
template <typename Char, typename Traits>
|
||||||
|
void_t<> operator<<(std::basic_ostream<Char, Traits>&, Char);
|
||||||
|
template <typename Char, typename Traits>
|
||||||
|
void_t<> operator<<(std::basic_ostream<Char, Traits>&, char);
|
||||||
|
template <typename Traits>
|
||||||
|
void_t<> operator<<(std::basic_ostream<char, Traits>&, char);
|
||||||
|
template <typename Traits>
|
||||||
|
void_t<> operator<<(std::basic_ostream<char, Traits>&, signed char);
|
||||||
|
template <typename Traits>
|
||||||
|
void_t<> operator<<(std::basic_ostream<char, Traits>&, unsigned char);
|
||||||
|
|
||||||
// Checks if T has a user-defined operator<< (e.g. not a member of
|
// Checks if T has a user-defined operator<< (e.g. not a member of
|
||||||
// std::ostream).
|
// std::ostream).
|
||||||
template <typename T, typename Char> class is_streamable {
|
template <typename T, typename Char> class is_streamable {
|
||||||
|
@ -75,7 +90,7 @@ template <typename T, typename Char> class is_streamable {
|
||||||
|
|
||||||
// Write the content of buf to os.
|
// Write the content of buf to os.
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
void write(std::basic_ostream<Char>& os, buffer<Char>& buf) {
|
void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) {
|
||||||
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();
|
||||||
|
@ -93,32 +108,53 @@ void format_value(buffer<Char>& buf, const T& value,
|
||||||
locale_ref loc = locale_ref()) {
|
locale_ref loc = locale_ref()) {
|
||||||
formatbuf<Char> format_buf(buf);
|
formatbuf<Char> format_buf(buf);
|
||||||
std::basic_ostream<Char> output(&format_buf);
|
std::basic_ostream<Char> output(&format_buf);
|
||||||
|
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
|
||||||
if (loc) output.imbue(loc.get<std::locale>());
|
if (loc) output.imbue(loc.get<std::locale>());
|
||||||
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
#endif
|
||||||
output << value;
|
output << value;
|
||||||
buf.resize(buf.size());
|
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<<.
|
// Formats an object of type T that has an overloaded ostream operator<<.
|
||||||
template <typename T, typename Char>
|
template <typename T, typename Char>
|
||||||
struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>>
|
struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>>
|
||||||
: formatter<basic_string_view<Char>, Char> {
|
: private formatter<basic_string_view<Char>, Char> {
|
||||||
template <typename Context>
|
FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
|
||||||
auto format(const T& value, Context& ctx) -> decltype(ctx.out()) {
|
-> decltype(ctx.begin()) {
|
||||||
|
return formatter<basic_string_view<Char>, Char>::parse(ctx);
|
||||||
|
}
|
||||||
|
template <typename ParseCtx,
|
||||||
|
FMT_ENABLE_IF(std::is_same<
|
||||||
|
ParseCtx, basic_printf_parse_context<Char>>::value)>
|
||||||
|
auto parse(ParseCtx& ctx) -> decltype(ctx.begin()) {
|
||||||
|
return ctx.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputIt>
|
||||||
|
auto format(const T& value, basic_format_context<OutputIt, Char>& ctx)
|
||||||
|
-> OutputIt {
|
||||||
basic_memory_buffer<Char> buffer;
|
basic_memory_buffer<Char> buffer;
|
||||||
format_value(buffer, value, ctx.locale());
|
format_value(buffer, value, ctx.locale());
|
||||||
basic_string_view<Char> str(buffer.data(), buffer.size());
|
basic_string_view<Char> str(buffer.data(), buffer.size());
|
||||||
return formatter<basic_string_view<Char>, Char>::format(str, ctx);
|
return formatter<basic_string_view<Char>, Char>::format(str, ctx);
|
||||||
}
|
}
|
||||||
|
template <typename OutputIt>
|
||||||
|
auto format(const T& value, basic_printf_context<OutputIt, Char>& ctx)
|
||||||
|
-> OutputIt {
|
||||||
|
basic_memory_buffer<Char> buffer;
|
||||||
|
format_value(buffer, value, ctx.locale());
|
||||||
|
return std::copy(buffer.begin(), buffer.end(), ctx.out());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
} // namespace internal
|
} // namespace detail
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
|
void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
|
||||||
basic_format_args<buffer_context<Char>> args) {
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
basic_memory_buffer<Char> buffer;
|
basic_memory_buffer<Char> buffer;
|
||||||
internal::vformat_to(buffer, format_str, args);
|
detail::vformat_to(buffer, format_str, args);
|
||||||
internal::write(os, buffer);
|
detail::write_buffer(os, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -131,10 +167,10 @@ void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename S, typename... Args,
|
template <typename S, typename... Args,
|
||||||
typename Char = enable_if_t<internal::is_string<S>::value, char_t<S>>>
|
typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
|
||||||
void print(std::basic_ostream<Char>& os, const S& format_str, Args&&... args) {
|
void print(std::basic_ostream<Char>& os, const S& format_str, Args&&... args) {
|
||||||
vprint(os, to_string_view(format_str),
|
vprint(os, to_string_view(format_str),
|
||||||
{internal::make_args_checked<Args...>(format_str, args...)});
|
fmt::make_args_checked<Args...>(format_str, args...));
|
||||||
}
|
}
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
|
323
Externals/fmt/include/fmt/posix.h
vendored
323
Externals/fmt/include/fmt/posix.h
vendored
|
@ -1,321 +1,2 @@
|
||||||
// A C++ interface to POSIX functions.
|
#include "os.h"
|
||||||
//
|
#warning "fmt/posix.h is deprecated; use fmt/os.h instead"
|
||||||
// Copyright (c) 2012 - 2016, Victor Zverovich
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// For the license information refer to format.h.
|
|
||||||
|
|
||||||
#ifndef FMT_POSIX_H_
|
|
||||||
#define FMT_POSIX_H_
|
|
||||||
|
|
||||||
#if defined(__MINGW32__) || defined(__CYGWIN__)
|
|
||||||
// Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/.
|
|
||||||
# undef __STRICT_ANSI__
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <cerrno>
|
|
||||||
#include <clocale> // for locale_t
|
|
||||||
#include <cstdio>
|
|
||||||
#include <cstdlib> // for strtod_l
|
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
|
|
||||||
#if defined __APPLE__ || defined(__FreeBSD__)
|
|
||||||
# include <xlocale.h> // for LC_NUMERIC_MASK on OS X
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "format.h"
|
|
||||||
|
|
||||||
// UWP doesn't provide _pipe.
|
|
||||||
#if FMT_HAS_INCLUDE("winapifamily.h")
|
|
||||||
# include <winapifamily.h>
|
|
||||||
#endif
|
|
||||||
#if FMT_HAS_INCLUDE("fcntl.h") && \
|
|
||||||
(!defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
|
|
||||||
# include <fcntl.h> // for O_RDONLY
|
|
||||||
# define FMT_USE_FCNTL 1
|
|
||||||
#else
|
|
||||||
# define FMT_USE_FCNTL 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef FMT_POSIX
|
|
||||||
# if defined(_WIN32) && !defined(__MINGW32__)
|
|
||||||
// Fix warnings about deprecated symbols.
|
|
||||||
# define FMT_POSIX(call) _##call
|
|
||||||
# else
|
|
||||||
# define FMT_POSIX(call) call
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Calls to system functions are wrapped in FMT_SYSTEM for testability.
|
|
||||||
#ifdef FMT_SYSTEM
|
|
||||||
# define FMT_POSIX_CALL(call) FMT_SYSTEM(call)
|
|
||||||
#else
|
|
||||||
# define FMT_SYSTEM(call) call
|
|
||||||
# ifdef _WIN32
|
|
||||||
// Fix warnings about deprecated symbols.
|
|
||||||
# define FMT_POSIX_CALL(call) ::_##call
|
|
||||||
# else
|
|
||||||
# define FMT_POSIX_CALL(call) ::call
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Retries the expression while it evaluates to error_result and errno
|
|
||||||
// equals to EINTR.
|
|
||||||
#ifndef _WIN32
|
|
||||||
# define FMT_RETRY_VAL(result, expression, error_result) \
|
|
||||||
do { \
|
|
||||||
(result) = (expression); \
|
|
||||||
} while ((result) == (error_result) && errno == EINTR)
|
|
||||||
#else
|
|
||||||
# define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
|
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
|
||||||
|
|
||||||
/**
|
|
||||||
\rst
|
|
||||||
A reference to a null-terminated string. It can be constructed from a C
|
|
||||||
string or ``std::string``.
|
|
||||||
|
|
||||||
You can use one of the following type aliases for common character types:
|
|
||||||
|
|
||||||
+---------------+-----------------------------+
|
|
||||||
| Type | Definition |
|
|
||||||
+===============+=============================+
|
|
||||||
| cstring_view | basic_cstring_view<char> |
|
|
||||||
+---------------+-----------------------------+
|
|
||||||
| wcstring_view | basic_cstring_view<wchar_t> |
|
|
||||||
+---------------+-----------------------------+
|
|
||||||
|
|
||||||
This class is most useful as a parameter type to allow passing
|
|
||||||
different types of strings to a function, for example::
|
|
||||||
|
|
||||||
template <typename... Args>
|
|
||||||
std::string format(cstring_view format_str, const Args & ... args);
|
|
||||||
|
|
||||||
format("{}", 42);
|
|
||||||
format(std::string("{}"), 42);
|
|
||||||
\endrst
|
|
||||||
*/
|
|
||||||
template <typename Char> class basic_cstring_view {
|
|
||||||
private:
|
|
||||||
const Char* data_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
/** Constructs a string reference object from a C string. */
|
|
||||||
basic_cstring_view(const Char* s) : data_(s) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
\rst
|
|
||||||
Constructs a string reference from an ``std::string`` object.
|
|
||||||
\endrst
|
|
||||||
*/
|
|
||||||
basic_cstring_view(const std::basic_string<Char>& s) : data_(s.c_str()) {}
|
|
||||||
|
|
||||||
/** Returns the pointer to a C string. */
|
|
||||||
const Char* c_str() const { return data_; }
|
|
||||||
};
|
|
||||||
|
|
||||||
using cstring_view = basic_cstring_view<char>;
|
|
||||||
using wcstring_view = basic_cstring_view<wchar_t>;
|
|
||||||
|
|
||||||
// An error code.
|
|
||||||
class error_code {
|
|
||||||
private:
|
|
||||||
int value_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit error_code(int value = 0) FMT_NOEXCEPT : value_(value) {}
|
|
||||||
|
|
||||||
int get() const FMT_NOEXCEPT { return value_; }
|
|
||||||
};
|
|
||||||
|
|
||||||
// A buffered file.
|
|
||||||
class buffered_file {
|
|
||||||
private:
|
|
||||||
FILE* file_;
|
|
||||||
|
|
||||||
friend class file;
|
|
||||||
|
|
||||||
explicit buffered_file(FILE* f) : file_(f) {}
|
|
||||||
|
|
||||||
public:
|
|
||||||
buffered_file(const buffered_file&) = delete;
|
|
||||||
void operator=(const buffered_file&) = delete;
|
|
||||||
|
|
||||||
// Constructs a buffered_file object which doesn't represent any file.
|
|
||||||
buffered_file() FMT_NOEXCEPT : file_(nullptr) {}
|
|
||||||
|
|
||||||
// Destroys the object closing the file it represents if any.
|
|
||||||
FMT_API ~buffered_file() FMT_NOEXCEPT;
|
|
||||||
|
|
||||||
public:
|
|
||||||
buffered_file(buffered_file&& other) FMT_NOEXCEPT : file_(other.file_) {
|
|
||||||
other.file_ = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffered_file& operator=(buffered_file&& other) {
|
|
||||||
close();
|
|
||||||
file_ = other.file_;
|
|
||||||
other.file_ = nullptr;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Opens a file.
|
|
||||||
FMT_API buffered_file(cstring_view filename, cstring_view mode);
|
|
||||||
|
|
||||||
// Closes the file.
|
|
||||||
FMT_API void close();
|
|
||||||
|
|
||||||
// Returns the pointer to a FILE object representing this file.
|
|
||||||
FILE* get() const FMT_NOEXCEPT { return file_; }
|
|
||||||
|
|
||||||
// We place parentheses around fileno to workaround a bug in some versions
|
|
||||||
// of MinGW that define fileno as a macro.
|
|
||||||
FMT_API int(fileno)() const;
|
|
||||||
|
|
||||||
void vprint(string_view format_str, format_args args) {
|
|
||||||
fmt::vprint(file_, format_str, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename... Args>
|
|
||||||
inline void print(string_view format_str, const Args&... args) {
|
|
||||||
vprint(format_str, make_format_args(args...));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#if FMT_USE_FCNTL
|
|
||||||
// A file. Closed file is represented by a file object with descriptor -1.
|
|
||||||
// Methods that are not declared with FMT_NOEXCEPT may throw
|
|
||||||
// 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
|
|
||||||
// than an exception. You can get standard behavior by overriding the
|
|
||||||
// invalid parameter handler with _set_invalid_parameter_handler.
|
|
||||||
class file {
|
|
||||||
private:
|
|
||||||
int fd_; // File descriptor.
|
|
||||||
|
|
||||||
// Constructs a file object with a given descriptor.
|
|
||||||
explicit file(int fd) : fd_(fd) {}
|
|
||||||
|
|
||||||
public:
|
|
||||||
// Possible values for the oflag argument to the constructor.
|
|
||||||
enum {
|
|
||||||
RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
|
|
||||||
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
|
|
||||||
RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing.
|
|
||||||
};
|
|
||||||
|
|
||||||
// Constructs a file object which doesn't represent any file.
|
|
||||||
file() FMT_NOEXCEPT : fd_(-1) {}
|
|
||||||
|
|
||||||
// Opens a file and constructs a file object representing this file.
|
|
||||||
FMT_API file(cstring_view path, int oflag);
|
|
||||||
|
|
||||||
public:
|
|
||||||
file(const file&) = delete;
|
|
||||||
void operator=(const file&) = delete;
|
|
||||||
|
|
||||||
file(file&& other) FMT_NOEXCEPT : fd_(other.fd_) { other.fd_ = -1; }
|
|
||||||
|
|
||||||
file& operator=(file&& other) FMT_NOEXCEPT {
|
|
||||||
close();
|
|
||||||
fd_ = other.fd_;
|
|
||||||
other.fd_ = -1;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destroys the object closing the file it represents if any.
|
|
||||||
FMT_API ~file() FMT_NOEXCEPT;
|
|
||||||
|
|
||||||
// Returns the file descriptor.
|
|
||||||
int descriptor() const FMT_NOEXCEPT { return fd_; }
|
|
||||||
|
|
||||||
// Closes the file.
|
|
||||||
FMT_API void close();
|
|
||||||
|
|
||||||
// Returns the file size. The size has signed type for consistency with
|
|
||||||
// stat::st_size.
|
|
||||||
FMT_API long long size() const;
|
|
||||||
|
|
||||||
// Attempts to read count bytes from the file into the specified buffer.
|
|
||||||
FMT_API std::size_t read(void* buffer, std::size_t count);
|
|
||||||
|
|
||||||
// Attempts to write count bytes from the specified buffer to the file.
|
|
||||||
FMT_API std::size_t write(const void* buffer, std::size_t count);
|
|
||||||
|
|
||||||
// Duplicates a file descriptor with the dup function and returns
|
|
||||||
// the duplicate as a file object.
|
|
||||||
FMT_API static file dup(int fd);
|
|
||||||
|
|
||||||
// Makes fd be the copy of this file descriptor, closing fd first if
|
|
||||||
// necessary.
|
|
||||||
FMT_API void dup2(int fd);
|
|
||||||
|
|
||||||
// Makes fd be the copy of this file descriptor, closing fd first if
|
|
||||||
// necessary.
|
|
||||||
FMT_API void dup2(int fd, error_code& ec) FMT_NOEXCEPT;
|
|
||||||
|
|
||||||
// Creates a pipe setting up read_end and write_end file objects for reading
|
|
||||||
// and writing respectively.
|
|
||||||
FMT_API static void pipe(file& read_end, file& write_end);
|
|
||||||
|
|
||||||
// Creates a buffered_file object associated with this file and detaches
|
|
||||||
// this file object from the file.
|
|
||||||
FMT_API buffered_file fdopen(const char* mode);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Returns the memory page size.
|
|
||||||
long getpagesize();
|
|
||||||
#endif // FMT_USE_FCNTL
|
|
||||||
|
|
||||||
#ifdef FMT_LOCALE
|
|
||||||
// A "C" numeric locale.
|
|
||||||
class Locale {
|
|
||||||
private:
|
|
||||||
# ifdef _WIN32
|
|
||||||
using locale_t = _locale_t;
|
|
||||||
|
|
||||||
enum { LC_NUMERIC_MASK = LC_NUMERIC };
|
|
||||||
|
|
||||||
static locale_t newlocale(int category_mask, const char* locale, locale_t) {
|
|
||||||
return _create_locale(category_mask, locale);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void freelocale(locale_t locale) { _free_locale(locale); }
|
|
||||||
|
|
||||||
static double strtod_l(const char* nptr, char** endptr, _locale_t locale) {
|
|
||||||
return _strtod_l(nptr, endptr, locale);
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
|
|
||||||
locale_t locale_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
using type = locale_t;
|
|
||||||
Locale(const Locale&) = delete;
|
|
||||||
void operator=(const Locale&) = delete;
|
|
||||||
|
|
||||||
Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", nullptr)) {
|
|
||||||
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.
|
|
||||||
double strtod(const char*& str) const {
|
|
||||||
char* end = nullptr;
|
|
||||||
double result = strtod_l(str, &end, locale_);
|
|
||||||
str = end;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#endif // FMT_LOCALE
|
|
||||||
FMT_END_NAMESPACE
|
|
||||||
|
|
||||||
#endif // FMT_POSIX_H_
|
|
||||||
|
|
200
Externals/fmt/include/fmt/printf.h
vendored
200
Externals/fmt/include/fmt/printf.h
vendored
|
@ -14,7 +14,7 @@
|
||||||
#include "ostream.h"
|
#include "ostream.h"
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
namespace internal {
|
namespace detail {
|
||||||
|
|
||||||
// Checks if a value fits in int - used to avoid warnings about comparing
|
// Checks if a value fits in int - used to avoid warnings about comparing
|
||||||
// signed and unsigned integers.
|
// signed and unsigned integers.
|
||||||
|
@ -28,7 +28,7 @@ template <bool IsSigned> struct int_checker {
|
||||||
|
|
||||||
template <> struct int_checker<true> {
|
template <> struct int_checker<true> {
|
||||||
template <typename T> static bool fits_in_int(T value) {
|
template <typename T> static bool fits_in_int(T value) {
|
||||||
return value >= std::numeric_limits<int>::min() &&
|
return value >= (std::numeric_limits<int>::min)() &&
|
||||||
value <= max_value<int>();
|
value <= max_value<int>();
|
||||||
}
|
}
|
||||||
static bool fits_in_int(int) { return true; }
|
static bool fits_in_int(int) { return true; }
|
||||||
|
@ -90,11 +90,11 @@ template <typename T, typename Context> class arg_converter {
|
||||||
if (const_check(sizeof(target_type) <= sizeof(int))) {
|
if (const_check(sizeof(target_type) <= sizeof(int))) {
|
||||||
// Extra casts are used to silence warnings.
|
// Extra casts are used to silence warnings.
|
||||||
if (is_signed) {
|
if (is_signed) {
|
||||||
arg_ = internal::make_arg<Context>(
|
arg_ = detail::make_arg<Context>(
|
||||||
static_cast<int>(static_cast<target_type>(value)));
|
static_cast<int>(static_cast<target_type>(value)));
|
||||||
} else {
|
} else {
|
||||||
using unsigned_type = typename make_unsigned_or_bool<target_type>::type;
|
using unsigned_type = typename make_unsigned_or_bool<target_type>::type;
|
||||||
arg_ = internal::make_arg<Context>(
|
arg_ = detail::make_arg<Context>(
|
||||||
static_cast<unsigned>(static_cast<unsigned_type>(value)));
|
static_cast<unsigned>(static_cast<unsigned_type>(value)));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -102,9 +102,9 @@ template <typename T, typename Context> class arg_converter {
|
||||||
// glibc's printf doesn't sign extend arguments of smaller types:
|
// glibc's printf doesn't sign extend arguments of smaller types:
|
||||||
// std::printf("%lld", -42); // prints "4294967254"
|
// std::printf("%lld", -42); // prints "4294967254"
|
||||||
// but we don't have to do the same because it's a UB.
|
// but we don't have to do the same because it's a UB.
|
||||||
arg_ = internal::make_arg<Context>(static_cast<long long>(value));
|
arg_ = detail::make_arg<Context>(static_cast<long long>(value));
|
||||||
} else {
|
} else {
|
||||||
arg_ = internal::make_arg<Context>(
|
arg_ = detail::make_arg<Context>(
|
||||||
static_cast<typename make_unsigned_or_bool<U>::type>(value));
|
static_cast<typename make_unsigned_or_bool<U>::type>(value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,7 +133,7 @@ template <typename Context> class char_converter {
|
||||||
|
|
||||||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
||||||
void operator()(T value) {
|
void operator()(T value) {
|
||||||
arg_ = internal::make_arg<Context>(
|
arg_ = detail::make_arg<Context>(
|
||||||
static_cast<typename Context::char_type>(value));
|
static_cast<typename Context::char_type>(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,6 +141,13 @@ template <typename Context> class char_converter {
|
||||||
void operator()(T) {} // No conversion needed for non-integral types.
|
void operator()(T) {} // No conversion needed for non-integral types.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// An argument visitor that return a pointer to a C string if argument is a
|
||||||
|
// string or null otherwise.
|
||||||
|
template <typename Char> struct get_cstring {
|
||||||
|
template <typename T> const Char* operator()(T) { return nullptr; }
|
||||||
|
const Char* operator()(const Char* s) { return s; }
|
||||||
|
};
|
||||||
|
|
||||||
// Checks if an argument is a valid printf width specifier and sets
|
// Checks if an argument is a valid printf width specifier and sets
|
||||||
// left alignment if it is negative.
|
// left alignment if it is negative.
|
||||||
template <typename Char> class printf_width_handler {
|
template <typename Char> class printf_width_handler {
|
||||||
|
@ -155,7 +162,7 @@ template <typename Char> class printf_width_handler {
|
||||||
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
template <typename T, FMT_ENABLE_IF(std::is_integral<T>::value)>
|
||||||
unsigned operator()(T value) {
|
unsigned operator()(T value) {
|
||||||
auto width = static_cast<uint32_or_64_or_128_t<T>>(value);
|
auto width = static_cast<uint32_or_64_or_128_t<T>>(value);
|
||||||
if (internal::is_negative(value)) {
|
if (detail::is_negative(value)) {
|
||||||
specs_.align = align::left;
|
specs_.align = align::left;
|
||||||
width = 0 - width;
|
width = 0 - width;
|
||||||
}
|
}
|
||||||
|
@ -172,23 +179,25 @@ template <typename Char> class printf_width_handler {
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Char, typename Context>
|
template <typename Char, typename Context>
|
||||||
void printf(buffer<Char>& buf, basic_string_view<Char> format,
|
void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
||||||
basic_format_args<Context> args) {
|
basic_format_args<Context> args) {
|
||||||
Context(std::back_inserter(buf), format, args).format();
|
Context(buffer_appender<Char>(buf), format, args).format();
|
||||||
}
|
}
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
template <typename OutputIt, typename Char, typename Context>
|
// For printing into memory_buffer.
|
||||||
internal::truncating_iterator<OutputIt> printf(
|
template <typename Char, typename Context>
|
||||||
internal::truncating_iterator<OutputIt> it, basic_string_view<Char> format,
|
FMT_DEPRECATED void printf(detail::buffer<Char>& buf,
|
||||||
basic_format_args<Context> args) {
|
basic_string_view<Char> format,
|
||||||
return Context(it, format, args).format();
|
basic_format_args<Context> args) {
|
||||||
|
return detail::vprintf(buf, format, args);
|
||||||
}
|
}
|
||||||
} // namespace internal
|
using detail::vprintf;
|
||||||
|
|
||||||
using internal::printf; // For printing into memory_buffer.
|
|
||||||
|
|
||||||
template <typename Range> class printf_arg_formatter;
|
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
class basic_printf_parse_context : public basic_format_parse_context<Char> {
|
||||||
|
using basic_format_parse_context<Char>::basic_format_parse_context;
|
||||||
|
};
|
||||||
template <typename OutputIt, typename Char> class basic_printf_context;
|
template <typename OutputIt, typename Char> class basic_printf_context;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -196,15 +205,15 @@ template <typename OutputIt, typename Char> class basic_printf_context;
|
||||||
The ``printf`` argument formatter.
|
The ``printf`` argument formatter.
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename Range>
|
template <typename OutputIt, typename Char>
|
||||||
class printf_arg_formatter : public internal::arg_formatter_base<Range> {
|
class printf_arg_formatter : public detail::arg_formatter_base<OutputIt, Char> {
|
||||||
public:
|
public:
|
||||||
using iterator = typename Range::iterator;
|
using iterator = OutputIt;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using char_type = typename Range::value_type;
|
using char_type = Char;
|
||||||
using base = internal::arg_formatter_base<Range>;
|
using base = detail::arg_formatter_base<OutputIt, Char>;
|
||||||
using context_type = basic_printf_context<iterator, char_type>;
|
using context_type = basic_printf_context<OutputIt, Char>;
|
||||||
|
|
||||||
context_type& context_;
|
context_type& context_;
|
||||||
|
|
||||||
|
@ -229,9 +238,9 @@ class printf_arg_formatter : public internal::arg_formatter_base<Range> {
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
printf_arg_formatter(iterator iter, format_specs& specs, context_type& ctx)
|
printf_arg_formatter(iterator iter, format_specs& specs, context_type& ctx)
|
||||||
: base(Range(iter), &specs, internal::locale_ref()), context_(ctx) {}
|
: base(iter, &specs, detail::locale_ref()), context_(ctx) {}
|
||||||
|
|
||||||
template <typename T, FMT_ENABLE_IF(fmt::internal::is_integral<T>::value)>
|
template <typename T, FMT_ENABLE_IF(fmt::detail::is_integral<T>::value)>
|
||||||
iterator operator()(T value) {
|
iterator operator()(T value) {
|
||||||
// MSVC2013 fails to compile separate overloads for bool and char_type so
|
// MSVC2013 fails to compile separate overloads for bool and char_type so
|
||||||
// use std::is_same instead.
|
// use std::is_same instead.
|
||||||
|
@ -246,7 +255,11 @@ class printf_arg_formatter : public internal::arg_formatter_base<Range> {
|
||||||
return (*this)(static_cast<int>(value));
|
return (*this)(static_cast<int>(value));
|
||||||
fmt_specs.sign = sign::none;
|
fmt_specs.sign = sign::none;
|
||||||
fmt_specs.alt = false;
|
fmt_specs.alt = false;
|
||||||
fmt_specs.align = align::right;
|
fmt_specs.fill[0] = ' '; // Ignore '0' flag for char types.
|
||||||
|
// align::numeric needs to be overwritten here since the '0' flag is
|
||||||
|
// ignored for non-numeric types
|
||||||
|
if (fmt_specs.align == align::none || fmt_specs.align == align::numeric)
|
||||||
|
fmt_specs.align = align::right;
|
||||||
return base::operator()(value);
|
return base::operator()(value);
|
||||||
} else {
|
} else {
|
||||||
return base::operator()(value);
|
return base::operator()(value);
|
||||||
|
@ -303,6 +316,8 @@ class printf_arg_formatter : public internal::arg_formatter_base<Range> {
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T> struct printf_formatter {
|
template <typename T> struct printf_formatter {
|
||||||
|
printf_formatter() = delete;
|
||||||
|
|
||||||
template <typename ParseContext>
|
template <typename ParseContext>
|
||||||
auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
return ctx.begin();
|
return ctx.begin();
|
||||||
|
@ -310,17 +325,21 @@ template <typename T> struct printf_formatter {
|
||||||
|
|
||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
auto format(const T& value, FormatContext& ctx) -> decltype(ctx.out()) {
|
auto format(const T& value, FormatContext& ctx) -> decltype(ctx.out()) {
|
||||||
internal::format_value(internal::get_container(ctx.out()), value);
|
detail::format_value(detail::get_container(ctx.out()), value);
|
||||||
return ctx.out();
|
return ctx.out();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** This template formats data and writes the output to a writer. */
|
/**
|
||||||
|
This template formats data and writes the output through an output iterator.
|
||||||
|
*/
|
||||||
template <typename OutputIt, typename Char> class basic_printf_context {
|
template <typename OutputIt, typename Char> class basic_printf_context {
|
||||||
public:
|
public:
|
||||||
/** The character type for the output. */
|
/** The character type for the output. */
|
||||||
using char_type = Char;
|
using char_type = Char;
|
||||||
|
using iterator = OutputIt;
|
||||||
using format_arg = basic_format_arg<basic_printf_context>;
|
using format_arg = basic_format_arg<basic_printf_context>;
|
||||||
|
using parse_context_type = basic_printf_parse_context<Char>;
|
||||||
template <typename T> using formatter_type = printf_formatter<T>;
|
template <typename T> using formatter_type = printf_formatter<T>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -328,7 +347,7 @@ template <typename OutputIt, typename Char> class basic_printf_context {
|
||||||
|
|
||||||
OutputIt out_;
|
OutputIt out_;
|
||||||
basic_format_args<basic_printf_context> args_;
|
basic_format_args<basic_printf_context> args_;
|
||||||
basic_format_parse_context<Char> parse_ctx_;
|
parse_context_type parse_ctx_;
|
||||||
|
|
||||||
static void parse_flags(format_specs& specs, const Char*& it,
|
static void parse_flags(format_specs& specs, const Char*& it,
|
||||||
const Char* end);
|
const Char* end);
|
||||||
|
@ -343,9 +362,8 @@ template <typename OutputIt, typename Char> class basic_printf_context {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
Constructs a ``printf_context`` object. References to the arguments and
|
Constructs a ``printf_context`` object. References to the arguments are
|
||||||
the writer are stored in the context object so make sure they have
|
stored in the context object so make sure they have appropriate lifetimes.
|
||||||
appropriate lifetimes.
|
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
basic_printf_context(OutputIt out, basic_string_view<char_type> format_str,
|
basic_printf_context(OutputIt out, basic_string_view<char_type> format_str,
|
||||||
|
@ -355,16 +373,18 @@ template <typename OutputIt, typename Char> class basic_printf_context {
|
||||||
OutputIt out() { return out_; }
|
OutputIt out() { return out_; }
|
||||||
void advance_to(OutputIt it) { out_ = it; }
|
void advance_to(OutputIt it) { out_ = it; }
|
||||||
|
|
||||||
|
detail::locale_ref locale() { return {}; }
|
||||||
|
|
||||||
format_arg arg(int id) const { return args_.get(id); }
|
format_arg arg(int id) const { return args_.get(id); }
|
||||||
|
|
||||||
basic_format_parse_context<Char>& parse_context() { return parse_ctx_; }
|
parse_context_type& parse_context() { return parse_ctx_; }
|
||||||
|
|
||||||
FMT_CONSTEXPR void on_error(const char* message) {
|
FMT_CONSTEXPR void on_error(const char* message) {
|
||||||
parse_ctx_.on_error(message);
|
parse_ctx_.on_error(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Formats stored arguments and writes the output to the range. */
|
/** Formats stored arguments and writes the output to the range. */
|
||||||
template <typename ArgFormatter = printf_arg_formatter<buffer_range<Char>>>
|
template <typename ArgFormatter = printf_arg_formatter<OutputIt, Char>>
|
||||||
OutputIt format();
|
OutputIt format();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -384,7 +404,9 @@ void basic_printf_context<OutputIt, Char>::parse_flags(format_specs& specs,
|
||||||
specs.fill[0] = '0';
|
specs.fill[0] = '0';
|
||||||
break;
|
break;
|
||||||
case ' ':
|
case ' ':
|
||||||
specs.sign = sign::space;
|
if (specs.sign != sign::plus) {
|
||||||
|
specs.sign = sign::space;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case '#':
|
case '#':
|
||||||
specs.alt = true;
|
specs.alt = true;
|
||||||
|
@ -402,18 +424,19 @@ basic_printf_context<OutputIt, Char>::get_arg(int arg_index) {
|
||||||
arg_index = parse_ctx_.next_arg_id();
|
arg_index = parse_ctx_.next_arg_id();
|
||||||
else
|
else
|
||||||
parse_ctx_.check_arg_id(--arg_index);
|
parse_ctx_.check_arg_id(--arg_index);
|
||||||
return internal::get_arg(*this, arg_index);
|
return detail::get_arg(*this, arg_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIt, typename Char>
|
template <typename OutputIt, typename Char>
|
||||||
int basic_printf_context<OutputIt, Char>::parse_header(
|
int basic_printf_context<OutputIt, Char>::parse_header(const Char*& it,
|
||||||
const Char*& it, const Char* end, format_specs& specs) {
|
const Char* end,
|
||||||
|
format_specs& specs) {
|
||||||
int arg_index = -1;
|
int arg_index = -1;
|
||||||
char_type c = *it;
|
char_type c = *it;
|
||||||
if (c >= '0' && c <= '9') {
|
if (c >= '0' && c <= '9') {
|
||||||
// Parse an argument index (if followed by '$') or a width possibly
|
// Parse an argument index (if followed by '$') or a width possibly
|
||||||
// preceded with '0' flag(s).
|
// preceded with '0' flag(s).
|
||||||
internal::error_handler eh;
|
detail::error_handler eh;
|
||||||
int value = parse_nonnegative_int(it, end, eh);
|
int value = parse_nonnegative_int(it, end, eh);
|
||||||
if (it != end && *it == '$') { // value is an argument index
|
if (it != end && *it == '$') { // value is an argument index
|
||||||
++it;
|
++it;
|
||||||
|
@ -432,12 +455,12 @@ int basic_printf_context<OutputIt, Char>::parse_header(
|
||||||
// Parse width.
|
// Parse width.
|
||||||
if (it != end) {
|
if (it != end) {
|
||||||
if (*it >= '0' && *it <= '9') {
|
if (*it >= '0' && *it <= '9') {
|
||||||
internal::error_handler eh;
|
detail::error_handler eh;
|
||||||
specs.width = parse_nonnegative_int(it, end, eh);
|
specs.width = parse_nonnegative_int(it, end, eh);
|
||||||
} else if (*it == '*') {
|
} else if (*it == '*') {
|
||||||
++it;
|
++it;
|
||||||
specs.width = static_cast<int>(visit_format_arg(
|
specs.width = static_cast<int>(visit_format_arg(
|
||||||
internal::printf_width_handler<char_type>(specs), get_arg()));
|
detail::printf_width_handler<char_type>(specs), get_arg()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return arg_index;
|
return arg_index;
|
||||||
|
@ -465,38 +488,52 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
|
||||||
|
|
||||||
// Parse argument index, flags and width.
|
// Parse argument index, flags and width.
|
||||||
int arg_index = parse_header(it, end, specs);
|
int arg_index = parse_header(it, end, specs);
|
||||||
if (arg_index == 0) on_error("argument index out of range");
|
if (arg_index == 0) on_error("argument not found");
|
||||||
|
|
||||||
// Parse precision.
|
// Parse precision.
|
||||||
if (it != end && *it == '.') {
|
if (it != end && *it == '.') {
|
||||||
++it;
|
++it;
|
||||||
c = it != end ? *it : 0;
|
c = it != end ? *it : 0;
|
||||||
if ('0' <= c && c <= '9') {
|
if ('0' <= c && c <= '9') {
|
||||||
internal::error_handler eh;
|
detail::error_handler eh;
|
||||||
specs.precision = parse_nonnegative_int(it, end, eh);
|
specs.precision = parse_nonnegative_int(it, end, eh);
|
||||||
} else if (c == '*') {
|
} else if (c == '*') {
|
||||||
++it;
|
++it;
|
||||||
specs.precision =
|
specs.precision = static_cast<int>(
|
||||||
static_cast<int>(visit_format_arg(internal::printf_precision_handler(), get_arg()));
|
visit_format_arg(detail::printf_precision_handler(), get_arg()));
|
||||||
} else {
|
} else {
|
||||||
specs.precision = 0;
|
specs.precision = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
format_arg arg = get_arg(arg_index);
|
format_arg arg = get_arg(arg_index);
|
||||||
if (specs.alt && visit_format_arg(internal::is_zero_int(), arg))
|
// For d, i, o, u, x, and X conversion specifiers, if a precision is
|
||||||
|
// specified, the '0' flag is ignored
|
||||||
|
if (specs.precision >= 0 && arg.is_integral())
|
||||||
|
specs.fill[0] =
|
||||||
|
' '; // Ignore '0' flag for non-numeric types or if '-' present.
|
||||||
|
if (specs.precision >= 0 && arg.type() == detail::type::cstring_type) {
|
||||||
|
auto str = visit_format_arg(detail::get_cstring<Char>(), arg);
|
||||||
|
auto str_end = str + specs.precision;
|
||||||
|
auto nul = std::find(str, str_end, Char());
|
||||||
|
arg = detail::make_arg<basic_printf_context>(basic_string_view<Char>(
|
||||||
|
str,
|
||||||
|
detail::to_unsigned(nul != str_end ? nul - str : specs.precision)));
|
||||||
|
}
|
||||||
|
if (specs.alt && visit_format_arg(detail::is_zero_int(), arg))
|
||||||
specs.alt = false;
|
specs.alt = false;
|
||||||
if (specs.fill[0] == '0') {
|
if (specs.fill[0] == '0') {
|
||||||
if (arg.is_arithmetic())
|
if (arg.is_arithmetic() && specs.align != align::left)
|
||||||
specs.align = align::numeric;
|
specs.align = align::numeric;
|
||||||
else
|
else
|
||||||
specs.fill[0] = ' '; // Ignore '0' flag for non-numeric types.
|
specs.fill[0] = ' '; // Ignore '0' flag for non-numeric types or if '-'
|
||||||
|
// flag is also present.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse length and convert the argument to the required type.
|
// Parse length and convert the argument to the required type.
|
||||||
c = it != end ? *it++ : 0;
|
c = it != end ? *it++ : 0;
|
||||||
char_type t = it != end ? *it : 0;
|
char_type t = it != end ? *it : 0;
|
||||||
using internal::convert_arg;
|
using detail::convert_arg;
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'h':
|
case 'h':
|
||||||
if (t == 'h') {
|
if (t == 'h') {
|
||||||
|
@ -520,7 +557,7 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
|
||||||
convert_arg<intmax_t>(arg, t);
|
convert_arg<intmax_t>(arg, t);
|
||||||
break;
|
break;
|
||||||
case 'z':
|
case 'z':
|
||||||
convert_arg<std::size_t>(arg, t);
|
convert_arg<size_t>(arg, t);
|
||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
convert_arg<std::ptrdiff_t>(arg, t);
|
convert_arg<std::ptrdiff_t>(arg, t);
|
||||||
|
@ -545,7 +582,7 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
|
||||||
specs.type = 'd';
|
specs.type = 'd';
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
visit_format_arg(internal::char_converter<basic_printf_context>(arg),
|
visit_format_arg(detail::char_converter<basic_printf_context>(arg),
|
||||||
arg);
|
arg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -554,15 +591,14 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
|
||||||
start = it;
|
start = it;
|
||||||
|
|
||||||
// Format argument.
|
// Format argument.
|
||||||
visit_format_arg(ArgFormatter(out, specs, *this), arg);
|
out = visit_format_arg(ArgFormatter(out, specs, *this), arg);
|
||||||
}
|
}
|
||||||
return std::copy(start, it, out);
|
return std::copy(start, it, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
using basic_printf_context_t =
|
using basic_printf_context_t =
|
||||||
basic_printf_context<std::back_insert_iterator<internal::buffer<Char>>,
|
basic_printf_context<detail::buffer_appender<Char>, Char>;
|
||||||
Char>;
|
|
||||||
|
|
||||||
using printf_context = basic_printf_context_t<char>;
|
using printf_context = basic_printf_context_t<char>;
|
||||||
using wprintf_context = basic_printf_context_t<wchar_t>;
|
using wprintf_context = basic_printf_context_t<wchar_t>;
|
||||||
|
@ -596,9 +632,10 @@ inline format_arg_store<wprintf_context, Args...> make_wprintf_args(
|
||||||
|
|
||||||
template <typename S, typename Char = char_t<S>>
|
template <typename S, typename Char = char_t<S>>
|
||||||
inline std::basic_string<Char> vsprintf(
|
inline std::basic_string<Char> vsprintf(
|
||||||
const S& format, basic_format_args<basic_printf_context_t<Char>> args) {
|
const S& format,
|
||||||
|
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) {
|
||||||
basic_memory_buffer<Char> buffer;
|
basic_memory_buffer<Char> buffer;
|
||||||
printf(buffer, to_string_view(format), args);
|
vprintf(buffer, to_string_view(format), args);
|
||||||
return to_string(buffer);
|
return to_string(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -612,18 +649,19 @@ inline std::basic_string<Char> vsprintf(
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename S, typename... Args,
|
template <typename S, typename... Args,
|
||||||
typename Char = enable_if_t<internal::is_string<S>::value, char_t<S>>>
|
typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
|
||||||
inline std::basic_string<Char> sprintf(const S& format, const Args&... args) {
|
inline std::basic_string<Char> sprintf(const S& format, const Args&... args) {
|
||||||
using context = basic_printf_context_t<Char>;
|
using context = basic_printf_context_t<Char>;
|
||||||
return vsprintf(to_string_view(format), {make_format_args<context>(args...)});
|
return vsprintf(to_string_view(format), make_format_args<context>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S, typename Char = char_t<S>>
|
template <typename S, typename Char = char_t<S>>
|
||||||
inline int vfprintf(std::FILE* f, const S& format,
|
inline int vfprintf(
|
||||||
basic_format_args<basic_printf_context_t<Char>> args) {
|
std::FILE* f, const S& format,
|
||||||
|
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) {
|
||||||
basic_memory_buffer<Char> buffer;
|
basic_memory_buffer<Char> buffer;
|
||||||
printf(buffer, to_string_view(format), args);
|
vprintf(buffer, to_string_view(format), args);
|
||||||
std::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
|
||||||
: static_cast<int>(size);
|
: static_cast<int>(size);
|
||||||
|
@ -639,16 +677,17 @@ inline int vfprintf(std::FILE* f, const S& format,
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename S, typename... Args,
|
template <typename S, typename... Args,
|
||||||
typename Char = enable_if_t<internal::is_string<S>::value, char_t<S>>>
|
typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
|
||||||
inline int fprintf(std::FILE* f, const S& format, const Args&... args) {
|
inline int fprintf(std::FILE* f, const S& format, const Args&... args) {
|
||||||
using context = basic_printf_context_t<Char>;
|
using context = basic_printf_context_t<Char>;
|
||||||
return vfprintf(f, to_string_view(format),
|
return vfprintf(f, to_string_view(format),
|
||||||
{make_format_args<context>(args...)});
|
make_format_args<context>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S, typename Char = char_t<S>>
|
template <typename S, typename Char = char_t<S>>
|
||||||
inline int vprintf(const S& format,
|
inline int vprintf(
|
||||||
basic_format_args<basic_printf_context_t<Char>> args) {
|
const S& format,
|
||||||
|
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) {
|
||||||
return vfprintf(stdout, to_string_view(format), args);
|
return vfprintf(stdout, to_string_view(format), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -662,19 +701,20 @@ inline int vprintf(const S& format,
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename S, typename... Args,
|
template <typename S, typename... Args,
|
||||||
FMT_ENABLE_IF(internal::is_string<S>::value)>
|
FMT_ENABLE_IF(detail::is_string<S>::value)>
|
||||||
inline int printf(const S& format_str, const Args&... args) {
|
inline int printf(const S& format_str, const Args&... args) {
|
||||||
using context = basic_printf_context_t<char_t<S>>;
|
using context = basic_printf_context_t<char_t<S>>;
|
||||||
return vprintf(to_string_view(format_str),
|
return vprintf(to_string_view(format_str),
|
||||||
{make_format_args<context>(args...)});
|
make_format_args<context>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S, typename Char = char_t<S>>
|
template <typename S, typename Char = char_t<S>>
|
||||||
inline int vfprintf(std::basic_ostream<Char>& os, const S& format,
|
inline int vfprintf(
|
||||||
basic_format_args<basic_printf_context_t<Char>> args) {
|
std::basic_ostream<Char>& os, const S& format,
|
||||||
|
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) {
|
||||||
basic_memory_buffer<Char> buffer;
|
basic_memory_buffer<Char> buffer;
|
||||||
printf(buffer, to_string_view(format), args);
|
vprintf(buffer, to_string_view(format), args);
|
||||||
internal::write(os, buffer);
|
detail::write_buffer(os, buffer);
|
||||||
return static_cast<int>(buffer.size());
|
return static_cast<int>(buffer.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -682,9 +722,9 @@ inline int vfprintf(std::basic_ostream<Char>& os, const S& format,
|
||||||
template <typename ArgFormatter, typename Char,
|
template <typename ArgFormatter, typename Char,
|
||||||
typename Context =
|
typename Context =
|
||||||
basic_printf_context<typename ArgFormatter::iterator, Char>>
|
basic_printf_context<typename ArgFormatter::iterator, Char>>
|
||||||
typename ArgFormatter::iterator vprintf(internal::buffer<Char>& out,
|
typename ArgFormatter::iterator vprintf(
|
||||||
basic_string_view<Char> format_str,
|
detail::buffer<Char>& out, basic_string_view<Char> format_str,
|
||||||
basic_format_args<Context> args) {
|
basic_format_args<type_identity_t<Context>> args) {
|
||||||
typename ArgFormatter::iterator iter(out);
|
typename ArgFormatter::iterator iter(out);
|
||||||
Context(iter, format_str, args).template format<ArgFormatter>();
|
Context(iter, format_str, args).template format<ArgFormatter>();
|
||||||
return iter;
|
return iter;
|
||||||
|
@ -704,7 +744,7 @@ inline int fprintf(std::basic_ostream<Char>& os, const S& format_str,
|
||||||
const Args&... args) {
|
const Args&... args) {
|
||||||
using context = basic_printf_context_t<Char>;
|
using context = basic_printf_context_t<Char>;
|
||||||
return vfprintf(os, to_string_view(format_str),
|
return vfprintf(os, to_string_view(format_str),
|
||||||
{make_format_args<context>(args...)});
|
make_format_args<context>(args...));
|
||||||
}
|
}
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
|
112
Externals/fmt/include/fmt/ranges.h
vendored
112
Externals/fmt/include/fmt/ranges.h
vendored
|
@ -12,7 +12,9 @@
|
||||||
#ifndef FMT_RANGES_H_
|
#ifndef FMT_RANGES_H_
|
||||||
#define FMT_RANGES_H_
|
#define FMT_RANGES_H_
|
||||||
|
|
||||||
|
#include <initializer_list>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
|
||||||
// output only up to N items from the range.
|
// output only up to N items from the range.
|
||||||
|
@ -31,7 +33,7 @@ template <typename Char> struct formatting_base {
|
||||||
|
|
||||||
template <typename Char, typename Enable = void>
|
template <typename Char, typename Enable = void>
|
||||||
struct formatting_range : formatting_base<Char> {
|
struct formatting_range : formatting_base<Char> {
|
||||||
static FMT_CONSTEXPR_DECL const std::size_t range_length_limit =
|
static FMT_CONSTEXPR_DECL const size_t range_length_limit =
|
||||||
FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the
|
FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the
|
||||||
// range.
|
// range.
|
||||||
Char prefix;
|
Char prefix;
|
||||||
|
@ -52,7 +54,7 @@ struct formatting_tuple : formatting_base<Char> {
|
||||||
static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false;
|
static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace internal {
|
namespace detail {
|
||||||
|
|
||||||
template <typename RangeT, typename OutputIterator>
|
template <typename RangeT, typename OutputIterator>
|
||||||
OutputIterator copy(const RangeT& range, OutputIterator out) {
|
OutputIterator copy(const RangeT& range, OutputIterator out) {
|
||||||
|
@ -104,10 +106,7 @@ struct is_range_<
|
||||||
/// tuple_size and tuple_element check.
|
/// tuple_size and tuple_element check.
|
||||||
template <typename T> class is_tuple_like_ {
|
template <typename T> class is_tuple_like_ {
|
||||||
template <typename U>
|
template <typename U>
|
||||||
static auto check(U* p)
|
static auto check(U* p) -> decltype(std::tuple_size<U>::value, int());
|
||||||
-> decltype(std::tuple_size<U>::value,
|
|
||||||
(void)std::declval<typename std::tuple_element<0, U>::type>(),
|
|
||||||
int());
|
|
||||||
template <typename> static void check(...);
|
template <typename> static void check(...);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -119,26 +118,24 @@ template <typename T> class is_tuple_like_ {
|
||||||
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900
|
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 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 <std::size_t... N> using index_sequence = std::index_sequence<N...>;
|
template <size_t... N> using index_sequence = std::index_sequence<N...>;
|
||||||
template <std::size_t N>
|
template <size_t N> using make_index_sequence = std::make_index_sequence<N>;
|
||||||
using make_index_sequence = std::make_index_sequence<N>;
|
|
||||||
#else
|
#else
|
||||||
template <typename T, T... N> struct integer_sequence {
|
template <typename T, T... N> struct integer_sequence {
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
|
|
||||||
static FMT_CONSTEXPR std::size_t size() { return sizeof...(N); }
|
static FMT_CONSTEXPR size_t size() { return sizeof...(N); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <std::size_t... N>
|
template <size_t... N> using index_sequence = integer_sequence<size_t, N...>;
|
||||||
using index_sequence = integer_sequence<std::size_t, N...>;
|
|
||||||
|
|
||||||
template <typename T, std::size_t N, T... Ns>
|
template <typename T, size_t N, T... Ns>
|
||||||
struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> {};
|
struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> {};
|
||||||
template <typename T, T... Ns>
|
template <typename T, T... Ns>
|
||||||
struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...> {};
|
struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...> {};
|
||||||
|
|
||||||
template <std::size_t N>
|
template <size_t N>
|
||||||
using make_index_sequence = make_integer_sequence<std::size_t, N>;
|
using make_index_sequence = make_integer_sequence<size_t, N>;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <class Tuple, class F, size_t... Is>
|
template <class Tuple, class F, size_t... Is>
|
||||||
|
@ -160,6 +157,9 @@ 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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Range>
|
||||||
|
using value_type = remove_cvref_t<decltype(*std::declval<Range>().begin())>;
|
||||||
|
|
||||||
template <typename Arg, FMT_ENABLE_IF(!is_like_std_string<
|
template <typename Arg, FMT_ENABLE_IF(!is_like_std_string<
|
||||||
typename std::decay<Arg>::type>::value)>
|
typename std::decay<Arg>::type>::value)>
|
||||||
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&) {
|
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&) {
|
||||||
|
@ -185,12 +185,11 @@ FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char) {
|
||||||
FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t) {
|
FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t) {
|
||||||
return add_space ? L" '{}'" : L"'{}'";
|
return add_space ? L" '{}'" : L"'{}'";
|
||||||
}
|
}
|
||||||
|
} // namespace detail
|
||||||
} // namespace internal
|
|
||||||
|
|
||||||
template <typename T> struct is_tuple_like {
|
template <typename T> struct is_tuple_like {
|
||||||
static FMT_CONSTEXPR_DECL const bool value =
|
static FMT_CONSTEXPR_DECL const bool value =
|
||||||
internal::is_tuple_like_<T>::value && !internal::is_range_<T>::value;
|
detail::is_tuple_like_<T>::value && !detail::is_range_<T>::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename TupleT, typename Char>
|
template <typename TupleT, typename Char>
|
||||||
|
@ -203,17 +202,17 @@ struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
|
||||||
if (formatting.add_prepostfix_space) {
|
if (formatting.add_prepostfix_space) {
|
||||||
*out++ = ' ';
|
*out++ = ' ';
|
||||||
}
|
}
|
||||||
out = internal::copy(formatting.delimiter, out);
|
out = detail::copy(formatting.delimiter, out);
|
||||||
}
|
}
|
||||||
out = format_to(out,
|
out = format_to(out,
|
||||||
internal::format_str_quoted(
|
detail::format_str_quoted(
|
||||||
(formatting.add_delimiter_spaces && i > 0), v),
|
(formatting.add_delimiter_spaces && i > 0), v),
|
||||||
v);
|
v);
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
|
||||||
formatting_tuple<Char>& formatting;
|
formatting_tuple<Char>& formatting;
|
||||||
std::size_t& i;
|
size_t& i;
|
||||||
typename std::add_lvalue_reference<decltype(
|
typename std::add_lvalue_reference<decltype(
|
||||||
std::declval<FormatContext>().out())>::type out;
|
std::declval<FormatContext>().out())>::type out;
|
||||||
};
|
};
|
||||||
|
@ -229,14 +228,14 @@ 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) -> decltype(ctx.out()) {
|
||||||
auto out = ctx.out();
|
auto out = ctx.out();
|
||||||
std::size_t i = 0;
|
size_t i = 0;
|
||||||
internal::copy(formatting.prefix, out);
|
detail::copy(formatting.prefix, out);
|
||||||
|
|
||||||
internal::for_each(values, format_each<FormatContext>{formatting, i, out});
|
detail::for_each(values, format_each<FormatContext>{formatting, i, out});
|
||||||
if (formatting.add_prepostfix_space) {
|
if (formatting.add_prepostfix_space) {
|
||||||
*out++ = ' ';
|
*out++ = ' ';
|
||||||
}
|
}
|
||||||
internal::copy(formatting.postfix, out);
|
detail::copy(formatting.postfix, out);
|
||||||
|
|
||||||
return ctx.out();
|
return ctx.out();
|
||||||
}
|
}
|
||||||
|
@ -244,15 +243,20 @@ 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 FMT_CONSTEXPR_DECL const bool value =
|
||||||
internal::is_range_<T>::value &&
|
detail::is_range_<T>::value && !detail::is_like_std_string<T>::value &&
|
||||||
!internal::is_like_std_string<T>::value &&
|
|
||||||
!std::is_convertible<T, std::basic_string<Char>>::value &&
|
!std::is_convertible<T, std::basic_string<Char>>::value &&
|
||||||
!std::is_constructible<internal::std_string_view<Char>, T>::value;
|
!std::is_constructible<detail::std_string_view<Char>, T>::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename RangeT, typename Char>
|
template <typename T, typename Char>
|
||||||
struct formatter<RangeT, Char,
|
struct formatter<
|
||||||
enable_if_t<fmt::is_range<RangeT, Char>::value>> {
|
T, Char,
|
||||||
|
enable_if_t<fmt::is_range<T, Char>::value
|
||||||
|
// Workaround a bug in MSVC 2017 and earlier.
|
||||||
|
#if !FMT_MSC_VER || FMT_MSC_VER >= 1927
|
||||||
|
&& has_formatter<detail::value_type<T>, format_context>::value
|
||||||
|
#endif
|
||||||
|
>> {
|
||||||
formatting_range<Char> formatting;
|
formatting_range<Char> formatting;
|
||||||
|
|
||||||
template <typename ParseContext>
|
template <typename ParseContext>
|
||||||
|
@ -261,17 +265,18 @@ struct formatter<RangeT, Char,
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
typename FormatContext::iterator format(const RangeT& values,
|
typename FormatContext::iterator format(const T& values, FormatContext& ctx) {
|
||||||
FormatContext& ctx) {
|
auto out = detail::copy(formatting.prefix, ctx.out());
|
||||||
auto out = internal::copy(formatting.prefix, ctx.out());
|
size_t i = 0;
|
||||||
std::size_t i = 0;
|
auto it = values.begin();
|
||||||
for (auto it = values.begin(), end = values.end(); it != end; ++it) {
|
auto end = values.end();
|
||||||
|
for (; it != end; ++it) {
|
||||||
if (i > 0) {
|
if (i > 0) {
|
||||||
if (formatting.add_prepostfix_space) *out++ = ' ';
|
if (formatting.add_prepostfix_space) *out++ = ' ';
|
||||||
out = internal::copy(formatting.delimiter, out);
|
out = detail::copy(formatting.delimiter, out);
|
||||||
}
|
}
|
||||||
out = format_to(out,
|
out = format_to(out,
|
||||||
internal::format_str_quoted(
|
detail::format_str_quoted(
|
||||||
(formatting.add_delimiter_spaces && i > 0), *it),
|
(formatting.add_delimiter_spaces && i > 0), *it),
|
||||||
*it);
|
*it);
|
||||||
if (++i > formatting.range_length_limit) {
|
if (++i > formatting.range_length_limit) {
|
||||||
|
@ -280,11 +285,11 @@ struct formatter<RangeT, Char,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (formatting.add_prepostfix_space) *out++ = ' ';
|
if (formatting.add_prepostfix_space) *out++ = ' ';
|
||||||
return internal::copy(formatting.postfix, out);
|
return detail::copy(formatting.postfix, out);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Char, typename... T> struct tuple_arg_join : internal::view {
|
template <typename Char, typename... T> struct tuple_arg_join : detail::view {
|
||||||
const std::tuple<T...>& tuple;
|
const std::tuple<T...>& tuple;
|
||||||
basic_string_view<Char> sep;
|
basic_string_view<Char> sep;
|
||||||
|
|
||||||
|
@ -302,14 +307,14 @@ struct formatter<tuple_arg_join<Char, T...>, Char> {
|
||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
typename FormatContext::iterator format(
|
typename FormatContext::iterator format(
|
||||||
const tuple_arg_join<Char, T...>& value, FormatContext& ctx) {
|
const tuple_arg_join<Char, T...>& value, FormatContext& ctx) {
|
||||||
return format(value, ctx, internal::make_index_sequence<sizeof...(T)>{});
|
return format(value, ctx, detail::make_index_sequence<sizeof...(T)>{});
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename FormatContext, size_t... N>
|
template <typename FormatContext, size_t... N>
|
||||||
typename FormatContext::iterator format(
|
typename FormatContext::iterator format(
|
||||||
const tuple_arg_join<Char, T...>& value, FormatContext& ctx,
|
const tuple_arg_join<Char, T...>& value, FormatContext& ctx,
|
||||||
internal::index_sequence<N...>) {
|
detail::index_sequence<N...>) {
|
||||||
return format_args(value, ctx, std::get<N>(value.tuple)...);
|
return format_args(value, ctx, std::get<N>(value.tuple)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -360,6 +365,29 @@ FMT_CONSTEXPR tuple_arg_join<wchar_t, T...> join(const std::tuple<T...>& tuple,
|
||||||
return {tuple, sep};
|
return {tuple, sep};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
Returns an object that formats `initializer_list` with elements separated by
|
||||||
|
`sep`.
|
||||||
|
|
||||||
|
**Example**::
|
||||||
|
|
||||||
|
fmt::print("{}", fmt::join({1, 2, 3}, ", "));
|
||||||
|
// Output: "1, 2, 3"
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
arg_join<const T*, const T*, char> join(std::initializer_list<T> list,
|
||||||
|
string_view sep) {
|
||||||
|
return join(std::begin(list), std::end(list), sep);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
arg_join<const T*, const T*, wchar_t> join(std::initializer_list<T> list,
|
||||||
|
wstring_view sep) {
|
||||||
|
return join(std::begin(list), std::end(list), sep);
|
||||||
|
}
|
||||||
|
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
#endif // FMT_RANGES_H_
|
#endif // FMT_RANGES_H_
|
||||||
|
|
167
Externals/fmt/src/format.cc
vendored
167
Externals/fmt/src/format.cc
vendored
|
@ -8,169 +8,62 @@
|
||||||
#include "fmt/format-inl.h"
|
#include "fmt/format-inl.h"
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
namespace internal {
|
namespace detail {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
int format_float(char* buf, std::size_t size, const char* format, int precision,
|
int format_float(char* buf, std::size_t size, const char* format, int precision,
|
||||||
T value) {
|
T value) {
|
||||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
#ifdef FMT_FUZZ
|
||||||
if (precision > 100000)
|
if (precision > 100000)
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
"fuzz mode - avoid large allocation inside snprintf");
|
"fuzz mode - avoid large allocation inside snprintf");
|
||||||
#endif
|
#endif
|
||||||
// Suppress the warning about nonliteral format string.
|
// Suppress the warning about nonliteral format string.
|
||||||
auto snprintf_ptr = FMT_SNPRINTF;
|
int (*snprintf_ptr)(char*, size_t, const char*, ...) = FMT_SNPRINTF;
|
||||||
return precision < 0 ? snprintf_ptr(buf, size, format, value)
|
return precision < 0 ? snprintf_ptr(buf, size, format, value)
|
||||||
: snprintf_ptr(buf, size, format, precision, value);
|
: snprintf_ptr(buf, size, format, precision, value);
|
||||||
}
|
}
|
||||||
struct sprintf_specs {
|
} // namespace detail
|
||||||
int precision;
|
|
||||||
char type;
|
|
||||||
bool alt : 1;
|
|
||||||
|
|
||||||
template <typename Char>
|
template struct FMT_INSTANTIATION_DEF_API detail::basic_data<void>;
|
||||||
constexpr sprintf_specs(basic_format_specs<Char> specs)
|
|
||||||
: precision(specs.precision), type(specs.type), alt(specs.alt) {}
|
|
||||||
|
|
||||||
constexpr bool has_precision() const { return precision >= 0; }
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is deprecated and is kept only to preserve ABI compatibility.
|
|
||||||
template <typename Double>
|
|
||||||
char* sprintf_format(Double value, internal::buffer<char>& buf,
|
|
||||||
sprintf_specs specs) {
|
|
||||||
// Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail.
|
|
||||||
FMT_ASSERT(buf.capacity() != 0, "empty buffer");
|
|
||||||
|
|
||||||
// Build format string.
|
|
||||||
enum { max_format_size = 10 }; // longest format: %#-*.*Lg
|
|
||||||
char format[max_format_size];
|
|
||||||
char* format_ptr = format;
|
|
||||||
*format_ptr++ = '%';
|
|
||||||
if (specs.alt || !specs.type) *format_ptr++ = '#';
|
|
||||||
if (specs.precision >= 0) {
|
|
||||||
*format_ptr++ = '.';
|
|
||||||
*format_ptr++ = '*';
|
|
||||||
}
|
|
||||||
if (std::is_same<Double, long double>::value) *format_ptr++ = 'L';
|
|
||||||
|
|
||||||
char type = specs.type;
|
|
||||||
|
|
||||||
if (type == '%')
|
|
||||||
type = 'f';
|
|
||||||
else if (type == 0 || type == 'n')
|
|
||||||
type = 'g';
|
|
||||||
#if FMT_MSC_VER
|
|
||||||
if (type == 'F') {
|
|
||||||
// MSVC's printf doesn't support 'F'.
|
|
||||||
type = 'f';
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
*format_ptr++ = type;
|
|
||||||
*format_ptr = '\0';
|
|
||||||
|
|
||||||
// Format using snprintf.
|
|
||||||
char* start = nullptr;
|
|
||||||
char* decimal_point_pos = nullptr;
|
|
||||||
for (;;) {
|
|
||||||
std::size_t buffer_size = buf.capacity();
|
|
||||||
start = &buf[0];
|
|
||||||
int result =
|
|
||||||
format_float(start, buffer_size, format, specs.precision, value);
|
|
||||||
if (result >= 0) {
|
|
||||||
unsigned n = internal::to_unsigned(result);
|
|
||||||
if (n < buf.capacity()) {
|
|
||||||
// Find the decimal point.
|
|
||||||
auto p = buf.data(), end = p + n;
|
|
||||||
if (*p == '+' || *p == '-') ++p;
|
|
||||||
if (specs.type != 'a' && specs.type != 'A') {
|
|
||||||
while (p < end && *p >= '0' && *p <= '9') ++p;
|
|
||||||
if (p < end && *p != 'e' && *p != 'E') {
|
|
||||||
decimal_point_pos = p;
|
|
||||||
if (!specs.type) {
|
|
||||||
// Keep only one trailing zero after the decimal point.
|
|
||||||
++p;
|
|
||||||
if (*p == '0') ++p;
|
|
||||||
while (p != end && *p >= '1' && *p <= '9') ++p;
|
|
||||||
char* where = p;
|
|
||||||
while (p != end && *p == '0') ++p;
|
|
||||||
if (p == end || *p < '0' || *p > '9') {
|
|
||||||
if (p != end) std::memmove(where, p, to_unsigned(end - p));
|
|
||||||
n -= static_cast<unsigned>(p - where);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buf.resize(n);
|
|
||||||
break; // The buffer is large enough - continue with formatting.
|
|
||||||
}
|
|
||||||
buf.reserve(n + 1);
|
|
||||||
} else {
|
|
||||||
// If result is negative we ask to increase the capacity by at least 1,
|
|
||||||
// but as std::vector, the buffer grows exponentially.
|
|
||||||
buf.reserve(buf.capacity() + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return decimal_point_pos;
|
|
||||||
}
|
|
||||||
} // namespace internal
|
|
||||||
|
|
||||||
template FMT_API char* internal::sprintf_format(double, internal::buffer<char>&,
|
|
||||||
sprintf_specs);
|
|
||||||
template FMT_API char* internal::sprintf_format(long double,
|
|
||||||
internal::buffer<char>&,
|
|
||||||
sprintf_specs);
|
|
||||||
|
|
||||||
template struct FMT_API internal::basic_data<void>;
|
|
||||||
|
|
||||||
// Workaround a bug in MSVC2013 that prevents instantiation of format_float.
|
// Workaround a bug in MSVC2013 that prevents instantiation of format_float.
|
||||||
int (*instantiate_format_float)(double, int, internal::float_specs,
|
int (*instantiate_format_float)(double, int, detail::float_specs,
|
||||||
internal::buffer<char>&) =
|
detail::buffer<char>&) = detail::format_float;
|
||||||
internal::format_float;
|
|
||||||
|
|
||||||
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
|
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
|
||||||
template FMT_API internal::locale_ref::locale_ref(const std::locale& loc);
|
template FMT_API detail::locale_ref::locale_ref(const std::locale& loc);
|
||||||
template FMT_API std::locale internal::locale_ref::get<std::locale>() const;
|
template FMT_API std::locale detail::locale_ref::get<std::locale>() const;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Explicit instantiations for char.
|
// Explicit instantiations for char.
|
||||||
|
|
||||||
template FMT_API std::string internal::grouping_impl<char>(locale_ref);
|
template FMT_API std::string detail::grouping_impl<char>(locale_ref);
|
||||||
template FMT_API char internal::thousands_sep_impl(locale_ref);
|
template FMT_API char detail::thousands_sep_impl(locale_ref);
|
||||||
template FMT_API char internal::decimal_point_impl(locale_ref);
|
template FMT_API char detail::decimal_point_impl(locale_ref);
|
||||||
|
|
||||||
template FMT_API void internal::buffer<char>::append(const char*, const char*);
|
template FMT_API void detail::buffer<char>::append(const char*, const char*);
|
||||||
|
|
||||||
template FMT_API void internal::arg_map<format_context>::init(
|
template FMT_API void detail::vformat_to(
|
||||||
const basic_format_args<format_context>& args);
|
detail::buffer<char>&, string_view,
|
||||||
|
basic_format_args<FMT_BUFFER_CONTEXT(char)>, detail::locale_ref);
|
||||||
|
|
||||||
template FMT_API std::string internal::vformat<char>(
|
template FMT_API int detail::snprintf_float(double, int, detail::float_specs,
|
||||||
string_view, basic_format_args<format_context>);
|
detail::buffer<char>&);
|
||||||
|
template FMT_API int detail::snprintf_float(long double, int,
|
||||||
template FMT_API format_context::iterator internal::vformat_to(
|
detail::float_specs,
|
||||||
internal::buffer<char>&, string_view, basic_format_args<format_context>);
|
detail::buffer<char>&);
|
||||||
|
template FMT_API int detail::format_float(double, int, detail::float_specs,
|
||||||
template FMT_API int internal::snprintf_float(double, int,
|
detail::buffer<char>&);
|
||||||
internal::float_specs,
|
template FMT_API int detail::format_float(long double, int, detail::float_specs,
|
||||||
internal::buffer<char>&);
|
detail::buffer<char>&);
|
||||||
template FMT_API int internal::snprintf_float(long double, int,
|
|
||||||
internal::float_specs,
|
|
||||||
internal::buffer<char>&);
|
|
||||||
template FMT_API int internal::format_float(double, int, internal::float_specs,
|
|
||||||
internal::buffer<char>&);
|
|
||||||
template FMT_API int internal::format_float(long double, int,
|
|
||||||
internal::float_specs,
|
|
||||||
internal::buffer<char>&);
|
|
||||||
|
|
||||||
// Explicit instantiations for wchar_t.
|
// Explicit instantiations for wchar_t.
|
||||||
|
|
||||||
template FMT_API std::string internal::grouping_impl<wchar_t>(locale_ref);
|
template FMT_API std::string detail::grouping_impl<wchar_t>(locale_ref);
|
||||||
template FMT_API wchar_t internal::thousands_sep_impl(locale_ref);
|
template FMT_API wchar_t detail::thousands_sep_impl(locale_ref);
|
||||||
template FMT_API wchar_t internal::decimal_point_impl(locale_ref);
|
template FMT_API wchar_t detail::decimal_point_impl(locale_ref);
|
||||||
|
|
||||||
template FMT_API void internal::buffer<wchar_t>::append(const wchar_t*,
|
template FMT_API void detail::buffer<wchar_t>::append(const wchar_t*,
|
||||||
const wchar_t*);
|
const wchar_t*);
|
||||||
|
|
||||||
template FMT_API std::wstring internal::vformat<wchar_t>(
|
|
||||||
wstring_view, basic_format_args<wformat_context>);
|
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
173
Externals/fmt/src/posix.cc → Externals/fmt/src/os.cc
vendored
Executable file → Normal file
173
Externals/fmt/src/posix.cc → Externals/fmt/src/os.cc
vendored
Executable file → Normal file
|
@ -1,4 +1,4 @@
|
||||||
// A C++ interface to POSIX functions.
|
// Formatting library for C++ - optional OS-specific functionality
|
||||||
//
|
//
|
||||||
// Copyright (c) 2012 - 2016, Victor Zverovich
|
// Copyright (c) 2012 - 2016, Victor Zverovich
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
|
@ -10,39 +10,43 @@
|
||||||
# define _CRT_SECURE_NO_WARNINGS
|
# define _CRT_SECURE_NO_WARNINGS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "fmt/posix.h"
|
#include "fmt/os.h"
|
||||||
|
|
||||||
#include <climits>
|
#include <climits>
|
||||||
|
|
||||||
#if FMT_USE_FCNTL
|
#if FMT_USE_FCNTL
|
||||||
#include <sys/stat.h>
|
# include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
# include <sys/types.h>
|
||||||
|
|
||||||
#ifndef _WIN32
|
# ifndef _WIN32
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
#else
|
# else
|
||||||
# ifndef WIN32_LEAN_AND_MEAN
|
# ifndef WIN32_LEAN_AND_MEAN
|
||||||
# define WIN32_LEAN_AND_MEAN
|
# define WIN32_LEAN_AND_MEAN
|
||||||
# endif
|
# endif
|
||||||
# include <io.h>
|
# include <io.h>
|
||||||
|
# include <windows.h>
|
||||||
|
|
||||||
|
# define O_CREAT _O_CREAT
|
||||||
|
# define O_TRUNC _O_TRUNC
|
||||||
|
|
||||||
|
# ifndef S_IRUSR
|
||||||
|
# define S_IRUSR _S_IREAD
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifndef S_IWUSR
|
||||||
|
# define S_IWUSR _S_IWRITE
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# ifdef __MINGW32__
|
||||||
|
# define _SH_DENYNO 0x40
|
||||||
|
# endif
|
||||||
|
# endif // _WIN32
|
||||||
|
#endif // FMT_USE_FCNTL
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
|
#endif
|
||||||
# define O_CREAT _O_CREAT
|
|
||||||
# define O_TRUNC _O_TRUNC
|
|
||||||
|
|
||||||
# ifndef S_IRUSR
|
|
||||||
# define S_IRUSR _S_IREAD
|
|
||||||
# endif
|
|
||||||
|
|
||||||
# ifndef S_IWUSR
|
|
||||||
# define S_IWUSR _S_IWRITE
|
|
||||||
# endif
|
|
||||||
|
|
||||||
# ifdef __MINGW32__
|
|
||||||
# define _SH_DENYNO 0x40
|
|
||||||
# endif
|
|
||||||
#endif // _WIN32
|
|
||||||
#endif // FMT_USE_FCNTL
|
|
||||||
|
|
||||||
#ifdef fileno
|
#ifdef fileno
|
||||||
# undef fileno
|
# undef fileno
|
||||||
|
@ -58,7 +62,7 @@ using RWResult = int;
|
||||||
inline unsigned convert_rwcount(std::size_t count) {
|
inline unsigned convert_rwcount(std::size_t count) {
|
||||||
return count <= UINT_MAX ? static_cast<unsigned>(count) : UINT_MAX;
|
return count <= UINT_MAX ? static_cast<unsigned>(count) : UINT_MAX;
|
||||||
}
|
}
|
||||||
#else
|
#elif FMT_USE_FCNTL
|
||||||
// Return type of read and write functions.
|
// Return type of read and write functions.
|
||||||
using RWResult = ssize_t;
|
using RWResult = ssize_t;
|
||||||
|
|
||||||
|
@ -68,6 +72,79 @@ inline std::size_t convert_rwcount(std::size_t count) { return count; }
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
detail::utf16_to_utf8::utf16_to_utf8(wstring_view s) {
|
||||||
|
if (int error_code = convert(s)) {
|
||||||
|
FMT_THROW(windows_error(error_code,
|
||||||
|
"cannot convert string from UTF-16 to UTF-8"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int detail::utf16_to_utf8::convert(wstring_view s) {
|
||||||
|
if (s.size() > INT_MAX) return ERROR_INVALID_PARAMETER;
|
||||||
|
int s_size = static_cast<int>(s.size());
|
||||||
|
if (s_size == 0) {
|
||||||
|
// WideCharToMultiByte does not support zero length, handle separately.
|
||||||
|
buffer_.resize(1);
|
||||||
|
buffer_[0] = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, nullptr, 0,
|
||||||
|
nullptr, nullptr);
|
||||||
|
if (length == 0) return GetLastError();
|
||||||
|
buffer_.resize(length + 1);
|
||||||
|
length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, &buffer_[0],
|
||||||
|
length, nullptr, nullptr);
|
||||||
|
if (length == 0) return GetLastError();
|
||||||
|
buffer_[length] = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void windows_error::init(int err_code, string_view format_str,
|
||||||
|
format_args args) {
|
||||||
|
error_code_ = err_code;
|
||||||
|
memory_buffer buffer;
|
||||||
|
detail::format_windows_error(buffer, err_code, vformat(format_str, args));
|
||||||
|
std::runtime_error& base = *this;
|
||||||
|
base = std::runtime_error(to_string(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
void detail::format_windows_error(detail::buffer<char>& out, int error_code,
|
||||||
|
string_view message) FMT_NOEXCEPT {
|
||||||
|
FMT_TRY {
|
||||||
|
wmemory_buffer buf;
|
||||||
|
buf.resize(inline_buffer_size);
|
||||||
|
for (;;) {
|
||||||
|
wchar_t* system_message = &buf[0];
|
||||||
|
int result = FormatMessageW(
|
||||||
|
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr,
|
||||||
|
error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), system_message,
|
||||||
|
static_cast<uint32_t>(buf.size()), nullptr);
|
||||||
|
if (result != 0) {
|
||||||
|
utf16_to_utf8 utf8_message;
|
||||||
|
if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
|
||||||
|
format_to(buffer_appender<char>(out), "{}: {}", message,
|
||||||
|
utf8_message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
||||||
|
break; // Can't get error message, report error code instead.
|
||||||
|
buf.resize(buf.size() * 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FMT_CATCH(...) {}
|
||||||
|
format_error_code(out, error_code, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void report_windows_error(int error_code,
|
||||||
|
fmt::string_view message) FMT_NOEXCEPT {
|
||||||
|
report_error(detail::format_windows_error, error_code, message);
|
||||||
|
}
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
buffered_file::~buffered_file() FMT_NOEXCEPT {
|
buffered_file::~buffered_file() FMT_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");
|
||||||
|
@ -99,12 +176,12 @@ int buffered_file::fileno() const {
|
||||||
#if FMT_USE_FCNTL
|
#if FMT_USE_FCNTL
|
||||||
file::file(cstring_view path, int oflag) {
|
file::file(cstring_view path, int oflag) {
|
||||||
int mode = S_IRUSR | S_IWUSR;
|
int mode = S_IRUSR | S_IWUSR;
|
||||||
#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));
|
||||||
#else
|
# else
|
||||||
FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode)));
|
FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode)));
|
||||||
#endif
|
# endif
|
||||||
if (fd_ == -1)
|
if (fd_ == -1)
|
||||||
FMT_THROW(system_error(errno, "cannot open file {}", path.c_str()));
|
FMT_THROW(system_error(errno, "cannot open file {}", path.c_str()));
|
||||||
}
|
}
|
||||||
|
@ -126,7 +203,7 @@ void file::close() {
|
||||||
}
|
}
|
||||||
|
|
||||||
long long file::size() const {
|
long long file::size() const {
|
||||||
#ifdef _WIN32
|
# ifdef _WIN32
|
||||||
// Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT
|
// Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT
|
||||||
// is less than 0x0500 as is the case with some default MinGW builds.
|
// is less than 0x0500 as is the case with some default MinGW builds.
|
||||||
// Both functions support large file sizes.
|
// Both functions support large file sizes.
|
||||||
|
@ -140,7 +217,7 @@ long long file::size() const {
|
||||||
}
|
}
|
||||||
unsigned long long long_size = size_upper;
|
unsigned long long long_size = size_upper;
|
||||||
return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower;
|
return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower;
|
||||||
#else
|
# else
|
||||||
using Stat = struct stat;
|
using Stat = struct stat;
|
||||||
Stat file_stat = Stat();
|
Stat file_stat = Stat();
|
||||||
if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1)
|
if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1)
|
||||||
|
@ -148,21 +225,21 @@ long long file::size() const {
|
||||||
static_assert(sizeof(long long) >= sizeof(file_stat.st_size),
|
static_assert(sizeof(long long) >= sizeof(file_stat.st_size),
|
||||||
"return type of file::size is not large enough");
|
"return type of file::size is not large enough");
|
||||||
return file_stat.st_size;
|
return file_stat.st_size;
|
||||||
#endif
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t file::read(void* buffer, std::size_t count) {
|
std::size_t file::read(void* buffer, std::size_t count) {
|
||||||
RWResult result = 0;
|
RWResult result = 0;
|
||||||
FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count))));
|
FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count))));
|
||||||
if (result < 0) FMT_THROW(system_error(errno, "cannot read from file"));
|
if (result < 0) FMT_THROW(system_error(errno, "cannot read from file"));
|
||||||
return internal::to_unsigned(result);
|
return detail::to_unsigned(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t file::write(const void* buffer, std::size_t count) {
|
std::size_t file::write(const void* buffer, std::size_t count) {
|
||||||
RWResult result = 0;
|
RWResult result = 0;
|
||||||
FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count))));
|
FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count))));
|
||||||
if (result < 0) FMT_THROW(system_error(errno, "cannot write to file"));
|
if (result < 0) FMT_THROW(system_error(errno, "cannot write to file"));
|
||||||
return internal::to_unsigned(result);
|
return detail::to_unsigned(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
file file::dup(int fd) {
|
file file::dup(int fd) {
|
||||||
|
@ -195,15 +272,15 @@ void file::pipe(file& read_end, file& write_end) {
|
||||||
read_end.close();
|
read_end.close();
|
||||||
write_end.close();
|
write_end.close();
|
||||||
int fds[2] = {};
|
int fds[2] = {};
|
||||||
#ifdef _WIN32
|
# ifdef _WIN32
|
||||||
// Make the default pipe capacity same as on Linux 2.6.11+.
|
// Make the default pipe capacity same as on Linux 2.6.11+.
|
||||||
enum { DEFAULT_CAPACITY = 65536 };
|
enum { DEFAULT_CAPACITY = 65536 };
|
||||||
int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY));
|
int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY));
|
||||||
#else
|
# else
|
||||||
// Don't retry as the pipe function doesn't return EINTR.
|
// Don't retry as the pipe function doesn't return EINTR.
|
||||||
// http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
|
// http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
|
||||||
int result = FMT_POSIX_CALL(pipe(fds));
|
int result = FMT_POSIX_CALL(pipe(fds));
|
||||||
#endif
|
# endif
|
||||||
if (result != 0) FMT_THROW(system_error(errno, "cannot create pipe"));
|
if (result != 0) FMT_THROW(system_error(errno, "cannot create pipe"));
|
||||||
// The following assignments don't throw because read_fd and write_fd
|
// The following assignments don't throw because read_fd and write_fd
|
||||||
// are closed.
|
// are closed.
|
||||||
|
@ -212,8 +289,12 @@ void file::pipe(file& read_end, file& write_end) {
|
||||||
}
|
}
|
||||||
|
|
||||||
buffered_file file::fdopen(const char* mode) {
|
buffered_file file::fdopen(const char* mode) {
|
||||||
// Don't retry as fdopen doesn't return EINTR.
|
// Don't retry as fdopen doesn't return EINTR.
|
||||||
|
# if defined(__MINGW32__) && defined(_POSIX_)
|
||||||
|
FILE* f = ::fdopen(fd_, mode);
|
||||||
|
# else
|
||||||
FILE* f = FMT_POSIX_CALL(fdopen(fd_, mode));
|
FILE* f = FMT_POSIX_CALL(fdopen(fd_, mode));
|
||||||
|
# endif
|
||||||
if (!f)
|
if (!f)
|
||||||
FMT_THROW(
|
FMT_THROW(
|
||||||
system_error(errno, "cannot associate stream with file descriptor"));
|
system_error(errno, "cannot associate stream with file descriptor"));
|
||||||
|
@ -223,15 +304,19 @@ buffered_file file::fdopen(const char* mode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
long getpagesize() {
|
long getpagesize() {
|
||||||
#ifdef _WIN32
|
# ifdef _WIN32
|
||||||
SYSTEM_INFO si;
|
SYSTEM_INFO si;
|
||||||
GetSystemInfo(&si);
|
GetSystemInfo(&si);
|
||||||
return si.dwPageSize;
|
return si.dwPageSize;
|
||||||
#else
|
# else
|
||||||
long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE));
|
long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE));
|
||||||
if (size < 0) FMT_THROW(system_error(errno, "cannot get memory page size"));
|
if (size < 0) FMT_THROW(system_error(errno, "cannot get memory page size"));
|
||||||
return size;
|
return size;
|
||||||
#endif
|
# endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void ostream::grow(size_t) {
|
||||||
|
if (this->size() == this->capacity()) flush();
|
||||||
}
|
}
|
||||||
#endif // FMT_USE_FCNTL
|
#endif // FMT_USE_FCNTL
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
2
Externals/fmt/support/README
vendored
2
Externals/fmt/support/README
vendored
|
@ -2,5 +2,3 @@ This directory contains build support files such as
|
||||||
|
|
||||||
* CMake modules
|
* CMake modules
|
||||||
* Build scripts
|
* Build scripts
|
||||||
* qmake (static build with dynamic libc only)
|
|
||||||
|
|
||||||
|
|
1
Externals/fmt/support/Vagrantfile
vendored
1
Externals/fmt/support/Vagrantfile
vendored
|
@ -4,6 +4,7 @@
|
||||||
# A vagrant config for testing against gcc-4.8.
|
# A vagrant config for testing against gcc-4.8.
|
||||||
Vagrant.configure("2") do |config|
|
Vagrant.configure("2") do |config|
|
||||||
config.vm.box = "ubuntu/xenial64"
|
config.vm.box = "ubuntu/xenial64"
|
||||||
|
config.disksize.size = '15GB'
|
||||||
|
|
||||||
config.vm.provider "virtualbox" do |vb|
|
config.vm.provider "virtualbox" do |vb|
|
||||||
vb.memory = "4096"
|
vb.memory = "4096"
|
||||||
|
|
26
Externals/fmt/support/cmake/JoinPaths.cmake
vendored
Normal file
26
Externals/fmt/support/cmake/JoinPaths.cmake
vendored
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
# This module provides function for joining paths
|
||||||
|
# known from from most languages
|
||||||
|
#
|
||||||
|
# Original license:
|
||||||
|
# SPDX-License-Identifier: (MIT OR CC0-1.0)
|
||||||
|
# Explicit permission given to distribute this module under
|
||||||
|
# the terms of the project as described in /LICENSE.rst.
|
||||||
|
# Copyright 2020 Jan Tojnar
|
||||||
|
# https://github.com/jtojnar/cmake-snips
|
||||||
|
#
|
||||||
|
# Modelled after Python’s os.path.join
|
||||||
|
# https://docs.python.org/3.7/library/os.path.html#os.path.join
|
||||||
|
# Windows not supported
|
||||||
|
function(join_paths joined_path first_path_segment)
|
||||||
|
set(temp_path "${first_path_segment}")
|
||||||
|
foreach(current_segment IN LISTS ARGN)
|
||||||
|
if(NOT ("${current_segment}" STREQUAL ""))
|
||||||
|
if(IS_ABSOLUTE "${current_segment}")
|
||||||
|
set(temp_path "${current_segment}")
|
||||||
|
else()
|
||||||
|
set(temp_path "${temp_path}/${current_segment}")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endforeach()
|
||||||
|
set(${joined_path} "${temp_path}" PARENT_SCOPE)
|
||||||
|
endfunction()
|
11
Externals/fmt/support/cmake/cxx14.cmake
vendored
11
Externals/fmt/support/cmake/cxx14.cmake
vendored
|
@ -48,17 +48,6 @@ endif ()
|
||||||
|
|
||||||
set(CMAKE_REQUIRED_FLAGS ${CXX_STANDARD_FLAG})
|
set(CMAKE_REQUIRED_FLAGS ${CXX_STANDARD_FLAG})
|
||||||
|
|
||||||
# Check if variadic templates are working and not affected by GCC bug 39653:
|
|
||||||
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39653
|
|
||||||
# Can be removed once gcc 4.4 support is dropped.
|
|
||||||
check_cxx_source_compiles("
|
|
||||||
template <class T, class ...Types>
|
|
||||||
struct S { typedef typename S<Types...>::type type; };
|
|
||||||
int main() {}" SUPPORTS_VARIADIC_TEMPLATES)
|
|
||||||
if (NOT SUPPORTS_VARIADIC_TEMPLATES)
|
|
||||||
set (SUPPORTS_VARIADIC_TEMPLATES OFF)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
# Check if user-defined literals are available
|
# Check if user-defined literals are available
|
||||||
check_cxx_source_compiles("
|
check_cxx_source_compiles("
|
||||||
void operator\"\" _udl(long double);
|
void operator\"\" _udl(long double);
|
||||||
|
|
6
Externals/fmt/support/cmake/fmt.pc.in
vendored
6
Externals/fmt/support/cmake/fmt.pc.in
vendored
|
@ -1,11 +1,11 @@
|
||||||
prefix=@CMAKE_INSTALL_PREFIX@
|
prefix=@CMAKE_INSTALL_PREFIX@
|
||||||
exec_prefix=@CMAKE_INSTALL_PREFIX@
|
exec_prefix=@CMAKE_INSTALL_PREFIX@
|
||||||
libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@
|
libdir=@libdir_for_pc_file@
|
||||||
includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@
|
includedir=@includedir_for_pc_file@
|
||||||
|
|
||||||
Name: fmt
|
Name: fmt
|
||||||
Description: A modern formatting library
|
Description: A modern formatting library
|
||||||
Version: @FMT_VERSION@
|
Version: @FMT_VERSION@
|
||||||
Libs: -L${libdir} -lfmt
|
Libs: -L${libdir} -l@FMT_LIB_NAME@
|
||||||
Cflags: -I${includedir}
|
Cflags: -I${includedir}
|
||||||
|
|
||||||
|
|
27
Externals/fmt/support/fmt.pro
vendored
27
Externals/fmt/support/fmt.pro
vendored
|
@ -1,27 +0,0 @@
|
||||||
# Staticlib configuration for qmake builds
|
|
||||||
# For some reason qmake 3.1 fails to identify source dependencies and excludes format.cc and printf.cc
|
|
||||||
# from compilation so it _MUST_ be called as qmake -nodepend
|
|
||||||
# A workaround is implemented below: a custom compiler is defined which does not track dependencies
|
|
||||||
|
|
||||||
TEMPLATE = lib
|
|
||||||
|
|
||||||
TARGET = fmt
|
|
||||||
|
|
||||||
QMAKE_EXT_CPP = .cc
|
|
||||||
|
|
||||||
CONFIG = staticlib warn_on c++11
|
|
||||||
|
|
||||||
FMT_SOURCES = \
|
|
||||||
../src/format.cc \
|
|
||||||
../src/posix.cc
|
|
||||||
|
|
||||||
fmt.name = libfmt
|
|
||||||
fmt.input = FMT_SOURCES
|
|
||||||
fmt.output = ${QMAKE_FILE_BASE}$$QMAKE_EXT_OBJ
|
|
||||||
fmt.clean = ${QMAKE_FILE_BASE}$$QMAKE_EXT_OBJ
|
|
||||||
fmt.depends = ${QMAKE_FILE_IN}
|
|
||||||
# QMAKE_RUN_CXX will not be expanded
|
|
||||||
fmt.commands = $$QMAKE_CXX -c $$QMAKE_CXXFLAGS $$QMAKE_CXXFLAGS_WARN_ON $$QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO $$QMAKE_CXXFLAGS_CXX11 ${QMAKE_FILE_IN}
|
|
||||||
fmt.variable_out = OBJECTS
|
|
||||||
fmt.CONFIG = no_dependencies no_link
|
|
||||||
QMAKE_EXTRA_COMPILERS += fmt
|
|
31
Externals/fmt/support/manage.py
vendored
31
Externals/fmt/support/manage.py
vendored
|
@ -137,15 +137,40 @@ def update_site(env):
|
||||||
if not os.path.exists(contents):
|
if not os.path.exists(contents):
|
||||||
os.rename(os.path.join(target_doc_dir, 'index.rst'), contents)
|
os.rename(os.path.join(target_doc_dir, 'index.rst'), contents)
|
||||||
# Fix issues in reference.rst/api.rst.
|
# Fix issues in reference.rst/api.rst.
|
||||||
for filename in ['reference.rst', 'api.rst']:
|
for filename in ['reference.rst', 'api.rst', 'index.rst']:
|
||||||
pattern = re.compile('doxygenfunction.. (bin|oct|hexu|hex)$', re.M)
|
pattern = re.compile('doxygenfunction.. (bin|oct|hexu|hex)$', re.M)
|
||||||
with rewrite(os.path.join(target_doc_dir, filename)) as b:
|
with rewrite(os.path.join(target_doc_dir, filename)) as b:
|
||||||
b.data = b.data.replace('std::ostream &', 'std::ostream&')
|
b.data = b.data.replace('std::ostream &', 'std::ostream&')
|
||||||
b.data = re.sub(pattern, r'doxygenfunction:: \1(int)', b.data)
|
b.data = re.sub(pattern, r'doxygenfunction:: \1(int)', b.data)
|
||||||
b.data = b.data.replace('std::FILE*', 'std::FILE *')
|
b.data = b.data.replace('std::FILE*', 'std::FILE *')
|
||||||
b.data = b.data.replace('unsigned int', 'unsigned')
|
b.data = b.data.replace('unsigned int', 'unsigned')
|
||||||
b.data = b.data.replace('operator""_', 'operator"" _')
|
#b.data = b.data.replace('operator""_', 'operator"" _')
|
||||||
b.data = b.data.replace(', size_t', ', std::size_t')
|
b.data = b.data.replace(
|
||||||
|
'format_to_n(OutputIt, size_t, string_view, Args&&',
|
||||||
|
'format_to_n(OutputIt, size_t, const S&, const Args&')
|
||||||
|
b.data = b.data.replace(
|
||||||
|
'format_to_n(OutputIt, std::size_t, string_view, Args&&',
|
||||||
|
'format_to_n(OutputIt, std::size_t, const S&, const Args&')
|
||||||
|
if version == ('3.0.2'):
|
||||||
|
b.data = b.data.replace(
|
||||||
|
'fprintf(std::ostream&', 'fprintf(std::ostream &')
|
||||||
|
if version == ('5.3.0'):
|
||||||
|
b.data = b.data.replace(
|
||||||
|
'format_to(OutputIt, const S&, const Args&...)',
|
||||||
|
'format_to(OutputIt, const S &, const Args &...)')
|
||||||
|
if version.startswith('5.') or version.startswith('6.'):
|
||||||
|
b.data = b.data.replace(', size_t', ', std::size_t')
|
||||||
|
if version.startswith('7.'):
|
||||||
|
b.data = b.data.replace(', std::size_t', ', size_t')
|
||||||
|
b.data = b.data.replace('join(It, It', 'join(It, Sentinel')
|
||||||
|
b.data = b.data.replace('aa long', 'a long')
|
||||||
|
b.data = b.data.replace('serveral', 'several')
|
||||||
|
if version.startswith('6.2.'):
|
||||||
|
b.data = b.data.replace(
|
||||||
|
'vformat(const S&, basic_format_args<' +
|
||||||
|
'buffer_context<Char>>)',
|
||||||
|
'vformat(const S&, basic_format_args<' +
|
||||||
|
'buffer_context<type_identity_t<Char>>>)')
|
||||||
# Fix a broken link in index.rst.
|
# Fix a broken link in index.rst.
|
||||||
index = os.path.join(target_doc_dir, 'index.rst')
|
index = os.path.join(target_doc_dir, 'index.rst')
|
||||||
with rewrite(index) as b:
|
with rewrite(index) as b:
|
||||||
|
|
30
Externals/fmt/support/update-coverity-branch.py
vendored
30
Externals/fmt/support/update-coverity-branch.py
vendored
|
@ -1,30 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
# Update the coverity branch from the master branch.
|
|
||||||
# It is not done automatically because Coverity Scan limits
|
|
||||||
# the number of submissions per day.
|
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
import shutil, tempfile
|
|
||||||
from subprocess import check_output, STDOUT
|
|
||||||
|
|
||||||
class Git:
|
|
||||||
def __init__(self, dir):
|
|
||||||
self.dir = dir
|
|
||||||
|
|
||||||
def __call__(self, *args):
|
|
||||||
output = check_output(['git'] + list(args), cwd=self.dir, stderr=STDOUT)
|
|
||||||
print(output)
|
|
||||||
return output
|
|
||||||
|
|
||||||
dir = tempfile.mkdtemp()
|
|
||||||
try:
|
|
||||||
git = Git(dir)
|
|
||||||
git('clone', '-b', 'coverity', 'git@github.com:fmtlib/fmt.git', dir)
|
|
||||||
output = git('merge', '-X', 'theirs', '--no-commit', 'origin/master')
|
|
||||||
if 'Fast-forward' not in output:
|
|
||||||
git('reset', 'HEAD', '.travis.yml')
|
|
||||||
git('checkout', '--', '.travis.yml')
|
|
||||||
git('commit', '-m', 'Update coverity branch')
|
|
||||||
git('push')
|
|
||||||
finally:
|
|
||||||
shutil.rmtree(dir)
|
|
674
Externals/gettext/gettext-license.txt
vendored
Normal file
674
Externals/gettext/gettext-license.txt
vendored
Normal file
|
@ -0,0 +1,674 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The GNU General Public License is a free, copyleft license for
|
||||||
|
software and other kinds of works.
|
||||||
|
|
||||||
|
The licenses for most software and other practical works are designed
|
||||||
|
to take away your freedom to share and change the works. By contrast,
|
||||||
|
the GNU General Public License is intended to guarantee your freedom to
|
||||||
|
share and change all versions of a program--to make sure it remains free
|
||||||
|
software for all its users. We, the Free Software Foundation, use the
|
||||||
|
GNU General Public License for most of our software; it applies also to
|
||||||
|
any other work released this way by its authors. You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
them if you wish), that you receive source code or can get it if you
|
||||||
|
want it, that you can change the software or use pieces of it in new
|
||||||
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to prevent others from denying you
|
||||||
|
these rights or asking you to surrender the rights. Therefore, you have
|
||||||
|
certain responsibilities if you distribute copies of the software, or if
|
||||||
|
you modify it: responsibilities to respect the freedom of others.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must pass on to the recipients the same
|
||||||
|
freedoms that you received. You must make sure that they, too, receive
|
||||||
|
or can get the source code. And you must show them these terms so they
|
||||||
|
know their rights.
|
||||||
|
|
||||||
|
Developers that use the GNU GPL protect your rights with two steps:
|
||||||
|
(1) assert copyright on the software, and (2) offer you this License
|
||||||
|
giving you legal permission to copy, distribute and/or modify it.
|
||||||
|
|
||||||
|
For the developers' and authors' protection, the GPL clearly explains
|
||||||
|
that there is no warranty for this free software. For both users' and
|
||||||
|
authors' sake, the GPL requires that modified versions be marked as
|
||||||
|
changed, so that their problems will not be attributed erroneously to
|
||||||
|
authors of previous versions.
|
||||||
|
|
||||||
|
Some devices are designed to deny users access to install or run
|
||||||
|
modified versions of the software inside them, although the manufacturer
|
||||||
|
can do so. This is fundamentally incompatible with the aim of
|
||||||
|
protecting users' freedom to change the software. The systematic
|
||||||
|
pattern of such abuse occurs in the area of products for individuals to
|
||||||
|
use, which is precisely where it is most unacceptable. Therefore, we
|
||||||
|
have designed this version of the GPL to prohibit the practice for those
|
||||||
|
products. If such problems arise substantially in other domains, we
|
||||||
|
stand ready to extend this provision to those domains in future versions
|
||||||
|
of the GPL, as needed to protect the freedom of users.
|
||||||
|
|
||||||
|
Finally, every program is threatened constantly by software patents.
|
||||||
|
States should not allow patents to restrict development and use of
|
||||||
|
software on general-purpose computers, but in those that do, we wish to
|
||||||
|
avoid the special danger that patents applied to a free program could
|
||||||
|
make it effectively proprietary. To prevent this, the GPL assures that
|
||||||
|
patents cannot be used to render the program non-free.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
0. Definitions.
|
||||||
|
|
||||||
|
"This License" refers to version 3 of the GNU General Public License.
|
||||||
|
|
||||||
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
|
works, such as semiconductor masks.
|
||||||
|
|
||||||
|
"The Program" refers to any copyrightable work licensed under this
|
||||||
|
License. Each licensee is addressed as "you". "Licensees" and
|
||||||
|
"recipients" may be individuals or organizations.
|
||||||
|
|
||||||
|
To "modify" a work means to copy from or adapt all or part of the work
|
||||||
|
in a fashion requiring copyright permission, other than the making of an
|
||||||
|
exact copy. The resulting work is called a "modified version" of the
|
||||||
|
earlier work or a work "based on" the earlier work.
|
||||||
|
|
||||||
|
A "covered work" means either the unmodified Program or a work based
|
||||||
|
on the Program.
|
||||||
|
|
||||||
|
To "propagate" a work means to do anything with it that, without
|
||||||
|
permission, would make you directly or secondarily liable for
|
||||||
|
infringement under applicable copyright law, except executing it on a
|
||||||
|
computer or modifying a private copy. Propagation includes copying,
|
||||||
|
distribution (with or without modification), making available to the
|
||||||
|
public, and in some countries other activities as well.
|
||||||
|
|
||||||
|
To "convey" a work means any kind of propagation that enables other
|
||||||
|
parties to make or receive copies. Mere interaction with a user through
|
||||||
|
a computer network, with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
|
An interactive user interface displays "Appropriate Legal Notices"
|
||||||
|
to the extent that it includes a convenient and prominently visible
|
||||||
|
feature that (1) displays an appropriate copyright notice, and (2)
|
||||||
|
tells the user that there is no warranty for the work (except to the
|
||||||
|
extent that warranties are provided), that licensees may convey the
|
||||||
|
work under this License, and how to view a copy of this License. If
|
||||||
|
the interface presents a list of user commands or options, such as a
|
||||||
|
menu, a prominent item in the list meets this criterion.
|
||||||
|
|
||||||
|
1. Source Code.
|
||||||
|
|
||||||
|
The "source code" for a work means the preferred form of the work
|
||||||
|
for making modifications to it. "Object code" means any non-source
|
||||||
|
form of a work.
|
||||||
|
|
||||||
|
A "Standard Interface" means an interface that either is an official
|
||||||
|
standard defined by a recognized standards body, or, in the case of
|
||||||
|
interfaces specified for a particular programming language, one that
|
||||||
|
is widely used among developers working in that language.
|
||||||
|
|
||||||
|
The "System Libraries" of an executable work include anything, other
|
||||||
|
than the work as a whole, that (a) is included in the normal form of
|
||||||
|
packaging a Major Component, but which is not part of that Major
|
||||||
|
Component, and (b) serves only to enable use of the work with that
|
||||||
|
Major Component, or to implement a Standard Interface for which an
|
||||||
|
implementation is available to the public in source code form. A
|
||||||
|
"Major Component", in this context, means a major essential component
|
||||||
|
(kernel, window system, and so on) of the specific operating system
|
||||||
|
(if any) on which the executable work runs, or a compiler used to
|
||||||
|
produce the work, or an object code interpreter used to run it.
|
||||||
|
|
||||||
|
The "Corresponding Source" for a work in object code form means all
|
||||||
|
the source code needed to generate, install, and (for an executable
|
||||||
|
work) run the object code and to modify the work, including scripts to
|
||||||
|
control those activities. However, it does not include the work's
|
||||||
|
System Libraries, or general-purpose tools or generally available free
|
||||||
|
programs which are used unmodified in performing those activities but
|
||||||
|
which are not part of the work. For example, Corresponding Source
|
||||||
|
includes interface definition files associated with source files for
|
||||||
|
the work, and the source code for shared libraries and dynamically
|
||||||
|
linked subprograms that the work is specifically designed to require,
|
||||||
|
such as by intimate data communication or control flow between those
|
||||||
|
subprograms and other parts of the work.
|
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users
|
||||||
|
can regenerate automatically from other parts of the Corresponding
|
||||||
|
Source.
|
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that
|
||||||
|
same work.
|
||||||
|
|
||||||
|
2. Basic Permissions.
|
||||||
|
|
||||||
|
All rights granted under this License are granted for the term of
|
||||||
|
copyright on the Program, and are irrevocable provided the stated
|
||||||
|
conditions are met. This License explicitly affirms your unlimited
|
||||||
|
permission to run the unmodified Program. The output from running a
|
||||||
|
covered work is covered by this License only if the output, given its
|
||||||
|
content, constitutes a covered work. This License acknowledges your
|
||||||
|
rights of fair use or other equivalent, as provided by copyright law.
|
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not
|
||||||
|
convey, without conditions so long as your license otherwise remains
|
||||||
|
in force. You may convey covered works to others for the sole purpose
|
||||||
|
of having them make modifications exclusively for you, or provide you
|
||||||
|
with facilities for running those works, provided that you comply with
|
||||||
|
the terms of this License in conveying all material for which you do
|
||||||
|
not control copyright. Those thus making or running the covered works
|
||||||
|
for you must do so exclusively on your behalf, under your direction
|
||||||
|
and control, on terms that prohibit them from making any copies of
|
||||||
|
your copyrighted material outside their relationship with you.
|
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under
|
||||||
|
the conditions stated below. Sublicensing is not allowed; section 10
|
||||||
|
makes it unnecessary.
|
||||||
|
|
||||||
|
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||||
|
|
||||||
|
No covered work shall be deemed part of an effective technological
|
||||||
|
measure under any applicable law fulfilling obligations under article
|
||||||
|
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||||
|
similar laws prohibiting or restricting circumvention of such
|
||||||
|
measures.
|
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid
|
||||||
|
circumvention of technological measures to the extent such circumvention
|
||||||
|
is effected by exercising rights under this License with respect to
|
||||||
|
the covered work, and you disclaim any intention to limit operation or
|
||||||
|
modification of the work as a means of enforcing, against the work's
|
||||||
|
users, your or third parties' legal rights to forbid circumvention of
|
||||||
|
technological measures.
|
||||||
|
|
||||||
|
4. Conveying Verbatim Copies.
|
||||||
|
|
||||||
|
You may convey verbatim copies of the Program's source code as you
|
||||||
|
receive it, in any medium, provided that you conspicuously and
|
||||||
|
appropriately publish on each copy an appropriate copyright notice;
|
||||||
|
keep intact all notices stating that this License and any
|
||||||
|
non-permissive terms added in accord with section 7 apply to the code;
|
||||||
|
keep intact all notices of the absence of any warranty; and give all
|
||||||
|
recipients a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey,
|
||||||
|
and you may offer support or warranty protection for a fee.
|
||||||
|
|
||||||
|
5. Conveying Modified Source Versions.
|
||||||
|
|
||||||
|
You may convey a work based on the Program, or the modifications to
|
||||||
|
produce it from the Program, in the form of source code under the
|
||||||
|
terms of section 4, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The work must carry prominent notices stating that you modified
|
||||||
|
it, and giving a relevant date.
|
||||||
|
|
||||||
|
b) The work must carry prominent notices stating that it is
|
||||||
|
released under this License and any conditions added under section
|
||||||
|
7. This requirement modifies the requirement in section 4 to
|
||||||
|
"keep intact all notices".
|
||||||
|
|
||||||
|
c) You must license the entire work, as a whole, under this
|
||||||
|
License to anyone who comes into possession of a copy. This
|
||||||
|
License will therefore apply, along with any applicable section 7
|
||||||
|
additional terms, to the whole of the work, and all its parts,
|
||||||
|
regardless of how they are packaged. This License gives no
|
||||||
|
permission to license the work in any other way, but it does not
|
||||||
|
invalidate such permission if you have separately received it.
|
||||||
|
|
||||||
|
d) If the work has interactive user interfaces, each must display
|
||||||
|
Appropriate Legal Notices; however, if the Program has interactive
|
||||||
|
interfaces that do not display Appropriate Legal Notices, your
|
||||||
|
work need not make them do so.
|
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent
|
||||||
|
works, which are not by their nature extensions of the covered work,
|
||||||
|
and which are not combined with it such as to form a larger program,
|
||||||
|
in or on a volume of a storage or distribution medium, is called an
|
||||||
|
"aggregate" if the compilation and its resulting copyright are not
|
||||||
|
used to limit the access or legal rights of the compilation's users
|
||||||
|
beyond what the individual works permit. Inclusion of a covered work
|
||||||
|
in an aggregate does not cause this License to apply to the other
|
||||||
|
parts of the aggregate.
|
||||||
|
|
||||||
|
6. Conveying Non-Source Forms.
|
||||||
|
|
||||||
|
You may convey a covered work in object code form under the terms
|
||||||
|
of sections 4 and 5, provided that you also convey the
|
||||||
|
machine-readable Corresponding Source under the terms of this License,
|
||||||
|
in one of these ways:
|
||||||
|
|
||||||
|
a) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by the
|
||||||
|
Corresponding Source fixed on a durable physical medium
|
||||||
|
customarily used for software interchange.
|
||||||
|
|
||||||
|
b) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by a
|
||||||
|
written offer, valid for at least three years and valid for as
|
||||||
|
long as you offer spare parts or customer support for that product
|
||||||
|
model, to give anyone who possesses the object code either (1) a
|
||||||
|
copy of the Corresponding Source for all the software in the
|
||||||
|
product that is covered by this License, on a durable physical
|
||||||
|
medium customarily used for software interchange, for a price no
|
||||||
|
more than your reasonable cost of physically performing this
|
||||||
|
conveying of source, or (2) access to copy the
|
||||||
|
Corresponding Source from a network server at no charge.
|
||||||
|
|
||||||
|
c) Convey individual copies of the object code with a copy of the
|
||||||
|
written offer to provide the Corresponding Source. This
|
||||||
|
alternative is allowed only occasionally and noncommercially, and
|
||||||
|
only if you received the object code with such an offer, in accord
|
||||||
|
with subsection 6b.
|
||||||
|
|
||||||
|
d) Convey the object code by offering access from a designated
|
||||||
|
place (gratis or for a charge), and offer equivalent access to the
|
||||||
|
Corresponding Source in the same way through the same place at no
|
||||||
|
further charge. You need not require recipients to copy the
|
||||||
|
Corresponding Source along with the object code. If the place to
|
||||||
|
copy the object code is a network server, the Corresponding Source
|
||||||
|
may be on a different server (operated by you or a third party)
|
||||||
|
that supports equivalent copying facilities, provided you maintain
|
||||||
|
clear directions next to the object code saying where to find the
|
||||||
|
Corresponding Source. Regardless of what server hosts the
|
||||||
|
Corresponding Source, you remain obligated to ensure that it is
|
||||||
|
available for as long as needed to satisfy these requirements.
|
||||||
|
|
||||||
|
e) Convey the object code using peer-to-peer transmission, provided
|
||||||
|
you inform other peers where the object code and Corresponding
|
||||||
|
Source of the work are being offered to the general public at no
|
||||||
|
charge under subsection 6d.
|
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded
|
||||||
|
from the Corresponding Source as a System Library, need not be
|
||||||
|
included in conveying the object code work.
|
||||||
|
|
||||||
|
A "User Product" is either (1) a "consumer product", which means any
|
||||||
|
tangible personal property which is normally used for personal, family,
|
||||||
|
or household purposes, or (2) anything designed or sold for incorporation
|
||||||
|
into a dwelling. In determining whether a product is a consumer product,
|
||||||
|
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||||
|
product received by a particular user, "normally used" refers to a
|
||||||
|
typical or common use of that class of product, regardless of the status
|
||||||
|
of the particular user or of the way in which the particular user
|
||||||
|
actually uses, or expects or is expected to use, the product. A product
|
||||||
|
is a consumer product regardless of whether the product has substantial
|
||||||
|
commercial, industrial or non-consumer uses, unless such uses represent
|
||||||
|
the only significant mode of use of the product.
|
||||||
|
|
||||||
|
"Installation Information" for a User Product means any methods,
|
||||||
|
procedures, authorization keys, or other information required to install
|
||||||
|
and execute modified versions of a covered work in that User Product from
|
||||||
|
a modified version of its Corresponding Source. The information must
|
||||||
|
suffice to ensure that the continued functioning of the modified object
|
||||||
|
code is in no case prevented or interfered with solely because
|
||||||
|
modification has been made.
|
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or
|
||||||
|
specifically for use in, a User Product, and the conveying occurs as
|
||||||
|
part of a transaction in which the right of possession and use of the
|
||||||
|
User Product is transferred to the recipient in perpetuity or for a
|
||||||
|
fixed term (regardless of how the transaction is characterized), the
|
||||||
|
Corresponding Source conveyed under this section must be accompanied
|
||||||
|
by the Installation Information. But this requirement does not apply
|
||||||
|
if neither you nor any third party retains the ability to install
|
||||||
|
modified object code on the User Product (for example, the work has
|
||||||
|
been installed in ROM).
|
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a
|
||||||
|
requirement to continue to provide support service, warranty, or updates
|
||||||
|
for a work that has been modified or installed by the recipient, or for
|
||||||
|
the User Product in which it has been modified or installed. Access to a
|
||||||
|
network may be denied when the modification itself materially and
|
||||||
|
adversely affects the operation of the network or violates the rules and
|
||||||
|
protocols for communication across the network.
|
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided,
|
||||||
|
in accord with this section must be in a format that is publicly
|
||||||
|
documented (and with an implementation available to the public in
|
||||||
|
source code form), and must require no special password or key for
|
||||||
|
unpacking, reading or copying.
|
||||||
|
|
||||||
|
7. Additional Terms.
|
||||||
|
|
||||||
|
"Additional permissions" are terms that supplement the terms of this
|
||||||
|
License by making exceptions from one or more of its conditions.
|
||||||
|
Additional permissions that are applicable to the entire Program shall
|
||||||
|
be treated as though they were included in this License, to the extent
|
||||||
|
that they are valid under applicable law. If additional permissions
|
||||||
|
apply only to part of the Program, that part may be used separately
|
||||||
|
under those permissions, but the entire Program remains governed by
|
||||||
|
this License without regard to the additional permissions.
|
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option
|
||||||
|
remove any additional permissions from that copy, or from any part of
|
||||||
|
it. (Additional permissions may be written to require their own
|
||||||
|
removal in certain cases when you modify the work.) You may place
|
||||||
|
additional permissions on material, added by you to a covered work,
|
||||||
|
for which you have or can give appropriate copyright permission.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you
|
||||||
|
add to a covered work, you may (if authorized by the copyright holders of
|
||||||
|
that material) supplement the terms of this License with terms:
|
||||||
|
|
||||||
|
a) Disclaiming warranty or limiting liability differently from the
|
||||||
|
terms of sections 15 and 16 of this License; or
|
||||||
|
|
||||||
|
b) Requiring preservation of specified reasonable legal notices or
|
||||||
|
author attributions in that material or in the Appropriate Legal
|
||||||
|
Notices displayed by works containing it; or
|
||||||
|
|
||||||
|
c) Prohibiting misrepresentation of the origin of that material, or
|
||||||
|
requiring that modified versions of such material be marked in
|
||||||
|
reasonable ways as different from the original version; or
|
||||||
|
|
||||||
|
d) Limiting the use for publicity purposes of names of licensors or
|
||||||
|
authors of the material; or
|
||||||
|
|
||||||
|
e) Declining to grant rights under trademark law for use of some
|
||||||
|
trade names, trademarks, or service marks; or
|
||||||
|
|
||||||
|
f) Requiring indemnification of licensors and authors of that
|
||||||
|
material by anyone who conveys the material (or modified versions of
|
||||||
|
it) with contractual assumptions of liability to the recipient, for
|
||||||
|
any liability that these contractual assumptions directly impose on
|
||||||
|
those licensors and authors.
|
||||||
|
|
||||||
|
All other non-permissive additional terms are considered "further
|
||||||
|
restrictions" within the meaning of section 10. If the Program as you
|
||||||
|
received it, or any part of it, contains a notice stating that it is
|
||||||
|
governed by this License along with a term that is a further
|
||||||
|
restriction, you may remove that term. If a license document contains
|
||||||
|
a further restriction but permits relicensing or conveying under this
|
||||||
|
License, you may add to a covered work material governed by the terms
|
||||||
|
of that license document, provided that the further restriction does
|
||||||
|
not survive such relicensing or conveying.
|
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you
|
||||||
|
must place, in the relevant source files, a statement of the
|
||||||
|
additional terms that apply to those files, or a notice indicating
|
||||||
|
where to find the applicable terms.
|
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the
|
||||||
|
form of a separately written license, or stated as exceptions;
|
||||||
|
the above requirements apply either way.
|
||||||
|
|
||||||
|
8. Termination.
|
||||||
|
|
||||||
|
You may not propagate or modify a covered work except as expressly
|
||||||
|
provided under this License. Any attempt otherwise to propagate or
|
||||||
|
modify it is void, and will automatically terminate your rights under
|
||||||
|
this License (including any patent licenses granted under the third
|
||||||
|
paragraph of section 11).
|
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your
|
||||||
|
license from a particular copyright holder is reinstated (a)
|
||||||
|
provisionally, unless and until the copyright holder explicitly and
|
||||||
|
finally terminates your license, and (b) permanently, if the copyright
|
||||||
|
holder fails to notify you of the violation by some reasonable means
|
||||||
|
prior to 60 days after the cessation.
|
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is
|
||||||
|
reinstated permanently if the copyright holder notifies you of the
|
||||||
|
violation by some reasonable means, this is the first time you have
|
||||||
|
received notice of violation of this License (for any work) from that
|
||||||
|
copyright holder, and you cure the violation prior to 30 days after
|
||||||
|
your receipt of the notice.
|
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the
|
||||||
|
licenses of parties who have received copies or rights from you under
|
||||||
|
this License. If your rights have been terminated and not permanently
|
||||||
|
reinstated, you do not qualify to receive new licenses for the same
|
||||||
|
material under section 10.
|
||||||
|
|
||||||
|
9. Acceptance Not Required for Having Copies.
|
||||||
|
|
||||||
|
You are not required to accept this License in order to receive or
|
||||||
|
run a copy of the Program. Ancillary propagation of a covered work
|
||||||
|
occurring solely as a consequence of using peer-to-peer transmission
|
||||||
|
to receive a copy likewise does not require acceptance. However,
|
||||||
|
nothing other than this License grants you permission to propagate or
|
||||||
|
modify any covered work. These actions infringe copyright if you do
|
||||||
|
not accept this License. Therefore, by modifying or propagating a
|
||||||
|
covered work, you indicate your acceptance of this License to do so.
|
||||||
|
|
||||||
|
10. Automatic Licensing of Downstream Recipients.
|
||||||
|
|
||||||
|
Each time you convey a covered work, the recipient automatically
|
||||||
|
receives a license from the original licensors, to run, modify and
|
||||||
|
propagate that work, subject to this License. You are not responsible
|
||||||
|
for enforcing compliance by third parties with this License.
|
||||||
|
|
||||||
|
An "entity transaction" is a transaction transferring control of an
|
||||||
|
organization, or substantially all assets of one, or subdividing an
|
||||||
|
organization, or merging organizations. If propagation of a covered
|
||||||
|
work results from an entity transaction, each party to that
|
||||||
|
transaction who receives a copy of the work also receives whatever
|
||||||
|
licenses to the work the party's predecessor in interest had or could
|
||||||
|
give under the previous paragraph, plus a right to possession of the
|
||||||
|
Corresponding Source of the work from the predecessor in interest, if
|
||||||
|
the predecessor has it or can get it with reasonable efforts.
|
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the
|
||||||
|
rights granted or affirmed under this License. For example, you may
|
||||||
|
not impose a license fee, royalty, or other charge for exercise of
|
||||||
|
rights granted under this License, and you may not initiate litigation
|
||||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||||
|
any patent claim is infringed by making, using, selling, offering for
|
||||||
|
sale, or importing the Program or any portion of it.
|
||||||
|
|
||||||
|
11. Patents.
|
||||||
|
|
||||||
|
A "contributor" is a copyright holder who authorizes use under this
|
||||||
|
License of the Program or a work on which the Program is based. The
|
||||||
|
work thus licensed is called the contributor's "contributor version".
|
||||||
|
|
||||||
|
A contributor's "essential patent claims" are all patent claims
|
||||||
|
owned or controlled by the contributor, whether already acquired or
|
||||||
|
hereafter acquired, that would be infringed by some manner, permitted
|
||||||
|
by this License, of making, using, or selling its contributor version,
|
||||||
|
but do not include claims that would be infringed only as a
|
||||||
|
consequence of further modification of the contributor version. For
|
||||||
|
purposes of this definition, "control" includes the right to grant
|
||||||
|
patent sublicenses in a manner consistent with the requirements of
|
||||||
|
this License.
|
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||||
|
patent license under the contributor's essential patent claims, to
|
||||||
|
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||||
|
propagate the contents of its contributor version.
|
||||||
|
|
||||||
|
In the following three paragraphs, a "patent license" is any express
|
||||||
|
agreement or commitment, however denominated, not to enforce a patent
|
||||||
|
(such as an express permission to practice a patent or covenant not to
|
||||||
|
sue for patent infringement). To "grant" such a patent license to a
|
||||||
|
party means to make such an agreement or commitment not to enforce a
|
||||||
|
patent against the party.
|
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license,
|
||||||
|
and the Corresponding Source of the work is not available for anyone
|
||||||
|
to copy, free of charge and under the terms of this License, through a
|
||||||
|
publicly available network server or other readily accessible means,
|
||||||
|
then you must either (1) cause the Corresponding Source to be so
|
||||||
|
available, or (2) arrange to deprive yourself of the benefit of the
|
||||||
|
patent license for this particular work, or (3) arrange, in a manner
|
||||||
|
consistent with the requirements of this License, to extend the patent
|
||||||
|
license to downstream recipients. "Knowingly relying" means you have
|
||||||
|
actual knowledge that, but for the patent license, your conveying the
|
||||||
|
covered work in a country, or your recipient's use of the covered work
|
||||||
|
in a country, would infringe one or more identifiable patents in that
|
||||||
|
country that you have reason to believe are valid.
|
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or
|
||||||
|
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||||
|
covered work, and grant a patent license to some of the parties
|
||||||
|
receiving the covered work authorizing them to use, propagate, modify
|
||||||
|
or convey a specific copy of the covered work, then the patent license
|
||||||
|
you grant is automatically extended to all recipients of the covered
|
||||||
|
work and works based on it.
|
||||||
|
|
||||||
|
A patent license is "discriminatory" if it does not include within
|
||||||
|
the scope of its coverage, prohibits the exercise of, or is
|
||||||
|
conditioned on the non-exercise of one or more of the rights that are
|
||||||
|
specifically granted under this License. You may not convey a covered
|
||||||
|
work if you are a party to an arrangement with a third party that is
|
||||||
|
in the business of distributing software, under which you make payment
|
||||||
|
to the third party based on the extent of your activity of conveying
|
||||||
|
the work, and under which the third party grants, to any of the
|
||||||
|
parties who would receive the covered work from you, a discriminatory
|
||||||
|
patent license (a) in connection with copies of the covered work
|
||||||
|
conveyed by you (or copies made from those copies), or (b) primarily
|
||||||
|
for and in connection with specific products or compilations that
|
||||||
|
contain the covered work, unless you entered into that arrangement,
|
||||||
|
or that patent license was granted, prior to 28 March 2007.
|
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting
|
||||||
|
any implied license or other defenses to infringement that may
|
||||||
|
otherwise be available to you under applicable patent law.
|
||||||
|
|
||||||
|
12. No Surrender of Others' Freedom.
|
||||||
|
|
||||||
|
If conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot convey a
|
||||||
|
covered work so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you may
|
||||||
|
not convey it at all. For example, if you agree to terms that obligate you
|
||||||
|
to collect a royalty for further conveying from those to whom you convey
|
||||||
|
the Program, the only way you could satisfy both those terms and this
|
||||||
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
|
13. Use with the GNU Affero General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, you have
|
||||||
|
permission to link or combine any covered work with a work licensed
|
||||||
|
under version 3 of the GNU Affero General Public License into a single
|
||||||
|
combined work, and to convey the resulting work. The terms of this
|
||||||
|
License will continue to apply to the part which is the covered work,
|
||||||
|
but the special requirements of the GNU Affero General Public License,
|
||||||
|
section 13, concerning interaction through a network will apply to the
|
||||||
|
combination as such.
|
||||||
|
|
||||||
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the GNU General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Program specifies that a certain numbered version of the GNU General
|
||||||
|
Public License "or any later version" applies to it, you have the
|
||||||
|
option of following the terms and conditions either of that numbered
|
||||||
|
version or of any later version published by the Free Software
|
||||||
|
Foundation. If the Program does not specify a version number of the
|
||||||
|
GNU General Public License, you may choose any version ever published
|
||||||
|
by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future
|
||||||
|
versions of the GNU General Public License can be used, that proxy's
|
||||||
|
public statement of acceptance of a version permanently authorizes you
|
||||||
|
to choose that version for the Program.
|
||||||
|
|
||||||
|
Later license versions may give you additional or different
|
||||||
|
permissions. However, no additional obligations are imposed on any
|
||||||
|
author or copyright holder as a result of your choosing to follow a
|
||||||
|
later version.
|
||||||
|
|
||||||
|
15. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||||
|
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||||
|
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||||
|
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||||
|
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||||
|
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. Limitation of Liability.
|
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||||
|
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||||
|
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||||
|
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||||
|
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||||
|
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||||
|
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGES.
|
||||||
|
|
||||||
|
17. Interpretation of Sections 15 and 16.
|
||||||
|
|
||||||
|
If the disclaimer of warranty and limitation of liability provided
|
||||||
|
above cannot be given local legal effect according to their terms,
|
||||||
|
reviewing courts shall apply local law that most closely approximates
|
||||||
|
an absolute waiver of all civil liability in connection with the
|
||||||
|
Program, unless a warranty or assumption of liability accompanies a
|
||||||
|
copy of the Program in return for a fee.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
state the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program does terminal interaction, make it output a short
|
||||||
|
notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
|
<program> Copyright (C) <year> <name of author>
|
||||||
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, your program's commands
|
||||||
|
might be different; for a GUI interface, you would use an "about box".
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or school,
|
||||||
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||||
|
For more information on this, and how to apply and follow the GNU GPL, see
|
||||||
|
<https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
The GNU General Public License does not permit incorporating your program
|
||||||
|
into proprietary programs. If your program is a subroutine library, you
|
||||||
|
may consider it more useful to permit linking proprietary applications with
|
||||||
|
the library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License. But first, please read
|
||||||
|
<https://www.gnu.org/philosophy/why-not-lgpl.html>.
|
BIN
Externals/gettext/libgettextlib.dll
vendored
BIN
Externals/gettext/libgettextlib.dll
vendored
Binary file not shown.
BIN
Externals/gettext/libgettextsrc.dll
vendored
BIN
Externals/gettext/libgettextsrc.dll
vendored
Binary file not shown.
BIN
Externals/gettext/libiconv2.dll
vendored
BIN
Externals/gettext/libiconv2.dll
vendored
Binary file not shown.
BIN
Externals/gettext/libintl3.dll
vendored
BIN
Externals/gettext/libintl3.dll
vendored
Binary file not shown.
BIN
Externals/gettext/msgfmt.exe
vendored
BIN
Externals/gettext/msgfmt.exe
vendored
Binary file not shown.
2
Externals/liblzma/config.h
vendored
2
Externals/liblzma/config.h
vendored
|
@ -190,7 +190,9 @@
|
||||||
#define HAVE_POSIX_FADVISE 1
|
#define HAVE_POSIX_FADVISE 1
|
||||||
|
|
||||||
/* Define to 1 if you have the `pthread_condattr_setclock' function. */
|
/* Define to 1 if you have the `pthread_condattr_setclock' function. */
|
||||||
|
#ifndef __APPLE__
|
||||||
#define HAVE_PTHREAD_CONDATTR_SETCLOCK 1
|
#define HAVE_PTHREAD_CONDATTR_SETCLOCK 1
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Have PTHREAD_PRIO_INHERIT. */
|
/* Have PTHREAD_PRIO_INHERIT. */
|
||||||
#define HAVE_PTHREAD_PRIO_INHERIT 1
|
#define HAVE_PTHREAD_PRIO_INHERIT 1
|
||||||
|
|
2
Externals/libpng/CMakeLists.txt
vendored
2
Externals/libpng/CMakeLists.txt
vendored
|
@ -23,7 +23,7 @@ PUBLIC
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(png PUBLIC z)
|
target_link_libraries(png PUBLIC ZLIB::ZLIB)
|
||||||
|
|
||||||
if(NOT MSVC)
|
if(NOT MSVC)
|
||||||
target_compile_options(png
|
target_compile_options(png
|
||||||
|
|
7
Externals/libusb/libusb/libusb.h
vendored
7
Externals/libusb/libusb/libusb.h
vendored
|
@ -25,6 +25,9 @@
|
||||||
#define LIBUSB_H
|
#define LIBUSB_H
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(push)
|
||||||
|
/* Disable: warning C4200: nonstandard extension used : zero-sized array in struct/union */
|
||||||
|
#pragma warning(disable:4200)
|
||||||
/* on MS environments, the inline keyword is available in C++ only */
|
/* on MS environments, the inline keyword is available in C++ only */
|
||||||
#if !defined(__cplusplus)
|
#if !defined(__cplusplus)
|
||||||
#define inline __inline
|
#define inline __inline
|
||||||
|
@ -2059,6 +2062,10 @@ enum libusb_option {
|
||||||
|
|
||||||
int LIBUSB_CALL libusb_set_option(libusb_context *ctx, enum libusb_option option, ...);
|
int LIBUSB_CALL libusb_set_option(libusb_context *ctx, enum libusb_option option, ...);
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
2
Externals/licenses.md
vendored
2
Externals/licenses.md
vendored
|
@ -56,6 +56,8 @@ Dolphin includes or links code of the following third-party software projects:
|
||||||
[LGPLv2.1+](http://cgit.freedesktop.org/pulseaudio/pulseaudio/tree/LICENSE)
|
[LGPLv2.1+](http://cgit.freedesktop.org/pulseaudio/pulseaudio/tree/LICENSE)
|
||||||
- [Qt5](http://qt-project.org/):
|
- [Qt5](http://qt-project.org/):
|
||||||
[LGPLv3 and other licenses](http://doc.qt.io/qt-5/licensing.html)
|
[LGPLv3 and other licenses](http://doc.qt.io/qt-5/licensing.html)
|
||||||
|
- [rangeset](https://github.com/AdmiralCurtiss/rangeset)
|
||||||
|
[zlib license](https://github.com/AdmiralCurtiss/rangeset/blob/master/LICENSE)
|
||||||
- [SDL](https://www.libsdl.org/):
|
- [SDL](https://www.libsdl.org/):
|
||||||
[zlib license](http://hg.libsdl.org/SDL/file/tip/COPYING.txt)
|
[zlib license](http://hg.libsdl.org/SDL/file/tip/COPYING.txt)
|
||||||
- [SFML](http://www.sfml-dev.org/):
|
- [SFML](http://www.sfml-dev.org/):
|
||||||
|
|
2
Externals/minizip/CMakeLists.txt
vendored
2
Externals/minizip/CMakeLists.txt
vendored
|
@ -13,6 +13,6 @@ endif()
|
||||||
add_library(minizip STATIC ${SRCS})
|
add_library(minizip STATIC ${SRCS})
|
||||||
target_include_directories(minizip PUBLIC .)
|
target_include_directories(minizip PUBLIC .)
|
||||||
|
|
||||||
target_link_libraries(minizip PUBLIC z)
|
target_link_libraries(minizip PUBLIC ZLIB::ZLIB)
|
||||||
|
|
||||||
add_library(MiniZip::minizip ALIAS minizip)
|
add_library(MiniZip::minizip ALIAS minizip)
|
||||||
|
|
4
Externals/rangeset/CMakeLists.txt
vendored
Normal file
4
Externals/rangeset/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
add_library(RangeSet::RangeSet INTERFACE IMPORTED GLOBAL)
|
||||||
|
set_target_properties(RangeSet::RangeSet PROPERTIES
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_LIST_DIR}/include
|
||||||
|
)
|
17
Externals/rangeset/LICENSE
vendored
Normal file
17
Externals/rangeset/LICENSE
vendored
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
Copyright (c) 2020 Admiral H. Curtiss
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any damages
|
||||||
|
arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any purpose,
|
||||||
|
including commercial applications, and to alter it and redistribute it
|
||||||
|
freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you must not
|
||||||
|
claim that you wrote the original software. If you use this software
|
||||||
|
in a product, an acknowledgment in the product documentation would be
|
||||||
|
appreciated but is not required.
|
||||||
|
2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
misrepresented as being the original software.
|
||||||
|
3. This notice may not be removed or altered from any source distribution.
|
368
Externals/rangeset/include/rangeset/rangeset.h
vendored
Normal file
368
Externals/rangeset/include/rangeset/rangeset.h
vendored
Normal file
|
@ -0,0 +1,368 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace HyoutaUtilities {
|
||||||
|
template <typename T> class RangeSet {
|
||||||
|
private:
|
||||||
|
using MapT = std::map<T, T>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct const_iterator {
|
||||||
|
public:
|
||||||
|
const T& from() const {
|
||||||
|
return It->first;
|
||||||
|
}
|
||||||
|
|
||||||
|
const T& to() const {
|
||||||
|
return It->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator& operator++() {
|
||||||
|
++It;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator operator++(int) {
|
||||||
|
const_iterator old = *this;
|
||||||
|
++It;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator& operator--() {
|
||||||
|
--It;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator operator--(int) {
|
||||||
|
const_iterator old = *this;
|
||||||
|
--It;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const const_iterator& rhs) const {
|
||||||
|
return this->It == rhs.It;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const const_iterator& rhs) const {
|
||||||
|
return !operator==(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
typename MapT::const_iterator It;
|
||||||
|
const_iterator(typename MapT::const_iterator it) : It(it) {}
|
||||||
|
friend class RangeSet;
|
||||||
|
};
|
||||||
|
|
||||||
|
void insert(T from, T to) {
|
||||||
|
if (from >= to)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Start by finding the closest range.
|
||||||
|
// upper_bound() returns the closest range whose starting position
|
||||||
|
// is greater than 'from'.
|
||||||
|
auto bound = Map.upper_bound(from);
|
||||||
|
if (bound == Map.end()) {
|
||||||
|
// There is no range that starts greater than the given one.
|
||||||
|
// This means we have three options:
|
||||||
|
// - 1. No range exists yet, this is the first range.
|
||||||
|
if (Map.empty()) {
|
||||||
|
insert_range(from, to);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - 2. The given range does not overlap the last range.
|
||||||
|
--bound;
|
||||||
|
if (from > get_to(bound)) {
|
||||||
|
insert_range(from, to);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - 3. The given range does overlap the last range.
|
||||||
|
maybe_expand_to(bound, to);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bound == Map.begin()) {
|
||||||
|
// The given range starts before any of the existing ones.
|
||||||
|
// We must insert this as a new range even if we potentially overlap
|
||||||
|
// an existing one as we can't modify a key in a std::map.
|
||||||
|
auto inserted = insert_range(from, to);
|
||||||
|
merge_from_iterator_to_value(inserted, bound, to);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto abound = bound--;
|
||||||
|
|
||||||
|
// 'bound' now points at the first range in the map that
|
||||||
|
// could possibly be affected.
|
||||||
|
|
||||||
|
// If 'bound' overlaps with given range, update bounds object.
|
||||||
|
if (get_to(bound) >= from) {
|
||||||
|
maybe_expand_to(bound, to);
|
||||||
|
auto inserted = bound;
|
||||||
|
++bound;
|
||||||
|
merge_from_iterator_to_value(inserted, bound, to);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'bound' *doesn't* overlap with given range, check next range.
|
||||||
|
|
||||||
|
// If this range overlaps with given range,
|
||||||
|
if (get_from(abound) <= to) {
|
||||||
|
// insert new range
|
||||||
|
auto inserted = insert_range(from, to >= get_to(abound) ? to : get_to(abound));
|
||||||
|
// and delete overlaps
|
||||||
|
abound = erase_range(abound);
|
||||||
|
merge_from_iterator_to_value(inserted, abound, to);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, if we come here, then this new range overlaps nothing
|
||||||
|
// and must be inserted as a new range.
|
||||||
|
insert_range(from, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
void erase(T from, T to) {
|
||||||
|
if (from >= to)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Like insert(), we use upper_bound to find the closest range.
|
||||||
|
auto bound = Map.upper_bound(from);
|
||||||
|
if (bound == Map.end()) {
|
||||||
|
// There is no range that starts greater than the given one.
|
||||||
|
if (Map.empty()) {
|
||||||
|
// nothing to do
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
--bound;
|
||||||
|
// 'bound' now points at the last range.
|
||||||
|
if (from >= get_to(bound)) {
|
||||||
|
// Given range is larger than any range that exists, nothing to do.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (to >= get_to(bound)) {
|
||||||
|
if (from == get_from(bound)) {
|
||||||
|
// Given range fully overlaps last range, erase it.
|
||||||
|
erase_range(bound);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// Given range overlaps end of last range, reduce it.
|
||||||
|
reduce_to(bound, from);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (from == get_from(bound)) {
|
||||||
|
// Given range overlaps begin of last range, reduce it.
|
||||||
|
reduce_from(bound, to);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// Given range overlaps middle of last range, bisect it.
|
||||||
|
bisect_range(bound, from, to);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bound == Map.begin()) {
|
||||||
|
// If we found the first range that means 'from' is before any stored range.
|
||||||
|
// This means we can just erase from start until 'to' and be done with it.
|
||||||
|
erase_from_iterator_to_value(bound, to);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check previous range
|
||||||
|
auto abound = bound--;
|
||||||
|
|
||||||
|
if (from == get_from(bound)) {
|
||||||
|
// Similarly, if the previous range starts with the given one, just erase until 'to'.
|
||||||
|
erase_from_iterator_to_value(bound, to);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we come here, the given range may or may not overlap part of the current 'bound'
|
||||||
|
// (but never the full range), which means we may need to update the end position of it,
|
||||||
|
// or possibly even split it into two.
|
||||||
|
if (from < get_to(bound)) {
|
||||||
|
if (to < get_to(bound)) {
|
||||||
|
// need to split in two
|
||||||
|
bisect_range(bound, from, to);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// just update end
|
||||||
|
reduce_to(bound, from);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// and then just erase until 'to'
|
||||||
|
erase_from_iterator_to_value(abound, to);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator erase(const_iterator it) {
|
||||||
|
return const_iterator(erase_range(it.It));
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
Map.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool contains(T value) const {
|
||||||
|
auto it = Map.upper_bound(value);
|
||||||
|
if (it == Map.begin())
|
||||||
|
return false;
|
||||||
|
--it;
|
||||||
|
return get_from(it) <= value && value < get_to(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const {
|
||||||
|
return Map.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const {
|
||||||
|
return Map.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(RangeSet<T>& other) {
|
||||||
|
Map.swap(other.Map);
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator begin() const {
|
||||||
|
return const_iterator(Map.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator end() const {
|
||||||
|
return const_iterator(Map.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator cbegin() const {
|
||||||
|
return const_iterator(Map.cbegin());
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator cend() const {
|
||||||
|
return const_iterator(Map.cend());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const RangeSet<T>& other) const {
|
||||||
|
return this->Map == other.Map;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const RangeSet<T>& other) const {
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Assumptions that can be made about the data:
|
||||||
|
// - Range are stored in the form [from, to[
|
||||||
|
// That is, the starting value is inclusive, and the end value is exclusive.
|
||||||
|
// - 'from' is the map key, 'to' is the map value
|
||||||
|
// - 'from' is always smaller than 'to'
|
||||||
|
// - Stored ranges never touch.
|
||||||
|
// - Stored ranges never overlap.
|
||||||
|
MapT Map;
|
||||||
|
|
||||||
|
T get_from(typename MapT::iterator it) const {
|
||||||
|
return it->first;
|
||||||
|
}
|
||||||
|
|
||||||
|
T get_to(typename MapT::iterator it) const {
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
T get_from(typename MapT::const_iterator it) const {
|
||||||
|
return it->first;
|
||||||
|
}
|
||||||
|
|
||||||
|
T get_to(typename MapT::const_iterator it) const {
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
typename MapT::iterator insert_range(T from, T to) {
|
||||||
|
return Map.emplace(from, to).first;
|
||||||
|
}
|
||||||
|
|
||||||
|
typename MapT::iterator erase_range(typename MapT::iterator it) {
|
||||||
|
return Map.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
typename MapT::const_iterator erase_range(typename MapT::const_iterator it) {
|
||||||
|
return Map.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bisect_range(typename MapT::iterator it, T from, T to) {
|
||||||
|
assert(get_from(it) < from);
|
||||||
|
assert(get_from(it) < to);
|
||||||
|
assert(get_to(it) > from);
|
||||||
|
assert(get_to(it) > to);
|
||||||
|
assert(from < to);
|
||||||
|
T itto = get_to(it);
|
||||||
|
reduce_to(it, from);
|
||||||
|
insert_range(to, itto);
|
||||||
|
}
|
||||||
|
|
||||||
|
typename MapT::iterator reduce_from(typename MapT::iterator it, T from) {
|
||||||
|
assert(get_from(it) < from);
|
||||||
|
T itto = get_to(it);
|
||||||
|
erase_range(it);
|
||||||
|
return insert_range(from, itto);
|
||||||
|
}
|
||||||
|
|
||||||
|
void maybe_expand_to(typename MapT::iterator it, T to) {
|
||||||
|
if (to <= get_to(it))
|
||||||
|
return;
|
||||||
|
|
||||||
|
expand_to(it, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
void expand_to(typename MapT::iterator it, T to) {
|
||||||
|
assert(get_to(it) < to);
|
||||||
|
it->second = to;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reduce_to(typename MapT::iterator it, T to) {
|
||||||
|
assert(get_to(it) > to);
|
||||||
|
it->second = to;
|
||||||
|
}
|
||||||
|
|
||||||
|
void merge_from_iterator_to_value(typename MapT::iterator inserted, typename MapT::iterator bound, T to) {
|
||||||
|
// Erase all ranges that overlap the inserted while updating the upper end.
|
||||||
|
while (bound != Map.end() && get_from(bound) <= to) {
|
||||||
|
maybe_expand_to(inserted, get_to(bound));
|
||||||
|
bound = erase_range(bound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void erase_from_iterator_to_value(typename MapT::iterator bound, T to) {
|
||||||
|
// Assumption: Given bound starts at or after the 'from' value of the range to erase.
|
||||||
|
while (true) {
|
||||||
|
// Given range starts before stored range.
|
||||||
|
if (to <= get_from(bound)) {
|
||||||
|
// Range ends before this range too, nothing to do.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (to < get_to(bound)) {
|
||||||
|
// Range ends in the middle of current range, reduce current.
|
||||||
|
reduce_from(bound, to);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (to == get_to(bound)) {
|
||||||
|
// Range ends exactly with current range, erase current.
|
||||||
|
erase_range(bound);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Range ends later than current range.
|
||||||
|
// First erase current, then loop to check the range(s) after this one too.
|
||||||
|
bound = erase_range(bound);
|
||||||
|
if (bound == Map.end()) {
|
||||||
|
// Unless that was the last range, in which case there's nothing else to do.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace HyoutaUtilities
|
541
Externals/rangeset/include/rangeset/rangesizeset.h
vendored
Normal file
541
Externals/rangeset/include/rangeset/rangesizeset.h
vendored
Normal file
|
@ -0,0 +1,541 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <map>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace HyoutaUtilities {
|
||||||
|
// Like RangeSet, but additionally stores a map of the ranges sorted by their size, for quickly finding the largest or
|
||||||
|
// smallest range.
|
||||||
|
template <typename T> class RangeSizeSet {
|
||||||
|
private:
|
||||||
|
// Key type used in the by-size multimap. Should be a type big enough to hold all possible distances between
|
||||||
|
// possible 'from' and 'to'.
|
||||||
|
// I'd actually love to just do
|
||||||
|
// using SizeT = typename std::conditional<std::is_pointer_v<T>,
|
||||||
|
// std::size_t, typename std::make_unsigned<T>::type>::type;
|
||||||
|
// but that's apparently not possible due to the std::make_unsigned<T>::type not existing for pointer types
|
||||||
|
// so we'll work around this...
|
||||||
|
template <typename U, bool IsPointer> struct GetSizeType { using S = typename std::make_unsigned<U>::type; };
|
||||||
|
template <typename U> struct GetSizeType<U, true> { using S = std::size_t; };
|
||||||
|
|
||||||
|
public:
|
||||||
|
using SizeT = typename GetSizeType<T, std::is_pointer_v<T>>::S;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Value type stored in the regular range map.
|
||||||
|
struct Value {
|
||||||
|
// End point of the range.
|
||||||
|
T To;
|
||||||
|
|
||||||
|
// Pointer to the same range in the by-size multimap.
|
||||||
|
typename std::multimap<SizeT, typename std::map<T, Value>::iterator, std::greater<SizeT>>::iterator SizeIt;
|
||||||
|
|
||||||
|
Value(T to) : To(to) {}
|
||||||
|
|
||||||
|
bool operator==(const Value& other) const {
|
||||||
|
return this->To == other.To;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const Value& other) const {
|
||||||
|
return !operator==(other);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using MapT = std::map<T, Value>;
|
||||||
|
using SizeMapT = std::multimap<SizeT, typename MapT::iterator, std::greater<SizeT>>;
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct by_size_const_iterator;
|
||||||
|
|
||||||
|
struct const_iterator {
|
||||||
|
public:
|
||||||
|
const T& from() const {
|
||||||
|
return It->first;
|
||||||
|
}
|
||||||
|
|
||||||
|
const T& to() const {
|
||||||
|
return It->second.To;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator& operator++() {
|
||||||
|
++It;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator operator++(int) {
|
||||||
|
const_iterator old = *this;
|
||||||
|
++It;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator& operator--() {
|
||||||
|
--It;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator operator--(int) {
|
||||||
|
const_iterator old = *this;
|
||||||
|
--It;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const const_iterator& rhs) const {
|
||||||
|
return this->It == rhs.It;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const const_iterator& rhs) const {
|
||||||
|
return !operator==(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
by_size_const_iterator to_size_iterator() {
|
||||||
|
return by_size_const_iterator(It->second.SizeIt);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
typename MapT::const_iterator It;
|
||||||
|
const_iterator(typename MapT::const_iterator it) : It(it) {}
|
||||||
|
friend class RangeSizeSet;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct by_size_const_iterator {
|
||||||
|
public:
|
||||||
|
const T& from() const {
|
||||||
|
return It->second->first;
|
||||||
|
}
|
||||||
|
|
||||||
|
const T& to() const {
|
||||||
|
return It->second->second.To;
|
||||||
|
}
|
||||||
|
|
||||||
|
by_size_const_iterator& operator++() {
|
||||||
|
++It;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
by_size_const_iterator operator++(int) {
|
||||||
|
by_size_const_iterator old = *this;
|
||||||
|
++It;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
by_size_const_iterator& operator--() {
|
||||||
|
--It;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
by_size_const_iterator operator--(int) {
|
||||||
|
by_size_const_iterator old = *this;
|
||||||
|
--It;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const by_size_const_iterator& rhs) const {
|
||||||
|
return this->It == rhs.It;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const by_size_const_iterator& rhs) const {
|
||||||
|
return !operator==(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator to_range_iterator() {
|
||||||
|
return const_iterator(It->second);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
typename SizeMapT::const_iterator It;
|
||||||
|
by_size_const_iterator(typename SizeMapT::const_iterator it) : It(it) {}
|
||||||
|
friend class RangeSizeSet;
|
||||||
|
};
|
||||||
|
|
||||||
|
// We store iterators internally, so disallow copying.
|
||||||
|
RangeSizeSet() = default;
|
||||||
|
RangeSizeSet(const RangeSizeSet<T>&) = delete;
|
||||||
|
RangeSizeSet(RangeSizeSet<T>&&) = default;
|
||||||
|
RangeSizeSet<T>& operator=(const RangeSizeSet<T>&) = delete;
|
||||||
|
RangeSizeSet<T>& operator=(RangeSizeSet<T>&&) = default;
|
||||||
|
|
||||||
|
void insert(T from, T to) {
|
||||||
|
if (from >= to)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Start by finding the closest range.
|
||||||
|
// upper_bound() returns the closest range whose starting position
|
||||||
|
// is greater than 'from'.
|
||||||
|
auto bound = Map.upper_bound(from);
|
||||||
|
if (bound == Map.end()) {
|
||||||
|
// There is no range that starts greater than the given one.
|
||||||
|
// This means we have three options:
|
||||||
|
// - 1. No range exists yet, this is the first range.
|
||||||
|
if (Map.empty()) {
|
||||||
|
insert_range(from, to);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - 2. The given range does not overlap the last range.
|
||||||
|
--bound;
|
||||||
|
if (from > get_to(bound)) {
|
||||||
|
insert_range(from, to);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - 3. The given range does overlap the last range.
|
||||||
|
maybe_expand_to(bound, to);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bound == Map.begin()) {
|
||||||
|
// The given range starts before any of the existing ones.
|
||||||
|
// We must insert this as a new range even if we potentially overlap
|
||||||
|
// an existing one as we can't modify a key in a std::map.
|
||||||
|
auto inserted = insert_range(from, to);
|
||||||
|
merge_from_iterator_to_value(inserted, bound, to);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto abound = bound--;
|
||||||
|
|
||||||
|
// 'bound' now points at the first range in the map that
|
||||||
|
// could possibly be affected.
|
||||||
|
|
||||||
|
// If 'bound' overlaps with given range, update bounds object.
|
||||||
|
if (get_to(bound) >= from) {
|
||||||
|
maybe_expand_to(bound, to);
|
||||||
|
auto inserted = bound;
|
||||||
|
++bound;
|
||||||
|
merge_from_iterator_to_value(inserted, bound, to);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'bound' *doesn't* overlap with given range, check next range.
|
||||||
|
|
||||||
|
// If this range overlaps with given range,
|
||||||
|
if (get_from(abound) <= to) {
|
||||||
|
// insert new range
|
||||||
|
auto inserted = insert_range(from, to >= get_to(abound) ? to : get_to(abound));
|
||||||
|
// and delete overlaps
|
||||||
|
abound = erase_range(abound);
|
||||||
|
merge_from_iterator_to_value(inserted, abound, to);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, if we come here, then this new range overlaps nothing
|
||||||
|
// and must be inserted as a new range.
|
||||||
|
insert_range(from, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
void erase(T from, T to) {
|
||||||
|
if (from >= to)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Like insert(), we use upper_bound to find the closest range.
|
||||||
|
auto bound = Map.upper_bound(from);
|
||||||
|
if (bound == Map.end()) {
|
||||||
|
// There is no range that starts greater than the given one.
|
||||||
|
if (Map.empty()) {
|
||||||
|
// nothing to do
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
--bound;
|
||||||
|
// 'bound' now points at the last range.
|
||||||
|
if (from >= get_to(bound)) {
|
||||||
|
// Given range is larger than any range that exists, nothing to do.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (to >= get_to(bound)) {
|
||||||
|
if (from == get_from(bound)) {
|
||||||
|
// Given range fully overlaps last range, erase it.
|
||||||
|
erase_range(bound);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// Given range overlaps end of last range, reduce it.
|
||||||
|
reduce_to(bound, from);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (from == get_from(bound)) {
|
||||||
|
// Given range overlaps begin of last range, reduce it.
|
||||||
|
reduce_from(bound, to);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// Given range overlaps middle of last range, bisect it.
|
||||||
|
bisect_range(bound, from, to);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bound == Map.begin()) {
|
||||||
|
// If we found the first range that means 'from' is before any stored range.
|
||||||
|
// This means we can just erase from start until 'to' and be done with it.
|
||||||
|
erase_from_iterator_to_value(bound, to);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check previous range
|
||||||
|
auto abound = bound--;
|
||||||
|
|
||||||
|
if (from == get_from(bound)) {
|
||||||
|
// Similarly, if the previous range starts with the given one, just erase until 'to'.
|
||||||
|
erase_from_iterator_to_value(bound, to);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we come here, the given range may or may not overlap part of the current 'bound'
|
||||||
|
// (but never the full range), which means we may need to update the end position of it,
|
||||||
|
// or possibly even split it into two.
|
||||||
|
if (from < get_to(bound)) {
|
||||||
|
if (to < get_to(bound)) {
|
||||||
|
// need to split in two
|
||||||
|
bisect_range(bound, from, to);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// just update end
|
||||||
|
reduce_to(bound, from);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// and then just erase until 'to'
|
||||||
|
erase_from_iterator_to_value(abound, to);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator erase(const_iterator it) {
|
||||||
|
return const_iterator(erase_range(it.It));
|
||||||
|
}
|
||||||
|
|
||||||
|
by_size_const_iterator erase(by_size_const_iterator it) {
|
||||||
|
return by_size_const_iterator(erase_range_by_size(it.It));
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
Map.clear();
|
||||||
|
Sizes.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool contains(T value) const {
|
||||||
|
auto it = Map.upper_bound(value);
|
||||||
|
if (it == Map.begin())
|
||||||
|
return false;
|
||||||
|
--it;
|
||||||
|
return get_from(it) <= value && value < get_to(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const {
|
||||||
|
return Map.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const {
|
||||||
|
return Map.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t by_size_count(const SizeT& key) const {
|
||||||
|
return Sizes.count(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
by_size_const_iterator by_size_find(const SizeT& key) const {
|
||||||
|
return Sizes.find(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<by_size_const_iterator, by_size_const_iterator> by_size_equal_range(const SizeT& key) const {
|
||||||
|
auto p = Sizes.equal_range(key);
|
||||||
|
return std::pair<by_size_const_iterator, by_size_const_iterator>(by_size_const_iterator(p.first),
|
||||||
|
by_size_const_iterator(p.second));
|
||||||
|
}
|
||||||
|
|
||||||
|
by_size_const_iterator by_size_lower_bound(const SizeT& key) const {
|
||||||
|
return Sizes.lower_bound(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
by_size_const_iterator by_size_upper_bound(const SizeT& key) const {
|
||||||
|
return Sizes.upper_bound(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(RangeSizeSet<T>& other) {
|
||||||
|
Map.swap(other.Map);
|
||||||
|
Sizes.swap(other.Sizes);
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator begin() const {
|
||||||
|
return const_iterator(Map.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator end() const {
|
||||||
|
return const_iterator(Map.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator cbegin() const {
|
||||||
|
return const_iterator(Map.cbegin());
|
||||||
|
}
|
||||||
|
|
||||||
|
const_iterator cend() const {
|
||||||
|
return const_iterator(Map.cend());
|
||||||
|
}
|
||||||
|
|
||||||
|
by_size_const_iterator by_size_begin() const {
|
||||||
|
return by_size_const_iterator(Sizes.begin());
|
||||||
|
}
|
||||||
|
|
||||||
|
by_size_const_iterator by_size_end() const {
|
||||||
|
return by_size_const_iterator(Sizes.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
by_size_const_iterator by_size_cbegin() const {
|
||||||
|
return by_size_const_iterator(Sizes.cbegin());
|
||||||
|
}
|
||||||
|
|
||||||
|
by_size_const_iterator by_size_cend() const {
|
||||||
|
return by_size_const_iterator(Sizes.cend());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const RangeSizeSet<T>& other) const {
|
||||||
|
return this->Map == other.Map;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const RangeSizeSet<T>& other) const {
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static SizeT calc_size(T from, T to) {
|
||||||
|
if constexpr (std::is_pointer_v<T>) {
|
||||||
|
// For pointers we don't want pointer arithmetic here, else void* breaks.
|
||||||
|
static_assert(sizeof(T) <= sizeof(SizeT));
|
||||||
|
return reinterpret_cast<SizeT>(to) - reinterpret_cast<SizeT>(from);
|
||||||
|
} else {
|
||||||
|
return static_cast<SizeT>(to - from);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assumptions that can be made about the data:
|
||||||
|
// - Range are stored in the form [from, to[
|
||||||
|
// That is, the starting value is inclusive, and the end value is exclusive.
|
||||||
|
// - 'from' is the map key, 'to' is the map value
|
||||||
|
// - 'from' is always smaller than 'to'
|
||||||
|
// - Stored ranges never touch.
|
||||||
|
// - Stored ranges never overlap.
|
||||||
|
MapT Map;
|
||||||
|
|
||||||
|
// The by-size multimap.
|
||||||
|
// Key is the size of the range.
|
||||||
|
// Value is a pointer to the range in the regular range map.
|
||||||
|
// We use std::greater so that Sizes.begin() gives us the largest range.
|
||||||
|
SizeMapT Sizes;
|
||||||
|
|
||||||
|
T get_from(typename MapT::iterator it) const {
|
||||||
|
return it->first;
|
||||||
|
}
|
||||||
|
|
||||||
|
T get_to(typename MapT::iterator it) const {
|
||||||
|
return it->second.To;
|
||||||
|
}
|
||||||
|
|
||||||
|
T get_from(typename MapT::const_iterator it) const {
|
||||||
|
return it->first;
|
||||||
|
}
|
||||||
|
|
||||||
|
T get_to(typename MapT::const_iterator it) const {
|
||||||
|
return it->second.To;
|
||||||
|
}
|
||||||
|
|
||||||
|
typename MapT::iterator insert_range(T from, T to) {
|
||||||
|
auto m = Map.emplace(from, to).first;
|
||||||
|
m->second.SizeIt = Sizes.emplace(calc_size(from, to), m);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
typename MapT::iterator erase_range(typename MapT::iterator it) {
|
||||||
|
Sizes.erase(it->second.SizeIt);
|
||||||
|
return Map.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
typename MapT::const_iterator erase_range(typename MapT::const_iterator it) {
|
||||||
|
Sizes.erase(it->second.SizeIt);
|
||||||
|
return Map.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
typename SizeMapT::const_iterator erase_range_by_size(typename SizeMapT::const_iterator it) {
|
||||||
|
Map.erase(it->second);
|
||||||
|
return Sizes.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bisect_range(typename MapT::iterator it, T from, T to) {
|
||||||
|
assert(get_from(it) < from);
|
||||||
|
assert(get_from(it) < to);
|
||||||
|
assert(get_to(it) > from);
|
||||||
|
assert(get_to(it) > to);
|
||||||
|
assert(from < to);
|
||||||
|
T itto = get_to(it);
|
||||||
|
reduce_to(it, from);
|
||||||
|
insert_range(to, itto);
|
||||||
|
}
|
||||||
|
|
||||||
|
typename MapT::iterator reduce_from(typename MapT::iterator it, T from) {
|
||||||
|
assert(get_from(it) < from);
|
||||||
|
T itto = get_to(it);
|
||||||
|
erase_range(it);
|
||||||
|
return insert_range(from, itto);
|
||||||
|
}
|
||||||
|
|
||||||
|
void maybe_expand_to(typename MapT::iterator it, T to) {
|
||||||
|
if (to <= get_to(it))
|
||||||
|
return;
|
||||||
|
|
||||||
|
expand_to(it, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
void expand_to(typename MapT::iterator it, T to) {
|
||||||
|
assert(get_to(it) < to);
|
||||||
|
it->second.To = to;
|
||||||
|
Sizes.erase(it->second.SizeIt);
|
||||||
|
it->second.SizeIt = Sizes.emplace(calc_size(get_from(it), to), it);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reduce_to(typename MapT::iterator it, T to) {
|
||||||
|
assert(get_to(it) > to);
|
||||||
|
it->second.To = to;
|
||||||
|
Sizes.erase(it->second.SizeIt);
|
||||||
|
it->second.SizeIt = Sizes.emplace(calc_size(get_from(it), to), it);
|
||||||
|
}
|
||||||
|
|
||||||
|
void merge_from_iterator_to_value(typename MapT::iterator inserted, typename MapT::iterator bound, T to) {
|
||||||
|
// Erase all ranges that overlap the inserted while updating the upper end.
|
||||||
|
while (bound != Map.end() && get_from(bound) <= to) {
|
||||||
|
maybe_expand_to(inserted, get_to(bound));
|
||||||
|
bound = erase_range(bound);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void erase_from_iterator_to_value(typename MapT::iterator bound, T to) {
|
||||||
|
// Assumption: Given bound starts at or after the 'from' value of the range to erase.
|
||||||
|
while (true) {
|
||||||
|
// Given range starts before stored range.
|
||||||
|
if (to <= get_from(bound)) {
|
||||||
|
// Range ends before this range too, nothing to do.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (to < get_to(bound)) {
|
||||||
|
// Range ends in the middle of current range, reduce current.
|
||||||
|
reduce_from(bound, to);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (to == get_to(bound)) {
|
||||||
|
// Range ends exactly with current range, erase current.
|
||||||
|
erase_range(bound);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Range ends later than current range.
|
||||||
|
// First erase current, then loop to check the range(s) after this one too.
|
||||||
|
bound = erase_range(bound);
|
||||||
|
if (bound == Map.end()) {
|
||||||
|
// Unless that was the last range, in which case there's nothing else to do.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace HyoutaUtilities
|
4
Externals/soundtouch/PeakFinder.cpp
vendored
4
Externals/soundtouch/PeakFinder.cpp
vendored
|
@ -64,7 +64,7 @@ int PeakFinder::findTop(const float *data, int peakpos) const
|
||||||
|
|
||||||
refvalue = data[peakpos];
|
refvalue = data[peakpos];
|
||||||
|
|
||||||
// seek within ±10 points
|
// seek within ±10 points
|
||||||
start = peakpos - 10;
|
start = peakpos - 10;
|
||||||
if (start < minPos) start = minPos;
|
if (start < minPos) start = minPos;
|
||||||
end = peakpos + 10;
|
end = peakpos + 10;
|
||||||
|
@ -265,7 +265,7 @@ double PeakFinder::detectPeak(const float *data, int aminPos, int amaxPos)
|
||||||
|
|
||||||
// accept harmonic peak if
|
// accept harmonic peak if
|
||||||
// (a) it is found
|
// (a) it is found
|
||||||
// (b) is within ±4% of the expected harmonic interval
|
// (b) is within ±4% of the expected harmonic interval
|
||||||
// (c) has at least half x-corr value of the max. peak
|
// (c) has at least half x-corr value of the max. peak
|
||||||
|
|
||||||
double diff = harmonic * peaktmp / highPeak;
|
double diff = harmonic * peaktmp / highPeak;
|
||||||
|
|
4763
Languages/po/ar.po
4763
Languages/po/ar.po
File diff suppressed because it is too large
Load diff
4178
Languages/po/ca.po
4178
Languages/po/ca.po
File diff suppressed because it is too large
Load diff
4246
Languages/po/cs.po
4246
Languages/po/cs.po
File diff suppressed because it is too large
Load diff
4263
Languages/po/da.po
4263
Languages/po/da.po
File diff suppressed because it is too large
Load diff
4980
Languages/po/de.po
4980
Languages/po/de.po
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
4183
Languages/po/el.po
4183
Languages/po/el.po
File diff suppressed because it is too large
Load diff
4098
Languages/po/en.po
4098
Languages/po/en.po
File diff suppressed because it is too large
Load diff
4892
Languages/po/es.po
4892
Languages/po/es.po
File diff suppressed because it is too large
Load diff
4159
Languages/po/fa.po
4159
Languages/po/fa.po
File diff suppressed because it is too large
Load diff
4857
Languages/po/fr.po
4857
Languages/po/fr.po
File diff suppressed because it is too large
Load diff
4175
Languages/po/hr.po
4175
Languages/po/hr.po
File diff suppressed because it is too large
Load diff
4263
Languages/po/hu.po
4263
Languages/po/hu.po
File diff suppressed because it is too large
Load diff
4852
Languages/po/it.po
4852
Languages/po/it.po
File diff suppressed because it is too large
Load diff
4693
Languages/po/ja.po
4693
Languages/po/ja.po
File diff suppressed because it is too large
Load diff
4823
Languages/po/ko.po
4823
Languages/po/ko.po
File diff suppressed because it is too large
Load diff
4322
Languages/po/ms.po
4322
Languages/po/ms.po
File diff suppressed because it is too large
Load diff
5394
Languages/po/nb.po
5394
Languages/po/nb.po
File diff suppressed because it is too large
Load diff
4874
Languages/po/nl.po
4874
Languages/po/nl.po
File diff suppressed because it is too large
Load diff
4265
Languages/po/pl.po
4265
Languages/po/pl.po
File diff suppressed because it is too large
Load diff
4155
Languages/po/pt.po
4155
Languages/po/pt.po
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
84
Languages/po/qt-strings.pot
Normal file
84
Languages/po/qt-strings.pot
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
# This file contains strings which are defined in Qt's source code
|
||||||
|
# and may be accessed in applications which use Qt. Extracted from Qt 5.15.1.
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: qtbase/src/gui/kernel/qguiapplication.cpp:234
|
||||||
|
msgctxt ""
|
||||||
|
"Translate this string to the string 'LTR' in left-to-right languages or to "
|
||||||
|
"'RTL' in right-to-left languages (such as Hebrew and Arabic) to get proper "
|
||||||
|
"widget layout."
|
||||||
|
msgid "QT_LAYOUT_DIRECTION"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: qtbase/src/gui/kernel/qplatformtheme.cpp:708
|
||||||
|
msgid "OK"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: qtbase/src/gui/kernel/qplatformtheme.cpp:710
|
||||||
|
msgid "Save"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: qtbase/src/gui/kernel/qplatformtheme.cpp:712
|
||||||
|
msgid "Save All"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: qtbase/src/gui/kernel/qplatformtheme.cpp:714
|
||||||
|
msgid "Open"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: qtbase/src/gui/kernel/qplatformtheme.cpp:716
|
||||||
|
msgid "&Yes"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: qtbase/src/gui/kernel/qplatformtheme.cpp:718
|
||||||
|
msgid "Yes to &All"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: qtbase/src/gui/kernel/qplatformtheme.cpp:720
|
||||||
|
msgid "&No"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: qtbase/src/gui/kernel/qplatformtheme.cpp:722
|
||||||
|
msgid "N&o to All"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: qtbase/src/gui/kernel/qplatformtheme.cpp:724
|
||||||
|
msgid "Abort"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: qtbase/src/gui/kernel/qplatformtheme.cpp:726
|
||||||
|
msgid "Retry"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: qtbase/src/gui/kernel/qplatformtheme.cpp:728
|
||||||
|
msgid "Ignore"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: qtbase/src/gui/kernel/qplatformtheme.cpp:730
|
||||||
|
msgid "Close"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: qtbase/src/gui/kernel/qplatformtheme.cpp:732
|
||||||
|
msgid "Cancel"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: qtbase/src/gui/kernel/qplatformtheme.cpp:734
|
||||||
|
msgid "Discard"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: qtbase/src/gui/kernel/qplatformtheme.cpp:736
|
||||||
|
msgid "Help"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: qtbase/src/gui/kernel/qplatformtheme.cpp:738
|
||||||
|
msgid "Apply"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: qtbase/src/gui/kernel/qplatformtheme.cpp:740
|
||||||
|
msgid "Reset"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: qtbase/src/gui/kernel/qplatformtheme.cpp:742
|
||||||
|
msgid "Restore Defaults"
|
||||||
|
msgstr ""
|
4172
Languages/po/ro.po
4172
Languages/po/ro.po
File diff suppressed because it is too large
Load diff
4828
Languages/po/ru.po
4828
Languages/po/ru.po
File diff suppressed because it is too large
Load diff
4102
Languages/po/sr.po
4102
Languages/po/sr.po
File diff suppressed because it is too large
Load diff
4878
Languages/po/sv.po
4878
Languages/po/sv.po
File diff suppressed because it is too large
Load diff
4687
Languages/po/tr.po
4687
Languages/po/tr.po
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -4,13 +4,34 @@
|
||||||
# the source code.
|
# the source code.
|
||||||
|
|
||||||
cd "$(dirname "$0")/.."
|
cd "$(dirname "$0")/.."
|
||||||
|
|
||||||
|
# Scan the source code for strings and put them in dolphin-emu.pot
|
||||||
SRCDIR=Source
|
SRCDIR=Source
|
||||||
find $SRCDIR -name '*.cpp' -o -name '*.h' -o -name '*.c' | \
|
find $SRCDIR -name '*.cpp' -o -name '*.h' -o -name '*.c' | \
|
||||||
xgettext -d dolphin-emu -s --keyword=_ --keyword=wxTRANSLATE --keyword=SuccessAlertT \
|
xgettext -s -p ./Languages/po -o dolphin-emu.pot --package-name="Dolphin Emulator" \
|
||||||
--keyword=PanicAlertT --keyword=PanicYesNoT --keyword=AskYesNoT --keyword=CriticalAlertT \
|
--keyword=_ \
|
||||||
--keyword=GetStringT --keyword=_trans --keyword=tr --keyword=QT_TR_NOOP \
|
--keyword=wxTRANSLATE \
|
||||||
--add-comments=i18n -p ./Languages/po -o dolphin-emu.pot -f - --package-name="Dolphin Emulator" \
|
--keyword=AskYesNoT \
|
||||||
--from-code=utf-8
|
--keyword=AskYesNoFmtT \
|
||||||
|
--keyword=CriticalAlertT \
|
||||||
|
--keyword=CriticalAlertFmtT \
|
||||||
|
--keyword=PanicAlertT \
|
||||||
|
--keyword=PanicAlertFmtT \
|
||||||
|
--keyword=PanicYesNoT \
|
||||||
|
--keyword=PanicYesNoFmtT \
|
||||||
|
--keyword=SuccessAlertT \
|
||||||
|
--keyword=SuccessAlertFmtT \
|
||||||
|
--keyword=GetStringT \
|
||||||
|
--keyword=_trans \
|
||||||
|
--keyword=tr:1,1t \
|
||||||
|
--keyword=tr:1,2c \
|
||||||
|
--keyword=QT_TR_NOOP \
|
||||||
|
--keyword=FmtFormatT \
|
||||||
|
--add-comments=i18n --from-code=utf-8 -f -
|
||||||
|
|
||||||
|
# Copy strings from qt-strings.pot to dolphin-emu.pot
|
||||||
|
xgettext -s -p ./Languages/po -o dolphin-emu.pot --package-name="Dolphin Emulator" \
|
||||||
|
-j ./Languages/po/qt-strings.pot
|
||||||
|
|
||||||
sed -i "s/SOME DESCRIPTIVE TITLE\./Translation of dolphin-emu.pot to LANGUAGE/" Languages/po/dolphin-emu.pot
|
sed -i "s/SOME DESCRIPTIVE TITLE\./Translation of dolphin-emu.pot to LANGUAGE/" Languages/po/dolphin-emu.pot
|
||||||
sed -i "s/YEAR THE PACKAGE'S COPYRIGHT HOLDER/2003-2013/" Languages/po/dolphin-emu.pot
|
sed -i "s/YEAR THE PACKAGE'S COPYRIGHT HOLDER/2003-2013/" Languages/po/dolphin-emu.pot
|
||||||
|
|
|
@ -14,7 +14,7 @@ Ping or message @r2dliu in the slippi discord.
|
||||||
|
|
||||||
# Dolphin - A GameCube and Wii Emulator
|
# Dolphin - A GameCube and Wii Emulator
|
||||||
|
|
||||||
[Homepage](https://dolphin-emu.org/) | [Project Site](https://github.com/dolphin-emu/dolphin) | [Forums](https://forums.dolphin-emu.org/) | [Wiki](https://wiki.dolphin-emu.org/) | [Issue Tracker](https://bugs.dolphin-emu.org/projects/emulator/issues) | [Coding Style](https://github.com/dolphin-emu/dolphin/blob/master/Contributing.md) | [Transifex Page](https://www.transifex.com/projects/p/dolphin-emu/)
|
[Homepage](https://dolphin-emu.org/) | [Project Site](https://github.com/dolphin-emu/dolphin) | [Buildbot](https://dolphin.ci) | [Forums](https://forums.dolphin-emu.org/) | [Wiki](https://wiki.dolphin-emu.org/) | [Issue Tracker](https://bugs.dolphin-emu.org/projects/emulator/issues) | [Coding Style](https://github.com/dolphin-emu/dolphin/blob/master/Contributing.md) | [Transifex Page](https://www.transifex.com/projects/p/dolphin-emu/)
|
||||||
|
|
||||||
Dolphin is an emulator for running GameCube and Wii games on Windows,
|
Dolphin is an emulator for running GameCube and Wii games on Windows,
|
||||||
Linux, macOS, and recent Android devices. It's licensed under the terms
|
Linux, macOS, and recent Android devices. It's licensed under the terms
|
||||||
|
@ -156,7 +156,7 @@ see where it's stored) if you don't plan to reinstall Dolphin.
|
||||||
|
|
||||||
Available DSP emulation engines are HLE (High Level Emulation) and
|
Available DSP emulation engines are HLE (High Level Emulation) and
|
||||||
LLE (Low Level Emulation). HLE is faster but less accurate whereas
|
LLE (Low Level Emulation). HLE is faster but less accurate whereas
|
||||||
LLE is slower but close to perfect. Note that LLE has two submodes (Interpreter and Recompiler)
|
LLE is slower but close to perfect. Note that LLE has two submodes (Interpreter and Recompiler)
|
||||||
but they cannot be selected from the command line.
|
but they cannot be selected from the command line.
|
||||||
|
|
||||||
Available video backends are "D3D" and "D3D12" (they are only available on Windows), "OGL", and "Vulkan".
|
Available video backends are "D3D" and "D3D12" (they are only available on Windows), "OGL", and "Vulkan".
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 29
|
compileSdkVersion 30
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
|
// Flag to enable support for the new language APIs
|
||||||
|
coreLibraryDesugaringEnabled true
|
||||||
|
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
}
|
}
|
||||||
|
@ -76,11 +79,14 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.9'
|
||||||
|
|
||||||
implementation 'androidx.appcompat:appcompat:1.1.0'
|
implementation 'androidx.appcompat:appcompat:1.1.0'
|
||||||
implementation 'androidx.exifinterface:exifinterface:1.1.0'
|
implementation 'androidx.exifinterface:exifinterface:1.1.0'
|
||||||
implementation 'androidx.cardview:cardview:1.0.0'
|
implementation 'androidx.cardview:cardview:1.0.0'
|
||||||
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
implementation 'androidx.recyclerview:recyclerview:1.1.0'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
|
||||||
|
implementation 'androidx.lifecycle:lifecycle-viewmodel:2.2.0'
|
||||||
implementation 'com.google.android.material:material:1.1.0'
|
implementation 'com.google.android.material:material:1.1.0'
|
||||||
|
|
||||||
// Android TV UI libraries.
|
// Android TV UI libraries.
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
<uses-feature android:glEsVersion="0x00030000"/>
|
<uses-feature android:glEsVersion="0x00030000"/>
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
@ -73,7 +74,8 @@
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".activities.EmulationActivity"
|
android:name=".activities.EmulationActivity"
|
||||||
android:theme="@style/DolphinEmulationBase"/>
|
android:theme="@style/DolphinEmulationBase"
|
||||||
|
android:preferMinimalPostProcessing="true"/>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".activities.CustomFilePickerActivity"
|
android:name=".activities.CustomFilePickerActivity"
|
||||||
|
@ -95,6 +97,10 @@
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".activities.ConvertActivity"
|
||||||
|
android:theme="@style/DolphinBase" />
|
||||||
|
|
||||||
<service android:name=".utils.DirectoryInitialization"/>
|
<service android:name=".utils.DirectoryInitialization"/>
|
||||||
<service android:name=".services.GameFileCacheService"/>
|
<service android:name=".services.GameFileCacheService"/>
|
||||||
<service
|
<service
|
||||||
|
|
|
@ -18,8 +18,8 @@ IR/Right = `Axis 115`
|
||||||
IR/Forward = `Axis 116`
|
IR/Forward = `Axis 116`
|
||||||
IR/Backward = `Axis 117`
|
IR/Backward = `Axis 117`
|
||||||
IR/Hide = `Button 118`
|
IR/Hide = `Button 118`
|
||||||
IR/Total Pitch = 15
|
IR/Total Pitch = 20
|
||||||
IR/Total Yaw = 15
|
IR/Total Yaw = 25
|
||||||
IR/Vertical Offset = 10
|
IR/Vertical Offset = 10
|
||||||
Swing/Up = `Axis 120`
|
Swing/Up = `Axis 120`
|
||||||
Swing/Down = `Axis 121`
|
Swing/Down = `Axis 121`
|
||||||
|
|
|
@ -18,8 +18,8 @@ IR/Right = `Axis 115`
|
||||||
IR/Forward = `Axis 116`
|
IR/Forward = `Axis 116`
|
||||||
IR/Backward = `Axis 117`
|
IR/Backward = `Axis 117`
|
||||||
IR/Hide = `Button 118`
|
IR/Hide = `Button 118`
|
||||||
IR/Total Pitch = 15
|
IR/Total Pitch = 20
|
||||||
IR/Total Yaw = 15
|
IR/Total Yaw = 25
|
||||||
IR/Vertical Offset = 10
|
IR/Vertical Offset = 10
|
||||||
Swing/Up = `Axis 120`
|
Swing/Up = `Axis 120`
|
||||||
Swing/Down = `Axis 121`
|
Swing/Down = `Axis 121`
|
||||||
|
|
|
@ -7,7 +7,6 @@ import android.hardware.usb.UsbManager;
|
||||||
import org.dolphinemu.dolphinemu.utils.DirectoryInitialization;
|
import org.dolphinemu.dolphinemu.utils.DirectoryInitialization;
|
||||||
import org.dolphinemu.dolphinemu.utils.Java_GCAdapter;
|
import org.dolphinemu.dolphinemu.utils.Java_GCAdapter;
|
||||||
import org.dolphinemu.dolphinemu.utils.Java_WiimoteAdapter;
|
import org.dolphinemu.dolphinemu.utils.Java_WiimoteAdapter;
|
||||||
import org.dolphinemu.dolphinemu.utils.PermissionsHandler;
|
|
||||||
import org.dolphinemu.dolphinemu.utils.VolleyUtil;
|
import org.dolphinemu.dolphinemu.utils.VolleyUtil;
|
||||||
|
|
||||||
public class DolphinApplication extends Application
|
public class DolphinApplication extends Application
|
||||||
|
@ -25,7 +24,7 @@ public class DolphinApplication extends Application
|
||||||
Java_GCAdapter.manager = (UsbManager) getSystemService(Context.USB_SERVICE);
|
Java_GCAdapter.manager = (UsbManager) getSystemService(Context.USB_SERVICE);
|
||||||
Java_WiimoteAdapter.manager = (UsbManager) getSystemService(Context.USB_SERVICE);
|
Java_WiimoteAdapter.manager = (UsbManager) getSystemService(Context.USB_SERVICE);
|
||||||
|
|
||||||
if (PermissionsHandler.hasWriteAccess(getApplicationContext()))
|
if (DirectoryInitialization.shouldStart(getApplicationContext()))
|
||||||
DirectoryInitialization.start(getApplicationContext());
|
DirectoryInitialization.start(getApplicationContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,15 +6,23 @@
|
||||||
|
|
||||||
package org.dolphinemu.dolphinemu;
|
package org.dolphinemu.dolphinemu;
|
||||||
|
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.Looper;
|
||||||
|
import android.util.DisplayMetrics;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.annotation.Keep;
|
||||||
|
import androidx.fragment.app.FragmentManager;
|
||||||
|
|
||||||
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
|
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
|
||||||
|
import org.dolphinemu.dolphinemu.dialogs.AlertMessage;
|
||||||
|
import org.dolphinemu.dolphinemu.utils.CompressCallback;
|
||||||
import org.dolphinemu.dolphinemu.utils.Log;
|
import org.dolphinemu.dolphinemu.utils.Log;
|
||||||
import org.dolphinemu.dolphinemu.utils.Rumble;
|
import org.dolphinemu.dolphinemu.utils.Rumble;
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class which contains methods that interact
|
* Class which contains methods that interact
|
||||||
|
@ -22,6 +30,9 @@ import java.lang.ref.WeakReference;
|
||||||
*/
|
*/
|
||||||
public final class NativeLibrary
|
public final class NativeLibrary
|
||||||
{
|
{
|
||||||
|
private static final Object sAlertMessageLock = new Object();
|
||||||
|
private static boolean sIsShowingAlertMessage = false;
|
||||||
|
|
||||||
private static WeakReference<EmulationActivity> sEmulationActivity = new WeakReference<>(null);
|
private static WeakReference<EmulationActivity> sEmulationActivity = new WeakReference<>(null);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -106,7 +117,7 @@ public final class NativeLibrary
|
||||||
public static final int NUNCHUK_SWING_UP = 208;
|
public static final int NUNCHUK_SWING_UP = 208;
|
||||||
public static final int NUNCHUK_SWING_DOWN = 209;
|
public static final int NUNCHUK_SWING_DOWN = 209;
|
||||||
public static final int NUNCHUK_SWING_LEFT = 210;
|
public static final int NUNCHUK_SWING_LEFT = 210;
|
||||||
public static final int NUNCHUK_SWING_RIGHT = 221;
|
public static final int NUNCHUK_SWING_RIGHT = 211;
|
||||||
public static final int NUNCHUK_SWING_FORWARD = 212;
|
public static final int NUNCHUK_SWING_FORWARD = 212;
|
||||||
public static final int NUNCHUK_SWING_BACKWARD = 213;
|
public static final int NUNCHUK_SWING_BACKWARD = 213;
|
||||||
public static final int NUNCHUK_TILT = 214;
|
public static final int NUNCHUK_TILT = 214;
|
||||||
|
@ -254,6 +265,7 @@ public final class NativeLibrary
|
||||||
* @param padID Ignored for now. Future use would be to pass rumble to a connected controller
|
* @param padID Ignored for now. Future use would be to pass rumble to a connected controller
|
||||||
* @param state Ignored for now since phone rumble can't just be 'turned' on/off
|
* @param state Ignored for now since phone rumble can't just be 'turned' on/off
|
||||||
*/
|
*/
|
||||||
|
@Keep
|
||||||
public static void rumble(int padID, double state)
|
public static void rumble(int padID, double state)
|
||||||
{
|
{
|
||||||
final EmulationActivity emulationActivity = sEmulationActivity.get();
|
final EmulationActivity emulationActivity = sEmulationActivity.get();
|
||||||
|
@ -272,43 +284,6 @@ public final class NativeLibrary
|
||||||
// Angle is in radians and should be non-negative
|
// Angle is in radians and should be non-negative
|
||||||
public static native double GetInputRadiusAtAngle(int emu_pad_id, int stick, double angle);
|
public static native double GetInputRadiusAtAngle(int emu_pad_id, int stick, double angle);
|
||||||
|
|
||||||
public static native void NewGameIniFile();
|
|
||||||
|
|
||||||
public static native void LoadGameIniFile(String gameId);
|
|
||||||
|
|
||||||
public static native void SaveGameIniFile(String gameId);
|
|
||||||
|
|
||||||
public static native String GetUserSetting(String gameID, String Section, String Key);
|
|
||||||
|
|
||||||
public static native void SetUserSetting(String gameID, String Section, String Key, String Value);
|
|
||||||
|
|
||||||
public static native void SetProfileSetting(String profile, String Section, String Key,
|
|
||||||
String Value);
|
|
||||||
|
|
||||||
public static native void InitGameIni(String gameID);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a value from a key in the given ini-based config file.
|
|
||||||
*
|
|
||||||
* @param configFile The ini-based config file to get the value from.
|
|
||||||
* @param Section The section key that the actual key is in.
|
|
||||||
* @param Key The key to get the value from.
|
|
||||||
* @param Default The value to return in the event the given key doesn't exist.
|
|
||||||
* @return the value stored at the key, or a default value if it doesn't exist.
|
|
||||||
*/
|
|
||||||
public static native String GetConfig(String configFile, String Section, String Key,
|
|
||||||
String Default);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a value to a key in the given ini config file.
|
|
||||||
*
|
|
||||||
* @param configFile The ini-based config file to add the value to.
|
|
||||||
* @param Section The section key for the ini key
|
|
||||||
* @param Key The actual ini key to set.
|
|
||||||
* @param Value The string to set the ini key to.
|
|
||||||
*/
|
|
||||||
public static native void SetConfig(String configFile, String Section, String Key, String Value);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the Dolphin version string.
|
* Gets the Dolphin version string.
|
||||||
*
|
*
|
||||||
|
@ -355,6 +330,11 @@ public final class NativeLibrary
|
||||||
*/
|
*/
|
||||||
public static native void LoadStateAs(String path);
|
public static native void LoadStateAs(String path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns when the savestate in the given slot was created, or 0 if the slot is empty.
|
||||||
|
*/
|
||||||
|
public static native long GetUnixTimeOfStateSlot(int slot);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the current working user directory
|
* Sets the current working user directory
|
||||||
* If not set, it auto-detects a location
|
* If not set, it auto-detects a location
|
||||||
|
@ -370,8 +350,14 @@ public final class NativeLibrary
|
||||||
|
|
||||||
public static native int DefaultCPUCore();
|
public static native int DefaultCPUCore();
|
||||||
|
|
||||||
|
public static native String GetDefaultGraphicsBackendName();
|
||||||
|
|
||||||
|
public static native int GetMaxLogLevel();
|
||||||
|
|
||||||
public static native void ReloadConfig();
|
public static native void ReloadConfig();
|
||||||
|
|
||||||
|
public static native void UpdateGCAdapterScanThread();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the native parts of the app.
|
* Initializes the native parts of the app.
|
||||||
*
|
*
|
||||||
|
@ -421,13 +407,13 @@ public final class NativeLibrary
|
||||||
*/
|
*/
|
||||||
public static native void StopEmulation();
|
public static native void StopEmulation();
|
||||||
|
|
||||||
public static native void WaitUntilDoneBooting();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if emulation is running (or is paused).
|
* Returns true if emulation is running (or is paused).
|
||||||
*/
|
*/
|
||||||
public static native boolean IsRunning();
|
public static native boolean IsRunning();
|
||||||
|
|
||||||
|
public static native boolean IsRunningAndStarted();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enables or disables CPU block profiling
|
* Enables or disables CPU block profiling
|
||||||
*
|
*
|
||||||
|
@ -452,92 +438,133 @@ public final class NativeLibrary
|
||||||
|
|
||||||
public static native void ReloadWiimoteConfig();
|
public static native void ReloadWiimoteConfig();
|
||||||
|
|
||||||
|
public static native LinkedHashMap<String, String> GetLogTypeNames();
|
||||||
|
|
||||||
|
public static native void ReloadLoggerConfig();
|
||||||
|
|
||||||
public static native boolean InstallWAD(String file);
|
public static native boolean InstallWAD(String file);
|
||||||
|
|
||||||
|
public static native boolean ConvertDiscImage(String inPath, String outPath, int platform,
|
||||||
|
int format, int blockSize, int compression, int compressionLevel, boolean scrub,
|
||||||
|
CompressCallback callback);
|
||||||
|
|
||||||
public static native String FormatSize(long bytes, int decimals);
|
public static native String FormatSize(long bytes, int decimals);
|
||||||
|
|
||||||
private static boolean alertResult = false;
|
public static native void SetObscuredPixelsLeft(int width);
|
||||||
|
|
||||||
|
public static native void SetObscuredPixelsTop(int height);
|
||||||
|
|
||||||
|
public static native boolean IsGameMetadataValid();
|
||||||
|
|
||||||
|
public static boolean IsEmulatingWii()
|
||||||
|
{
|
||||||
|
CheckGameMetadataValid();
|
||||||
|
return IsEmulatingWiiUnchecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String GetCurrentGameID()
|
||||||
|
{
|
||||||
|
CheckGameMetadataValid();
|
||||||
|
return GetCurrentGameIDUnchecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String GetCurrentTitleDescription()
|
||||||
|
{
|
||||||
|
CheckGameMetadataValid();
|
||||||
|
return GetCurrentTitleDescriptionUnchecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CheckGameMetadataValid()
|
||||||
|
{
|
||||||
|
if (!IsGameMetadataValid())
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("No game is running");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static native boolean IsEmulatingWiiUnchecked();
|
||||||
|
|
||||||
|
private static native String GetCurrentGameIDUnchecked();
|
||||||
|
|
||||||
|
private static native String GetCurrentTitleDescriptionUnchecked();
|
||||||
|
|
||||||
|
@Keep
|
||||||
public static boolean displayAlertMsg(final String caption, final String text,
|
public static boolean displayAlertMsg(final String caption, final String text,
|
||||||
final boolean yesNo)
|
final boolean yesNo, final boolean isWarning, final boolean nonBlocking)
|
||||||
{
|
{
|
||||||
Log.error("[NativeLibrary] Alert: " + text);
|
Log.error("[NativeLibrary] Alert: " + text);
|
||||||
final EmulationActivity emulationActivity = sEmulationActivity.get();
|
final EmulationActivity emulationActivity = sEmulationActivity.get();
|
||||||
boolean result = false;
|
boolean result = false;
|
||||||
if (emulationActivity == null)
|
if (isWarning && emulationActivity != null && emulationActivity.isIgnoringWarnings())
|
||||||
{
|
{
|
||||||
Log.warning("[NativeLibrary] EmulationActivity is null, can't do panic alert.");
|
return true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Create object used for waiting.
|
// We can't use AlertMessages unless we have a non-null activity reference
|
||||||
final Object lock = new Object();
|
// and are allowed to block. As a fallback, we can use toasts.
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(emulationActivity,
|
if (emulationActivity == null || nonBlocking)
|
||||||
R.style.DolphinDialogBase)
|
|
||||||
.setTitle(caption)
|
|
||||||
.setMessage(text);
|
|
||||||
|
|
||||||
// If not yes/no dialog just have one button that dismisses modal,
|
|
||||||
// otherwise have a yes and no button that sets alertResult accordingly.
|
|
||||||
if (!yesNo)
|
|
||||||
{
|
{
|
||||||
builder
|
new Handler(Looper.getMainLooper()).post(
|
||||||
.setCancelable(false)
|
() -> Toast.makeText(DolphinApplication.getAppContext(), text, Toast.LENGTH_LONG)
|
||||||
.setPositiveButton("OK", (dialog, whichButton) ->
|
.show());
|
||||||
{
|
|
||||||
dialog.dismiss();
|
|
||||||
synchronized (lock)
|
|
||||||
{
|
|
||||||
lock.notify();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
alertResult = false;
|
sIsShowingAlertMessage = true;
|
||||||
|
|
||||||
builder
|
emulationActivity.runOnUiThread(() ->
|
||||||
.setPositiveButton("Yes", (dialog, whichButton) ->
|
|
||||||
{
|
|
||||||
alertResult = true;
|
|
||||||
dialog.dismiss();
|
|
||||||
synchronized (lock)
|
|
||||||
{
|
|
||||||
lock.notify();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.setNegativeButton("No", (dialog, whichButton) ->
|
|
||||||
{
|
|
||||||
alertResult = false;
|
|
||||||
dialog.dismiss();
|
|
||||||
synchronized (lock)
|
|
||||||
{
|
|
||||||
lock.notify();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show the AlertDialog on the main thread.
|
|
||||||
emulationActivity.runOnUiThread(builder::show);
|
|
||||||
|
|
||||||
// Wait for the lock to notify that it is complete.
|
|
||||||
synchronized (lock)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
lock.wait();
|
FragmentManager fragmentManager = emulationActivity.getSupportFragmentManager();
|
||||||
|
if (fragmentManager.isStateSaved())
|
||||||
|
{
|
||||||
|
// The activity is being destroyed, so we can't use it to display an AlertMessage.
|
||||||
|
// Fall back to a toast.
|
||||||
|
Toast.makeText(emulationActivity, text, Toast.LENGTH_LONG).show();
|
||||||
|
NotifyAlertMessageLock();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AlertMessage.newInstance(caption, text, yesNo, isWarning)
|
||||||
|
.show(fragmentManager, "AlertMessage");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Wait for the lock to notify that it is complete.
|
||||||
|
synchronized (sAlertMessageLock)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
sAlertMessageLock.wait();
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
|
||||||
|
if (yesNo)
|
||||||
{
|
{
|
||||||
|
result = AlertMessage.getAlertResult();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (yesNo)
|
|
||||||
result = alertResult;
|
|
||||||
}
|
}
|
||||||
|
sIsShowingAlertMessage = false;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean IsShowingAlertMessage()
|
||||||
|
{
|
||||||
|
return sIsShowingAlertMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void NotifyAlertMessageLock()
|
||||||
|
{
|
||||||
|
synchronized (sAlertMessageLock)
|
||||||
|
{
|
||||||
|
sAlertMessageLock.notify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void setEmulationActivity(EmulationActivity emulationActivity)
|
public static void setEmulationActivity(EmulationActivity emulationActivity)
|
||||||
{
|
{
|
||||||
Log.verbose("[NativeLibrary] Registering EmulationActivity.");
|
Log.verbose("[NativeLibrary] Registering EmulationActivity.");
|
||||||
|
@ -551,6 +578,22 @@ public final class NativeLibrary
|
||||||
sEmulationActivity.clear();
|
sEmulationActivity.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
public static void finishEmulationActivity()
|
||||||
|
{
|
||||||
|
final EmulationActivity emulationActivity = sEmulationActivity.get();
|
||||||
|
if (emulationActivity == null)
|
||||||
|
{
|
||||||
|
Log.warning("[NativeLibrary] EmulationActivity is null.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.verbose("[NativeLibrary] Finishing EmulationActivity.");
|
||||||
|
emulationActivity.runOnUiThread(emulationActivity::finish);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Keep
|
||||||
public static void updateTouchPointer()
|
public static void updateTouchPointer()
|
||||||
{
|
{
|
||||||
final EmulationActivity emulationActivity = sEmulationActivity.get();
|
final EmulationActivity emulationActivity = sEmulationActivity.get();
|
||||||
|
@ -564,5 +607,27 @@ public final class NativeLibrary
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
public static void onTitleChanged()
|
||||||
|
{
|
||||||
|
final EmulationActivity emulationActivity = sEmulationActivity.get();
|
||||||
|
if (emulationActivity == null)
|
||||||
|
{
|
||||||
|
Log.warning("[NativeLibrary] EmulationActivity is null.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
emulationActivity.runOnUiThread(emulationActivity::onTitleChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
public static float getRenderSurfaceScale()
|
||||||
|
{
|
||||||
|
DisplayMetrics metrics = new DisplayMetrics();
|
||||||
|
sEmulationActivity.get().getWindowManager().getDefaultDisplay().getMetrics(metrics);
|
||||||
|
return metrics.scaledDensity;
|
||||||
|
}
|
||||||
|
|
||||||
public static native float GetGameAspectRatio();
|
public static native float GetGameAspectRatio();
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,20 +6,17 @@ import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.IntentFilter;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentActivity;
|
||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||||
|
|
||||||
import android.util.Log;
|
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import org.dolphinemu.dolphinemu.R;
|
|
||||||
import org.dolphinemu.dolphinemu.model.GameFile;
|
import org.dolphinemu.dolphinemu.model.GameFile;
|
||||||
import org.dolphinemu.dolphinemu.utils.DirectoryInitialization;
|
|
||||||
import org.dolphinemu.dolphinemu.services.GameFileCacheService;
|
import org.dolphinemu.dolphinemu.services.GameFileCacheService;
|
||||||
import org.dolphinemu.dolphinemu.ui.main.TvMainActivity;
|
import org.dolphinemu.dolphinemu.ui.main.TvMainActivity;
|
||||||
|
import org.dolphinemu.dolphinemu.utils.AfterDirectoryInitializationRunner;
|
||||||
import org.dolphinemu.dolphinemu.utils.AppLinkHelper;
|
import org.dolphinemu.dolphinemu.utils.AppLinkHelper;
|
||||||
import org.dolphinemu.dolphinemu.utils.DirectoryStateReceiver;
|
import org.dolphinemu.dolphinemu.utils.DirectoryInitialization;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Linker between leanback homescreen and app
|
* Linker between leanback homescreen and app
|
||||||
|
@ -29,8 +26,7 @@ public class AppLinkActivity extends FragmentActivity
|
||||||
private static final String TAG = "AppLinkActivity";
|
private static final String TAG = "AppLinkActivity";
|
||||||
|
|
||||||
private AppLinkHelper.PlayAction playAction;
|
private AppLinkHelper.PlayAction playAction;
|
||||||
private DirectoryStateReceiver directoryStateReceiver;
|
private AfterDirectoryInitializationRunner mAfterDirectoryInitializationRunner;
|
||||||
private BroadcastReceiver gameFileCacheReceiver;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState)
|
protected void onCreate(Bundle savedInstanceState)
|
||||||
|
@ -68,49 +64,25 @@ public class AppLinkActivity extends FragmentActivity
|
||||||
*/
|
*/
|
||||||
private void initResources()
|
private void initResources()
|
||||||
{
|
{
|
||||||
IntentFilter directoryStateIntentFilter = new IntentFilter(
|
mAfterDirectoryInitializationRunner = new AfterDirectoryInitializationRunner();
|
||||||
DirectoryInitialization.BROADCAST_ACTION);
|
mAfterDirectoryInitializationRunner.run(this, true, () -> tryPlay(playAction));
|
||||||
|
|
||||||
IntentFilter gameFileCacheIntentFilter = new IntentFilter(
|
IntentFilter gameFileCacheIntentFilter = new IntentFilter(
|
||||||
GameFileCacheService.BROADCAST_ACTION);
|
GameFileCacheService.BROADCAST_ACTION);
|
||||||
|
|
||||||
directoryStateReceiver =
|
BroadcastReceiver gameFileCacheReceiver = new BroadcastReceiver()
|
||||||
new DirectoryStateReceiver(directoryInitializationState ->
|
{
|
||||||
{
|
@Override
|
||||||
if (directoryInitializationState ==
|
public void onReceive(Context context, Intent intent)
|
||||||
DirectoryInitialization.DirectoryInitializationState.DOLPHIN_DIRECTORIES_INITIALIZED)
|
{
|
||||||
{
|
if (DirectoryInitialization.areDolphinDirectoriesReady())
|
||||||
tryPlay(playAction);
|
{
|
||||||
}
|
tryPlay(playAction);
|
||||||
else if (directoryInitializationState ==
|
}
|
||||||
DirectoryInitialization.DirectoryInitializationState.EXTERNAL_STORAGE_PERMISSION_NEEDED)
|
}
|
||||||
{
|
};
|
||||||
Toast.makeText(this, R.string.write_permission_needed, Toast.LENGTH_SHORT)
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
else if (directoryInitializationState ==
|
|
||||||
DirectoryInitialization.DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE)
|
|
||||||
{
|
|
||||||
Toast.makeText(this, R.string.external_storage_not_mounted, Toast.LENGTH_SHORT)
|
|
||||||
.show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
gameFileCacheReceiver =
|
|
||||||
new BroadcastReceiver()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent)
|
|
||||||
{
|
|
||||||
if (DirectoryInitialization.areDolphinDirectoriesReady())
|
|
||||||
{
|
|
||||||
tryPlay(playAction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(this);
|
LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(this);
|
||||||
broadcastManager.registerReceiver(directoryStateReceiver, directoryStateIntentFilter);
|
|
||||||
broadcastManager.registerReceiver(gameFileCacheReceiver, gameFileCacheIntentFilter);
|
broadcastManager.registerReceiver(gameFileCacheReceiver, gameFileCacheIntentFilter);
|
||||||
|
|
||||||
DirectoryInitialization.start(this);
|
DirectoryInitialization.start(this);
|
||||||
|
@ -162,11 +134,11 @@ public class AppLinkActivity extends FragmentActivity
|
||||||
|
|
||||||
private void startGame(GameFile game)
|
private void startGame(GameFile game)
|
||||||
{
|
{
|
||||||
if (directoryStateReceiver != null)
|
if (mAfterDirectoryInitializationRunner != null)
|
||||||
{
|
{
|
||||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(directoryStateReceiver);
|
mAfterDirectoryInitializationRunner.cancel();
|
||||||
directoryStateReceiver = null;
|
mAfterDirectoryInitializationRunner = null;
|
||||||
}
|
}
|
||||||
EmulationActivity.launch(this, game);
|
EmulationActivity.launch(this, GameFileCacheService.findSecondDiscAndGetPaths(game));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
package org.dolphinemu.dolphinemu.activities;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import org.dolphinemu.dolphinemu.R;
|
||||||
|
import org.dolphinemu.dolphinemu.fragments.ConvertFragment;
|
||||||
|
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
|
||||||
|
public class ConvertActivity extends AppCompatActivity
|
||||||
|
{
|
||||||
|
private static final String ARG_GAME_PATH = "game_path";
|
||||||
|
|
||||||
|
public static void launch(Context context, String gamePath)
|
||||||
|
{
|
||||||
|
Intent launcher = new Intent(context, ConvertActivity.class);
|
||||||
|
launcher.putExtra(ARG_GAME_PATH, gamePath);
|
||||||
|
context.startActivity(launcher);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState)
|
||||||
|
{
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
setContentView(R.layout.activity_convert);
|
||||||
|
|
||||||
|
String path = getIntent().getStringExtra(ARG_GAME_PATH);
|
||||||
|
|
||||||
|
ConvertFragment fragment = (ConvertFragment) getSupportFragmentManager()
|
||||||
|
.findFragmentById(R.id.fragment_convert);
|
||||||
|
if (fragment == null)
|
||||||
|
{
|
||||||
|
fragment = ConvertFragment.newInstance(path);
|
||||||
|
getSupportFragmentManager().beginTransaction().add(R.id.fragment_convert, fragment).commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue