mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2024-11-08 08:47:17 +01:00
Compare commits
7 Commits
11fb1fa25c
...
e2cbd7d5cf
Author | SHA1 | Date | |
---|---|---|---|
|
e2cbd7d5cf | ||
|
2725387112 | ||
|
7248351469 | ||
|
e253dc2038 | ||
|
38f0a53cd8 | ||
|
1c7fee69ea | ||
|
2b85b3a035 |
@ -161,7 +161,7 @@ bool Area::IsInside(float x, float y) const
|
|||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
AreaManager::AreaManager(size_t sz) noexcept
|
AreaManager::AreaManager(size_t sz) noexcept
|
||||||
: m_Queue(), m_ProcList(), m_Grid{}
|
: m_Queue(), m_ProcList(), m_Grid{}, m_Cells{}
|
||||||
{
|
{
|
||||||
// Negative half grid size (left)
|
// Negative half grid size (left)
|
||||||
int l = (-GRIDH * CELLD);
|
int l = (-GRIDH * CELLD);
|
||||||
@ -171,21 +171,30 @@ AreaManager::AreaManager(size_t sz) noexcept
|
|||||||
int r = (l + CELLD);
|
int r = (l + CELLD);
|
||||||
// Positive half grid size (top)
|
// Positive half grid size (top)
|
||||||
int t = abs(l);
|
int t = abs(l);
|
||||||
|
// Row/Column of the grid
|
||||||
|
int row = 0, col = 0;
|
||||||
// Initialize the grid cells
|
// Initialize the grid cells
|
||||||
for (auto & a : m_Grid)
|
for (auto & a : m_Grid)
|
||||||
{
|
{
|
||||||
|
// Reset the column
|
||||||
|
col = 0;
|
||||||
|
// Process row
|
||||||
for (auto & c : a)
|
for (auto & c : a)
|
||||||
{
|
{
|
||||||
|
auto & cx = m_Cells[row][col];
|
||||||
// Grab a reference to the cell
|
// Grab a reference to the cell
|
||||||
// Configure the range of the cell
|
// Configure the range of the cell
|
||||||
c.mL = static_cast< float >(l);
|
c.mL = cx.mL = static_cast< float >(l);
|
||||||
c.mB = static_cast< float >(b);
|
c.mB = cx.mB = static_cast< float >(b);
|
||||||
c.mR = static_cast< float >(r);
|
c.mR = cx.mR = static_cast< float >(r);
|
||||||
c.mT = static_cast< float >(t);
|
c.mT = cx.mT = static_cast< float >(t);
|
||||||
// Reserve area memory if requested
|
// Reserve area memory if requested
|
||||||
c.mAreas.reserve(sz);
|
c.mAreas.reserve(sz);
|
||||||
// Reset the locks on this area
|
// Reset the locks on this area
|
||||||
c.mLocks = 0;
|
c.mLocks = 0;
|
||||||
|
// Set the row and column
|
||||||
|
c.mRow = row;
|
||||||
|
c.mCol = col++;
|
||||||
// Advance the left side
|
// Advance the left side
|
||||||
l = r;
|
l = r;
|
||||||
// Advance the right side
|
// Advance the right side
|
||||||
@ -203,6 +212,8 @@ AreaManager::AreaManager(size_t sz) noexcept
|
|||||||
t -= CELLD;
|
t -= CELLD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Advance row
|
||||||
|
++row;
|
||||||
}
|
}
|
||||||
// Reserve some space in the queue
|
// Reserve some space in the queue
|
||||||
m_Queue.reserve(128);
|
m_Queue.reserve(128);
|
||||||
@ -340,6 +351,21 @@ void AreaManager::RemoveArea(Area & a)
|
|||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
Vector2i AreaManager::LocateCell(float x, float y)
|
Vector2i AreaManager::LocateCell(float x, float y)
|
||||||
{
|
{
|
||||||
|
for (int r = 0; r < GRIDN; ++r)
|
||||||
|
{
|
||||||
|
for (int c = 0; c < GRIDN; ++c)
|
||||||
|
{
|
||||||
|
auto & bb = m_Cells[r][c];
|
||||||
|
// Check whether point is inside cell
|
||||||
|
if (bb.mL <= x && bb.mR >= x && bb.mB <= y && bb.mT >= y)
|
||||||
|
{
|
||||||
|
return {r, c}; // Is inside
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Point is out of bounds
|
||||||
|
return {NOCELL, NOCELL};
|
||||||
|
/*
|
||||||
// Transform the world coordinates into a cell coordinates
|
// Transform the world coordinates into a cell coordinates
|
||||||
// and cast to integral after rounding the value
|
// and cast to integral after rounding the value
|
||||||
int xc = static_cast< int >(std::round(x / CELLD));
|
int xc = static_cast< int >(std::round(x / CELLD));
|
||||||
@ -364,6 +390,7 @@ Vector2i AreaManager::LocateCell(float x, float y)
|
|||||||
}
|
}
|
||||||
// Return the identified cell row and column
|
// Return the identified cell row and column
|
||||||
return {GRIDH+xc, GRIDH-yc};
|
return {GRIDH+xc, GRIDH-yc};
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
@ -469,6 +496,7 @@ void Register_Areas(HSQUIRRELVM vm)
|
|||||||
.Func(_SC("TestEx"), &Area::TestEx)
|
.Func(_SC("TestEx"), &Area::TestEx)
|
||||||
.Func(_SC("Manage"), &Area::Manage)
|
.Func(_SC("Manage"), &Area::Manage)
|
||||||
.Func(_SC("Unmanage"), &Area::Unmanage)
|
.Func(_SC("Unmanage"), &Area::Unmanage)
|
||||||
|
.CbFunc(_SC("EachCell"), &Area::EachCell)
|
||||||
// Static Functions
|
// Static Functions
|
||||||
.StaticFunc(_SC("GlobalTest"), &Areas_TestPoint)
|
.StaticFunc(_SC("GlobalTest"), &Areas_TestPoint)
|
||||||
.StaticFunc(_SC("GlobalTestEx"), &Areas_TestPointEx)
|
.StaticFunc(_SC("GlobalTestEx"), &Areas_TestPointEx)
|
||||||
|
@ -29,15 +29,25 @@ struct AreaCell
|
|||||||
Areas mAreas; // Areas that intersect with the cell.
|
Areas mAreas; // Areas that intersect with the cell.
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
int mLocks; // The amount of locks on the cell.
|
int mLocks; // The amount of locks on the cell.
|
||||||
|
int mRow; // Row location in the grid.
|
||||||
|
int mCol; // Column location in the grid.
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Default constructor.
|
* Default constructor.
|
||||||
*/
|
*/
|
||||||
AreaCell()
|
AreaCell()
|
||||||
: mL(0), mB(0), mR(0), mT(0), mAreas(0), mLocks(0)
|
: mL(0), mB(0), mR(0), mT(0), mAreas(0), mLocks(0), mRow(0), mCol(0)
|
||||||
{
|
{
|
||||||
//...
|
//...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Show information (mainly for debug purposes).
|
||||||
|
*/
|
||||||
|
String Dump()
|
||||||
|
{
|
||||||
|
return fmt::format("({} : {} | {} : {}) {} : {}", mL, mB, mR, mT, mRow, mCol);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
/* ------------------------------------------------------------------------------------------------
|
||||||
@ -454,6 +464,17 @@ struct Area
|
|||||||
*/
|
*/
|
||||||
bool Unmanage();
|
bool Unmanage();
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Iterate all managed cells through a functor.
|
||||||
|
*/
|
||||||
|
void EachCell(Function & fn) const
|
||||||
|
{
|
||||||
|
for (const auto & e : mCells)
|
||||||
|
{
|
||||||
|
fn.Execute(static_cast< SQInteger >(e->mRow), static_cast< SQInteger >(e->mCol));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
@ -610,7 +631,10 @@ private:
|
|||||||
ProcList m_ProcList; // Actions ready to be completed.
|
ProcList m_ProcList; // Actions ready to be completed.
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
AreaCell m_Grid[GRIDN][GRIDN]; // A grid of area lists.
|
AreaCell m_Grid[GRIDN][GRIDN]; // A grid of area lists.
|
||||||
|
// --------------------------------------------------------------------------------------------
|
||||||
|
struct {
|
||||||
|
float mL, mB, mR, mT;
|
||||||
|
} m_Cells[GRIDN][GRIDN];
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
@ -664,7 +688,7 @@ public:
|
|||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Clear all cell lists and release any script references.
|
* Clear all cell lists and release any script references.
|
||||||
*/
|
*/
|
||||||
static Vector2i LocateCell(float x, float y);
|
Vector2i LocateCell(float x, float y);
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------------------------
|
||||||
* Test a point to see whether it intersects with any areas
|
* Test a point to see whether it intersects with any areas
|
||||||
@ -679,7 +703,7 @@ public:
|
|||||||
return; // Not our problem
|
return; // Not our problem
|
||||||
}
|
}
|
||||||
// Retrieve a reference to the identified cell
|
// Retrieve a reference to the identified cell
|
||||||
AreaCell & c = m_Grid[cc.y][cc.x];
|
AreaCell & c = m_Grid[cc.x][cc.y];
|
||||||
// Is this cell empty?
|
// Is this cell empty?
|
||||||
if (c.mAreas.empty())
|
if (c.mAreas.empty())
|
||||||
{
|
{
|
||||||
|
@ -1723,6 +1723,7 @@ void Register_Signal(HSQUIRRELVM vm)
|
|||||||
.SquirrelFunc(_SC("Eliminate"), &Signal::SqEliminate)
|
.SquirrelFunc(_SC("Eliminate"), &Signal::SqEliminate)
|
||||||
.SquirrelFunc(_SC("EliminateThis"), &Signal::SqEliminateThis)
|
.SquirrelFunc(_SC("EliminateThis"), &Signal::SqEliminateThis)
|
||||||
.SquirrelFunc(_SC("EliminateFunc"), &Signal::SqEliminateFunc)
|
.SquirrelFunc(_SC("EliminateFunc"), &Signal::SqEliminateFunc)
|
||||||
|
.SquirrelFunc(_SC("Broadcast"), &Signal::SqEmit)
|
||||||
.SquirrelFunc(_SC("Emit"), &Signal::SqEmit)
|
.SquirrelFunc(_SC("Emit"), &Signal::SqEmit)
|
||||||
.SquirrelFunc(_SC("Query"), &Signal::SqQuery)
|
.SquirrelFunc(_SC("Query"), &Signal::SqQuery)
|
||||||
.SquirrelFunc(_SC("Consume"), &Signal::SqConsume)
|
.SquirrelFunc(_SC("Consume"), &Signal::SqConsume)
|
||||||
|
@ -2063,7 +2063,7 @@ public:
|
|||||||
// Do we have a valid handle?
|
// Do we have a valid handle?
|
||||||
if (m_Handle)
|
if (m_Handle)
|
||||||
{
|
{
|
||||||
fmt::format("{}", m_Handle->mFieldCount);
|
return fmt::format("{}", m_Handle->mFieldCount);
|
||||||
}
|
}
|
||||||
// Default to a negative value
|
// Default to a negative value
|
||||||
return "-1";
|
return "-1";
|
||||||
|
@ -69,17 +69,17 @@ void Register_POCO_RegEx(HSQUIRRELVM vm, Table & ns)
|
|||||||
// Member Methods
|
// Member Methods
|
||||||
//.Func(_SC("Assign"), &PcRegEx::assign)
|
//.Func(_SC("Assign"), &PcRegEx::assign)
|
||||||
// Overloaded Member Methods
|
// Overloaded Member Methods
|
||||||
.Overload(_SC("MatchFirst"), &PcRegEx::MatchFirst)
|
.FmtFunc(_SC("MatchFirst"), &PcRegEx::MatchFirst)
|
||||||
.Overload(_SC("MatchFirst"), &PcRegEx::MatchFirst_)
|
.FmtFunc(_SC("MatchFirstEx"), &PcRegEx::MatchFirst_)
|
||||||
.Overload(_SC("MatchFirstFrom"), &PcRegEx::MatchFirstFrom)
|
.FmtFunc(_SC("MatchFirstFrom"), &PcRegEx::MatchFirstFrom)
|
||||||
.Overload(_SC("MatchFirstFrom"), &PcRegEx::MatchFirstFrom_)
|
.FmtFunc(_SC("MatchFirstFromEx"), &PcRegEx::MatchFirstFrom_)
|
||||||
.Overload(_SC("Match"), &PcRegEx::Match)
|
.FmtFunc(_SC("Match"), &PcRegEx::Match)
|
||||||
.Overload(_SC("Match"), &PcRegEx::Match_)
|
.FmtFunc(_SC("MatchEx"), &PcRegEx::Match_)
|
||||||
.Overload(_SC("MatchFrom"), &PcRegEx::MatchFrom)
|
.FmtFunc(_SC("MatchFrom"), &PcRegEx::MatchFrom)
|
||||||
.Overload(_SC("MatchFrom"), &PcRegEx::MatchFrom_)
|
.FmtFunc(_SC("MatchFromEx"), &PcRegEx::MatchFrom_)
|
||||||
.Overload(_SC("Matches"), &PcRegEx::Matches)
|
.FmtFunc(_SC("Matches"), &PcRegEx::Matches)
|
||||||
.Overload(_SC("Matches"), &PcRegEx::Matches_)
|
.FmtFunc(_SC("MatchesEx"), &PcRegEx::Matches_)
|
||||||
.Overload(_SC("Matches"), &PcRegEx::MatchesEx)
|
.FmtFunc(_SC("MatchesEx2"), &PcRegEx::MatchesEx)
|
||||||
);
|
);
|
||||||
// --------------------------------------------------------------------------------------------
|
// --------------------------------------------------------------------------------------------
|
||||||
ConstTable(vm).Enum(_SC("SqRegExOption"), Enumeration(vm)
|
ConstTable(vm).Enum(_SC("SqRegExOption"), Enumeration(vm)
|
||||||
|
38
vendor/Fmt/CMakeLists.txt
vendored
38
vendor/Fmt/CMakeLists.txt
vendored
@ -81,6 +81,7 @@ 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)
|
option(FMT_OS "Include core requiring OS (Windows/Posix) " ON)
|
||||||
option(FMT_MODULE "Build a module instead of a traditional library." OFF)
|
option(FMT_MODULE "Build a module instead of a traditional library." OFF)
|
||||||
|
option(FMT_SYSTEM_HEADERS "Expose headers with marking them as system." OFF)
|
||||||
|
|
||||||
set(FMT_CAN_MODULE OFF)
|
set(FMT_CAN_MODULE OFF)
|
||||||
if (CMAKE_CXX_STANDARD GREATER 17 AND
|
if (CMAKE_CXX_STANDARD GREATER 17 AND
|
||||||
@ -96,6 +97,10 @@ if (FMT_TEST AND FMT_MODULE)
|
|||||||
# The tests require {fmt} to be compiled as traditional library
|
# The tests require {fmt} to be compiled as traditional library
|
||||||
message(STATUS "Testing is incompatible with build mode 'module'.")
|
message(STATUS "Testing is incompatible with build mode 'module'.")
|
||||||
endif ()
|
endif ()
|
||||||
|
set(FMT_SYSTEM_HEADERS_ATTRIBUTE "")
|
||||||
|
if (FMT_SYSTEM_HEADERS)
|
||||||
|
set(FMT_SYSTEM_HEADERS_ATTRIBUTE SYSTEM)
|
||||||
|
endif ()
|
||||||
|
|
||||||
# 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)
|
||||||
@ -151,7 +156,7 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
|||||||
-Wcast-align
|
-Wcast-align
|
||||||
-Wctor-dtor-privacy -Wdisabled-optimization
|
-Wctor-dtor-privacy -Wdisabled-optimization
|
||||||
-Winvalid-pch -Woverloaded-virtual
|
-Winvalid-pch -Woverloaded-virtual
|
||||||
-Wconversion -Wswitch-enum -Wundef
|
-Wconversion -Wundef
|
||||||
-Wno-ctor-dtor-privacy -Wno-format-nonliteral)
|
-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}
|
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS}
|
||||||
@ -204,18 +209,6 @@ if (FMT_MASTER_PROJECT AND CMAKE_GENERATOR MATCHES "Visual Studio")
|
|||||||
${CMAKE_MAKE_PROGRAM} -p:FrameworkPathOverride=\"${netfxpath}\" %*")
|
${CMAKE_MAKE_PROGRAM} -p:FrameworkPathOverride=\"${netfxpath}\" %*")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
set(strtod_l_headers stdlib.h)
|
|
||||||
if (APPLE)
|
|
||||||
set(strtod_l_headers ${strtod_l_headers} xlocale.h)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
include(CheckSymbolExists)
|
|
||||||
if (WIN32)
|
|
||||||
check_symbol_exists(_strtod_l "${strtod_l_headers}" HAVE_STRTOD_L)
|
|
||||||
else ()
|
|
||||||
check_symbol_exists(strtod_l "${strtod_l_headers}" HAVE_STRTOD_L)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
function(add_headers VAR)
|
function(add_headers VAR)
|
||||||
set(headers ${${VAR}})
|
set(headers ${${VAR}})
|
||||||
foreach (header ${ARGN})
|
foreach (header ${ARGN})
|
||||||
@ -239,17 +232,6 @@ endif ()
|
|||||||
add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} README.rst ChangeLog.rst)
|
add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} README.rst ChangeLog.rst)
|
||||||
add_library(fmt::fmt ALIAS fmt)
|
add_library(fmt::fmt ALIAS fmt)
|
||||||
|
|
||||||
if (HAVE_STRTOD_L)
|
|
||||||
target_compile_definitions(fmt PUBLIC FMT_LOCALE)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
if (MINGW)
|
|
||||||
check_cxx_compiler_flag("Wa,-mbig-obj" FMT_HAS_MBIG_OBJ)
|
|
||||||
if (${FMT_HAS_MBIG_OBJ})
|
|
||||||
target_compile_options(fmt PUBLIC "-Wa,-mbig-obj")
|
|
||||||
endif()
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
if (FMT_WERROR)
|
if (FMT_WERROR)
|
||||||
target_compile_options(fmt PRIVATE ${WERROR_FLAG})
|
target_compile_options(fmt PRIVATE ${WERROR_FLAG})
|
||||||
endif ()
|
endif ()
|
||||||
@ -262,7 +244,7 @@ endif ()
|
|||||||
|
|
||||||
target_compile_features(fmt INTERFACE ${FMT_REQUIRED_FEATURES})
|
target_compile_features(fmt INTERFACE ${FMT_REQUIRED_FEATURES})
|
||||||
|
|
||||||
target_include_directories(fmt PUBLIC
|
target_include_directories(fmt ${FMT_SYSTEM_HEADERS_ATTRIBUTE} PUBLIC
|
||||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
|
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
|
||||||
$<INSTALL_INTERFACE:${FMT_INC_DIR}>)
|
$<INSTALL_INTERFACE:${FMT_INC_DIR}>)
|
||||||
|
|
||||||
@ -270,6 +252,7 @@ set(FMT_DEBUG_POSTFIX d CACHE STRING "Debug library postfix.")
|
|||||||
|
|
||||||
set_target_properties(fmt PROPERTIES
|
set_target_properties(fmt PROPERTIES
|
||||||
VERSION ${FMT_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR}
|
VERSION ${FMT_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR}
|
||||||
|
PUBLIC_HEADER "${FMT_HEADERS}"
|
||||||
DEBUG_POSTFIX "${FMT_DEBUG_POSTFIX}")
|
DEBUG_POSTFIX "${FMT_DEBUG_POSTFIX}")
|
||||||
|
|
||||||
# Set FMT_LIB_NAME for pkg-config fmt.pc. We cannot use the OUTPUT_NAME target
|
# Set FMT_LIB_NAME for pkg-config fmt.pc. We cannot use the OUTPUT_NAME target
|
||||||
@ -298,7 +281,7 @@ 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 ${FMT_SYSTEM_HEADERS_ATTRIBUTE} INTERFACE
|
||||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
|
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
|
||||||
$<INSTALL_INTERFACE:${FMT_INC_DIR}>)
|
$<INSTALL_INTERFACE:${FMT_INC_DIR}>)
|
||||||
|
|
||||||
@ -347,6 +330,8 @@ if (FMT_INSTALL)
|
|||||||
install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name}
|
install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name}
|
||||||
LIBRARY DESTINATION ${FMT_LIB_DIR}
|
LIBRARY DESTINATION ${FMT_LIB_DIR}
|
||||||
ARCHIVE DESTINATION ${FMT_LIB_DIR}
|
ARCHIVE DESTINATION ${FMT_LIB_DIR}
|
||||||
|
PUBLIC_HEADER DESTINATION "${FMT_INC_DIR}/fmt"
|
||||||
|
FRAMEWORK DESTINATION "."
|
||||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||||
|
|
||||||
# Use a namespace because CMake provides better diagnostics for namespaced
|
# Use a namespace because CMake provides better diagnostics for namespaced
|
||||||
@ -363,7 +348,6 @@ if (FMT_INSTALL)
|
|||||||
|
|
||||||
install(FILES $<TARGET_PDB_FILE:${INSTALL_TARGETS}>
|
install(FILES $<TARGET_PDB_FILE:${INSTALL_TARGETS}>
|
||||||
DESTINATION ${FMT_LIB_DIR} OPTIONAL)
|
DESTINATION ${FMT_LIB_DIR} OPTIONAL)
|
||||||
install(FILES ${FMT_HEADERS} DESTINATION "${FMT_INC_DIR}/fmt")
|
|
||||||
install(FILES "${pkgconfig}" DESTINATION "${FMT_PKGCONFIG_DIR}")
|
install(FILES "${pkgconfig}" DESTINATION "${FMT_PKGCONFIG_DIR}")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
390
vendor/Fmt/ChangeLog.rst
vendored
390
vendor/Fmt/ChangeLog.rst
vendored
@ -1,3 +1,374 @@
|
|||||||
|
8.1.1 - 2022-01-06
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* Restored ABI compatibility with version 8.0.x
|
||||||
|
(`#2695 <https://github.com/fmtlib/fmt/issues/2695>`_,
|
||||||
|
`#2696 <https://github.com/fmtlib/fmt/pull/2696>`_).
|
||||||
|
Thanks `@saraedum (Julian Rüth) <https://github.com/saraedum>`_.
|
||||||
|
|
||||||
|
* Fixed chrono formatting on big endian systems
|
||||||
|
(`#2698 <https://github.com/fmtlib/fmt/issues/2698>`_,
|
||||||
|
`#2699 <https://github.com/fmtlib/fmt/pull/2699>`_).
|
||||||
|
Thanks `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_ and
|
||||||
|
`@xvitaly (Vitaly Zaitsev) <https://github.com/xvitaly>`_.
|
||||||
|
|
||||||
|
* Fixed a linkage error with mingw
|
||||||
|
(`#2691 <https://github.com/fmtlib/fmt/issues/2691>`_,
|
||||||
|
`#2692 <https://github.com/fmtlib/fmt/pull/2692>`_).
|
||||||
|
Thanks `@rbberger (Richard Berger) <https://github.com/rbberger>`_.
|
||||||
|
|
||||||
|
8.1.0 - 2022-01-02
|
||||||
|
------------------
|
||||||
|
|
||||||
|
* Optimized chrono formatting
|
||||||
|
(`#2500 <https://github.com/fmtlib/fmt/pull/2500>`_,
|
||||||
|
`#2537 <https://github.com/fmtlib/fmt/pull/2537>`_,
|
||||||
|
`#2541 <https://github.com/fmtlib/fmt/issues/2541>`_,
|
||||||
|
`#2544 <https://github.com/fmtlib/fmt/pull/2544>`_,
|
||||||
|
`#2550 <https://github.com/fmtlib/fmt/pull/2550>`_,
|
||||||
|
`#2551 <https://github.com/fmtlib/fmt/pull/2551>`_,
|
||||||
|
`#2576 <https://github.com/fmtlib/fmt/pull/2576>`_,
|
||||||
|
`#2577 <https://github.com/fmtlib/fmt/issues/2577>`_,
|
||||||
|
`#2586 <https://github.com/fmtlib/fmt/pull/2586>`_,
|
||||||
|
`#2591 <https://github.com/fmtlib/fmt/pull/2591>`_,
|
||||||
|
`#2594 <https://github.com/fmtlib/fmt/pull/2594>`_,
|
||||||
|
`#2602 <https://github.com/fmtlib/fmt/pull/2602>`_,
|
||||||
|
`#2617 <https://github.com/fmtlib/fmt/pull/2617>`_,
|
||||||
|
`#2628 <https://github.com/fmtlib/fmt/issues/2628>`_,
|
||||||
|
`#2633 <https://github.com/fmtlib/fmt/pull/2633>`_,
|
||||||
|
`#2670 <https://github.com/fmtlib/fmt/issues/2670>`_,
|
||||||
|
`#2671 <https://github.com/fmtlib/fmt/pull/2671>`_).
|
||||||
|
|
||||||
|
Processing of some specifiers such as ``%z`` and ``%Y`` is now up to 10-20
|
||||||
|
times faster, for example on GCC 11 with libstdc++::
|
||||||
|
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
Benchmark Before After
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
FMTFormatter_z 261 ns 26.3 ns
|
||||||
|
FMTFormatterCompile_z 246 ns 11.6 ns
|
||||||
|
FMTFormatter_Y 263 ns 26.1 ns
|
||||||
|
FMTFormatterCompile_Y 244 ns 10.5 ns
|
||||||
|
----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Thanks `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_ and
|
||||||
|
`@toughengineer (Pavel Novikov) <https://github.com/toughengineer>`_.
|
||||||
|
|
||||||
|
* Implemented subsecond formatting for chrono durations
|
||||||
|
(`#2623 <https://github.com/fmtlib/fmt/pull/2623>`_).
|
||||||
|
For example (`godbolt <https://godbolt.org/z/es7vWTETe>`__):
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
#include <fmt/chrono.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
fmt::print("{:%S}", std::chrono::milliseconds(1234));
|
||||||
|
}
|
||||||
|
|
||||||
|
prints "01.234".
|
||||||
|
|
||||||
|
Thanks `@matrackif <https://github.com/matrackif>`_.
|
||||||
|
|
||||||
|
* Fixed handling of precision 0 when formatting chrono durations
|
||||||
|
(`#2587 <https://github.com/fmtlib/fmt/issues/2587>`_,
|
||||||
|
`#2588 <https://github.com/fmtlib/fmt/pull/2588>`_).
|
||||||
|
Thanks `@lukester1975 <https://github.com/lukester1975>`_.
|
||||||
|
|
||||||
|
* Fixed an overflow on invalid inputs in the ``tm`` formatter
|
||||||
|
(`#2564 <https://github.com/fmtlib/fmt/pull/2564>`_).
|
||||||
|
Thanks `@phprus (Vladislav Shchapov) <https://github.com/phprus>`_.
|
||||||
|
|
||||||
|
* Added ``fmt::group_digits`` that formats integers with a non-localized digit
|
||||||
|
separator (comma) for groups of three digits.
|
||||||
|
For example (`godbolt <https://godbolt.org/z/TxGxG9Poq>`__):
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
fmt::print("{} dollars", fmt::group_digits(1000000));
|
||||||
|
}
|
||||||
|
|
||||||
|
prints "1,000,000 dollars".
|
||||||
|
|
||||||
|
* Added support for faint, conceal, reverse and blink text styles
|
||||||
|
(`#2394 <https://github.com/fmtlib/fmt/pull/2394>`_):
|
||||||
|
|
||||||
|
https://user-images.githubusercontent.com/576385/147710227-c68f5317-f8fa-42c3-9123-7c4ba3c398cb.mp4
|
||||||
|
|
||||||
|
Thanks `@benit8 (Benoît Lormeau) <https://github.com/benit8>`_ and
|
||||||
|
`@data-man (Dmitry Atamanov) <https://github.com/data-man>`_.
|
||||||
|
|
||||||
|
* Added experimental support for compile-time floating point formatting
|
||||||
|
(`#2426 <https://github.com/fmtlib/fmt/pull/2426>`_,
|
||||||
|
`#2470 <https://github.com/fmtlib/fmt/pull/2470>`_).
|
||||||
|
It is currently limited to the header-only mode.
|
||||||
|
Thanks `@alexezeder (Alexey Ochapov) <https://github.com/alexezeder>`_.
|
||||||
|
|
||||||
|
* Added UDL-based named argument support to compile-time format string checks
|
||||||
|
(`#2640 <https://github.com/fmtlib/fmt/issues/2640>`_,
|
||||||
|
`#2649 <https://github.com/fmtlib/fmt/pull/2649>`_).
|
||||||
|
For example (`godbolt <https://godbolt.org/z/ohGbbvonv>`__):
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
using namespace fmt::literals;
|
||||||
|
fmt::print("{answer:s}", "answer"_a=42);
|
||||||
|
}
|
||||||
|
|
||||||
|
gives a compile-time error on compilers with C++20 ``consteval`` and non-type
|
||||||
|
template parameter support (gcc 10+) because ``s`` is not a valid format
|
||||||
|
specifier for an integer.
|
||||||
|
|
||||||
|
Thanks `@alexezeder (Alexey Ochapov) <https://github.com/alexezeder>`_.
|
||||||
|
|
||||||
|
* Implemented escaping of string range elements.
|
||||||
|
For example (`godbolt <https://godbolt.org/z/rKvM1vKf3>`__):
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
#include <fmt/ranges.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
fmt::print("{}", std::vector<std::string>{"\naan"});
|
||||||
|
}
|
||||||
|
|
||||||
|
is now printed as::
|
||||||
|
|
||||||
|
["\naan"]
|
||||||
|
|
||||||
|
instead of::
|
||||||
|
|
||||||
|
["
|
||||||
|
aan"]
|
||||||
|
|
||||||
|
* Switched to JSON-like representation of maps and sets for consistency with
|
||||||
|
Python's ``str.format``.
|
||||||
|
For example (`godbolt <https://godbolt.org/z/seKjoY9W5>`__):
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
#include <fmt/ranges.h>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
fmt::print("{}", std::map<std::string, int>{{"answer", 42}});
|
||||||
|
}
|
||||||
|
|
||||||
|
is now printed as::
|
||||||
|
|
||||||
|
{"answer": 42}
|
||||||
|
|
||||||
|
* Extended ``fmt::join`` to support C++20-only ranges
|
||||||
|
(`#2549 <https://github.com/fmtlib/fmt/pull/2549>`_).
|
||||||
|
Thanks `@BRevzin (Barry Revzin) <https://github.com/BRevzin>`_.
|
||||||
|
|
||||||
|
* Optimized handling of non-const-iterable ranges and implemented initial
|
||||||
|
support for non-const-formattable types.
|
||||||
|
|
||||||
|
* Disabled implicit conversions of scoped enums to integers that was
|
||||||
|
accidentally introduced in earlier versions
|
||||||
|
(`#1841 <https://github.com/fmtlib/fmt/pull/1841>`_).
|
||||||
|
|
||||||
|
* Deprecated implicit conversion of ``[const] signed char*`` and
|
||||||
|
``[const] unsigned char*`` to C strings.
|
||||||
|
|
||||||
|
* Deprecated ``_format``, a legacy UDL-based format API
|
||||||
|
(`#2646 <https://github.com/fmtlib/fmt/pull/2646>`_).
|
||||||
|
Thanks `@alexezeder (Alexey Ochapov) <https://github.com/alexezeder>`_.
|
||||||
|
|
||||||
|
* Marked ``format``, ``formatted_size`` and ``to_string`` as ``[[nodiscard]]``
|
||||||
|
(`#2612 <https://github.com/fmtlib/fmt/pull/2612>`_).
|
||||||
|
`@0x8000-0000 (Florin Iucha) <https://github.com/0x8000-0000>`_.
|
||||||
|
|
||||||
|
* Added missing diagnostic when trying to format function and member pointers
|
||||||
|
as well as objects convertible to pointers which is explicitly disallowed
|
||||||
|
(`#2598 <https://github.com/fmtlib/fmt/issues/2598>`_,
|
||||||
|
`#2609 <https://github.com/fmtlib/fmt/pull/2609>`_,
|
||||||
|
`#2610 <https://github.com/fmtlib/fmt/pull/2610>`_).
|
||||||
|
Thanks `@AlexGuteniev (Alex Guteniev) <https://github.com/AlexGuteniev>`_.
|
||||||
|
|
||||||
|
* Optimized writing to a contiguous buffer with ``format_to_n``
|
||||||
|
(`#2489 <https://github.com/fmtlib/fmt/pull/2489>`_).
|
||||||
|
Thanks `@Roman-Koshelev <https://github.com/Roman-Koshelev>`_.
|
||||||
|
|
||||||
|
* Optimized writing to non-``char`` buffers
|
||||||
|
(`#2477 <https://github.com/fmtlib/fmt/pull/2477>`_).
|
||||||
|
Thanks `@Roman-Koshelev <https://github.com/Roman-Koshelev>`_.
|
||||||
|
|
||||||
|
* Decimal point is now localized when using the ``L`` specifier.
|
||||||
|
|
||||||
|
* Improved floating point formatter implementation
|
||||||
|
(`#2498 <https://github.com/fmtlib/fmt/pull/2498>`_,
|
||||||
|
`#2499 <https://github.com/fmtlib/fmt/pull/2499>`_).
|
||||||
|
Thanks `@Roman-Koshelev <https://github.com/Roman-Koshelev>`_.
|
||||||
|
|
||||||
|
* Fixed handling of very large precision in fixed format
|
||||||
|
(`#2616 <https://github.com/fmtlib/fmt/pull/2616>`_).
|
||||||
|
|
||||||
|
* Made a table of cached powers used in FP formatting static
|
||||||
|
(`#2509 <https://github.com/fmtlib/fmt/pull/2509>`_).
|
||||||
|
Thanks `@jk-jeon (Junekey Jeon) <https://github.com/jk-jeon>`_.
|
||||||
|
|
||||||
|
* Resolved a lookup ambiguity with C++20 format-related functions due to ADL
|
||||||
|
(`#2639 <https://github.com/fmtlib/fmt/issues/2639>`_,
|
||||||
|
`#2641 <https://github.com/fmtlib/fmt/pull/2641>`_).
|
||||||
|
Thanks `@mkurdej (Marek Kurdej) <https://github.com/mkurdej>`_.
|
||||||
|
|
||||||
|
* Removed unnecessary inline namespace qualification
|
||||||
|
(`#2642 <https://github.com/fmtlib/fmt/issues/2642>`_,
|
||||||
|
`#2643 <https://github.com/fmtlib/fmt/pull/2643>`_).
|
||||||
|
Thanks `@mkurdej (Marek Kurdej) <https://github.com/mkurdej>`_.
|
||||||
|
|
||||||
|
* Implemented argument forwarding in ``format_to_n``
|
||||||
|
(`#2462 <https://github.com/fmtlib/fmt/issues/2462>`_,
|
||||||
|
`#2463 <https://github.com/fmtlib/fmt/pull/2463>`_).
|
||||||
|
Thanks `@owent (WenTao Ou) <https://github.com/owent>`_.
|
||||||
|
|
||||||
|
* Fixed handling of implicit conversions in ``fmt::to_string`` and format string
|
||||||
|
compilation (`#2565 <https://github.com/fmtlib/fmt/issues/2565>`_).
|
||||||
|
|
||||||
|
* Changed the default access mode of files created by ``fmt::output_file`` to
|
||||||
|
``-rw-r--r--`` for consistency with ``fopen``
|
||||||
|
(`#2530 <https://github.com/fmtlib/fmt/issues/2530>`_).
|
||||||
|
|
||||||
|
* Make ``fmt::ostream::flush`` public
|
||||||
|
(`#2435 <https://github.com/fmtlib/fmt/issues/2435>`_).
|
||||||
|
|
||||||
|
* Improved C++14/17 attribute detection
|
||||||
|
(`#2615 <https://github.com/fmtlib/fmt/pull/2615>`_).
|
||||||
|
Thanks `@AlexGuteniev (Alex Guteniev) <https://github.com/AlexGuteniev>`_.
|
||||||
|
|
||||||
|
* Improved ``consteval`` detection for MSVC
|
||||||
|
(`#2559 <https://github.com/fmtlib/fmt/pull/2559>`_).
|
||||||
|
Thanks `@DanielaE (Daniela Engert) <https://github.com/DanielaE>`_.
|
||||||
|
|
||||||
|
* Improved documentation
|
||||||
|
(`#2406 <https://github.com/fmtlib/fmt/issues/2406>`_,
|
||||||
|
`#2446 <https://github.com/fmtlib/fmt/pull/2446>`_,
|
||||||
|
`#2493 <https://github.com/fmtlib/fmt/issues/2493>`_,
|
||||||
|
`#2513 <https://github.com/fmtlib/fmt/issues/2513>`_,
|
||||||
|
`#2515 <https://github.com/fmtlib/fmt/pull/2515>`_,
|
||||||
|
`#2522 <https://github.com/fmtlib/fmt/issues/2522>`_,
|
||||||
|
`#2562 <https://github.com/fmtlib/fmt/pull/2562>`_,
|
||||||
|
`#2575 <https://github.com/fmtlib/fmt/pull/2575>`_,
|
||||||
|
`#2606 <https://github.com/fmtlib/fmt/pull/2606>`_,
|
||||||
|
`#2620 <https://github.com/fmtlib/fmt/pull/2620>`_,
|
||||||
|
`#2676 <https://github.com/fmtlib/fmt/issues/2676>`_).
|
||||||
|
Thanks `@sobolevn (Nikita Sobolev) <https://github.com/sobolevn>`_,
|
||||||
|
`@UnePierre (Max FERGER) <https://github.com/UnePierre>`_,
|
||||||
|
`@zhsj <https://github.com/zhsj>`_,
|
||||||
|
`@phprus (Vladislav Shchapov) <https://github.com/phprus>`_,
|
||||||
|
`@ericcurtin (Eric Curtin) <https://github.com/ericcurtin>`_,
|
||||||
|
`@Lounarok <https://github.com/Lounarok>`_.
|
||||||
|
|
||||||
|
* Improved fuzzers and added a fuzzer for chrono timepoint formatting
|
||||||
|
(`#2461 <https://github.com/fmtlib/fmt/pull/2461>`_,
|
||||||
|
`#2469 <https://github.com/fmtlib/fmt/pull/2469>`_).
|
||||||
|
`@pauldreik (Paul Dreik) <https://github.com/pauldreik>`_,
|
||||||
|
|
||||||
|
* Added the ``FMT_SYSTEM_HEADERS`` CMake option setting which marks {fmt}'s
|
||||||
|
headers as system. It can be used to suppress warnings
|
||||||
|
(`#2644 <https://github.com/fmtlib/fmt/issues/2644>`_,
|
||||||
|
`#2651 <https://github.com/fmtlib/fmt/pull/2651>`_).
|
||||||
|
Thanks `@alexezeder (Alexey Ochapov) <https://github.com/alexezeder>`_.
|
||||||
|
|
||||||
|
* Added the Bazel build system support
|
||||||
|
(`#2505 <https://github.com/fmtlib/fmt/pull/2505>`_,
|
||||||
|
`#2516 <https://github.com/fmtlib/fmt/pull/2516>`_).
|
||||||
|
Thanks `@Vertexwahn <https://github.com/Vertexwahn>`_.
|
||||||
|
|
||||||
|
* Improved build configuration and tests
|
||||||
|
(`#2437 <https://github.com/fmtlib/fmt/issues/2437>`_,
|
||||||
|
`#2558 <https://github.com/fmtlib/fmt/pull/2558>`_,
|
||||||
|
`#2648 <https://github.com/fmtlib/fmt/pull/2648>`_,
|
||||||
|
`#2650 <https://github.com/fmtlib/fmt/pull/2650>`_,
|
||||||
|
`#2663 <https://github.com/fmtlib/fmt/pull/2663>`_,
|
||||||
|
`#2677 <https://github.com/fmtlib/fmt/pull/2677>`_).
|
||||||
|
Thanks `@DanielaE (Daniela Engert) <https://github.com/DanielaE>`_,
|
||||||
|
`@alexezeder (Alexey Ochapov) <https://github.com/alexezeder>`_,
|
||||||
|
`@phprus (Vladislav Shchapov) <https://github.com/phprus>`_.
|
||||||
|
|
||||||
|
* Fixed various warnings and compilation issues
|
||||||
|
(`#2353 <https://github.com/fmtlib/fmt/pull/2353>`_,
|
||||||
|
`#2356 <https://github.com/fmtlib/fmt/pull/2356>`_,
|
||||||
|
`#2399 <https://github.com/fmtlib/fmt/pull/2399>`_,
|
||||||
|
`#2408 <https://github.com/fmtlib/fmt/issues/2408>`_,
|
||||||
|
`#2414 <https://github.com/fmtlib/fmt/pull/2414>`_,
|
||||||
|
`#2427 <https://github.com/fmtlib/fmt/pull/2427>`_,
|
||||||
|
`#2432 <https://github.com/fmtlib/fmt/pull/2432>`_,
|
||||||
|
`#2442 <https://github.com/fmtlib/fmt/pull/2442>`_,
|
||||||
|
`#2434 <https://github.com/fmtlib/fmt/pull/2434>`_,
|
||||||
|
`#2439 <https://github.com/fmtlib/fmt/issues/2439>`_,
|
||||||
|
`#2447 <https://github.com/fmtlib/fmt/pull/2447>`_,
|
||||||
|
`#2450 <https://github.com/fmtlib/fmt/pull/2450>`_,
|
||||||
|
`#2455 <https://github.com/fmtlib/fmt/issues/2455>`_,
|
||||||
|
`#2465 <https://github.com/fmtlib/fmt/issues/2465>`_,
|
||||||
|
`#2472 <https://github.com/fmtlib/fmt/issues/2472>`_,
|
||||||
|
`#2474 <https://github.com/fmtlib/fmt/issues/2474>`_,
|
||||||
|
`#2476 <https://github.com/fmtlib/fmt/pull/2476>`_,
|
||||||
|
`#2478 <https://github.com/fmtlib/fmt/issues/2478>`_,
|
||||||
|
`#2479 <https://github.com/fmtlib/fmt/issues/2479>`_,
|
||||||
|
`#2481 <https://github.com/fmtlib/fmt/issues/2481>`_,
|
||||||
|
`#2482 <https://github.com/fmtlib/fmt/pull/2482>`_,
|
||||||
|
`#2483 <https://github.com/fmtlib/fmt/pull/2483>`_,
|
||||||
|
`#2490 <https://github.com/fmtlib/fmt/issues/2490>`_,
|
||||||
|
`#2491 <https://github.com/fmtlib/fmt/pull/2491>`_,
|
||||||
|
`#2510 <https://github.com/fmtlib/fmt/pull/2510>`_,
|
||||||
|
`#2518 <https://github.com/fmtlib/fmt/pull/2518>`_,
|
||||||
|
`#2528 <https://github.com/fmtlib/fmt/issues/2528>`_,
|
||||||
|
`#2529 <https://github.com/fmtlib/fmt/pull/2529>`_,
|
||||||
|
`#2539 <https://github.com/fmtlib/fmt/pull/2539>`_,
|
||||||
|
`#2540 <https://github.com/fmtlib/fmt/issues/2540>`_,
|
||||||
|
`#2545 <https://github.com/fmtlib/fmt/pull/2545>`_,
|
||||||
|
`#2555 <https://github.com/fmtlib/fmt/pull/2555>`_,
|
||||||
|
`#2557 <https://github.com/fmtlib/fmt/issues/2557>`_,
|
||||||
|
`#2570 <https://github.com/fmtlib/fmt/issues/2570>`_,
|
||||||
|
`#2573 <https://github.com/fmtlib/fmt/pull/2573>`_,
|
||||||
|
`#2582 <https://github.com/fmtlib/fmt/pull/2582>`_,
|
||||||
|
`#2605 <https://github.com/fmtlib/fmt/issues/2605>`_,
|
||||||
|
`#2611 <https://github.com/fmtlib/fmt/pull/2611>`_,
|
||||||
|
`#2647 <https://github.com/fmtlib/fmt/pull/2647>`_,
|
||||||
|
`#2627 <https://github.com/fmtlib/fmt/issues/2627>`_,
|
||||||
|
`#2630 <https://github.com/fmtlib/fmt/pull/2630>`_,
|
||||||
|
`#2635 <https://github.com/fmtlib/fmt/issues/2635>`_,
|
||||||
|
`#2638 <https://github.com/fmtlib/fmt/issues/2638>`_,
|
||||||
|
`#2653 <https://github.com/fmtlib/fmt/issues/2653>`_,
|
||||||
|
`#2654 <https://github.com/fmtlib/fmt/issues/2654>`_,
|
||||||
|
`#2661 <https://github.com/fmtlib/fmt/issues/2661>`_,
|
||||||
|
`#2664 <https://github.com/fmtlib/fmt/pull/2664>`_,
|
||||||
|
`#2684 <https://github.com/fmtlib/fmt/pull/2684>`_).
|
||||||
|
Thanks `@DanielaE (Daniela Engert) <https://github.com/DanielaE>`_,
|
||||||
|
`@mwinterb <https://github.com/mwinterb>`_,
|
||||||
|
`@cdacamar (Cameron DaCamara) <https://github.com/cdacamar>`_,
|
||||||
|
`@TrebledJ (Johnathan) <https://github.com/TrebledJ>`_,
|
||||||
|
`@bodomartin (brm) <https://github.com/bodomartin>`_,
|
||||||
|
`@cquammen (Cory Quammen) <https://github.com/cquammen>`_,
|
||||||
|
`@white238 (Chris White) <https://github.com/white238>`_,
|
||||||
|
`@mmarkeloff (Max) <https://github.com/mmarkeloff>`_,
|
||||||
|
`@palacaze (Pierre-Antoine Lacaze) <https://github.com/palacaze>`_,
|
||||||
|
`@jcelerier (Jean-Michaël Celerier) <https://github.com/jcelerier>`_,
|
||||||
|
`@mborn-adi (Mathias Born) <https://github.com/mborn-adi>`_,
|
||||||
|
`@BrukerJWD (Jonathan W) <https://github.com/BrukerJWD>`_,
|
||||||
|
`@spyridon97 (Spiros Tsalikis) <https://github.com/spyridon97>`_,
|
||||||
|
`@phprus (Vladislav Shchapov) <https://github.com/phprus>`_,
|
||||||
|
`@oliverlee (Oliver Lee) <https://github.com/oliverlee>`_,
|
||||||
|
`@joshessman-llnl (Josh Essman) <https://github.com/joshessman-llnl>`_,
|
||||||
|
`@akohlmey (Axel Kohlmeyer) <https://github.com/akohlmey>`_,
|
||||||
|
`@timkalu <https://github.com/timkalu>`_,
|
||||||
|
`@olupton (Olli Lupton) <https://github.com/olupton>`_,
|
||||||
|
`@Acretock <https://github.com/Acretock>`_,
|
||||||
|
`@alexezeder (Alexey Ochapov) <https://github.com/alexezeder>`_,
|
||||||
|
`@andrewcorrigan (Andrew Corrigan) <https://github.com/andrewcorrigan>`_,
|
||||||
|
`@lucpelletier <https://github.com/lucpelletier>`_,
|
||||||
|
`@HazardyKnusperkeks (Björn Schäpers) <https://github.com/HazardyKnusperkeks>`_.
|
||||||
|
|
||||||
8.0.1 - 2021-07-02
|
8.0.1 - 2021-07-02
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
@ -34,7 +405,7 @@
|
|||||||
`#2389 <https://github.com/fmtlib/fmt/pull/2389>`_,
|
`#2389 <https://github.com/fmtlib/fmt/pull/2389>`_,
|
||||||
`#2395 <https://github.com/fmtlib/fmt/pull/2395>`_,
|
`#2395 <https://github.com/fmtlib/fmt/pull/2395>`_,
|
||||||
`#2397 <https://github.com/fmtlib/fmt/pull/2397>`_,
|
`#2397 <https://github.com/fmtlib/fmt/pull/2397>`_,
|
||||||
`#2400 <https://github.com/fmtlib/fmt/issues/2400>`_
|
`#2400 <https://github.com/fmtlib/fmt/issues/2400>`_,
|
||||||
`#2401 <https://github.com/fmtlib/fmt/issues/2401>`_,
|
`#2401 <https://github.com/fmtlib/fmt/issues/2401>`_,
|
||||||
`#2407 <https://github.com/fmtlib/fmt/pull/2407>`_).
|
`#2407 <https://github.com/fmtlib/fmt/pull/2407>`_).
|
||||||
Thanks `@zx2c4 (Jason A. Donenfeld) <https://github.com/zx2c4>`_,
|
Thanks `@zx2c4 (Jason A. Donenfeld) <https://github.com/zx2c4>`_,
|
||||||
@ -50,7 +421,7 @@
|
|||||||
8.0.0 - 2021-06-21
|
8.0.0 - 2021-06-21
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
* Enabled compile-time format string check by default.
|
* Enabled compile-time format string checks by default.
|
||||||
For example (`godbolt <https://godbolt.org/z/sMxcohGjz>`__):
|
For example (`godbolt <https://godbolt.org/z/sMxcohGjz>`__):
|
||||||
|
|
||||||
.. code:: c++
|
.. code:: c++
|
||||||
@ -281,6 +652,9 @@
|
|||||||
This doesn't introduce a dependency on ``<locale>`` so there is virtually no
|
This doesn't introduce a dependency on ``<locale>`` so there is virtually no
|
||||||
compile time effect.
|
compile time effect.
|
||||||
|
|
||||||
|
* Deprecated an undocumented ``format_to`` overload that takes
|
||||||
|
``basic_memory_buffer``.
|
||||||
|
|
||||||
* Made parameter order in ``vformat_to`` consistent with ``format_to``
|
* Made parameter order in ``vformat_to`` consistent with ``format_to``
|
||||||
(`#2327 <https://github.com/fmtlib/fmt/issues/2327>`_).
|
(`#2327 <https://github.com/fmtlib/fmt/issues/2327>`_).
|
||||||
|
|
||||||
@ -562,13 +936,13 @@
|
|||||||
`#2067 <https://github.com/fmtlib/fmt/pull/2067>`_,
|
`#2067 <https://github.com/fmtlib/fmt/pull/2067>`_,
|
||||||
`#2068 <https://github.com/fmtlib/fmt/pull/2068>`_,
|
`#2068 <https://github.com/fmtlib/fmt/pull/2068>`_,
|
||||||
`#2073 <https://github.com/fmtlib/fmt/pull/2073>`_,
|
`#2073 <https://github.com/fmtlib/fmt/pull/2073>`_,
|
||||||
`#2103 <https://github.com/fmtlib/fmt/issues/2103>`_
|
`#2103 <https://github.com/fmtlib/fmt/issues/2103>`_,
|
||||||
`#2105 <https://github.com/fmtlib/fmt/issues/2105>`_
|
`#2105 <https://github.com/fmtlib/fmt/issues/2105>`_,
|
||||||
`#2106 <https://github.com/fmtlib/fmt/pull/2106>`_,
|
`#2106 <https://github.com/fmtlib/fmt/pull/2106>`_,
|
||||||
`#2107 <https://github.com/fmtlib/fmt/pull/2107>`_,
|
`#2107 <https://github.com/fmtlib/fmt/pull/2107>`_,
|
||||||
`#2116 <https://github.com/fmtlib/fmt/issues/2116>`_
|
`#2116 <https://github.com/fmtlib/fmt/issues/2116>`_,
|
||||||
`#2117 <https://github.com/fmtlib/fmt/pull/2117>`_,
|
`#2117 <https://github.com/fmtlib/fmt/pull/2117>`_,
|
||||||
`#2118 <https://github.com/fmtlib/fmt/issues/2118>`_
|
`#2118 <https://github.com/fmtlib/fmt/issues/2118>`_,
|
||||||
`#2119 <https://github.com/fmtlib/fmt/pull/2119>`_,
|
`#2119 <https://github.com/fmtlib/fmt/pull/2119>`_,
|
||||||
`#2127 <https://github.com/fmtlib/fmt/issues/2127>`_,
|
`#2127 <https://github.com/fmtlib/fmt/issues/2127>`_,
|
||||||
`#2128 <https://github.com/fmtlib/fmt/pull/2128>`_,
|
`#2128 <https://github.com/fmtlib/fmt/pull/2128>`_,
|
||||||
@ -641,7 +1015,7 @@
|
|||||||
`@yeswalrus (Walter Gray) <https://github.com/yeswalrus>`_,
|
`@yeswalrus (Walter Gray) <https://github.com/yeswalrus>`_,
|
||||||
`@Finkman <https://github.com/Finkman>`_,
|
`@Finkman <https://github.com/Finkman>`_,
|
||||||
`@HazardyKnusperkeks (Björn Schäpers) <https://github.com/HazardyKnusperkeks>`_,
|
`@HazardyKnusperkeks (Björn Schäpers) <https://github.com/HazardyKnusperkeks>`_,
|
||||||
`@dkavolis (Daumantas Kavolis) <https://github.com/dkavolis>`_
|
`@dkavolis (Daumantas Kavolis) <https://github.com/dkavolis>`_,
|
||||||
`@concatime (Issam Maghni) <https://github.com/concatime>`_,
|
`@concatime (Issam Maghni) <https://github.com/concatime>`_,
|
||||||
`@chronoxor (Ivan Shynkarenka) <https://github.com/chronoxor>`_,
|
`@chronoxor (Ivan Shynkarenka) <https://github.com/chronoxor>`_,
|
||||||
`@summivox (Yin Zhong) <https://github.com/summivox>`_,
|
`@summivox (Yin Zhong) <https://github.com/summivox>`_,
|
||||||
@ -1098,7 +1472,7 @@
|
|||||||
`#1912 <https://github.com/fmtlib/fmt/issues/1912>`_,
|
`#1912 <https://github.com/fmtlib/fmt/issues/1912>`_,
|
||||||
`#1928 <https://github.com/fmtlib/fmt/issues/1928>`_,
|
`#1928 <https://github.com/fmtlib/fmt/issues/1928>`_,
|
||||||
`#1929 <https://github.com/fmtlib/fmt/pull/1929>`_,
|
`#1929 <https://github.com/fmtlib/fmt/pull/1929>`_,
|
||||||
`#1935 <https://github.com/fmtlib/fmt/issues/1935>`_
|
`#1935 <https://github.com/fmtlib/fmt/issues/1935>`_,
|
||||||
`#1937 <https://github.com/fmtlib/fmt/pull/1937>`_,
|
`#1937 <https://github.com/fmtlib/fmt/pull/1937>`_,
|
||||||
`#1942 <https://github.com/fmtlib/fmt/pull/1942>`_,
|
`#1942 <https://github.com/fmtlib/fmt/pull/1942>`_,
|
||||||
`#1949 <https://github.com/fmtlib/fmt/issues/1949>`_).
|
`#1949 <https://github.com/fmtlib/fmt/issues/1949>`_).
|
||||||
|
17
vendor/Fmt/README.rst
vendored
17
vendor/Fmt/README.rst
vendored
@ -1,5 +1,7 @@
|
|||||||
{fmt}
|
.. image:: https://user-images.githubusercontent.com/
|
||||||
=====
|
576385/156254208-f5b743a9-88cf-439d-b0c0-923d53e8d551.png
|
||||||
|
:width: 25%
|
||||||
|
:alt: {fmt}
|
||||||
|
|
||||||
.. image:: https://github.com/fmtlib/fmt/workflows/linux/badge.svg
|
.. image:: https://github.com/fmtlib/fmt/workflows/linux/badge.svg
|
||||||
:target: https://github.com/fmtlib/fmt/actions?query=workflow%3Alinux
|
:target: https://github.com/fmtlib/fmt/actions?query=workflow%3Alinux
|
||||||
@ -26,9 +28,8 @@
|
|||||||
**{fmt}** is an open-source formatting library providing a fast and safe
|
**{fmt}** is an open-source formatting library providing a fast and safe
|
||||||
alternative to C stdio and C++ iostreams.
|
alternative to C stdio and C++ iostreams.
|
||||||
|
|
||||||
If you like this project, please consider donating to the BYSOL
|
If you like this project, please consider donating to one of the funds that
|
||||||
Foundation that helps victims of political repressions in Belarus:
|
help victims of the war in Ukraine: https://www.stopputin.net/.
|
||||||
https://bysol.org/en/bs/general/.
|
|
||||||
|
|
||||||
`Documentation <https://fmt.dev>`__
|
`Documentation <https://fmt.dev>`__
|
||||||
|
|
||||||
@ -123,7 +124,7 @@ Output::
|
|||||||
Default format: 42s 100ms
|
Default format: 42s 100ms
|
||||||
strftime-like format: 03:15:30
|
strftime-like format: 03:15:30
|
||||||
|
|
||||||
**Print a container** (`run <https://godbolt.org/z/MjsY7c>`_)
|
**Print a container** (`run <https://godbolt.org/z/MxM1YqjE7>`_)
|
||||||
|
|
||||||
.. code:: c++
|
.. code:: c++
|
||||||
|
|
||||||
@ -205,7 +206,7 @@ The above results were generated by building ``tinyformat_test.cpp`` on macOS
|
|||||||
best of 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/src/tinyformat-test.cc>`_.
|
||||||
|
|
||||||
{fmt} is up to 20-30x faster than ``std::ostringstream`` and ``sprintf`` on
|
{fmt} is up to 20-30x faster than ``std::ostringstream`` and ``sprintf`` on
|
||||||
floating-point formatting (`dtoa-benchmark <https://github.com/fmtlib/dtoa-benchmark>`_)
|
floating-point formatting (`dtoa-benchmark <https://github.com/fmtlib/dtoa-benchmark>`_)
|
||||||
@ -469,7 +470,7 @@ 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`_).
|
||||||
|
|
||||||
|
88
vendor/Fmt/doc/api.rst
vendored
88
vendor/Fmt/doc/api.rst
vendored
@ -37,10 +37,12 @@ similar to that of Python's `str.format
|
|||||||
<https://docs.python.org/3/library/stdtypes.html#str.format>`_.
|
<https://docs.python.org/3/library/stdtypes.html#str.format>`_.
|
||||||
They take *fmt* and *args* as arguments.
|
They take *fmt* and *args* as arguments.
|
||||||
|
|
||||||
*fmt* is a format string that contains literal text and replacement
|
*fmt* is a format string that contains literal text and replacement fields
|
||||||
fields surrounded by braces ``{}``. The fields are replaced with formatted
|
surrounded by braces ``{}``. The fields are replaced with formatted arguments
|
||||||
arguments in the resulting string. A function taking *fmt* doesn't
|
in the resulting string. `~fmt::format_string` is a format string which can be
|
||||||
participate in an overload resolution if the latter is not a string.
|
implicitly constructed from a string literal or a ``constexpr`` string and is
|
||||||
|
checked at compile time in C++20. To pass a runtime format string wrap it in
|
||||||
|
`fmt::runtime`.
|
||||||
|
|
||||||
*args* is an argument list representing objects to be formatted.
|
*args* is an argument list representing objects to be formatted.
|
||||||
|
|
||||||
@ -50,7 +52,7 @@ participate in an overload resolution if the latter is not a string.
|
|||||||
.. doxygenfunction:: vformat(string_view fmt, format_args args) -> std::string
|
.. doxygenfunction:: vformat(string_view fmt, format_args args) -> std::string
|
||||||
|
|
||||||
.. doxygenfunction:: format_to(OutputIt out, format_string<T...> fmt, T&&... args) -> OutputIt
|
.. doxygenfunction:: format_to(OutputIt out, format_string<T...> fmt, T&&... args) -> OutputIt
|
||||||
.. doxygenfunction:: format_to_n(OutputIt out, size_t n, format_string<T...> fmt, const T&... args) -> format_to_n_result<OutputIt>
|
.. doxygenfunction:: format_to_n(OutputIt out, size_t n, format_string<T...> fmt, T&&... args) -> format_to_n_result<OutputIt>
|
||||||
.. doxygenfunction:: formatted_size(format_string<T...> fmt, T&&... args) -> size_t
|
.. doxygenfunction:: formatted_size(format_string<T...> fmt, T&&... args) -> size_t
|
||||||
|
|
||||||
.. doxygenstruct:: fmt::format_to_n_result
|
.. doxygenstruct:: fmt::format_to_n_result
|
||||||
@ -59,7 +61,7 @@ participate in an overload resolution if the latter is not a string.
|
|||||||
.. _print:
|
.. _print:
|
||||||
|
|
||||||
.. doxygenfunction:: fmt::print(format_string<T...> fmt, T&&... args)
|
.. doxygenfunction:: fmt::print(format_string<T...> fmt, T&&... args)
|
||||||
.. doxygenfunction:: vprint(string_view fmt, format_args args)
|
.. doxygenfunction:: fmt::vprint(string_view fmt, format_args args)
|
||||||
|
|
||||||
.. doxygenfunction:: print(std::FILE *f, format_string<T...> fmt, T&&... args)
|
.. doxygenfunction:: print(std::FILE *f, format_string<T...> fmt, T&&... args)
|
||||||
.. doxygenfunction:: vprint(std::FILE *f, string_view fmt, format_args args)
|
.. doxygenfunction:: vprint(std::FILE *f, string_view fmt, format_args args)
|
||||||
@ -70,6 +72,7 @@ Compile-time Format String Checks
|
|||||||
Compile-time checks are enabled when using ``FMT_STRING``. They support built-in
|
Compile-time checks are enabled when using ``FMT_STRING``. They support built-in
|
||||||
and string types as well as user-defined types with ``constexpr`` ``parse``
|
and string types as well as user-defined types with ``constexpr`` ``parse``
|
||||||
functions in their ``formatter`` specializations.
|
functions in their ``formatter`` specializations.
|
||||||
|
Requires C++14 and is a no-op in C++11.
|
||||||
|
|
||||||
.. doxygendefine:: FMT_STRING
|
.. doxygendefine:: FMT_STRING
|
||||||
|
|
||||||
@ -78,6 +81,13 @@ To force the use of compile-time checks, define the preprocessor variable
|
|||||||
will fail to compile with regular strings. Runtime-checked
|
will fail to compile with regular strings. Runtime-checked
|
||||||
formatting is still possible using ``fmt::vformat``, ``fmt::vprint``, etc.
|
formatting is still possible using ``fmt::vformat``, ``fmt::vprint``, etc.
|
||||||
|
|
||||||
|
.. doxygenclass:: fmt::basic_format_string
|
||||||
|
:members:
|
||||||
|
|
||||||
|
.. doxygentypedef:: fmt::format_string
|
||||||
|
|
||||||
|
.. doxygenfunction:: fmt::runtime(const S&)
|
||||||
|
|
||||||
Named Arguments
|
Named Arguments
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
@ -103,8 +113,7 @@ binary footprint, for example (https://godbolt.org/z/oba4Mc):
|
|||||||
|
|
||||||
template <typename S, typename... Args>
|
template <typename S, typename... Args>
|
||||||
void log(const char* file, int line, const S& format, Args&&... args) {
|
void log(const char* file, int line, const S& format, Args&&... args) {
|
||||||
vlog(file, line, format,
|
vlog(file, line, format, fmt::make_format_args(args...));
|
||||||
fmt::make_args_checked<Args...>(format, args...));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MY_LOG(format, ...) \
|
#define MY_LOG(format, ...) \
|
||||||
@ -115,8 +124,6 @@ binary footprint, for example (https://godbolt.org/z/oba4Mc):
|
|||||||
Note that ``vlog`` is not parameterized on argument types which improves compile
|
Note that ``vlog`` is not parameterized on argument types which improves compile
|
||||||
times and reduces binary code size compared to a fully parameterized version.
|
times and reduces binary code size compared to a fully parameterized version.
|
||||||
|
|
||||||
.. doxygenfunction:: fmt::make_args_checked(const S&, const remove_reference_t<Args>&...)
|
|
||||||
|
|
||||||
.. doxygenfunction:: fmt::make_format_args(const Args&...)
|
.. doxygenfunction:: fmt::make_format_args(const Args&...)
|
||||||
|
|
||||||
.. doxygenclass:: fmt::format_arg_store
|
.. doxygenclass:: fmt::format_arg_store
|
||||||
@ -172,12 +179,19 @@ functions and locale support.
|
|||||||
Formatting User-defined Types
|
Formatting User-defined Types
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
||||||
|
The {fmt} library provides formatters for many standard C++ types.
|
||||||
|
See :ref:`fmt/ranges.h <ranges-api>` for ranges and tuples including standard
|
||||||
|
containers such as ``std::vector`` and :ref:`fmt/chrono.h <chrono-api>` for date
|
||||||
|
and time formatting.
|
||||||
|
|
||||||
To make a user-defined type formattable, specialize the ``formatter<T>`` struct
|
To make a user-defined type formattable, specialize the ``formatter<T>`` struct
|
||||||
template and implement ``parse`` and ``format`` methods::
|
template and implement ``parse`` and ``format`` methods::
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
struct point { double x, y; };
|
struct point {
|
||||||
|
double x, y;
|
||||||
|
};
|
||||||
|
|
||||||
template <> struct fmt::formatter<point> {
|
template <> struct fmt::formatter<point> {
|
||||||
// Presentation format: 'f' - fixed, 'e' - exponential.
|
// Presentation format: 'f' - fixed, 'e' - exponential.
|
||||||
@ -201,8 +215,7 @@ template and implement ``parse`` and ``format`` methods::
|
|||||||
if (it != end && (*it == 'f' || *it == 'e')) presentation = *it++;
|
if (it != end && (*it == 'f' || *it == 'e')) presentation = *it++;
|
||||||
|
|
||||||
// Check if reached the end of the range:
|
// Check if reached the end of the range:
|
||||||
if (it != end && *it != '}')
|
if (it != end && *it != '}') throw format_error("invalid format");
|
||||||
throw format_error("invalid format");
|
|
||||||
|
|
||||||
// Return an iterator past the end of the parsed range:
|
// Return an iterator past the end of the parsed range:
|
||||||
return it;
|
return it;
|
||||||
@ -211,12 +224,11 @@ template and implement ``parse`` and ``format`` methods::
|
|||||||
// Formats the point p using the parsed format specification (presentation)
|
// Formats the point p using the parsed format specification (presentation)
|
||||||
// stored in this formatter.
|
// stored in this formatter.
|
||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
auto format(const point& p, FormatContext& ctx) -> decltype(ctx.out()) {
|
auto format(const point& p, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||||
// ctx.out() is an output iterator to write to.
|
// ctx.out() is an output iterator to write to.
|
||||||
return format_to(
|
return presentation == 'f'
|
||||||
ctx.out(),
|
? format_to(ctx.out(), "({:.1f}, {:.1f})", p.x, p.y)
|
||||||
presentation == 'f' ? "({:.1f}, {:.1f})" : "({:.1e}, {:.1e})",
|
: format_to(ctx.out(), "({:.1e}, {:.1e})", p.x, p.y);
|
||||||
p.x, p.y);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -234,7 +246,7 @@ example::
|
|||||||
template <> struct fmt::formatter<color>: formatter<string_view> {
|
template <> struct fmt::formatter<color>: formatter<string_view> {
|
||||||
// parse is inherited from formatter<string_view>.
|
// parse is inherited from formatter<string_view>.
|
||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
auto format(color c, FormatContext& ctx) {
|
auto format(color c, FormatContext& ctx) const {
|
||||||
string_view name = "unknown";
|
string_view name = "unknown";
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case color::red: name = "red"; break;
|
case color::red: name = "red"; break;
|
||||||
@ -272,7 +284,7 @@ You can also write a formatter for a hierarchy of classes::
|
|||||||
struct fmt::formatter<T, std::enable_if_t<std::is_base_of<A, T>::value, char>> :
|
struct fmt::formatter<T, std::enable_if_t<std::is_base_of<A, T>::value, char>> :
|
||||||
fmt::formatter<std::string> {
|
fmt::formatter<std::string> {
|
||||||
template <typename FormatCtx>
|
template <typename FormatCtx>
|
||||||
auto format(const A& a, FormatCtx& ctx) {
|
auto format(const A& a, FormatCtx& ctx) const {
|
||||||
return fmt::formatter<std::string>::format(a.name(), ctx);
|
return fmt::formatter<std::string>::format(a.name(), ctx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -306,6 +318,8 @@ Utilities
|
|||||||
.. doxygenfunction:: fmt::ptr(const std::unique_ptr<T> &p) -> const void*
|
.. doxygenfunction:: fmt::ptr(const std::unique_ptr<T> &p) -> const void*
|
||||||
.. doxygenfunction:: fmt::ptr(const std::shared_ptr<T> &p) -> const void*
|
.. doxygenfunction:: fmt::ptr(const std::shared_ptr<T> &p) -> const void*
|
||||||
|
|
||||||
|
.. doxygenfunction:: fmt::underlying(Enum e) -> typename std::underlying_type<Enum>::type
|
||||||
|
|
||||||
.. doxygenfunction:: fmt::to_string(const T &value) -> std::string
|
.. doxygenfunction:: fmt::to_string(const T &value) -> std::string
|
||||||
|
|
||||||
.. doxygenfunction:: fmt::to_string_view(const Char *s) -> basic_string_view<Char>
|
.. doxygenfunction:: fmt::to_string_view(const Char *s) -> basic_string_view<Char>
|
||||||
@ -314,6 +328,8 @@ Utilities
|
|||||||
|
|
||||||
.. doxygenfunction:: fmt::join(It begin, Sentinel end, string_view sep) -> join_view<It, Sentinel>
|
.. doxygenfunction:: fmt::join(It begin, Sentinel end, string_view sep) -> join_view<It, Sentinel>
|
||||||
|
|
||||||
|
.. doxygenfunction:: fmt::group_digits(T value) -> group_digits_view<T>
|
||||||
|
|
||||||
.. doxygenclass:: fmt::detail::buffer
|
.. doxygenclass:: fmt::detail::buffer
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
@ -434,16 +450,19 @@ The format syntax is described in :ref:`chrono-specs`.
|
|||||||
Format string compilation
|
Format string compilation
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
``fmt/compile.h`` provides format string compilation support when using
|
``fmt/compile.h`` provides format string compilation enabled via the
|
||||||
``FMT_COMPILE``. Format strings are parsed, checked and converted into efficient
|
``FMT_COMPILE`` macro or the ``_cf`` user-defined literal. Format strings
|
||||||
formatting code at compile-time. This supports arguments of built-in and string
|
marked with ``FMT_COMPILE`` or ``_cf`` are parsed, checked and converted into
|
||||||
types as well as user-defined types with ``constexpr`` ``parse`` functions in
|
efficient formatting code at compile-time. This supports arguments of built-in
|
||||||
their ``formatter`` specializations. Format string compilation can generate more
|
and string types as well as user-defined types with ``constexpr`` ``parse``
|
||||||
binary code compared to the default API and is only recommended in places where
|
functions in their ``formatter`` specializations. Format string compilation can
|
||||||
formatting is a performance bottleneck.
|
generate more binary code compared to the default API and is only recommended in
|
||||||
|
places where formatting is a performance bottleneck.
|
||||||
|
|
||||||
.. doxygendefine:: FMT_COMPILE
|
.. doxygendefine:: FMT_COMPILE
|
||||||
|
|
||||||
|
.. doxygenfunction:: operator""_cf()
|
||||||
|
|
||||||
.. _color-api:
|
.. _color-api:
|
||||||
|
|
||||||
Terminal color and text style
|
Terminal color and text style
|
||||||
@ -457,6 +476,8 @@ Terminal color and text style
|
|||||||
|
|
||||||
.. doxygenfunction:: bg(detail::color_type)
|
.. doxygenfunction:: bg(detail::color_type)
|
||||||
|
|
||||||
|
.. doxygenfunction:: styled(const T& value, text_style ts)
|
||||||
|
|
||||||
.. _os-api:
|
.. _os-api:
|
||||||
|
|
||||||
System APIs
|
System APIs
|
||||||
@ -474,7 +495,9 @@ System APIs
|
|||||||
========================
|
========================
|
||||||
|
|
||||||
``fmt/ostream.h`` provides ``std::ostream`` support including formatting of
|
``fmt/ostream.h`` provides ``std::ostream`` support including formatting of
|
||||||
user-defined types that have an overloaded insertion operator (``operator<<``)::
|
user-defined types that have an overloaded insertion operator (``operator<<``).
|
||||||
|
In order to make a type formattable via ``std::ostream`` you should provide a
|
||||||
|
``formatter`` specialization inherited from ``ostream_formatter``::
|
||||||
|
|
||||||
#include <fmt/ostream.h>
|
#include <fmt/ostream.h>
|
||||||
|
|
||||||
@ -488,12 +511,11 @@ user-defined types that have an overloaded insertion operator (``operator<<``)::
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <> struct fmt::formatter<date> : ostream_formatter {};
|
||||||
|
|
||||||
std::string s = fmt::format("The date is {}", date(2012, 12, 9));
|
std::string s = fmt::format("The date is {}", date(2012, 12, 9));
|
||||||
// s == "The date is 2012-12-9"
|
// s == "The date is 2012-12-9"
|
||||||
|
|
||||||
{fmt} only supports insertion operators that are defined in the same namespaces
|
|
||||||
as the types they format and can be found with the argument-dependent lookup.
|
|
||||||
|
|
||||||
.. doxygenfunction:: print(std::basic_ostream<Char> &os, const S &format_str, Args&&... args)
|
.. doxygenfunction:: print(std::basic_ostream<Char> &os, const S &format_str, Args&&... args)
|
||||||
|
|
||||||
.. _printf-api:
|
.. _printf-api:
|
||||||
@ -519,8 +541,8 @@ argument type doesn't match its format specification.
|
|||||||
``wchar_t`` Support
|
``wchar_t`` Support
|
||||||
===================
|
===================
|
||||||
|
|
||||||
The optional header ``fmt/wchar_t.h`` provides support for ``wchar_t`` and
|
The optional header ``fmt/xchar.h`` provides support for ``wchar_t`` and exotic
|
||||||
exotic character types.
|
character types.
|
||||||
|
|
||||||
.. doxygenstruct:: fmt::is_char
|
.. doxygenstruct:: fmt::is_char
|
||||||
|
|
||||||
|
4
vendor/Fmt/doc/basic-bootstrap/layout.html
vendored
4
vendor/Fmt/doc/basic-bootstrap/layout.html
vendored
@ -90,12 +90,14 @@
|
|||||||
VERSION: '{{ release|e }}',
|
VERSION: '{{ release|e }}',
|
||||||
COLLAPSE_INDEX: false,
|
COLLAPSE_INDEX: false,
|
||||||
FILE_SUFFIX: '{{ '' if no_search_suffix else file_suffix }}',
|
FILE_SUFFIX: '{{ '' if no_search_suffix else file_suffix }}',
|
||||||
|
LINK_SUFFIX: '{{ link_suffix }}',
|
||||||
|
SOURCELINK_SUFFIX: '{{ sourcelink_suffix }}',
|
||||||
HAS_SOURCE: {{ has_source|lower }},
|
HAS_SOURCE: {{ has_source|lower }},
|
||||||
SOURCELINK_SUFFIX: '{{ sourcelink_suffix }}'
|
SOURCELINK_SUFFIX: '{{ sourcelink_suffix }}'
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
{%- for scriptfile in script_files %}
|
{%- for scriptfile in script_files %}
|
||||||
<script type="text/javascript" src="{{ pathto(scriptfile, 1) }}"></script>
|
{{ js_tag(scriptfile) }}
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
{%- endmacro %}
|
{%- endmacro %}
|
||||||
|
|
||||||
|
6
vendor/Fmt/doc/build.py
vendored
6
vendor/Fmt/doc/build.py
vendored
@ -4,7 +4,7 @@
|
|||||||
import errno, os, re, sys
|
import errno, os, re, sys
|
||||||
from subprocess import check_call, CalledProcessError, Popen, PIPE, STDOUT
|
from subprocess import check_call, CalledProcessError, Popen, PIPE, STDOUT
|
||||||
|
|
||||||
versions = ['1.0.0', '1.1.0', '2.0.0', '3.0.2', '4.0.0', '4.1.0', '5.0.0', '5.1.0', '5.2.0', '5.2.1', '5.3.0', '6.0.0', '6.1.0', '6.1.1', '6.1.2', '6.2.0', '6.2.1', '7.0.0', '7.0.1', '7.0.2', '7.0.3', '7.1.0', '7.1.1', '7.1.2', '7.1.3', '8.0.0', '8.0.1']
|
versions = ['1.0.0', '1.1.0', '2.0.0', '3.0.2', '4.0.0', '4.1.0', '5.0.0', '5.1.0', '5.2.0', '5.2.1', '5.3.0', '6.0.0', '6.1.0', '6.1.1', '6.1.2', '6.2.0', '6.2.1', '7.0.0', '7.0.1', '7.0.2', '7.0.3', '7.1.0', '7.1.1', '7.1.2', '7.1.3', '8.0.0', '8.0.1', '8.1.0', '8.1.1']
|
||||||
|
|
||||||
class Pip:
|
class Pip:
|
||||||
def __init__(self, venv_dir):
|
def __init__(self, venv_dir):
|
||||||
@ -26,6 +26,8 @@ def create_build_env(venv_dir='virtualenv'):
|
|||||||
pip = Pip(venv_dir)
|
pip = Pip(venv_dir)
|
||||||
pip.install('wheel')
|
pip.install('wheel')
|
||||||
pip.install('six')
|
pip.install('six')
|
||||||
|
# See: https://github.com/sphinx-doc/sphinx/issues/9777
|
||||||
|
pip.install('docutils==0.17.1')
|
||||||
pip.install('sphinx-doc/sphinx', 'v3.3.0')
|
pip.install('sphinx-doc/sphinx', 'v3.3.0')
|
||||||
pip.install('michaeljones/breathe', 'v4.25.0')
|
pip.install('michaeljones/breathe', 'v4.25.0')
|
||||||
|
|
||||||
@ -58,10 +60,12 @@ def build_docs(version='dev', **kwargs):
|
|||||||
MACRO_EXPANSION = YES
|
MACRO_EXPANSION = YES
|
||||||
PREDEFINED = _WIN32=1 \
|
PREDEFINED = _WIN32=1 \
|
||||||
__linux__=1 \
|
__linux__=1 \
|
||||||
|
FMT_ENABLE_IF(...)= \
|
||||||
FMT_USE_VARIADIC_TEMPLATES=1 \
|
FMT_USE_VARIADIC_TEMPLATES=1 \
|
||||||
FMT_USE_RVALUE_REFERENCES=1 \
|
FMT_USE_RVALUE_REFERENCES=1 \
|
||||||
FMT_USE_USER_DEFINED_LITERALS=1 \
|
FMT_USE_USER_DEFINED_LITERALS=1 \
|
||||||
FMT_USE_ALIAS_TEMPLATES=1 \
|
FMT_USE_ALIAS_TEMPLATES=1 \
|
||||||
|
FMT_USE_NONTYPE_TEMPLATE_PARAMETERS=1 \
|
||||||
FMT_API= \
|
FMT_API= \
|
||||||
"FMT_BEGIN_NAMESPACE=namespace fmt {{" \
|
"FMT_BEGIN_NAMESPACE=namespace fmt {{" \
|
||||||
"FMT_END_NAMESPACE=}}" \
|
"FMT_END_NAMESPACE=}}" \
|
||||||
|
2
vendor/Fmt/doc/index.rst
vendored
2
vendor/Fmt/doc/index.rst
vendored
@ -101,7 +101,7 @@ The code
|
|||||||
format(FMT_STRING("The answer is {:d}"), "forty-two");
|
format(FMT_STRING("The answer is {:d}"), "forty-two");
|
||||||
|
|
||||||
reports a compile-time error on compilers that support relaxed ``constexpr``.
|
reports a compile-time error on compilers that support relaxed ``constexpr``.
|
||||||
See `here <api.html#c.fmt>`_ for details.
|
See `here <api.html#compile-time-format-string-checks>`_ for details.
|
||||||
|
|
||||||
The following code
|
The following code
|
||||||
|
|
||||||
|
54
vendor/Fmt/doc/syntax.rst
vendored
54
vendor/Fmt/doc/syntax.rst
vendored
@ -112,18 +112,18 @@ meaning in this case.
|
|||||||
The *sign* option is only valid for number types, and can be one of the
|
The *sign* option is only valid for number types, and can be one of the
|
||||||
following:
|
following:
|
||||||
|
|
||||||
+---------+----------------------------------------------------------+
|
+---------+------------------------------------------------------------+
|
||||||
| Option | Meaning |
|
| Option | Meaning |
|
||||||
+=========+==========================================================+
|
+=========+============================================================+
|
||||||
| ``'+'`` | indicates that a sign should be used for both |
|
| ``'+'`` | indicates that a sign should be used for both |
|
||||||
| | positive as well as negative numbers. |
|
| | nonnegative as well as negative numbers. |
|
||||||
+---------+----------------------------------------------------------+
|
+---------+------------------------------------------------------------+
|
||||||
| ``'-'`` | indicates that a sign should be used only for negative |
|
| ``'-'`` | indicates that a sign should be used only for negative |
|
||||||
| | numbers (this is the default behavior). |
|
| | numbers (this is the default behavior). |
|
||||||
+---------+----------------------------------------------------------+
|
+---------+------------------------------------------------------------+
|
||||||
| space | indicates that a leading space should be used on |
|
| space | indicates that a leading space should be used on |
|
||||||
| | positive numbers, and a minus sign on negative numbers. |
|
| | nonnegative numbers, and a minus sign on negative numbers. |
|
||||||
+---------+----------------------------------------------------------+
|
+---------+------------------------------------------------------------+
|
||||||
|
|
||||||
The ``'#'`` option causes the "alternate form" to be used for the
|
The ``'#'`` option causes the "alternate form" to be used for the
|
||||||
conversion. The alternate form is defined differently for different
|
conversion. The alternate form is defined differently for different
|
||||||
@ -161,7 +161,8 @@ displayed after the decimal point for a floating-point value formatted with
|
|||||||
value formatted with ``'g'`` or ``'G'``. For non-number types the field
|
value formatted with ``'g'`` or ``'G'``. For non-number types the field
|
||||||
indicates the maximum field size - in other words, how many characters will be
|
indicates the maximum field size - in other words, how many characters will be
|
||||||
used from the field content. The *precision* is not allowed for integer,
|
used from the field content. The *precision* is not allowed for integer,
|
||||||
character, Boolean, and pointer values.
|
character, Boolean, and pointer values. Note that a C string must be
|
||||||
|
null-terminated even if precision is specified.
|
||||||
|
|
||||||
The ``'L'`` option uses the current locale setting to insert the appropriate
|
The ``'L'`` option uses the current locale setting to insert the appropriate
|
||||||
number separator characters. This option is only valid for numeric types.
|
number separator characters. This option is only valid for numeric types.
|
||||||
@ -303,7 +304,8 @@ The available presentation types for pointers are:
|
|||||||
Chrono Format Specifications
|
Chrono Format Specifications
|
||||||
============================
|
============================
|
||||||
|
|
||||||
Format specifications for chrono types have the following syntax:
|
Format specifications for chrono types and ``std::tm`` have the following
|
||||||
|
syntax:
|
||||||
|
|
||||||
.. productionlist:: sf
|
.. productionlist:: sf
|
||||||
chrono_format_spec: [[`fill`]`align`][`width`]["." `precision`][`chrono_specs`]
|
chrono_format_spec: [[`fill`]`align`][`width`]["." `precision`][`chrono_specs`]
|
||||||
@ -347,9 +349,35 @@ points are:
|
|||||||
Specifiers that have a calendaric component such as `'d'` (the day of month)
|
Specifiers that have a calendaric component such as `'d'` (the day of month)
|
||||||
are valid only for ``std::tm`` and not durations or time points.
|
are valid only for ``std::tm`` and not durations or time points.
|
||||||
|
|
||||||
``std::tm`` uses the system's `strftime
|
.. range-specs:
|
||||||
<https://en.cppreference.com/w/cpp/chrono/c/strftime>`_ so refer to its
|
|
||||||
documentation for details on supported conversion specifiers.
|
Range Format Specifications
|
||||||
|
===========================
|
||||||
|
|
||||||
|
Format specifications for range types have the following syntax:
|
||||||
|
|
||||||
|
..productionlist:: sf
|
||||||
|
range_format_spec: [":" [`underlying_spec`]]
|
||||||
|
|
||||||
|
The `underlying_spec` is parsed based on the formatter of the range's
|
||||||
|
reference type.
|
||||||
|
|
||||||
|
By default, a range of characters or strings is printed escaped and quoted. But
|
||||||
|
if any `underlying_spec` is provided (even if it is empty), then the characters
|
||||||
|
or strings are printed according to the provided specification.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
fmt::format("{}", std::vector{10, 20, 30});
|
||||||
|
// Result: [10, 20, 30]
|
||||||
|
fmt::format("{::#x}", std::vector{10, 20, 30});
|
||||||
|
// Result: [0xa, 0x14, 0x13]
|
||||||
|
fmt::format("{}", vector{'h', 'e', 'l', 'l', 'o'});
|
||||||
|
// Result: ['h', 'e', 'l', 'l', 'o']
|
||||||
|
fmt::format("{::}", vector{'h', 'e', 'l', 'l', 'o'});
|
||||||
|
// Result: [h, e, l, l, o]
|
||||||
|
fmt::format("{::d}", vector{'h', 'e', 'l', 'l', 'o'});
|
||||||
|
// Result: [104, 101, 108, 108, 111]
|
||||||
|
|
||||||
.. _formatexamples:
|
.. _formatexamples:
|
||||||
|
|
||||||
@ -449,7 +477,7 @@ Using type-specific formatting::
|
|||||||
|
|
||||||
Using the comma as a thousands separator::
|
Using the comma as a thousands separator::
|
||||||
|
|
||||||
#include <fmt/locale.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
auto s = fmt::format(std::locale("en_US.UTF-8"), "{:L}", 1234567890);
|
auto s = fmt::format(std::locale("en_US.UTF-8"), "{:L}", 1234567890);
|
||||||
// s == "1,234,567,890"
|
// s == "1,234,567,890"
|
||||||
|
14
vendor/Fmt/include/fmt/args.h
vendored
14
vendor/Fmt/include/fmt/args.h
vendored
@ -95,8 +95,8 @@ class dynamic_format_arg_store
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using stored_type = conditional_t<detail::is_string<T>::value &&
|
using stored_type = conditional_t<
|
||||||
!has_formatter<T, Context>::value &&
|
std::is_convertible<T, std::basic_string<char_type>>::value &&
|
||||||
!detail::is_reference_wrapper<T>::value,
|
!detail::is_reference_wrapper<T>::value,
|
||||||
std::basic_string<char_type>, T>;
|
std::basic_string<char_type>, T>;
|
||||||
|
|
||||||
@ -145,16 +145,6 @@ class dynamic_format_arg_store
|
|||||||
public:
|
public:
|
||||||
constexpr dynamic_format_arg_store() = default;
|
constexpr dynamic_format_arg_store() = default;
|
||||||
|
|
||||||
constexpr dynamic_format_arg_store(
|
|
||||||
const dynamic_format_arg_store<Context>& store)
|
|
||||||
:
|
|
||||||
#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
|
|
||||||
basic_format_args<Context>(),
|
|
||||||
#endif
|
|
||||||
data_(store.data_),
|
|
||||||
named_info_(store.named_info_) {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
Adds an argument into the dynamic store for later passing to a formatting
|
Adds an argument into the dynamic store for later passing to a formatting
|
||||||
|
1183
vendor/Fmt/include/fmt/chrono.h
vendored
1183
vendor/Fmt/include/fmt/chrono.h
vendored
File diff suppressed because it is too large
Load Diff
160
vendor/Fmt/include/fmt/color.h
vendored
160
vendor/Fmt/include/fmt/color.h
vendored
@ -214,17 +214,16 @@ FMT_BEGIN_DETAIL_NAMESPACE
|
|||||||
|
|
||||||
// color is a struct of either a rgb color or a terminal color.
|
// color is a struct of either a rgb color or a terminal color.
|
||||||
struct color_type {
|
struct color_type {
|
||||||
FMT_CONSTEXPR color_type() FMT_NOEXCEPT : is_rgb(), value{} {}
|
FMT_CONSTEXPR color_type() noexcept : is_rgb(), value{} {}
|
||||||
FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT : is_rgb(true),
|
FMT_CONSTEXPR color_type(color rgb_color) noexcept : is_rgb(true), value{} {
|
||||||
value{} {
|
|
||||||
value.rgb_color = static_cast<uint32_t>(rgb_color);
|
value.rgb_color = static_cast<uint32_t>(rgb_color);
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT : is_rgb(true), value{} {
|
FMT_CONSTEXPR color_type(rgb rgb_color) noexcept : is_rgb(true), value{} {
|
||||||
value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16) |
|
value.rgb_color = (static_cast<uint32_t>(rgb_color.r) << 16) |
|
||||||
(static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b;
|
(static_cast<uint32_t>(rgb_color.g) << 8) | rgb_color.b;
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT : is_rgb(),
|
FMT_CONSTEXPR color_type(terminal_color term_color) noexcept
|
||||||
value{} {
|
: is_rgb(), value{} {
|
||||||
value.term_color = static_cast<uint8_t>(term_color);
|
value.term_color = static_cast<uint8_t>(term_color);
|
||||||
}
|
}
|
||||||
bool is_rgb;
|
bool is_rgb;
|
||||||
@ -239,10 +238,8 @@ FMT_END_DETAIL_NAMESPACE
|
|||||||
/** A text style consisting of foreground and background colors and emphasis. */
|
/** A text style consisting of foreground and background colors and emphasis. */
|
||||||
class text_style {
|
class text_style {
|
||||||
public:
|
public:
|
||||||
FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT
|
FMT_CONSTEXPR text_style(emphasis em = emphasis()) noexcept
|
||||||
: set_foreground_color(),
|
: set_foreground_color(), set_background_color(), ems(em) {}
|
||||||
set_background_color(),
|
|
||||||
ems(em) {}
|
|
||||||
|
|
||||||
FMT_CONSTEXPR text_style& operator|=(const text_style& rhs) {
|
FMT_CONSTEXPR text_style& operator|=(const text_style& rhs) {
|
||||||
if (!set_foreground_color) {
|
if (!set_foreground_color) {
|
||||||
@ -283,34 +280,32 @@ class text_style {
|
|||||||
return lhs.and_assign(rhs);
|
return lhs.and_assign(rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR bool has_foreground() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR bool has_foreground() const noexcept {
|
||||||
return set_foreground_color;
|
return set_foreground_color;
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR bool has_background() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR bool has_background() const noexcept {
|
||||||
return set_background_color;
|
return set_background_color;
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR bool has_emphasis() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR bool has_emphasis() const noexcept {
|
||||||
return static_cast<uint8_t>(ems) != 0;
|
return static_cast<uint8_t>(ems) != 0;
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR detail::color_type get_foreground() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR detail::color_type get_foreground() const noexcept {
|
||||||
FMT_ASSERT(has_foreground(), "no foreground specified for this style");
|
FMT_ASSERT(has_foreground(), "no foreground specified for this style");
|
||||||
return foreground_color;
|
return foreground_color;
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR detail::color_type get_background() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR detail::color_type get_background() const noexcept {
|
||||||
FMT_ASSERT(has_background(), "no background specified for this style");
|
FMT_ASSERT(has_background(), "no background specified for this style");
|
||||||
return background_color;
|
return background_color;
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR emphasis get_emphasis() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR emphasis get_emphasis() const noexcept {
|
||||||
FMT_ASSERT(has_emphasis(), "no emphasis specified for this style");
|
FMT_ASSERT(has_emphasis(), "no emphasis specified for this style");
|
||||||
return ems;
|
return ems;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FMT_CONSTEXPR text_style(bool is_foreground,
|
FMT_CONSTEXPR text_style(bool is_foreground,
|
||||||
detail::color_type text_color) FMT_NOEXCEPT
|
detail::color_type text_color) noexcept
|
||||||
: set_foreground_color(),
|
: set_foreground_color(), set_background_color(), ems() {
|
||||||
set_background_color(),
|
|
||||||
ems() {
|
|
||||||
if (is_foreground) {
|
if (is_foreground) {
|
||||||
foreground_color = text_color;
|
foreground_color = text_color;
|
||||||
set_foreground_color = true;
|
set_foreground_color = true;
|
||||||
@ -345,11 +340,11 @@ class text_style {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend FMT_CONSTEXPR_DECL text_style fg(detail::color_type foreground)
|
friend FMT_CONSTEXPR_DECL text_style
|
||||||
FMT_NOEXCEPT;
|
fg(detail::color_type foreground) noexcept;
|
||||||
|
|
||||||
friend FMT_CONSTEXPR_DECL text_style bg(detail::color_type background)
|
friend FMT_CONSTEXPR_DECL text_style
|
||||||
FMT_NOEXCEPT;
|
bg(detail::color_type background) noexcept;
|
||||||
|
|
||||||
detail::color_type foreground_color;
|
detail::color_type foreground_color;
|
||||||
detail::color_type background_color;
|
detail::color_type background_color;
|
||||||
@ -359,17 +354,16 @@ class text_style {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/** Creates a text style from the foreground (text) color. */
|
/** Creates a text style from the foreground (text) color. */
|
||||||
FMT_CONSTEXPR inline text_style fg(detail::color_type foreground) FMT_NOEXCEPT {
|
FMT_CONSTEXPR inline text_style fg(detail::color_type foreground) noexcept {
|
||||||
return text_style(true, foreground);
|
return text_style(true, foreground);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Creates a text style from the background color. */
|
/** Creates a text style from the background color. */
|
||||||
FMT_CONSTEXPR inline text_style bg(detail::color_type background) FMT_NOEXCEPT {
|
FMT_CONSTEXPR inline text_style bg(detail::color_type background) noexcept {
|
||||||
return text_style(false, background);
|
return text_style(false, background);
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_CONSTEXPR inline text_style operator|(emphasis lhs,
|
FMT_CONSTEXPR inline text_style operator|(emphasis lhs, emphasis rhs) noexcept {
|
||||||
emphasis rhs) FMT_NOEXCEPT {
|
|
||||||
return text_style(lhs) | rhs;
|
return text_style(lhs) | rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -377,7 +371,7 @@ FMT_BEGIN_DETAIL_NAMESPACE
|
|||||||
|
|
||||||
template <typename Char> struct ansi_color_escape {
|
template <typename Char> struct ansi_color_escape {
|
||||||
FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color,
|
FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color,
|
||||||
const char* esc) FMT_NOEXCEPT {
|
const char* esc) noexcept {
|
||||||
// If we have a terminal color, we need to output another escape code
|
// If we have a terminal color, we need to output another escape code
|
||||||
// sequence.
|
// sequence.
|
||||||
if (!text_color.is_rgb) {
|
if (!text_color.is_rgb) {
|
||||||
@ -412,7 +406,7 @@ template <typename Char> struct ansi_color_escape {
|
|||||||
to_esc(color.b, buffer + 15, 'm');
|
to_esc(color.b, buffer + 15, 'm');
|
||||||
buffer[19] = static_cast<Char>(0);
|
buffer[19] = static_cast<Char>(0);
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT {
|
FMT_CONSTEXPR ansi_color_escape(emphasis em) noexcept {
|
||||||
uint8_t em_codes[num_emphases] = {};
|
uint8_t em_codes[num_emphases] = {};
|
||||||
if (has_emphasis(em, emphasis::bold)) em_codes[0] = 1;
|
if (has_emphasis(em, emphasis::bold)) em_codes[0] = 1;
|
||||||
if (has_emphasis(em, emphasis::faint)) em_codes[1] = 2;
|
if (has_emphasis(em, emphasis::faint)) em_codes[1] = 2;
|
||||||
@ -433,10 +427,10 @@ template <typename Char> struct ansi_color_escape {
|
|||||||
}
|
}
|
||||||
buffer[index++] = static_cast<Char>(0);
|
buffer[index++] = static_cast<Char>(0);
|
||||||
}
|
}
|
||||||
FMT_CONSTEXPR operator const Char*() const FMT_NOEXCEPT { return buffer; }
|
FMT_CONSTEXPR operator const Char*() const noexcept { return buffer; }
|
||||||
|
|
||||||
FMT_CONSTEXPR const Char* begin() const FMT_NOEXCEPT { return buffer; }
|
FMT_CONSTEXPR const Char* begin() const noexcept { return buffer; }
|
||||||
FMT_CONSTEXPR_CHAR_TRAITS const Char* end() const FMT_NOEXCEPT {
|
FMT_CONSTEXPR_CHAR_TRAITS const Char* end() const noexcept {
|
||||||
return buffer + std::char_traits<Char>::length(buffer);
|
return buffer + std::char_traits<Char>::length(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,59 +439,64 @@ template <typename Char> struct ansi_color_escape {
|
|||||||
Char buffer[7u + 3u * num_emphases + 1u];
|
Char buffer[7u + 3u * num_emphases + 1u];
|
||||||
|
|
||||||
static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out,
|
static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out,
|
||||||
char delimiter) FMT_NOEXCEPT {
|
char delimiter) noexcept {
|
||||||
out[0] = static_cast<Char>('0' + c / 100);
|
out[0] = static_cast<Char>('0' + c / 100);
|
||||||
out[1] = static_cast<Char>('0' + c / 10 % 10);
|
out[1] = static_cast<Char>('0' + c / 10 % 10);
|
||||||
out[2] = static_cast<Char>('0' + c % 10);
|
out[2] = static_cast<Char>('0' + c % 10);
|
||||||
out[3] = static_cast<Char>(delimiter);
|
out[3] = static_cast<Char>(delimiter);
|
||||||
}
|
}
|
||||||
static FMT_CONSTEXPR bool has_emphasis(emphasis em,
|
static FMT_CONSTEXPR bool has_emphasis(emphasis em, emphasis mask) noexcept {
|
||||||
emphasis mask) FMT_NOEXCEPT {
|
|
||||||
return static_cast<uint8_t>(em) & static_cast<uint8_t>(mask);
|
return static_cast<uint8_t>(em) & static_cast<uint8_t>(mask);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
FMT_CONSTEXPR ansi_color_escape<Char> make_foreground_color(
|
FMT_CONSTEXPR ansi_color_escape<Char> make_foreground_color(
|
||||||
detail::color_type foreground) FMT_NOEXCEPT {
|
detail::color_type foreground) noexcept {
|
||||||
return ansi_color_escape<Char>(foreground, "\x1b[38;2;");
|
return ansi_color_escape<Char>(foreground, "\x1b[38;2;");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
FMT_CONSTEXPR ansi_color_escape<Char> make_background_color(
|
FMT_CONSTEXPR ansi_color_escape<Char> make_background_color(
|
||||||
detail::color_type background) FMT_NOEXCEPT {
|
detail::color_type background) noexcept {
|
||||||
return ansi_color_escape<Char>(background, "\x1b[48;2;");
|
return ansi_color_escape<Char>(background, "\x1b[48;2;");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
FMT_CONSTEXPR ansi_color_escape<Char> make_emphasis(emphasis em) FMT_NOEXCEPT {
|
FMT_CONSTEXPR ansi_color_escape<Char> make_emphasis(emphasis em) noexcept {
|
||||||
return ansi_color_escape<Char>(em);
|
return ansi_color_escape<Char>(em);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char> inline void fputs(const Char* chars, FILE* stream) {
|
||||||
inline void fputs(const Char* chars, FILE* stream) FMT_NOEXCEPT {
|
int result = std::fputs(chars, stream);
|
||||||
std::fputs(chars, stream);
|
if (result < 0)
|
||||||
|
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
template <> inline void fputs<wchar_t>(const wchar_t* chars, FILE* stream) {
|
||||||
inline void fputs<wchar_t>(const wchar_t* chars, FILE* stream) FMT_NOEXCEPT {
|
int result = std::fputws(chars, stream);
|
||||||
std::fputws(chars, stream);
|
if (result < 0)
|
||||||
|
FMT_THROW(system_error(errno, FMT_STRING("cannot write to file")));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char> inline void reset_color(FILE* stream) FMT_NOEXCEPT {
|
template <typename Char> inline void reset_color(FILE* stream) {
|
||||||
fputs("\x1b[0m", stream);
|
fputs("\x1b[0m", stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <> inline void reset_color<wchar_t>(FILE* stream) FMT_NOEXCEPT {
|
template <> inline void reset_color<wchar_t>(FILE* stream) {
|
||||||
fputs(L"\x1b[0m", stream);
|
fputs(L"\x1b[0m", stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char> inline void reset_color(buffer<Char>& buffer) {
|
||||||
inline void reset_color(buffer<Char>& buffer) FMT_NOEXCEPT {
|
|
||||||
auto reset_color = string_view("\x1b[0m");
|
auto reset_color = string_view("\x1b[0m");
|
||||||
buffer.append(reset_color.begin(), reset_color.end());
|
buffer.append(reset_color.begin(), reset_color.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T> struct styled_arg {
|
||||||
|
const T& value;
|
||||||
|
text_style style;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
void vformat_to(buffer<Char>& buf, const text_style& ts,
|
void vformat_to(buffer<Char>& buf, const text_style& ts,
|
||||||
basic_string_view<Char> format_str,
|
basic_string_view<Char> format_str,
|
||||||
@ -529,9 +528,13 @@ void vprint(std::FILE* f, const text_style& ts, const S& format,
|
|||||||
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
basic_memory_buffer<Char> buf;
|
basic_memory_buffer<Char> buf;
|
||||||
detail::vformat_to(buf, ts, to_string_view(format), args);
|
detail::vformat_to(buf, ts, to_string_view(format), args);
|
||||||
|
if (detail::is_utf8()) {
|
||||||
|
detail::print(f, basic_string_view<Char>(buf.begin(), buf.size()));
|
||||||
|
} else {
|
||||||
buf.push_back(Char(0));
|
buf.push_back(Char(0));
|
||||||
detail::fputs(buf.data(), f);
|
detail::fputs(buf.data(), f);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
@ -549,7 +552,7 @@ template <typename S, typename... Args,
|
|||||||
void print(std::FILE* f, const text_style& ts, const S& format_str,
|
void print(std::FILE* f, const text_style& ts, const S& format_str,
|
||||||
const Args&... args) {
|
const Args&... args) {
|
||||||
vprint(f, ts, format_str,
|
vprint(f, ts, format_str,
|
||||||
fmt::make_args_checked<Args...>(format_str, args...));
|
fmt::make_format_args<buffer_context<char_t<S>>>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -594,7 +597,7 @@ template <typename S, typename... Args, typename Char = char_t<S>>
|
|||||||
inline std::basic_string<Char> format(const text_style& ts, const S& format_str,
|
inline std::basic_string<Char> format(const text_style& ts, const S& format_str,
|
||||||
const Args&... args) {
|
const Args&... args) {
|
||||||
return fmt::vformat(ts, to_string_view(format_str),
|
return fmt::vformat(ts, to_string_view(format_str),
|
||||||
fmt::make_args_checked<Args...>(format_str, args...));
|
fmt::make_format_args<buffer_context<Char>>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -629,7 +632,60 @@ inline auto format_to(OutputIt out, const text_style& ts, const S& format_str,
|
|||||||
Args&&... args) ->
|
Args&&... args) ->
|
||||||
typename std::enable_if<enable, OutputIt>::type {
|
typename std::enable_if<enable, OutputIt>::type {
|
||||||
return vformat_to(out, ts, to_string_view(format_str),
|
return vformat_to(out, ts, to_string_view(format_str),
|
||||||
fmt::make_args_checked<Args...>(format_str, args...));
|
fmt::make_format_args<buffer_context<char_t<S>>>(args...));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename Char>
|
||||||
|
struct formatter<detail::styled_arg<T>, Char> : formatter<T, Char> {
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(const detail::styled_arg<T>& arg, FormatContext& ctx) const
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
const auto& ts = arg.style;
|
||||||
|
const auto& value = arg.value;
|
||||||
|
auto out = ctx.out();
|
||||||
|
|
||||||
|
bool has_style = false;
|
||||||
|
if (ts.has_emphasis()) {
|
||||||
|
has_style = true;
|
||||||
|
auto emphasis = detail::make_emphasis<Char>(ts.get_emphasis());
|
||||||
|
out = std::copy(emphasis.begin(), emphasis.end(), out);
|
||||||
|
}
|
||||||
|
if (ts.has_foreground()) {
|
||||||
|
has_style = true;
|
||||||
|
auto foreground =
|
||||||
|
detail::make_foreground_color<Char>(ts.get_foreground());
|
||||||
|
out = std::copy(foreground.begin(), foreground.end(), out);
|
||||||
|
}
|
||||||
|
if (ts.has_background()) {
|
||||||
|
has_style = true;
|
||||||
|
auto background =
|
||||||
|
detail::make_background_color<Char>(ts.get_background());
|
||||||
|
out = std::copy(background.begin(), background.end(), out);
|
||||||
|
}
|
||||||
|
out = formatter<T, Char>::format(value, ctx);
|
||||||
|
if (has_style) {
|
||||||
|
auto reset_color = string_view("\x1b[0m");
|
||||||
|
out = std::copy(reset_color.begin(), reset_color.end(), out);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
Returns an argument that will be formatted using ANSI escape sequences,
|
||||||
|
to be used in a formatting function.
|
||||||
|
|
||||||
|
**Example**::
|
||||||
|
|
||||||
|
fmt::print("Elapsed time: {s:.2f} seconds",
|
||||||
|
fmt::styled(1.23, fmt::fg(fmt::colors::green) | fmt::bg(fmt::color::blue)));
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
FMT_CONSTEXPR auto styled(const T& value, text_style ts)
|
||||||
|
-> detail::styled_arg<remove_cvref_t<T>> {
|
||||||
|
return detail::styled_arg<remove_cvref_t<T>>{value, ts};
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_MODULE_EXPORT_END
|
FMT_MODULE_EXPORT_END
|
||||||
|
90
vendor/Fmt/include/fmt/compile.h
vendored
90
vendor/Fmt/include/fmt/compile.h
vendored
@ -13,45 +13,6 @@
|
|||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
// An output iterator that counts the number of objects written to it and
|
|
||||||
// discards them.
|
|
||||||
class counting_iterator {
|
|
||||||
private:
|
|
||||||
size_t count_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
using iterator_category = std::output_iterator_tag;
|
|
||||||
using difference_type = std::ptrdiff_t;
|
|
||||||
using pointer = void;
|
|
||||||
using reference = void;
|
|
||||||
using _Unchecked_type = counting_iterator; // Mark iterator as checked.
|
|
||||||
|
|
||||||
struct value_type {
|
|
||||||
template <typename T> void operator=(const T&) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
counting_iterator() : count_(0) {}
|
|
||||||
|
|
||||||
size_t count() const { return count_; }
|
|
||||||
|
|
||||||
counting_iterator& operator++() {
|
|
||||||
++count_;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
counting_iterator operator++(int) {
|
|
||||||
auto it = *this;
|
|
||||||
++*this;
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
friend counting_iterator operator+(counting_iterator it, difference_type n) {
|
|
||||||
it.count_ += static_cast<size_t>(n);
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
value_type operator*() const { return {}; }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Char, typename InputIt>
|
template <typename Char, typename InputIt>
|
||||||
inline counting_iterator copy_str(InputIt begin, InputIt end,
|
inline counting_iterator copy_str(InputIt begin, InputIt end,
|
||||||
counting_iterator it) {
|
counting_iterator it) {
|
||||||
@ -156,7 +117,7 @@ struct is_compiled_string : std::is_base_of<compiled_string, S> {};
|
|||||||
std::string s = fmt::format(FMT_COMPILE("{}"), 42);
|
std::string s = fmt::format(FMT_COMPILE("{}"), 42);
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
#ifdef __cpp_if_constexpr
|
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||||
# define FMT_COMPILE(s) \
|
# define FMT_COMPILE(s) \
|
||||||
FMT_STRING_IMPL(s, fmt::detail::compiled_string, explicit)
|
FMT_STRING_IMPL(s, fmt::detail::compiled_string, explicit)
|
||||||
#else
|
#else
|
||||||
@ -168,7 +129,7 @@ template <typename Char, size_t N,
|
|||||||
fmt::detail_exported::fixed_string<Char, N> Str>
|
fmt::detail_exported::fixed_string<Char, N> Str>
|
||||||
struct udl_compiled_string : compiled_string {
|
struct udl_compiled_string : compiled_string {
|
||||||
using char_type = Char;
|
using char_type = Char;
|
||||||
constexpr operator basic_string_view<char_type>() const {
|
explicit constexpr operator basic_string_view<char_type>() const {
|
||||||
return {Str.data, N - 1};
|
return {Str.data, N - 1};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -179,7 +140,7 @@ const T& first(const T& value, const Tail&...) {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cpp_if_constexpr
|
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||||
template <typename... Args> struct type_list {};
|
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...].
|
||||||
@ -190,7 +151,7 @@ constexpr const auto& get([[maybe_unused]] const T& first,
|
|||||||
if constexpr (N == 0)
|
if constexpr (N == 0)
|
||||||
return first;
|
return first;
|
||||||
else
|
else
|
||||||
return get<N - 1>(rest...);
|
return detail::get<N - 1>(rest...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename... Args>
|
template <typename Char, typename... Args>
|
||||||
@ -202,7 +163,8 @@ constexpr int get_arg_index_by_name(basic_string_view<Char> name,
|
|||||||
template <int N, typename> struct get_type_impl;
|
template <int N, typename> struct get_type_impl;
|
||||||
|
|
||||||
template <int N, typename... Args> struct get_type_impl<N, type_list<Args...>> {
|
template <int N, typename... Args> struct get_type_impl<N, type_list<Args...>> {
|
||||||
using type = remove_cvref_t<decltype(get<N>(std::declval<Args>()...))>;
|
using type =
|
||||||
|
remove_cvref_t<decltype(detail::get<N>(std::declval<Args>()...))>;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <int N, typename T>
|
template <int N, typename T>
|
||||||
@ -242,7 +204,7 @@ template <typename Char> struct code_unit {
|
|||||||
// This ensures that the argument type is convertible to `const T&`.
|
// This ensures that the argument type is convertible to `const T&`.
|
||||||
template <typename T, int N, typename... Args>
|
template <typename T, int N, typename... Args>
|
||||||
constexpr const T& get_arg_checked(const Args&... args) {
|
constexpr const T& get_arg_checked(const Args&... args) {
|
||||||
const auto& arg = get<N>(args...);
|
const auto& arg = detail::get<N>(args...);
|
||||||
if constexpr (detail::is_named_arg<remove_cvref_t<decltype(arg)>>()) {
|
if constexpr (detail::is_named_arg<remove_cvref_t<decltype(arg)>>()) {
|
||||||
return arg.value;
|
return arg.value;
|
||||||
} else {
|
} else {
|
||||||
@ -399,7 +361,9 @@ template <typename Char> struct arg_id_handler {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void on_error(const char* message) { FMT_THROW(format_error(message)); }
|
constexpr void on_error(const char* message) {
|
||||||
|
FMT_THROW(format_error(message));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Char> struct parse_arg_id_result {
|
template <typename Char> struct parse_arg_id_result {
|
||||||
@ -527,12 +491,12 @@ constexpr auto compile(S format_str) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // __cpp_if_constexpr
|
#endif // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
FMT_MODULE_EXPORT_BEGIN
|
FMT_MODULE_EXPORT_BEGIN
|
||||||
|
|
||||||
#ifdef __cpp_if_constexpr
|
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||||
|
|
||||||
template <typename CompiledFormat, typename... Args,
|
template <typename CompiledFormat, typename... Args,
|
||||||
typename Char = typename CompiledFormat::char_type,
|
typename Char = typename CompiledFormat::char_type,
|
||||||
@ -570,10 +534,11 @@ FMT_INLINE std::basic_string<typename S::char_type> format(const S&,
|
|||||||
constexpr auto compiled = detail::compile<Args...>(S());
|
constexpr auto compiled = detail::compile<Args...>(S());
|
||||||
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
|
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
|
||||||
detail::unknown_format>()) {
|
detail::unknown_format>()) {
|
||||||
return format(static_cast<basic_string_view<typename S::char_type>>(S()),
|
return fmt::format(
|
||||||
|
static_cast<basic_string_view<typename S::char_type>>(S()),
|
||||||
std::forward<Args>(args)...);
|
std::forward<Args>(args)...);
|
||||||
} else {
|
} else {
|
||||||
return format(compiled, std::forward<Args>(args)...);
|
return fmt::format(compiled, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -583,11 +548,11 @@ FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) {
|
|||||||
constexpr auto compiled = detail::compile<Args...>(S());
|
constexpr auto compiled = detail::compile<Args...>(S());
|
||||||
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
|
if constexpr (std::is_same<remove_cvref_t<decltype(compiled)>,
|
||||||
detail::unknown_format>()) {
|
detail::unknown_format>()) {
|
||||||
return format_to(out,
|
return fmt::format_to(
|
||||||
static_cast<basic_string_view<typename S::char_type>>(S()),
|
out, static_cast<basic_string_view<typename S::char_type>>(S()),
|
||||||
std::forward<Args>(args)...);
|
std::forward<Args>(args)...);
|
||||||
} else {
|
} else {
|
||||||
return format_to(out, compiled, std::forward<Args>(args)...);
|
return fmt::format_to(out, compiled, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -596,22 +561,23 @@ template <typename OutputIt, typename S, typename... Args,
|
|||||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||||
format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n,
|
format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n,
|
||||||
const S& format_str, Args&&... args) {
|
const S& format_str, Args&&... args) {
|
||||||
auto it = format_to(detail::truncating_iterator<OutputIt>(out, n), format_str,
|
auto it = fmt::format_to(detail::truncating_iterator<OutputIt>(out, n),
|
||||||
std::forward<Args>(args)...);
|
format_str, std::forward<Args>(args)...);
|
||||||
return {it.base(), it.count()};
|
return {it.base(), it.count()};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S, typename... Args,
|
template <typename S, typename... Args,
|
||||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||||
size_t formatted_size(const S& format_str, const Args&... args) {
|
size_t formatted_size(const S& format_str, const Args&... args) {
|
||||||
return format_to(detail::counting_iterator(), format_str, args...).count();
|
return fmt::format_to(detail::counting_iterator(), format_str, args...)
|
||||||
|
.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S, typename... Args,
|
template <typename S, typename... Args,
|
||||||
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
|
||||||
void print(std::FILE* f, const S& format_str, const Args&... args) {
|
void print(std::FILE* f, const S& format_str, const Args&... args) {
|
||||||
memory_buffer buffer;
|
memory_buffer buffer;
|
||||||
format_to(std::back_inserter(buffer), format_str, args...);
|
fmt::format_to(std::back_inserter(buffer), format_str, args...);
|
||||||
detail::print(f, {buffer.data(), buffer.size()});
|
detail::print(f, {buffer.data(), buffer.size()});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -623,12 +589,10 @@ void print(const S& format_str, const Args&... args) {
|
|||||||
|
|
||||||
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
#if FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
||||||
inline namespace literals {
|
inline namespace literals {
|
||||||
template <detail_exported::fixed_string Str>
|
template <detail_exported::fixed_string Str> constexpr auto operator""_cf() {
|
||||||
constexpr detail::udl_compiled_string<
|
using char_t = remove_cvref_t<decltype(Str.data[0])>;
|
||||||
remove_cvref_t<decltype(Str.data[0])>,
|
return detail::udl_compiled_string<char_t, sizeof(Str.data) / sizeof(char_t),
|
||||||
sizeof(Str.data) / sizeof(decltype(Str.data[0])), Str>
|
Str>();
|
||||||
operator""_cf() {
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
} // namespace literals
|
} // namespace literals
|
||||||
#endif
|
#endif
|
||||||
|
826
vendor/Fmt/include/fmt/core.h
vendored
826
vendor/Fmt/include/fmt/core.h
vendored
File diff suppressed because it is too large
Load Diff
2108
vendor/Fmt/include/fmt/format-inl.h
vendored
2108
vendor/Fmt/include/fmt/format-inl.h
vendored
File diff suppressed because it is too large
Load Diff
1187
vendor/Fmt/include/fmt/format.h
vendored
1187
vendor/Fmt/include/fmt/format.h
vendored
File diff suppressed because it is too large
Load Diff
110
vendor/Fmt/include/fmt/os.h
vendored
110
vendor/Fmt/include/fmt/os.h
vendored
@ -9,10 +9,8 @@
|
|||||||
#define FMT_OS_H_
|
#define FMT_OS_H_
|
||||||
|
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <clocale> // locale_t
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib> // strtod_l
|
|
||||||
#include <system_error> // std::system_error
|
#include <system_error> // std::system_error
|
||||||
|
|
||||||
#if defined __APPLE__ || defined(__FreeBSD__)
|
#if defined __APPLE__ || defined(__FreeBSD__)
|
||||||
@ -21,18 +19,21 @@
|
|||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
|
||||||
|
#ifndef FMT_USE_FCNTL
|
||||||
// UWP doesn't provide _pipe.
|
// UWP doesn't provide _pipe.
|
||||||
# if FMT_HAS_INCLUDE("winapifamily.h")
|
# if FMT_HAS_INCLUDE("winapifamily.h")
|
||||||
# include <winapifamily.h>
|
# include <winapifamily.h>
|
||||||
# endif
|
# endif
|
||||||
# if (FMT_HAS_INCLUDE(<fcntl.h>) || defined(__APPLE__) || \
|
# if (FMT_HAS_INCLUDE(<fcntl.h>) || defined(__APPLE__) || \
|
||||||
defined(__linux__)) && \
|
defined(__linux__)) && \
|
||||||
(!defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
|
(!defined(WINAPI_FAMILY) || \
|
||||||
|
(WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
|
||||||
# include <fcntl.h> // for O_RDONLY
|
# include <fcntl.h> // for O_RDONLY
|
||||||
# define FMT_USE_FCNTL 1
|
# define FMT_USE_FCNTL 1
|
||||||
# else
|
# else
|
||||||
# define FMT_USE_FCNTL 0
|
# define FMT_USE_FCNTL 0
|
||||||
# endif
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef FMT_POSIX
|
#ifndef FMT_POSIX
|
||||||
# if defined(_WIN32) && !defined(__MINGW32__)
|
# if defined(_WIN32) && !defined(__MINGW32__)
|
||||||
@ -138,7 +139,7 @@ template <typename Char> struct formatter<std::error_code, Char> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
FMT_API const std::error_category& system_category() FMT_NOEXCEPT;
|
FMT_API const std::error_category& system_category() noexcept;
|
||||||
|
|
||||||
FMT_BEGIN_DETAIL_NAMESPACE
|
FMT_BEGIN_DETAIL_NAMESPACE
|
||||||
// A converter from UTF-16 to UTF-8.
|
// A converter from UTF-16 to UTF-8.
|
||||||
@ -162,7 +163,7 @@ class utf16_to_utf8 {
|
|||||||
};
|
};
|
||||||
|
|
||||||
FMT_API void format_windows_error(buffer<char>& out, int error_code,
|
FMT_API void format_windows_error(buffer<char>& out, int error_code,
|
||||||
const char* message) FMT_NOEXCEPT;
|
const char* message) noexcept;
|
||||||
FMT_END_DETAIL_NAMESPACE
|
FMT_END_DETAIL_NAMESPACE
|
||||||
|
|
||||||
FMT_API std::system_error vwindows_error(int error_code, string_view format_str,
|
FMT_API std::system_error vwindows_error(int error_code, string_view format_str,
|
||||||
@ -204,10 +205,9 @@ std::system_error windows_error(int error_code, string_view message,
|
|||||||
|
|
||||||
// Reports a Windows error without throwing an exception.
|
// Reports a Windows error without throwing an exception.
|
||||||
// Can be used to report errors from destructors.
|
// Can be used to report errors from destructors.
|
||||||
FMT_API void report_windows_error(int error_code,
|
FMT_API void report_windows_error(int error_code, const char* message) noexcept;
|
||||||
const char* message) FMT_NOEXCEPT;
|
|
||||||
#else
|
#else
|
||||||
inline const std::error_category& system_category() FMT_NOEXCEPT {
|
inline const std::error_category& system_category() noexcept {
|
||||||
return std::system_category();
|
return std::system_category();
|
||||||
}
|
}
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
@ -234,13 +234,13 @@ class buffered_file {
|
|||||||
void operator=(const buffered_file&) = delete;
|
void operator=(const buffered_file&) = delete;
|
||||||
|
|
||||||
// Constructs a buffered_file object which doesn't represent any file.
|
// Constructs a buffered_file object which doesn't represent any file.
|
||||||
buffered_file() FMT_NOEXCEPT : file_(nullptr) {}
|
buffered_file() noexcept : file_(nullptr) {}
|
||||||
|
|
||||||
// Destroys the object closing the file it represents if any.
|
// Destroys the object closing the file it represents if any.
|
||||||
FMT_API ~buffered_file() FMT_NOEXCEPT;
|
FMT_API ~buffered_file() noexcept;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
buffered_file(buffered_file&& other) FMT_NOEXCEPT : file_(other.file_) {
|
buffered_file(buffered_file&& other) noexcept : file_(other.file_) {
|
||||||
other.file_ = nullptr;
|
other.file_ = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,10 +258,11 @@ class buffered_file {
|
|||||||
FMT_API void close();
|
FMT_API void close();
|
||||||
|
|
||||||
// Returns the pointer to a FILE object representing this file.
|
// Returns the pointer to a FILE object representing this file.
|
||||||
FILE* get() const FMT_NOEXCEPT { return file_; }
|
FILE* get() const noexcept { return file_; }
|
||||||
|
|
||||||
// We place parentheses around fileno to workaround a bug in some versions
|
// We place parentheses around fileno to workaround a bug in some versions
|
||||||
// of MinGW that define fileno as a macro.
|
// of MinGW that define fileno as a macro.
|
||||||
|
// DEPRECATED! Rename to descriptor to avoid issues with macros.
|
||||||
FMT_API int(fileno)() const;
|
FMT_API int(fileno)() const;
|
||||||
|
|
||||||
void vprint(string_view format_str, format_args args) {
|
void vprint(string_view format_str, format_args args) {
|
||||||
@ -276,12 +277,12 @@ class buffered_file {
|
|||||||
|
|
||||||
#if FMT_USE_FCNTL
|
#if FMT_USE_FCNTL
|
||||||
// A file. Closed file is represented by a file object with descriptor -1.
|
// A file. Closed file is represented by a file object with descriptor -1.
|
||||||
// Methods that are not declared with FMT_NOEXCEPT may throw
|
// Methods that are not declared with noexcept may throw
|
||||||
// fmt::system_error in case of failure. Note that some errors such as
|
// fmt::system_error in case of failure. Note that some errors such as
|
||||||
// closing the file multiple times will cause a crash on Windows rather
|
// closing the file multiple times will cause a crash on Windows rather
|
||||||
// than an exception. You can get standard behavior by overriding the
|
// than an exception. You can get standard behavior by overriding the
|
||||||
// invalid parameter handler with _set_invalid_parameter_handler.
|
// invalid parameter handler with _set_invalid_parameter_handler.
|
||||||
class file {
|
class FMT_API file {
|
||||||
private:
|
private:
|
||||||
int fd_; // File descriptor.
|
int fd_; // File descriptor.
|
||||||
|
|
||||||
@ -300,16 +301,16 @@ class file {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Constructs a file object which doesn't represent any file.
|
// Constructs a file object which doesn't represent any file.
|
||||||
file() FMT_NOEXCEPT : fd_(-1) {}
|
file() noexcept : fd_(-1) {}
|
||||||
|
|
||||||
// Opens a file and constructs a file object representing this file.
|
// Opens a file and constructs a file object representing this file.
|
||||||
FMT_API file(cstring_view path, int oflag);
|
file(cstring_view path, int oflag);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
file(const file&) = delete;
|
file(const file&) = delete;
|
||||||
void operator=(const file&) = delete;
|
void operator=(const file&) = delete;
|
||||||
|
|
||||||
file(file&& other) FMT_NOEXCEPT : fd_(other.fd_) { other.fd_ = -1; }
|
file(file&& other) noexcept : fd_(other.fd_) { other.fd_ = -1; }
|
||||||
|
|
||||||
// Move assignment is not noexcept because close may throw.
|
// Move assignment is not noexcept because close may throw.
|
||||||
file& operator=(file&& other) {
|
file& operator=(file&& other) {
|
||||||
@ -320,43 +321,43 @@ class file {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Destroys the object closing the file it represents if any.
|
// Destroys the object closing the file it represents if any.
|
||||||
FMT_API ~file() FMT_NOEXCEPT;
|
~file() noexcept;
|
||||||
|
|
||||||
// Returns the file descriptor.
|
// Returns the file descriptor.
|
||||||
int descriptor() const FMT_NOEXCEPT { return fd_; }
|
int descriptor() const noexcept { return fd_; }
|
||||||
|
|
||||||
// Closes the file.
|
// Closes the file.
|
||||||
FMT_API void close();
|
void close();
|
||||||
|
|
||||||
// Returns the file size. The size has signed type for consistency with
|
// Returns the file size. The size has signed type for consistency with
|
||||||
// stat::st_size.
|
// stat::st_size.
|
||||||
FMT_API long long size() const;
|
long long size() const;
|
||||||
|
|
||||||
// Attempts to read count bytes from the file into the specified buffer.
|
// Attempts to read count bytes from the file into the specified buffer.
|
||||||
FMT_API size_t read(void* buffer, size_t count);
|
size_t read(void* buffer, size_t count);
|
||||||
|
|
||||||
// Attempts to write count bytes from the specified buffer to the file.
|
// Attempts to write count bytes from the specified buffer to the file.
|
||||||
FMT_API size_t write(const void* buffer, size_t count);
|
size_t write(const void* buffer, size_t count);
|
||||||
|
|
||||||
// Duplicates a file descriptor with the dup function and returns
|
// Duplicates a file descriptor with the dup function and returns
|
||||||
// the duplicate as a file object.
|
// the duplicate as a file object.
|
||||||
FMT_API static file dup(int fd);
|
static file dup(int fd);
|
||||||
|
|
||||||
// Makes fd be the copy of this file descriptor, closing fd first if
|
// Makes fd be the copy of this file descriptor, closing fd first if
|
||||||
// necessary.
|
// necessary.
|
||||||
FMT_API void dup2(int fd);
|
void dup2(int fd);
|
||||||
|
|
||||||
// Makes fd be the copy of this file descriptor, closing fd first if
|
// Makes fd be the copy of this file descriptor, closing fd first if
|
||||||
// necessary.
|
// necessary.
|
||||||
FMT_API void dup2(int fd, std::error_code& ec) FMT_NOEXCEPT;
|
void dup2(int fd, std::error_code& ec) noexcept;
|
||||||
|
|
||||||
// Creates a pipe setting up read_end and write_end file objects for reading
|
// Creates a pipe setting up read_end and write_end file objects for reading
|
||||||
// and writing respectively.
|
// and writing respectively.
|
||||||
FMT_API static void pipe(file& read_end, file& write_end);
|
static void pipe(file& read_end, file& write_end);
|
||||||
|
|
||||||
// Creates a buffered_file object associated with this file and detaches
|
// Creates a buffered_file object associated with this file and detaches
|
||||||
// this file object from the file.
|
// this file object from the file.
|
||||||
FMT_API buffered_file fdopen(const char* mode);
|
buffered_file fdopen(const char* mode);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns the memory page size.
|
// Returns the memory page size.
|
||||||
@ -390,6 +391,13 @@ struct ostream_params {
|
|||||||
: ostream_params(params...) {
|
: ostream_params(params...) {
|
||||||
this->buffer_size = bs.value;
|
this->buffer_size = bs.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Intel has a bug that results in failure to deduce a constructor
|
||||||
|
// for empty parameter packs.
|
||||||
|
# if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 2000
|
||||||
|
ostream_params(int new_oflag) : oflag(new_oflag) {}
|
||||||
|
ostream_params(detail::buffer_size bs) : buffer_size(bs.value) {}
|
||||||
|
# endif
|
||||||
};
|
};
|
||||||
|
|
||||||
FMT_END_DETAIL_NAMESPACE
|
FMT_END_DETAIL_NAMESPACE
|
||||||
@ -452,7 +460,7 @@ class FMT_API ostream final : private detail::buffer<char> {
|
|||||||
|
|
||||||
* ``<integer>``: Flags passed to `open
|
* ``<integer>``: Flags passed to `open
|
||||||
<https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html>`_
|
<https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html>`_
|
||||||
(``file::WRONLY | file::CREATE`` by default)
|
(``file::WRONLY | file::CREATE | file::TRUNC`` by default)
|
||||||
* ``buffer_size=<integer>``: Output buffer size
|
* ``buffer_size=<integer>``: Output buffer size
|
||||||
|
|
||||||
**Example**::
|
**Example**::
|
||||||
@ -467,50 +475,6 @@ inline ostream output_file(cstring_view path, T... params) {
|
|||||||
}
|
}
|
||||||
#endif // FMT_USE_FCNTL
|
#endif // FMT_USE_FCNTL
|
||||||
|
|
||||||
#ifdef FMT_LOCALE
|
|
||||||
// A "C" numeric locale.
|
|
||||||
class locale {
|
|
||||||
private:
|
|
||||||
# ifdef _WIN32
|
|
||||||
using locale_t = _locale_t;
|
|
||||||
|
|
||||||
static void freelocale(locale_t loc) { _free_locale(loc); }
|
|
||||||
|
|
||||||
static double strtod_l(const char* nptr, char** endptr, _locale_t loc) {
|
|
||||||
return _strtod_l(nptr, endptr, loc);
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
|
|
||||||
locale_t locale_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
using type = locale_t;
|
|
||||||
locale(const locale&) = delete;
|
|
||||||
void operator=(const locale&) = delete;
|
|
||||||
|
|
||||||
locale() {
|
|
||||||
# ifndef _WIN32
|
|
||||||
locale_ = FMT_SYSTEM(newlocale(LC_NUMERIC_MASK, "C", nullptr));
|
|
||||||
# else
|
|
||||||
locale_ = _create_locale(LC_NUMERIC, "C");
|
|
||||||
# endif
|
|
||||||
if (!locale_) FMT_THROW(system_error(errno, "cannot create locale"));
|
|
||||||
}
|
|
||||||
~locale() { freelocale(locale_); }
|
|
||||||
|
|
||||||
type get() const { return locale_; }
|
|
||||||
|
|
||||||
// Converts string to floating-point number and advances str past the end
|
|
||||||
// of the parsed input.
|
|
||||||
double strtod(const char*& str) const {
|
|
||||||
char* end = nullptr;
|
|
||||||
double result = strtod_l(str, &end, locale_);
|
|
||||||
str = end;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
using Locale FMT_DEPRECATED_ALIAS = locale;
|
|
||||||
#endif // FMT_LOCALE
|
|
||||||
FMT_MODULE_EXPORT_END
|
FMT_MODULE_EXPORT_END
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
134
vendor/Fmt/include/fmt/ostream.h
vendored
134
vendor/Fmt/include/fmt/ostream.h
vendored
@ -14,73 +14,20 @@
|
|||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
template <typename Char> class basic_printf_parse_context;
|
|
||||||
template <typename OutputIt, typename Char> class basic_printf_context;
|
template <typename OutputIt, typename Char> class basic_printf_context;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template <class Char> class formatbuf : public std::basic_streambuf<Char> {
|
// Checks if T has a user-defined operator<<.
|
||||||
private:
|
template <typename T, typename Char, typename Enable = void>
|
||||||
using int_type = typename std::basic_streambuf<Char>::int_type;
|
class is_streamable {
|
||||||
using traits_type = typename std::basic_streambuf<Char>::traits_type;
|
|
||||||
|
|
||||||
buffer<Char>& buffer_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
formatbuf(buffer<Char>& buf) : buffer_(buf) {}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// The put-area is actually always empty. This makes the implementation
|
|
||||||
// simpler and has the advantage that the streambuf and the buffer are always
|
|
||||||
// in sync and sputc never writes into uninitialized memory. The obvious
|
|
||||||
// disadvantage is that each call to sputc always results in a (virtual) call
|
|
||||||
// to overflow. There is no disadvantage here for sputn since this always
|
|
||||||
// results in a call to xsputn.
|
|
||||||
|
|
||||||
int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE {
|
|
||||||
if (!traits_type::eq_int_type(ch, traits_type::eof()))
|
|
||||||
buffer_.push_back(static_cast<Char>(ch));
|
|
||||||
return ch;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::streamsize xsputn(const Char* s, std::streamsize count) FMT_OVERRIDE {
|
|
||||||
buffer_.append(s, s + count);
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct converter {
|
|
||||||
template <typename T, FMT_ENABLE_IF(is_integral<T>::value)> converter(T);
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Char> struct test_stream : std::basic_ostream<Char> {
|
|
||||||
private:
|
|
||||||
void_t<> operator<<(converter);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 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
|
|
||||||
// std::ostream).
|
|
||||||
template <typename T, typename Char> class is_streamable {
|
|
||||||
private:
|
private:
|
||||||
template <typename U>
|
template <typename U>
|
||||||
static bool_constant<!std::is_same<decltype(std::declval<test_stream<Char>&>()
|
static auto test(int)
|
||||||
<< std::declval<U>()),
|
-> bool_constant<sizeof(std::declval<std::basic_ostream<Char>&>()
|
||||||
void_t<>>::value>
|
<< std::declval<U>()) != 0>;
|
||||||
test(int);
|
|
||||||
|
|
||||||
template <typename> static std::false_type test(...);
|
template <typename> static auto test(...) -> std::false_type;
|
||||||
|
|
||||||
using result = decltype(test<T>(0));
|
using result = decltype(test<T>(0));
|
||||||
|
|
||||||
@ -90,7 +37,21 @@ template <typename T, typename Char> class is_streamable {
|
|||||||
static const bool value = result::value;
|
static const bool value = result::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Formatting of built-in types and arrays is intentionally disabled because
|
||||||
|
// it's handled by standard (non-ostream) formatters.
|
||||||
|
template <typename T, typename Char>
|
||||||
|
struct is_streamable<
|
||||||
|
T, Char,
|
||||||
|
enable_if_t<
|
||||||
|
std::is_arithmetic<T>::value || std::is_array<T>::value ||
|
||||||
|
std::is_pointer<T>::value || std::is_same<T, char8_type>::value ||
|
||||||
|
std::is_convertible<T, fmt::basic_string_view<Char>>::value ||
|
||||||
|
std::is_same<T, std_string_view<Char>>::value ||
|
||||||
|
(std::is_convertible<T, int>::value && !std::is_enum<T>::value)>>
|
||||||
|
: std::false_type {};
|
||||||
|
|
||||||
// Write the content of buf to os.
|
// Write the content of buf to os.
|
||||||
|
// It is a separate function rather than a part of vprint to simplify testing.
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) {
|
void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) {
|
||||||
const Char* buf_data = buf.data();
|
const Char* buf_data = buf.data();
|
||||||
@ -108,8 +69,8 @@ void write_buffer(std::basic_ostream<Char>& os, buffer<Char>& buf) {
|
|||||||
template <typename Char, typename T>
|
template <typename Char, typename T>
|
||||||
void format_value(buffer<Char>& buf, const T& value,
|
void format_value(buffer<Char>& buf, const T& value,
|
||||||
locale_ref loc = locale_ref()) {
|
locale_ref loc = locale_ref()) {
|
||||||
formatbuf<Char> format_buf(buf);
|
auto&& format_buf = formatbuf<std::basic_streambuf<Char>>(buf);
|
||||||
std::basic_ostream<Char> output(&format_buf);
|
auto&& output = std::basic_ostream<Char>(&format_buf);
|
||||||
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
|
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
|
||||||
if (loc) output.imbue(loc.get<std::locale>());
|
if (loc) output.imbue(loc.get<std::locale>());
|
||||||
#endif
|
#endif
|
||||||
@ -117,34 +78,35 @@ void format_value(buffer<Char>& buf, const T& value,
|
|||||||
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
||||||
buf.try_resize(buf.size());
|
buf.try_resize(buf.size());
|
||||||
}
|
}
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
// Formats an object of type T that has an overloaded ostream operator<<.
|
||||||
|
template <typename Char>
|
||||||
|
struct basic_ostream_formatter : formatter<basic_string_view<Char>, Char> {
|
||||||
|
template <typename T, typename OutputIt>
|
||||||
|
auto format(const T& value, basic_format_context<OutputIt, Char>& ctx) const
|
||||||
|
-> OutputIt {
|
||||||
|
auto buffer = basic_memory_buffer<Char>();
|
||||||
|
format_value(buffer, value, ctx.locale());
|
||||||
|
return formatter<basic_string_view<Char>, Char>::format(
|
||||||
|
{buffer.data(), buffer.size()}, ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using ostream_formatter = basic_ostream_formatter<char>;
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
// 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>>
|
||||||
: private formatter<basic_string_view<Char>, Char> {
|
: basic_ostream_formatter<Char> {
|
||||||
FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
|
using basic_ostream_formatter<Char>::format;
|
||||||
-> decltype(ctx.begin()) {
|
// DEPRECATED!
|
||||||
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>
|
template <typename OutputIt>
|
||||||
auto format(const T& value, basic_format_context<OutputIt, Char>& ctx)
|
auto format(const T& value, basic_printf_context<OutputIt, Char>& ctx) const
|
||||||
-> OutputIt {
|
-> OutputIt {
|
||||||
basic_memory_buffer<Char> buffer;
|
auto buffer = basic_memory_buffer<Char>();
|
||||||
format_value(buffer, value, ctx.locale());
|
|
||||||
basic_string_view<Char> str(buffer.data(), buffer.size());
|
|
||||||
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());
|
format_value(buffer, value, ctx.locale());
|
||||||
return std::copy(buffer.begin(), buffer.end(), ctx.out());
|
return std::copy(buffer.begin(), buffer.end(), ctx.out());
|
||||||
}
|
}
|
||||||
@ -155,7 +117,7 @@ FMT_MODULE_EXPORT
|
|||||||
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<type_identity_t<Char>>> args) {
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
basic_memory_buffer<Char> buffer;
|
auto buffer = basic_memory_buffer<Char>();
|
||||||
detail::vformat_to(buffer, format_str, args);
|
detail::vformat_to(buffer, format_str, args);
|
||||||
detail::write_buffer(os, buffer);
|
detail::write_buffer(os, buffer);
|
||||||
}
|
}
|
||||||
@ -174,7 +136,7 @@ template <typename S, typename... Args,
|
|||||||
typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
|
typename Char = enable_if_t<detail::is_string<S>::value, char_t<S>>>
|
||||||
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),
|
||||||
fmt::make_args_checked<Args...>(format_str, args...));
|
fmt::make_format_args<buffer_context<Char>>(args...));
|
||||||
}
|
}
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
19
vendor/Fmt/include/fmt/printf.h
vendored
19
vendor/Fmt/include/fmt/printf.h
vendored
@ -233,7 +233,7 @@ class printf_arg_formatter : public arg_formatter<Char> {
|
|||||||
|
|
||||||
OutputIt write_null_pointer(bool is_string = false) {
|
OutputIt write_null_pointer(bool is_string = false) {
|
||||||
auto s = this->specs;
|
auto s = this->specs;
|
||||||
s.type = 0;
|
s.type = presentation_type::none;
|
||||||
return write_bytes(this->out, is_string ? "(null)" : "(nil)", s);
|
return write_bytes(this->out, is_string ? "(null)" : "(nil)", s);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,8 +249,10 @@ class printf_arg_formatter : public arg_formatter<Char> {
|
|||||||
// std::is_same instead.
|
// std::is_same instead.
|
||||||
if (std::is_same<T, Char>::value) {
|
if (std::is_same<T, Char>::value) {
|
||||||
format_specs fmt_specs = this->specs;
|
format_specs fmt_specs = this->specs;
|
||||||
if (fmt_specs.type && fmt_specs.type != 'c')
|
if (fmt_specs.type != presentation_type::none &&
|
||||||
|
fmt_specs.type != presentation_type::chr) {
|
||||||
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.fill[0] = ' '; // Ignore '0' flag for char types.
|
fmt_specs.fill[0] = ' '; // Ignore '0' flag for char types.
|
||||||
@ -271,13 +273,13 @@ class printf_arg_formatter : public arg_formatter<Char> {
|
|||||||
/** Formats a null-terminated C string. */
|
/** Formats a null-terminated C string. */
|
||||||
OutputIt operator()(const char* value) {
|
OutputIt operator()(const char* value) {
|
||||||
if (value) return base::operator()(value);
|
if (value) return base::operator()(value);
|
||||||
return write_null_pointer(this->specs.type != 'p');
|
return write_null_pointer(this->specs.type != presentation_type::pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Formats a null-terminated wide C string. */
|
/** Formats a null-terminated wide C string. */
|
||||||
OutputIt operator()(const wchar_t* value) {
|
OutputIt operator()(const wchar_t* value) {
|
||||||
if (value) return base::operator()(value);
|
if (value) return base::operator()(value);
|
||||||
return write_null_pointer(this->specs.type != 'p');
|
return write_null_pointer(this->specs.type != presentation_type::pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
OutputIt operator()(basic_string_view<Char> value) {
|
OutputIt operator()(basic_string_view<Char> value) {
|
||||||
@ -490,13 +492,13 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
|||||||
|
|
||||||
// Parse type.
|
// Parse type.
|
||||||
if (it == end) FMT_THROW(format_error("invalid format string"));
|
if (it == end) FMT_THROW(format_error("invalid format string"));
|
||||||
specs.type = static_cast<char>(*it++);
|
char type = static_cast<char>(*it++);
|
||||||
if (arg.is_integral()) {
|
if (arg.is_integral()) {
|
||||||
// Normalize type.
|
// Normalize type.
|
||||||
switch (specs.type) {
|
switch (type) {
|
||||||
case 'i':
|
case 'i':
|
||||||
case 'u':
|
case 'u':
|
||||||
specs.type = 'd';
|
type = 'd';
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
visit_format_arg(
|
visit_format_arg(
|
||||||
@ -505,6 +507,9 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
specs.type = parse_presentation_type(type);
|
||||||
|
if (specs.type == presentation_type::none)
|
||||||
|
parse_ctx.on_error("invalid type specifier");
|
||||||
|
|
||||||
start = it;
|
start = it;
|
||||||
|
|
||||||
|
585
vendor/Fmt/include/fmt/ranges.h
vendored
585
vendor/Fmt/include/fmt/ranges.h
vendored
@ -13,37 +13,13 @@
|
|||||||
#define FMT_RANGES_H_
|
#define FMT_RANGES_H_
|
||||||
|
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
template <typename Char, typename Enable = void> struct formatting_range {
|
|
||||||
#ifdef FMT_DEPRECATED_BRACED_RANGES
|
|
||||||
Char prefix = '{';
|
|
||||||
Char postfix = '}';
|
|
||||||
#else
|
|
||||||
Char prefix = '[';
|
|
||||||
Char postfix = ']';
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template <typename ParseContext>
|
|
||||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
|
||||||
return ctx.begin();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Char, typename Enable = void> struct formatting_tuple {
|
|
||||||
Char prefix = '(';
|
|
||||||
Char postfix = ')';
|
|
||||||
|
|
||||||
template <typename ParseContext>
|
|
||||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
|
||||||
return ctx.begin();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
template <typename RangeT, typename OutputIterator>
|
template <typename RangeT, typename OutputIterator>
|
||||||
@ -71,7 +47,7 @@ OutputIterator copy(wchar_t ch, OutputIterator out) {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return true value if T has std::string interface, like std::string_view.
|
// Returns true if T has a std::string-like interface, like std::string_view.
|
||||||
template <typename T> class is_std_string_like {
|
template <typename T> class is_std_string_like {
|
||||||
template <typename U>
|
template <typename U>
|
||||||
static auto check(U* p)
|
static auto check(U* p)
|
||||||
@ -80,12 +56,40 @@ template <typename T> class is_std_string_like {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
static FMT_CONSTEXPR_DECL const bool value =
|
static FMT_CONSTEXPR_DECL const bool value =
|
||||||
is_string<T>::value || !std::is_void<decltype(check<T>(nullptr))>::value;
|
is_string<T>::value ||
|
||||||
|
std::is_convertible<T, std_string_view<char>>::value ||
|
||||||
|
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
struct is_std_string_like<fmt::basic_string_view<Char>> : std::true_type {};
|
struct is_std_string_like<fmt::basic_string_view<Char>> : std::true_type {};
|
||||||
|
|
||||||
|
template <typename T> class is_map {
|
||||||
|
template <typename U> static auto check(U*) -> typename U::mapped_type;
|
||||||
|
template <typename> static void check(...);
|
||||||
|
|
||||||
|
public:
|
||||||
|
#ifdef FMT_FORMAT_MAP_AS_LIST
|
||||||
|
static FMT_CONSTEXPR_DECL const bool value = false;
|
||||||
|
#else
|
||||||
|
static FMT_CONSTEXPR_DECL const bool value =
|
||||||
|
!std::is_void<decltype(check<T>(nullptr))>::value;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> class is_set {
|
||||||
|
template <typename U> static auto check(U*) -> typename U::key_type;
|
||||||
|
template <typename> static void check(...);
|
||||||
|
|
||||||
|
public:
|
||||||
|
#ifdef FMT_FORMAT_SET_AS_LIST
|
||||||
|
static FMT_CONSTEXPR_DECL const bool value = false;
|
||||||
|
#else
|
||||||
|
static FMT_CONSTEXPR_DECL const bool value =
|
||||||
|
!std::is_void<decltype(check<T>(nullptr))>::value && !is_map<T>::value;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
template <typename... Ts> struct conditional_helper {};
|
template <typename... Ts> struct conditional_helper {};
|
||||||
|
|
||||||
template <typename T, typename _ = void> struct is_range_ : std::false_type {};
|
template <typename T, typename _ = void> struct is_range_ : std::false_type {};
|
||||||
@ -163,7 +167,7 @@ struct is_range_<T, void>
|
|||||||
# undef FMT_DECLTYPE_RETURN
|
# undef FMT_DECLTYPE_RETURN
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// 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) -> decltype(std::tuple_size<U>::value, int());
|
static auto check(U* p) -> decltype(std::tuple_size<U>::value, int());
|
||||||
@ -199,7 +203,7 @@ 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>
|
||||||
void for_each(index_sequence<Is...>, Tuple&& tup, F&& f) FMT_NOEXCEPT {
|
void for_each(index_sequence<Is...>, Tuple&& tup, F&& f) noexcept {
|
||||||
using std::get;
|
using std::get;
|
||||||
// using free function get<I>(T) now.
|
// using free function get<I>(T) now.
|
||||||
const int _[] = {0, ((void)f(get<Is>(tup)), 0)...};
|
const int _[] = {0, ((void)f(get<Is>(tup)), 0)...};
|
||||||
@ -217,9 +221,28 @@ template <class Tuple, class F> void for_each(Tuple&& tup, F&& f) {
|
|||||||
for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f));
|
for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if FMT_MSC_VER
|
||||||
|
// Older MSVC doesn't get the reference type correctly for arrays.
|
||||||
|
template <typename R> struct range_reference_type_impl {
|
||||||
|
using type = decltype(*detail::range_begin(std::declval<R&>()));
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, std::size_t N> struct range_reference_type_impl<T[N]> {
|
||||||
|
using type = T&;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using range_reference_type = typename range_reference_type_impl<T>::type;
|
||||||
|
#else
|
||||||
template <typename Range>
|
template <typename Range>
|
||||||
using value_type =
|
using range_reference_type =
|
||||||
remove_cvref_t<decltype(*detail::range_begin(std::declval<Range>()))>;
|
decltype(*detail::range_begin(std::declval<Range&>()));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// We don't use the Range's value_type for anything, but we do need the Range's
|
||||||
|
// reference type, with cv-ref stripped.
|
||||||
|
template <typename Range>
|
||||||
|
using uncvref_type = remove_cvref_t<range_reference_type<Range>>;
|
||||||
|
|
||||||
template <typename OutputIt> OutputIt write_delimiter(OutputIt out) {
|
template <typename OutputIt> OutputIt write_delimiter(OutputIt out) {
|
||||||
*out++ = ',';
|
*out++ = ',';
|
||||||
@ -227,283 +250,22 @@ template <typename OutputIt> OutputIt write_delimiter(OutputIt out) {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct singleton {
|
|
||||||
unsigned char upper;
|
|
||||||
unsigned char lowercount;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline auto check(uint16_t x, const singleton* singletonuppers,
|
|
||||||
size_t singletonuppers_size,
|
|
||||||
const unsigned char* singletonlowers,
|
|
||||||
const unsigned char* normal, size_t normal_size) -> bool {
|
|
||||||
auto xupper = x >> 8;
|
|
||||||
auto lowerstart = 0;
|
|
||||||
for (size_t i = 0; i < singletonuppers_size; ++i) {
|
|
||||||
auto su = singletonuppers[i];
|
|
||||||
auto lowerend = lowerstart + su.lowercount;
|
|
||||||
if (xupper < su.upper) break;
|
|
||||||
if (xupper == su.upper) {
|
|
||||||
for (auto j = lowerstart; j < lowerend; ++j) {
|
|
||||||
if (singletonlowers[j] == x) return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lowerstart = lowerend;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto xsigned = static_cast<int>(x);
|
|
||||||
auto current = true;
|
|
||||||
for (size_t i = 0; i < normal_size; ++i) {
|
|
||||||
auto v = static_cast<int>(normal[i]);
|
|
||||||
auto len = (v & 0x80) != 0 ? (v & 0x7f) << 8 | normal[i++] : v;
|
|
||||||
xsigned -= len;
|
|
||||||
if (xsigned < 0) break;
|
|
||||||
current = !current;
|
|
||||||
}
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true iff the code point cp is printable.
|
|
||||||
// This code is generated by support/printable.py.
|
|
||||||
inline auto is_printable(uint32_t cp) -> bool {
|
|
||||||
static constexpr singleton singletons0u[] = {
|
|
||||||
{0x00, 1}, {0x03, 5}, {0x05, 6}, {0x06, 3}, {0x07, 6}, {0x08, 8},
|
|
||||||
{0x09, 17}, {0x0a, 28}, {0x0b, 25}, {0x0c, 20}, {0x0d, 16}, {0x0e, 13},
|
|
||||||
{0x0f, 4}, {0x10, 3}, {0x12, 18}, {0x13, 9}, {0x16, 1}, {0x17, 5},
|
|
||||||
{0x18, 2}, {0x19, 3}, {0x1a, 7}, {0x1c, 2}, {0x1d, 1}, {0x1f, 22},
|
|
||||||
{0x20, 3}, {0x2b, 3}, {0x2c, 2}, {0x2d, 11}, {0x2e, 1}, {0x30, 3},
|
|
||||||
{0x31, 2}, {0x32, 1}, {0xa7, 2}, {0xa9, 2}, {0xaa, 4}, {0xab, 8},
|
|
||||||
{0xfa, 2}, {0xfb, 5}, {0xfd, 4}, {0xfe, 3}, {0xff, 9},
|
|
||||||
};
|
|
||||||
static constexpr unsigned char singletons0l[] = {
|
|
||||||
0xad, 0x78, 0x79, 0x8b, 0x8d, 0xa2, 0x30, 0x57, 0x58, 0x8b, 0x8c, 0x90,
|
|
||||||
0x1c, 0x1d, 0xdd, 0x0e, 0x0f, 0x4b, 0x4c, 0xfb, 0xfc, 0x2e, 0x2f, 0x3f,
|
|
||||||
0x5c, 0x5d, 0x5f, 0xb5, 0xe2, 0x84, 0x8d, 0x8e, 0x91, 0x92, 0xa9, 0xb1,
|
|
||||||
0xba, 0xbb, 0xc5, 0xc6, 0xc9, 0xca, 0xde, 0xe4, 0xe5, 0xff, 0x00, 0x04,
|
|
||||||
0x11, 0x12, 0x29, 0x31, 0x34, 0x37, 0x3a, 0x3b, 0x3d, 0x49, 0x4a, 0x5d,
|
|
||||||
0x84, 0x8e, 0x92, 0xa9, 0xb1, 0xb4, 0xba, 0xbb, 0xc6, 0xca, 0xce, 0xcf,
|
|
||||||
0xe4, 0xe5, 0x00, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a,
|
|
||||||
0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, 0x64, 0x65, 0x84, 0x91, 0x9b, 0x9d,
|
|
||||||
0xc9, 0xce, 0xcf, 0x0d, 0x11, 0x29, 0x45, 0x49, 0x57, 0x64, 0x65, 0x8d,
|
|
||||||
0x91, 0xa9, 0xb4, 0xba, 0xbb, 0xc5, 0xc9, 0xdf, 0xe4, 0xe5, 0xf0, 0x0d,
|
|
||||||
0x11, 0x45, 0x49, 0x64, 0x65, 0x80, 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5,
|
|
||||||
0xd7, 0xf0, 0xf1, 0x83, 0x85, 0x8b, 0xa4, 0xa6, 0xbe, 0xbf, 0xc5, 0xc7,
|
|
||||||
0xce, 0xcf, 0xda, 0xdb, 0x48, 0x98, 0xbd, 0xcd, 0xc6, 0xce, 0xcf, 0x49,
|
|
||||||
0x4e, 0x4f, 0x57, 0x59, 0x5e, 0x5f, 0x89, 0x8e, 0x8f, 0xb1, 0xb6, 0xb7,
|
|
||||||
0xbf, 0xc1, 0xc6, 0xc7, 0xd7, 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7,
|
|
||||||
0xfe, 0xff, 0x80, 0x0d, 0x6d, 0x71, 0xde, 0xdf, 0x0e, 0x0f, 0x1f, 0x6e,
|
|
||||||
0x6f, 0x1c, 0x1d, 0x5f, 0x7d, 0x7e, 0xae, 0xaf, 0xbb, 0xbc, 0xfa, 0x16,
|
|
||||||
0x17, 0x1e, 0x1f, 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e, 0x7e,
|
|
||||||
0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0, 0xf1, 0xf5, 0x72, 0x73, 0x8f,
|
|
||||||
0x74, 0x75, 0x96, 0x2f, 0x5f, 0x26, 0x2e, 0x2f, 0xa7, 0xaf, 0xb7, 0xbf,
|
|
||||||
0xc7, 0xcf, 0xd7, 0xdf, 0x9a, 0x40, 0x97, 0x98, 0x30, 0x8f, 0x1f, 0xc0,
|
|
||||||
0xc1, 0xce, 0xff, 0x4e, 0x4f, 0x5a, 0x5b, 0x07, 0x08, 0x0f, 0x10, 0x27,
|
|
||||||
0x2f, 0xee, 0xef, 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, 0x90, 0x91,
|
|
||||||
0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, 0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7,
|
|
||||||
0xfe, 0xff,
|
|
||||||
};
|
|
||||||
static constexpr singleton singletons1u[] = {
|
|
||||||
{0x00, 6}, {0x01, 1}, {0x03, 1}, {0x04, 2}, {0x08, 8}, {0x09, 2},
|
|
||||||
{0x0a, 5}, {0x0b, 2}, {0x0e, 4}, {0x10, 1}, {0x11, 2}, {0x12, 5},
|
|
||||||
{0x13, 17}, {0x14, 1}, {0x15, 2}, {0x17, 2}, {0x19, 13}, {0x1c, 5},
|
|
||||||
{0x1d, 8}, {0x24, 1}, {0x6a, 3}, {0x6b, 2}, {0xbc, 2}, {0xd1, 2},
|
|
||||||
{0xd4, 12}, {0xd5, 9}, {0xd6, 2}, {0xd7, 2}, {0xda, 1}, {0xe0, 5},
|
|
||||||
{0xe1, 2}, {0xe8, 2}, {0xee, 32}, {0xf0, 4}, {0xf8, 2}, {0xf9, 2},
|
|
||||||
{0xfa, 2}, {0xfb, 1},
|
|
||||||
};
|
|
||||||
static constexpr unsigned char singletons1l[] = {
|
|
||||||
0x0c, 0x27, 0x3b, 0x3e, 0x4e, 0x4f, 0x8f, 0x9e, 0x9e, 0x9f, 0x06, 0x07,
|
|
||||||
0x09, 0x36, 0x3d, 0x3e, 0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, 0x36,
|
|
||||||
0x37, 0x56, 0x57, 0x7f, 0xaa, 0xae, 0xaf, 0xbd, 0x35, 0xe0, 0x12, 0x87,
|
|
||||||
0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a,
|
|
||||||
0x45, 0x46, 0x49, 0x4a, 0x4e, 0x4f, 0x64, 0x65, 0x5c, 0xb6, 0xb7, 0x1b,
|
|
||||||
0x1c, 0x07, 0x08, 0x0a, 0x0b, 0x14, 0x17, 0x36, 0x39, 0x3a, 0xa8, 0xa9,
|
|
||||||
0xd8, 0xd9, 0x09, 0x37, 0x90, 0x91, 0xa8, 0x07, 0x0a, 0x3b, 0x3e, 0x66,
|
|
||||||
0x69, 0x8f, 0x92, 0x6f, 0x5f, 0xee, 0xef, 0x5a, 0x62, 0x9a, 0x9b, 0x27,
|
|
||||||
0x28, 0x55, 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, 0xad, 0xba, 0xbc,
|
|
||||||
0xc4, 0x06, 0x0b, 0x0c, 0x15, 0x1d, 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7,
|
|
||||||
0xcc, 0xcd, 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0x3e, 0x3f, 0xc5, 0xc6,
|
|
||||||
0x04, 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, 0x38, 0x3a, 0x48, 0x4a, 0x4c,
|
|
||||||
0x50, 0x53, 0x55, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, 0x66,
|
|
||||||
0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, 0xaa, 0xaf, 0xb0, 0xc0, 0xd0,
|
|
||||||
0xae, 0xaf, 0x79, 0xcc, 0x6e, 0x6f, 0x93,
|
|
||||||
};
|
|
||||||
static constexpr unsigned char normal0[] = {
|
|
||||||
0x00, 0x20, 0x5f, 0x22, 0x82, 0xdf, 0x04, 0x82, 0x44, 0x08, 0x1b, 0x04,
|
|
||||||
0x06, 0x11, 0x81, 0xac, 0x0e, 0x80, 0xab, 0x35, 0x28, 0x0b, 0x80, 0xe0,
|
|
||||||
0x03, 0x19, 0x08, 0x01, 0x04, 0x2f, 0x04, 0x34, 0x04, 0x07, 0x03, 0x01,
|
|
||||||
0x07, 0x06, 0x07, 0x11, 0x0a, 0x50, 0x0f, 0x12, 0x07, 0x55, 0x07, 0x03,
|
|
||||||
0x04, 0x1c, 0x0a, 0x09, 0x03, 0x08, 0x03, 0x07, 0x03, 0x02, 0x03, 0x03,
|
|
||||||
0x03, 0x0c, 0x04, 0x05, 0x03, 0x0b, 0x06, 0x01, 0x0e, 0x15, 0x05, 0x3a,
|
|
||||||
0x03, 0x11, 0x07, 0x06, 0x05, 0x10, 0x07, 0x57, 0x07, 0x02, 0x07, 0x15,
|
|
||||||
0x0d, 0x50, 0x04, 0x43, 0x03, 0x2d, 0x03, 0x01, 0x04, 0x11, 0x06, 0x0f,
|
|
||||||
0x0c, 0x3a, 0x04, 0x1d, 0x25, 0x5f, 0x20, 0x6d, 0x04, 0x6a, 0x25, 0x80,
|
|
||||||
0xc8, 0x05, 0x82, 0xb0, 0x03, 0x1a, 0x06, 0x82, 0xfd, 0x03, 0x59, 0x07,
|
|
||||||
0x15, 0x0b, 0x17, 0x09, 0x14, 0x0c, 0x14, 0x0c, 0x6a, 0x06, 0x0a, 0x06,
|
|
||||||
0x1a, 0x06, 0x59, 0x07, 0x2b, 0x05, 0x46, 0x0a, 0x2c, 0x04, 0x0c, 0x04,
|
|
||||||
0x01, 0x03, 0x31, 0x0b, 0x2c, 0x04, 0x1a, 0x06, 0x0b, 0x03, 0x80, 0xac,
|
|
||||||
0x06, 0x0a, 0x06, 0x21, 0x3f, 0x4c, 0x04, 0x2d, 0x03, 0x74, 0x08, 0x3c,
|
|
||||||
0x03, 0x0f, 0x03, 0x3c, 0x07, 0x38, 0x08, 0x2b, 0x05, 0x82, 0xff, 0x11,
|
|
||||||
0x18, 0x08, 0x2f, 0x11, 0x2d, 0x03, 0x20, 0x10, 0x21, 0x0f, 0x80, 0x8c,
|
|
||||||
0x04, 0x82, 0x97, 0x19, 0x0b, 0x15, 0x88, 0x94, 0x05, 0x2f, 0x05, 0x3b,
|
|
||||||
0x07, 0x02, 0x0e, 0x18, 0x09, 0x80, 0xb3, 0x2d, 0x74, 0x0c, 0x80, 0xd6,
|
|
||||||
0x1a, 0x0c, 0x05, 0x80, 0xff, 0x05, 0x80, 0xdf, 0x0c, 0xee, 0x0d, 0x03,
|
|
||||||
0x84, 0x8d, 0x03, 0x37, 0x09, 0x81, 0x5c, 0x14, 0x80, 0xb8, 0x08, 0x80,
|
|
||||||
0xcb, 0x2a, 0x38, 0x03, 0x0a, 0x06, 0x38, 0x08, 0x46, 0x08, 0x0c, 0x06,
|
|
||||||
0x74, 0x0b, 0x1e, 0x03, 0x5a, 0x04, 0x59, 0x09, 0x80, 0x83, 0x18, 0x1c,
|
|
||||||
0x0a, 0x16, 0x09, 0x4c, 0x04, 0x80, 0x8a, 0x06, 0xab, 0xa4, 0x0c, 0x17,
|
|
||||||
0x04, 0x31, 0xa1, 0x04, 0x81, 0xda, 0x26, 0x07, 0x0c, 0x05, 0x05, 0x80,
|
|
||||||
0xa5, 0x11, 0x81, 0x6d, 0x10, 0x78, 0x28, 0x2a, 0x06, 0x4c, 0x04, 0x80,
|
|
||||||
0x8d, 0x04, 0x80, 0xbe, 0x03, 0x1b, 0x03, 0x0f, 0x0d,
|
|
||||||
};
|
|
||||||
static constexpr unsigned char normal1[] = {
|
|
||||||
0x5e, 0x22, 0x7b, 0x05, 0x03, 0x04, 0x2d, 0x03, 0x66, 0x03, 0x01, 0x2f,
|
|
||||||
0x2e, 0x80, 0x82, 0x1d, 0x03, 0x31, 0x0f, 0x1c, 0x04, 0x24, 0x09, 0x1e,
|
|
||||||
0x05, 0x2b, 0x05, 0x44, 0x04, 0x0e, 0x2a, 0x80, 0xaa, 0x06, 0x24, 0x04,
|
|
||||||
0x24, 0x04, 0x28, 0x08, 0x34, 0x0b, 0x01, 0x80, 0x90, 0x81, 0x37, 0x09,
|
|
||||||
0x16, 0x0a, 0x08, 0x80, 0x98, 0x39, 0x03, 0x63, 0x08, 0x09, 0x30, 0x16,
|
|
||||||
0x05, 0x21, 0x03, 0x1b, 0x05, 0x01, 0x40, 0x38, 0x04, 0x4b, 0x05, 0x2f,
|
|
||||||
0x04, 0x0a, 0x07, 0x09, 0x07, 0x40, 0x20, 0x27, 0x04, 0x0c, 0x09, 0x36,
|
|
||||||
0x03, 0x3a, 0x05, 0x1a, 0x07, 0x04, 0x0c, 0x07, 0x50, 0x49, 0x37, 0x33,
|
|
||||||
0x0d, 0x33, 0x07, 0x2e, 0x08, 0x0a, 0x81, 0x26, 0x52, 0x4e, 0x28, 0x08,
|
|
||||||
0x2a, 0x56, 0x1c, 0x14, 0x17, 0x09, 0x4e, 0x04, 0x1e, 0x0f, 0x43, 0x0e,
|
|
||||||
0x19, 0x07, 0x0a, 0x06, 0x48, 0x08, 0x27, 0x09, 0x75, 0x0b, 0x3f, 0x41,
|
|
||||||
0x2a, 0x06, 0x3b, 0x05, 0x0a, 0x06, 0x51, 0x06, 0x01, 0x05, 0x10, 0x03,
|
|
||||||
0x05, 0x80, 0x8b, 0x62, 0x1e, 0x48, 0x08, 0x0a, 0x80, 0xa6, 0x5e, 0x22,
|
|
||||||
0x45, 0x0b, 0x0a, 0x06, 0x0d, 0x13, 0x39, 0x07, 0x0a, 0x36, 0x2c, 0x04,
|
|
||||||
0x10, 0x80, 0xc0, 0x3c, 0x64, 0x53, 0x0c, 0x48, 0x09, 0x0a, 0x46, 0x45,
|
|
||||||
0x1b, 0x48, 0x08, 0x53, 0x1d, 0x39, 0x81, 0x07, 0x46, 0x0a, 0x1d, 0x03,
|
|
||||||
0x47, 0x49, 0x37, 0x03, 0x0e, 0x08, 0x0a, 0x06, 0x39, 0x07, 0x0a, 0x81,
|
|
||||||
0x36, 0x19, 0x80, 0xb7, 0x01, 0x0f, 0x32, 0x0d, 0x83, 0x9b, 0x66, 0x75,
|
|
||||||
0x0b, 0x80, 0xc4, 0x8a, 0xbc, 0x84, 0x2f, 0x8f, 0xd1, 0x82, 0x47, 0xa1,
|
|
||||||
0xb9, 0x82, 0x39, 0x07, 0x2a, 0x04, 0x02, 0x60, 0x26, 0x0a, 0x46, 0x0a,
|
|
||||||
0x28, 0x05, 0x13, 0x82, 0xb0, 0x5b, 0x65, 0x4b, 0x04, 0x39, 0x07, 0x11,
|
|
||||||
0x40, 0x05, 0x0b, 0x02, 0x0e, 0x97, 0xf8, 0x08, 0x84, 0xd6, 0x2a, 0x09,
|
|
||||||
0xa2, 0xf7, 0x81, 0x1f, 0x31, 0x03, 0x11, 0x04, 0x08, 0x81, 0x8c, 0x89,
|
|
||||||
0x04, 0x6b, 0x05, 0x0d, 0x03, 0x09, 0x07, 0x10, 0x93, 0x60, 0x80, 0xf6,
|
|
||||||
0x0a, 0x73, 0x08, 0x6e, 0x17, 0x46, 0x80, 0x9a, 0x14, 0x0c, 0x57, 0x09,
|
|
||||||
0x19, 0x80, 0x87, 0x81, 0x47, 0x03, 0x85, 0x42, 0x0f, 0x15, 0x85, 0x50,
|
|
||||||
0x2b, 0x80, 0xd5, 0x2d, 0x03, 0x1a, 0x04, 0x02, 0x81, 0x70, 0x3a, 0x05,
|
|
||||||
0x01, 0x85, 0x00, 0x80, 0xd7, 0x29, 0x4c, 0x04, 0x0a, 0x04, 0x02, 0x83,
|
|
||||||
0x11, 0x44, 0x4c, 0x3d, 0x80, 0xc2, 0x3c, 0x06, 0x01, 0x04, 0x55, 0x05,
|
|
||||||
0x1b, 0x34, 0x02, 0x81, 0x0e, 0x2c, 0x04, 0x64, 0x0c, 0x56, 0x0a, 0x80,
|
|
||||||
0xae, 0x38, 0x1d, 0x0d, 0x2c, 0x04, 0x09, 0x07, 0x02, 0x0e, 0x06, 0x80,
|
|
||||||
0x9a, 0x83, 0xd8, 0x08, 0x0d, 0x03, 0x0d, 0x03, 0x74, 0x0c, 0x59, 0x07,
|
|
||||||
0x0c, 0x14, 0x0c, 0x04, 0x38, 0x08, 0x0a, 0x06, 0x28, 0x08, 0x22, 0x4e,
|
|
||||||
0x81, 0x54, 0x0c, 0x15, 0x03, 0x03, 0x05, 0x07, 0x09, 0x19, 0x07, 0x07,
|
|
||||||
0x09, 0x03, 0x0d, 0x07, 0x29, 0x80, 0xcb, 0x25, 0x0a, 0x84, 0x06,
|
|
||||||
};
|
|
||||||
auto lower = static_cast<uint16_t>(cp);
|
|
||||||
if (cp < 0x10000) {
|
|
||||||
return check(lower, singletons0u,
|
|
||||||
sizeof(singletons0u) / sizeof(*singletons0u), singletons0l,
|
|
||||||
normal0, sizeof(normal0));
|
|
||||||
}
|
|
||||||
if (cp < 0x20000) {
|
|
||||||
return check(lower, singletons1u,
|
|
||||||
sizeof(singletons1u) / sizeof(*singletons1u), singletons1l,
|
|
||||||
normal1, sizeof(normal1));
|
|
||||||
}
|
|
||||||
if (0x2a6de <= cp && cp < 0x2a700) return false;
|
|
||||||
if (0x2b735 <= cp && cp < 0x2b740) return false;
|
|
||||||
if (0x2b81e <= cp && cp < 0x2b820) return false;
|
|
||||||
if (0x2cea2 <= cp && cp < 0x2ceb0) return false;
|
|
||||||
if (0x2ebe1 <= cp && cp < 0x2f800) return false;
|
|
||||||
if (0x2fa1e <= cp && cp < 0x30000) return false;
|
|
||||||
if (0x3134b <= cp && cp < 0xe0100) return false;
|
|
||||||
if (0xe01f0 <= cp && cp < 0x110000) return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto needs_escape(uint32_t cp) -> bool {
|
|
||||||
return cp < 0x20 || cp == 0x7f || cp == '"' || cp == '\\' ||
|
|
||||||
!is_printable(cp);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Char> struct find_escape_result {
|
|
||||||
const Char* begin;
|
|
||||||
const Char* end;
|
|
||||||
uint32_t cp;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Char>
|
|
||||||
auto find_escape(const Char* begin, const Char* end)
|
|
||||||
-> find_escape_result<Char> {
|
|
||||||
for (; begin != end; ++begin) {
|
|
||||||
auto cp = static_cast<typename std::make_unsigned<Char>::type>(*begin);
|
|
||||||
if (needs_escape(cp)) return {begin, begin + 1, cp};
|
|
||||||
}
|
|
||||||
return {begin, nullptr, 0};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto find_escape(const char* begin, const char* end)
|
|
||||||
-> find_escape_result<char> {
|
|
||||||
if (!is_utf8()) return find_escape<char>(begin, end);
|
|
||||||
auto result = find_escape_result<char>{end, nullptr, 0};
|
|
||||||
for_each_codepoint(string_view(begin, to_unsigned(end - begin)),
|
|
||||||
[&](uint32_t cp, string_view sv) {
|
|
||||||
if (needs_escape(cp)) {
|
|
||||||
result = {sv.begin(), sv.end(), cp};
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Char, typename OutputIt>
|
template <typename Char, typename OutputIt>
|
||||||
auto write_range_entry(OutputIt out, basic_string_view<Char> str) -> OutputIt {
|
auto write_range_entry(OutputIt out, basic_string_view<Char> str) -> OutputIt {
|
||||||
*out++ = '"';
|
return write_escaped_string(out, str);
|
||||||
auto begin = str.begin(), end = str.end();
|
|
||||||
do {
|
|
||||||
auto escape = find_escape(begin, end);
|
|
||||||
out = copy_str<Char>(begin, escape.begin, out);
|
|
||||||
begin = escape.end;
|
|
||||||
if (!begin) break;
|
|
||||||
auto c = static_cast<Char>(escape.cp);
|
|
||||||
switch (escape.cp) {
|
|
||||||
case '\n':
|
|
||||||
*out++ = '\\';
|
|
||||||
c = 'n';
|
|
||||||
break;
|
|
||||||
case '\r':
|
|
||||||
*out++ = '\\';
|
|
||||||
c = 'r';
|
|
||||||
break;
|
|
||||||
case '\t':
|
|
||||||
*out++ = '\\';
|
|
||||||
c = 't';
|
|
||||||
break;
|
|
||||||
case '"':
|
|
||||||
FMT_FALLTHROUGH;
|
|
||||||
case '\\':
|
|
||||||
*out++ = '\\';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (is_utf8() && escape.cp > 0xffff) {
|
|
||||||
out = format_to(out, "\\U{:08x}", escape.cp);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
for (Char escape_char : basic_string_view<Char>(
|
|
||||||
escape.begin, to_unsigned(escape.end - escape.begin))) {
|
template <typename Char, typename OutputIt, typename T,
|
||||||
out = format_to(
|
FMT_ENABLE_IF(std::is_convertible<T, std_string_view<char>>::value)>
|
||||||
out, "\\x{:02x}",
|
inline auto write_range_entry(OutputIt out, const T& str) -> OutputIt {
|
||||||
static_cast<typename std::make_unsigned<Char>::type>(escape_char));
|
auto sv = std_string_view<Char>(str);
|
||||||
}
|
return write_range_entry<Char>(out, basic_string_view<Char>(sv));
|
||||||
continue;
|
|
||||||
}
|
|
||||||
*out++ = c;
|
|
||||||
} while (begin != end);
|
|
||||||
*out++ = '"';
|
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char, typename OutputIt, typename Arg,
|
template <typename Char, typename OutputIt, typename Arg,
|
||||||
FMT_ENABLE_IF(std::is_same<Arg, Char>::value)>
|
FMT_ENABLE_IF(std::is_same<Arg, Char>::value)>
|
||||||
OutputIt write_range_entry(OutputIt out, const Arg v) {
|
OutputIt write_range_entry(OutputIt out, const Arg v) {
|
||||||
*out++ = '\'';
|
return write_escaped_char(out, v);
|
||||||
*out++ = v;
|
|
||||||
*out++ = '\'';
|
|
||||||
return out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <
|
template <
|
||||||
@ -524,63 +286,153 @@ template <typename T> struct is_tuple_like {
|
|||||||
template <typename TupleT, typename Char>
|
template <typename TupleT, typename Char>
|
||||||
struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
|
struct formatter<TupleT, Char, enable_if_t<fmt::is_tuple_like<TupleT>::value>> {
|
||||||
private:
|
private:
|
||||||
// C++11 generic lambda for format()
|
// C++11 generic lambda for format().
|
||||||
template <typename FormatContext> struct format_each {
|
template <typename FormatContext> struct format_each {
|
||||||
template <typename T> void operator()(const T& v) {
|
template <typename T> void operator()(const T& v) {
|
||||||
if (i > 0) out = detail::write_delimiter(out);
|
if (i > 0) out = detail::write_delimiter(out);
|
||||||
out = detail::write_range_entry<Char>(out, v);
|
out = detail::write_range_entry<Char>(out, v);
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
formatting_tuple<Char>& formatting;
|
int i;
|
||||||
size_t& i;
|
typename FormatContext::iterator& out;
|
||||||
typename std::add_lvalue_reference<
|
|
||||||
decltype(std::declval<FormatContext>().out())>::type out;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
formatting_tuple<Char> formatting;
|
|
||||||
|
|
||||||
template <typename ParseContext>
|
template <typename ParseContext>
|
||||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
return formatting.parse(ctx);
|
return ctx.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FormatContext = format_context>
|
template <typename FormatContext = format_context>
|
||||||
auto format(const TupleT& values, FormatContext& ctx) -> decltype(ctx.out()) {
|
auto format(const TupleT& values, FormatContext& ctx) const
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
auto out = ctx.out();
|
auto out = ctx.out();
|
||||||
size_t i = 0;
|
*out++ = '(';
|
||||||
|
detail::for_each(values, format_each<FormatContext>{0, out});
|
||||||
detail::copy(formatting.prefix, out);
|
*out++ = ')';
|
||||||
detail::for_each(values, format_each<FormatContext>{formatting, i, out});
|
return out;
|
||||||
detail::copy(formatting.postfix, out);
|
|
||||||
|
|
||||||
return ctx.out();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
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 =
|
||||||
detail::is_range_<T>::value && !detail::is_std_string_like<T>::value &&
|
detail::is_range_<T>::value && !detail::is_std_string_like<T>::value &&
|
||||||
|
!detail::is_map<T>::value &&
|
||||||
!std::is_convertible<T, std::basic_string<Char>>::value &&
|
!std::is_convertible<T, std::basic_string<Char>>::value &&
|
||||||
!std::is_constructible<detail::std_string_view<Char>, T>::value;
|
!std::is_constructible<detail::std_string_view<Char>, T>::value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
template <typename Context> struct range_mapper {
|
||||||
|
using mapper = arg_mapper<Context>;
|
||||||
|
|
||||||
|
template <typename T,
|
||||||
|
FMT_ENABLE_IF(has_formatter<remove_cvref_t<T>, Context>::value)>
|
||||||
|
static auto map(T&& value) -> T&& {
|
||||||
|
return static_cast<T&&>(value);
|
||||||
|
}
|
||||||
|
template <typename T,
|
||||||
|
FMT_ENABLE_IF(!has_formatter<remove_cvref_t<T>, Context>::value)>
|
||||||
|
static auto map(T&& value)
|
||||||
|
-> decltype(mapper().map(static_cast<T&&>(value))) {
|
||||||
|
return mapper().map(static_cast<T&&>(value));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char, typename Element>
|
||||||
|
using range_formatter_type = conditional_t<
|
||||||
|
is_formattable<Element, Char>::value,
|
||||||
|
formatter<remove_cvref_t<decltype(range_mapper<buffer_context<Char>>{}.map(
|
||||||
|
std::declval<Element>()))>,
|
||||||
|
Char>,
|
||||||
|
fallback_formatter<Element, Char>>;
|
||||||
|
|
||||||
|
template <typename R>
|
||||||
|
using maybe_const_range =
|
||||||
|
conditional_t<has_const_begin_end<R>::value, const R, R>;
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
template <typename R, typename Char>
|
||||||
|
struct formatter<
|
||||||
|
R, Char,
|
||||||
|
enable_if_t<
|
||||||
|
fmt::is_range<R, Char>::value
|
||||||
|
// Workaround a bug in MSVC 2019 and earlier.
|
||||||
|
#if !FMT_MSC_VER
|
||||||
|
&&
|
||||||
|
(is_formattable<detail::uncvref_type<detail::maybe_const_range<R>>,
|
||||||
|
Char>::value ||
|
||||||
|
detail::has_fallback_formatter<
|
||||||
|
detail::uncvref_type<detail::maybe_const_range<R>>, Char>::value)
|
||||||
|
#endif
|
||||||
|
>> {
|
||||||
|
|
||||||
|
using range_type = detail::maybe_const_range<R>;
|
||||||
|
using formatter_type =
|
||||||
|
detail::range_formatter_type<Char, detail::uncvref_type<range_type>>;
|
||||||
|
formatter_type underlying_;
|
||||||
|
bool custom_specs_ = false;
|
||||||
|
|
||||||
|
template <typename ParseContext>
|
||||||
|
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
|
auto it = ctx.begin();
|
||||||
|
auto end = ctx.end();
|
||||||
|
if (it == end || *it == '}') return it;
|
||||||
|
|
||||||
|
if (*it != ':')
|
||||||
|
FMT_THROW(format_error("no top-level range formatters supported"));
|
||||||
|
|
||||||
|
custom_specs_ = true;
|
||||||
|
++it;
|
||||||
|
ctx.advance_to(it);
|
||||||
|
return underlying_.parse(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(range_type& range, FormatContext& ctx) const
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
#ifdef FMT_DEPRECATED_BRACED_RANGES
|
||||||
|
Char prefix = '{';
|
||||||
|
Char postfix = '}';
|
||||||
|
#else
|
||||||
|
Char prefix = detail::is_set<R>::value ? '{' : '[';
|
||||||
|
Char postfix = detail::is_set<R>::value ? '}' : ']';
|
||||||
|
#endif
|
||||||
|
detail::range_mapper<buffer_context<Char>> mapper;
|
||||||
|
auto out = ctx.out();
|
||||||
|
*out++ = prefix;
|
||||||
|
int i = 0;
|
||||||
|
auto it = detail::range_begin(range);
|
||||||
|
auto end = detail::range_end(range);
|
||||||
|
for (; it != end; ++it) {
|
||||||
|
if (i > 0) out = detail::write_delimiter(out);
|
||||||
|
if (custom_specs_) {
|
||||||
|
ctx.advance_to(out);
|
||||||
|
out = underlying_.format(mapper.map(*it), ctx);
|
||||||
|
} else {
|
||||||
|
out = detail::write_range_entry<Char>(out, *it);
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
*out++ = postfix;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T, typename Char>
|
template <typename T, typename Char>
|
||||||
struct formatter<
|
struct formatter<
|
||||||
T, Char,
|
T, Char,
|
||||||
enable_if_t<
|
enable_if_t<detail::is_map<T>::value
|
||||||
fmt::is_range<T, Char>::value
|
// Workaround a bug in MSVC 2019 and earlier.
|
||||||
// Workaround a bug in MSVC 2017 and earlier.
|
#if !FMT_MSC_VER
|
||||||
#if !FMT_MSC_VER || FMT_MSC_VER >= 1927
|
&& (is_formattable<detail::uncvref_type<T>, Char>::value ||
|
||||||
&& (has_formatter<detail::value_type<T>, format_context>::value ||
|
detail::has_fallback_formatter<detail::uncvref_type<T>,
|
||||||
detail::has_fallback_formatter<detail::value_type<T>, Char>::value)
|
Char>::value)
|
||||||
#endif
|
#endif
|
||||||
>> {
|
>> {
|
||||||
formatting_range<Char> formatting;
|
|
||||||
|
|
||||||
template <typename ParseContext>
|
template <typename ParseContext>
|
||||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
return formatting.parse(ctx);
|
return ctx.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <
|
template <
|
||||||
@ -588,17 +440,20 @@ struct formatter<
|
|||||||
FMT_ENABLE_IF(
|
FMT_ENABLE_IF(
|
||||||
std::is_same<U, conditional_t<detail::has_const_begin_end<T>::value,
|
std::is_same<U, conditional_t<detail::has_const_begin_end<T>::value,
|
||||||
const T, T>>::value)>
|
const T, T>>::value)>
|
||||||
auto format(U& values, FormatContext& ctx) -> decltype(ctx.out()) {
|
auto format(U& map, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||||
auto out = detail::copy(formatting.prefix, ctx.out());
|
auto out = ctx.out();
|
||||||
size_t i = 0;
|
*out++ = '{';
|
||||||
auto it = std::begin(values);
|
int i = 0;
|
||||||
auto end = std::end(values);
|
for (const auto& item : map) {
|
||||||
for (; it != end; ++it) {
|
|
||||||
if (i > 0) out = detail::write_delimiter(out);
|
if (i > 0) out = detail::write_delimiter(out);
|
||||||
out = detail::write_range_entry<Char>(out, *it);
|
out = detail::write_range_entry<Char>(out, item.first);
|
||||||
|
*out++ = ':';
|
||||||
|
*out++ = ' ';
|
||||||
|
out = detail::write_range_entry<Char>(out, item.second);
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
return detail::copy(formatting.postfix, out);
|
*out++ = '}';
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -613,46 +468,70 @@ template <typename Char, typename... T> struct tuple_join_view : detail::view {
|
|||||||
template <typename Char, typename... T>
|
template <typename Char, typename... T>
|
||||||
using tuple_arg_join = tuple_join_view<Char, T...>;
|
using tuple_arg_join = tuple_join_view<Char, T...>;
|
||||||
|
|
||||||
|
// Define FMT_TUPLE_JOIN_SPECIFIERS to enable experimental format specifiers
|
||||||
|
// support in tuple_join. It is disabled by default because of issues with
|
||||||
|
// the dynamic width and precision.
|
||||||
|
#ifndef FMT_TUPLE_JOIN_SPECIFIERS
|
||||||
|
# define FMT_TUPLE_JOIN_SPECIFIERS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
template <typename Char, typename... T>
|
template <typename Char, typename... T>
|
||||||
struct formatter<tuple_join_view<Char, T...>, Char> {
|
struct formatter<tuple_join_view<Char, T...>, Char> {
|
||||||
template <typename ParseContext>
|
template <typename ParseContext>
|
||||||
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
FMT_CONSTEXPR auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
|
||||||
return ctx.begin();
|
return do_parse(ctx, std::integral_constant<size_t, sizeof...(T)>());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
auto format(const tuple_join_view<Char, T...>& value, FormatContext& ctx) ->
|
auto format(const tuple_join_view<Char, T...>& value,
|
||||||
typename FormatContext::iterator {
|
FormatContext& ctx) const -> typename FormatContext::iterator {
|
||||||
return format(value, ctx, detail::make_index_sequence<sizeof...(T)>{});
|
return do_format(value, ctx,
|
||||||
|
std::integral_constant<size_t, sizeof...(T)>());
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template <typename FormatContext, size_t... N>
|
std::tuple<formatter<typename std::decay<T>::type, Char>...> formatters_;
|
||||||
auto format(const tuple_join_view<Char, T...>& value, FormatContext& ctx,
|
|
||||||
detail::index_sequence<N...>) ->
|
template <typename ParseContext>
|
||||||
typename FormatContext::iterator {
|
FMT_CONSTEXPR auto do_parse(ParseContext& ctx,
|
||||||
using std::get;
|
std::integral_constant<size_t, 0>)
|
||||||
return format_args(value, ctx, get<N>(value.tuple)...);
|
-> decltype(ctx.begin()) {
|
||||||
|
return ctx.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ParseContext, size_t N>
|
||||||
|
FMT_CONSTEXPR auto do_parse(ParseContext& ctx,
|
||||||
|
std::integral_constant<size_t, N>)
|
||||||
|
-> decltype(ctx.begin()) {
|
||||||
|
auto end = ctx.begin();
|
||||||
|
#if FMT_TUPLE_JOIN_SPECIFIERS
|
||||||
|
end = std::get<sizeof...(T) - N>(formatters_).parse(ctx);
|
||||||
|
if (N > 1) {
|
||||||
|
auto end1 = do_parse(ctx, std::integral_constant<size_t, N - 1>());
|
||||||
|
if (end != end1)
|
||||||
|
FMT_THROW(format_error("incompatible format specs for tuple elements"));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return end;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
auto format_args(const tuple_join_view<Char, T...>&, FormatContext& ctx) ->
|
auto do_format(const tuple_join_view<Char, T...>&, FormatContext& ctx,
|
||||||
|
std::integral_constant<size_t, 0>) const ->
|
||||||
typename FormatContext::iterator {
|
typename FormatContext::iterator {
|
||||||
// NOTE: for compilers that support C++17, this empty function instantiation
|
|
||||||
// can be replaced with a constexpr branch in the variadic overload.
|
|
||||||
return ctx.out();
|
return ctx.out();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FormatContext, typename Arg, typename... Args>
|
template <typename FormatContext, size_t N>
|
||||||
auto format_args(const tuple_join_view<Char, T...>& value, FormatContext& ctx,
|
auto do_format(const tuple_join_view<Char, T...>& value, FormatContext& ctx,
|
||||||
const Arg& arg, const Args&... args) ->
|
std::integral_constant<size_t, N>) const ->
|
||||||
typename FormatContext::iterator {
|
typename FormatContext::iterator {
|
||||||
using base = formatter<typename std::decay<Arg>::type, Char>;
|
auto out = std::get<sizeof...(T) - N>(formatters_)
|
||||||
auto out = base().format(arg, ctx);
|
.format(std::get<sizeof...(T) - N>(value.tuple), ctx);
|
||||||
if (sizeof...(Args) > 0) {
|
if (N > 1) {
|
||||||
out = std::copy(value.sep.begin(), value.sep.end(), out);
|
out = std::copy(value.sep.begin(), value.sep.end(), out);
|
||||||
ctx.advance_to(out);
|
ctx.advance_to(out);
|
||||||
return format_args(value, ctx, args...);
|
return do_format(value, ctx, std::integral_constant<size_t, N - 1>());
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
36
vendor/Fmt/include/fmt/xchar.h
vendored
36
vendor/Fmt/include/fmt/xchar.h
vendored
@ -5,8 +5,8 @@
|
|||||||
//
|
//
|
||||||
// For the license information refer to format.h.
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
#ifndef FMT_WCHAR_H_
|
#ifndef FMT_XCHAR_H_
|
||||||
#define FMT_WCHAR_H_
|
#define FMT_XCHAR_H_
|
||||||
|
|
||||||
#include <cwchar>
|
#include <cwchar>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
@ -92,8 +92,8 @@ auto vformat(basic_string_view<Char> format_str,
|
|||||||
template <typename S, typename... Args, typename Char = char_t<S>,
|
template <typename S, typename... Args, typename Char = char_t<S>,
|
||||||
FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
|
FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
|
||||||
auto format(const S& format_str, Args&&... args) -> std::basic_string<Char> {
|
auto format(const S& format_str, Args&&... args) -> std::basic_string<Char> {
|
||||||
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
return vformat(to_string_view(format_str),
|
||||||
return vformat(to_string_view(format_str), vargs);
|
fmt::make_format_args<buffer_context<Char>>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Locale, typename S, typename Char = char_t<S>,
|
template <typename Locale, typename S, typename Char = char_t<S>,
|
||||||
@ -113,7 +113,7 @@ template <typename Locale, typename S, typename... Args,
|
|||||||
inline auto format(const Locale& loc, const S& format_str, Args&&... args)
|
inline auto format(const Locale& loc, const S& format_str, Args&&... args)
|
||||||
-> std::basic_string<Char> {
|
-> std::basic_string<Char> {
|
||||||
return detail::vformat(loc, to_string_view(format_str),
|
return detail::vformat(loc, to_string_view(format_str),
|
||||||
fmt::make_args_checked<Args...>(format_str, args...));
|
fmt::make_format_args<buffer_context<Char>>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIt, typename S, typename Char = char_t<S>,
|
template <typename OutputIt, typename S, typename Char = char_t<S>,
|
||||||
@ -132,8 +132,8 @@ template <typename OutputIt, typename S, typename... Args,
|
|||||||
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
|
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value&&
|
||||||
detail::is_exotic_char<Char>::value)>
|
detail::is_exotic_char<Char>::value)>
|
||||||
inline auto format_to(OutputIt out, const S& fmt, Args&&... args) -> OutputIt {
|
inline auto format_to(OutputIt out, const S& fmt, Args&&... args) -> OutputIt {
|
||||||
const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...);
|
return vformat_to(out, to_string_view(fmt),
|
||||||
return vformat_to(out, to_string_view(fmt), vargs);
|
fmt::make_format_args<buffer_context<Char>>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S, typename... Args, typename Char, size_t SIZE,
|
template <typename S, typename... Args, typename Char, size_t SIZE,
|
||||||
@ -141,8 +141,8 @@ template <typename S, typename... Args, typename Char, size_t SIZE,
|
|||||||
FMT_DEPRECATED auto format_to(basic_memory_buffer<Char, SIZE, Allocator>& buf,
|
FMT_DEPRECATED auto format_to(basic_memory_buffer<Char, SIZE, Allocator>& buf,
|
||||||
const S& format_str, Args&&... args) ->
|
const S& format_str, Args&&... args) ->
|
||||||
typename buffer_context<Char>::iterator {
|
typename buffer_context<Char>::iterator {
|
||||||
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
detail::vformat_to(buf, to_string_view(format_str),
|
||||||
detail::vformat_to(buf, to_string_view(format_str), vargs, {});
|
fmt::make_format_args<buffer_context<Char>>(args...), {});
|
||||||
return detail::buffer_appender<Char>(buf);
|
return detail::buffer_appender<Char>(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,8 +167,8 @@ template <
|
|||||||
inline auto format_to(OutputIt out, const Locale& loc, const S& format_str,
|
inline auto format_to(OutputIt out, const Locale& loc, const S& format_str,
|
||||||
Args&&... args) ->
|
Args&&... args) ->
|
||||||
typename std::enable_if<enable, OutputIt>::type {
|
typename std::enable_if<enable, OutputIt>::type {
|
||||||
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
|
return vformat_to(out, loc, to_string_view(format_str),
|
||||||
return vformat_to(out, loc, to_string_view(format_str), vargs);
|
fmt::make_format_args<buffer_context<Char>>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIt, typename Char, typename... Args,
|
template <typename OutputIt, typename Char, typename... Args,
|
||||||
@ -190,16 +190,16 @@ template <typename OutputIt, typename S, typename... Args,
|
|||||||
detail::is_exotic_char<Char>::value)>
|
detail::is_exotic_char<Char>::value)>
|
||||||
inline auto format_to_n(OutputIt out, size_t n, const S& fmt,
|
inline auto format_to_n(OutputIt out, size_t n, const S& fmt,
|
||||||
const Args&... args) -> format_to_n_result<OutputIt> {
|
const Args&... args) -> format_to_n_result<OutputIt> {
|
||||||
const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...);
|
return vformat_to_n(out, n, to_string_view(fmt),
|
||||||
return vformat_to_n(out, n, to_string_view(fmt), vargs);
|
fmt::make_format_args<buffer_context<Char>>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S, typename... Args, typename Char = char_t<S>,
|
template <typename S, typename... Args, typename Char = char_t<S>,
|
||||||
FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)>
|
FMT_ENABLE_IF(detail::is_exotic_char<Char>::value)>
|
||||||
inline auto formatted_size(const S& fmt, Args&&... args) -> size_t {
|
inline auto formatted_size(const S& fmt, Args&&... args) -> size_t {
|
||||||
detail::counting_buffer<Char> buf;
|
detail::counting_buffer<Char> buf;
|
||||||
const auto& vargs = fmt::make_args_checked<Args...>(fmt, args...);
|
detail::vformat_to(buf, to_string_view(fmt),
|
||||||
detail::vformat_to(buf, to_string_view(fmt), vargs);
|
fmt::make_format_args<buffer_context<Char>>(args...));
|
||||||
return buf.count();
|
return buf.count();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -217,11 +217,11 @@ inline void vprint(wstring_view fmt, wformat_args args) {
|
|||||||
|
|
||||||
template <typename... T>
|
template <typename... T>
|
||||||
void print(std::FILE* f, wformat_string<T...> fmt, T&&... args) {
|
void print(std::FILE* f, wformat_string<T...> fmt, T&&... args) {
|
||||||
return vprint(f, wstring_view(fmt), make_wformat_args(args...));
|
return vprint(f, wstring_view(fmt), fmt::make_wformat_args(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... T> void print(wformat_string<T...> fmt, T&&... args) {
|
template <typename... T> void print(wformat_string<T...> fmt, T&&... args) {
|
||||||
return vprint(wstring_view(fmt), make_wformat_args(args...));
|
return vprint(wstring_view(fmt), fmt::make_wformat_args(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -233,4 +233,4 @@ template <typename T> inline auto to_wstring(const T& value) -> std::wstring {
|
|||||||
FMT_MODULE_EXPORT_END
|
FMT_MODULE_EXPORT_END
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
#endif // FMT_WCHAR_H_
|
#endif // FMT_XCHAR_H_
|
||||||
|
1
vendor/Fmt/src/fmt.cc
vendored
1
vendor/Fmt/src/fmt.cc
vendored
@ -79,7 +79,6 @@ export module fmt;
|
|||||||
#define FMT_END_DETAIL_NAMESPACE \
|
#define FMT_END_DETAIL_NAMESPACE \
|
||||||
} \
|
} \
|
||||||
export {
|
export {
|
||||||
|
|
||||||
// all library-provided declarations and definitions
|
// all library-provided declarations and definitions
|
||||||
// must be in the module purview to be exported
|
// must be in the module purview to be exported
|
||||||
#include "fmt/args.h"
|
#include "fmt/args.h"
|
||||||
|
54
vendor/Fmt/src/format.cc
vendored
54
vendor/Fmt/src/format.cc
vendored
@ -10,6 +10,52 @@
|
|||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
|
// DEPRECATED!
|
||||||
|
template <typename T = void> struct basic_data {
|
||||||
|
FMT_API static constexpr const char digits[100][2] = {
|
||||||
|
{'0', '0'}, {'0', '1'}, {'0', '2'}, {'0', '3'}, {'0', '4'}, {'0', '5'},
|
||||||
|
{'0', '6'}, {'0', '7'}, {'0', '8'}, {'0', '9'}, {'1', '0'}, {'1', '1'},
|
||||||
|
{'1', '2'}, {'1', '3'}, {'1', '4'}, {'1', '5'}, {'1', '6'}, {'1', '7'},
|
||||||
|
{'1', '8'}, {'1', '9'}, {'2', '0'}, {'2', '1'}, {'2', '2'}, {'2', '3'},
|
||||||
|
{'2', '4'}, {'2', '5'}, {'2', '6'}, {'2', '7'}, {'2', '8'}, {'2', '9'},
|
||||||
|
{'3', '0'}, {'3', '1'}, {'3', '2'}, {'3', '3'}, {'3', '4'}, {'3', '5'},
|
||||||
|
{'3', '6'}, {'3', '7'}, {'3', '8'}, {'3', '9'}, {'4', '0'}, {'4', '1'},
|
||||||
|
{'4', '2'}, {'4', '3'}, {'4', '4'}, {'4', '5'}, {'4', '6'}, {'4', '7'},
|
||||||
|
{'4', '8'}, {'4', '9'}, {'5', '0'}, {'5', '1'}, {'5', '2'}, {'5', '3'},
|
||||||
|
{'5', '4'}, {'5', '5'}, {'5', '6'}, {'5', '7'}, {'5', '8'}, {'5', '9'},
|
||||||
|
{'6', '0'}, {'6', '1'}, {'6', '2'}, {'6', '3'}, {'6', '4'}, {'6', '5'},
|
||||||
|
{'6', '6'}, {'6', '7'}, {'6', '8'}, {'6', '9'}, {'7', '0'}, {'7', '1'},
|
||||||
|
{'7', '2'}, {'7', '3'}, {'7', '4'}, {'7', '5'}, {'7', '6'}, {'7', '7'},
|
||||||
|
{'7', '8'}, {'7', '9'}, {'8', '0'}, {'8', '1'}, {'8', '2'}, {'8', '3'},
|
||||||
|
{'8', '4'}, {'8', '5'}, {'8', '6'}, {'8', '7'}, {'8', '8'}, {'8', '9'},
|
||||||
|
{'9', '0'}, {'9', '1'}, {'9', '2'}, {'9', '3'}, {'9', '4'}, {'9', '5'},
|
||||||
|
{'9', '6'}, {'9', '7'}, {'9', '8'}, {'9', '9'}};
|
||||||
|
FMT_API static constexpr const char hex_digits[] = "0123456789abcdef";
|
||||||
|
FMT_API static constexpr const char signs[4] = {0, '-', '+', ' '};
|
||||||
|
FMT_API static constexpr const char left_padding_shifts[5] = {31, 31, 0, 1,
|
||||||
|
0};
|
||||||
|
FMT_API static constexpr const char right_padding_shifts[5] = {0, 31, 0, 1,
|
||||||
|
0};
|
||||||
|
FMT_API static constexpr const unsigned prefixes[4] = {0, 0, 0x1000000u | '+',
|
||||||
|
0x1000000u | ' '};
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef FMT_SHARED
|
||||||
|
// Required for -flto, -fivisibility=hidden and -shared to work
|
||||||
|
extern template struct basic_data<void>;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __cplusplus < 201703L
|
||||||
|
// DEPRECATED! These are here only for ABI compatiblity.
|
||||||
|
template <typename T> constexpr const char basic_data<T>::digits[][2];
|
||||||
|
template <typename T> constexpr const char basic_data<T>::hex_digits[];
|
||||||
|
template <typename T> constexpr const char basic_data<T>::signs[];
|
||||||
|
template <typename T> constexpr const char basic_data<T>::left_padding_shifts[];
|
||||||
|
template <typename T>
|
||||||
|
constexpr const char basic_data<T>::right_padding_shifts[];
|
||||||
|
template <typename T> constexpr const unsigned basic_data<T>::prefixes[];
|
||||||
|
#endif
|
||||||
|
|
||||||
template <typename T>
|
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) {
|
||||||
@ -24,10 +70,10 @@ int format_float(char* buf, std::size_t size, const char* format, int precision,
|
|||||||
: snprintf_ptr(buf, size, format, precision, value);
|
: snprintf_ptr(buf, size, format, precision, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template FMT_API dragonbox::decimal_fp<float> dragonbox::to_decimal(float x)
|
template FMT_API dragonbox::decimal_fp<float> dragonbox::to_decimal(
|
||||||
FMT_NOEXCEPT;
|
float x) noexcept;
|
||||||
template FMT_API dragonbox::decimal_fp<double> dragonbox::to_decimal(double x)
|
template FMT_API dragonbox::decimal_fp<double> dragonbox::to_decimal(
|
||||||
FMT_NOEXCEPT;
|
double x) noexcept;
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
// Workaround a bug in MSVC2013 that prevents instantiation of format_float.
|
// Workaround a bug in MSVC2013 that prevents instantiation of format_float.
|
||||||
|
44
vendor/Fmt/src/os.cc
vendored
44
vendor/Fmt/src/os.cc
vendored
@ -26,19 +26,23 @@
|
|||||||
# endif
|
# endif
|
||||||
# include <io.h>
|
# include <io.h>
|
||||||
|
|
||||||
# define O_CREAT _O_CREAT
|
|
||||||
# define O_TRUNC _O_TRUNC
|
|
||||||
|
|
||||||
# ifndef S_IRUSR
|
# ifndef S_IRUSR
|
||||||
# define S_IRUSR _S_IREAD
|
# define S_IRUSR _S_IREAD
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
# ifndef S_IWUSR
|
# ifndef S_IWUSR
|
||||||
# define S_IWUSR _S_IWRITE
|
# define S_IWUSR _S_IWRITE
|
||||||
# endif
|
# endif
|
||||||
|
# ifndef S_IRGRP
|
||||||
# ifdef __MINGW32__
|
# define S_IRGRP 0
|
||||||
# define _SH_DENYNO 0x40
|
# endif
|
||||||
|
# ifndef S_IWGRP
|
||||||
|
# define S_IWGRP 0
|
||||||
|
# endif
|
||||||
|
# ifndef S_IROTH
|
||||||
|
# define S_IROTH 0
|
||||||
|
# endif
|
||||||
|
# ifndef S_IWOTH
|
||||||
|
# define S_IWOTH 0
|
||||||
# endif
|
# endif
|
||||||
# endif // _WIN32
|
# endif // _WIN32
|
||||||
#endif // FMT_USE_FCNTL
|
#endif // FMT_USE_FCNTL
|
||||||
@ -109,7 +113,7 @@ class system_message {
|
|||||||
unsigned long result_;
|
unsigned long result_;
|
||||||
wchar_t* message_;
|
wchar_t* message_;
|
||||||
|
|
||||||
static bool is_whitespace(wchar_t c) FMT_NOEXCEPT {
|
static bool is_whitespace(wchar_t c) noexcept {
|
||||||
return c == L' ' || c == L'\n' || c == L'\r' || c == L'\t' || c == L'\0';
|
return c == L' ' || c == L'\n' || c == L'\r' || c == L'\t' || c == L'\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,15 +132,15 @@ class system_message {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
~system_message() { LocalFree(message_); }
|
~system_message() { LocalFree(message_); }
|
||||||
explicit operator bool() const FMT_NOEXCEPT { return result_ != 0; }
|
explicit operator bool() const noexcept { return result_ != 0; }
|
||||||
operator basic_string_view<wchar_t>() const FMT_NOEXCEPT {
|
operator basic_string_view<wchar_t>() const noexcept {
|
||||||
return basic_string_view<wchar_t>(message_, result_);
|
return basic_string_view<wchar_t>(message_, result_);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class utf8_system_category final : public std::error_category {
|
class utf8_system_category final : public std::error_category {
|
||||||
public:
|
public:
|
||||||
const char* name() const FMT_NOEXCEPT override { return "system"; }
|
const char* name() const noexcept override { return "system"; }
|
||||||
std::string message(int error_code) const override {
|
std::string message(int error_code) const override {
|
||||||
system_message msg(error_code);
|
system_message msg(error_code);
|
||||||
if (msg) {
|
if (msg) {
|
||||||
@ -151,7 +155,7 @@ class utf8_system_category final : public std::error_category {
|
|||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
FMT_API const std::error_category& system_category() FMT_NOEXCEPT {
|
FMT_API const std::error_category& system_category() noexcept {
|
||||||
static const detail::utf8_system_category category;
|
static const detail::utf8_system_category category;
|
||||||
return category;
|
return category;
|
||||||
}
|
}
|
||||||
@ -163,7 +167,7 @@ std::system_error vwindows_error(int err_code, string_view format_str,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void detail::format_windows_error(detail::buffer<char>& out, int error_code,
|
void detail::format_windows_error(detail::buffer<char>& out, int error_code,
|
||||||
const char* message) FMT_NOEXCEPT {
|
const char* message) noexcept {
|
||||||
FMT_TRY {
|
FMT_TRY {
|
||||||
system_message msg(error_code);
|
system_message msg(error_code);
|
||||||
if (msg) {
|
if (msg) {
|
||||||
@ -178,12 +182,12 @@ void detail::format_windows_error(detail::buffer<char>& out, int error_code,
|
|||||||
format_error_code(out, error_code, message);
|
format_error_code(out, error_code, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void report_windows_error(int error_code, const char* message) FMT_NOEXCEPT {
|
void report_windows_error(int error_code, const char* message) noexcept {
|
||||||
report_error(detail::format_windows_error, error_code, message);
|
report_error(detail::format_windows_error, error_code, message);
|
||||||
}
|
}
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
|
|
||||||
buffered_file::~buffered_file() FMT_NOEXCEPT {
|
buffered_file::~buffered_file() noexcept {
|
||||||
if (file_ && FMT_SYSTEM(fclose(file_)) != 0)
|
if (file_ && FMT_SYSTEM(fclose(file_)) != 0)
|
||||||
report_system_error(errno, "cannot close file");
|
report_system_error(errno, "cannot close file");
|
||||||
}
|
}
|
||||||
@ -213,7 +217,11 @@ 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;
|
# ifdef _WIN32
|
||||||
|
using mode_t = int;
|
||||||
|
# endif
|
||||||
|
constexpr mode_t mode =
|
||||||
|
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
|
||||||
# if defined(_WIN32) && !defined(__MINGW32__)
|
# if defined(_WIN32) && !defined(__MINGW32__)
|
||||||
fd_ = -1;
|
fd_ = -1;
|
||||||
FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode));
|
FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode));
|
||||||
@ -224,7 +232,7 @@ file::file(cstring_view path, int oflag) {
|
|||||||
FMT_THROW(system_error(errno, "cannot open file {}", path.c_str()));
|
FMT_THROW(system_error(errno, "cannot open file {}", path.c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
file::~file() FMT_NOEXCEPT {
|
file::~file() noexcept {
|
||||||
// Don't retry close in case of EINTR!
|
// Don't retry close in case of EINTR!
|
||||||
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
|
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
|
||||||
if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0)
|
if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0)
|
||||||
@ -298,7 +306,7 @@ void file::dup2(int fd) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void file::dup2(int fd, std::error_code& ec) FMT_NOEXCEPT {
|
void file::dup2(int fd, std::error_code& ec) noexcept {
|
||||||
int result = 0;
|
int result = 0;
|
||||||
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
|
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
|
||||||
if (result == -1) ec = std::error_code(errno, std::generic_category());
|
if (result == -1) ec = std::error_code(errno, std::generic_category());
|
||||||
|
29
vendor/Fmt/support/bazel/BUILD.bazel
vendored
Normal file
29
vendor/Fmt/support/bazel/BUILD.bazel
vendored
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
cc_library(
|
||||||
|
name = "fmt",
|
||||||
|
srcs = [
|
||||||
|
#"src/fmt.cc", # No C++ module support
|
||||||
|
"src/format.cc",
|
||||||
|
"src/os.cc",
|
||||||
|
],
|
||||||
|
hdrs = [
|
||||||
|
"include/fmt/args.h",
|
||||||
|
"include/fmt/chrono.h",
|
||||||
|
"include/fmt/color.h",
|
||||||
|
"include/fmt/compile.h",
|
||||||
|
"include/fmt/core.h",
|
||||||
|
"include/fmt/format.h",
|
||||||
|
"include/fmt/format-inl.h",
|
||||||
|
"include/fmt/locale.h",
|
||||||
|
"include/fmt/os.h",
|
||||||
|
"include/fmt/ostream.h",
|
||||||
|
"include/fmt/printf.h",
|
||||||
|
"include/fmt/ranges.h",
|
||||||
|
"include/fmt/xchar.h",
|
||||||
|
],
|
||||||
|
includes = [
|
||||||
|
"include",
|
||||||
|
"src",
|
||||||
|
],
|
||||||
|
strip_include_prefix = "include",
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
)
|
73
vendor/Fmt/support/bazel/README.md
vendored
Normal file
73
vendor/Fmt/support/bazel/README.md
vendored
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
# Bazel support
|
||||||
|
|
||||||
|
To get [Bazel](https://bazel.build/) working with {fmt} you can copy the files `BUILD.bazel`, `WORKSPACE.bazel`, `.bazelrc`, and `.bazelversion` from this folder (`support/bazel`) to the root folder of this project. This way {fmt} gets bazelized and can be used with Bazel (e.g. doing a `bazel build //...` on {fmt}).
|
||||||
|
|
||||||
|
## Using {fmt} as a dependency
|
||||||
|
|
||||||
|
The following minimal example shows how to use {fmt} as a dependency within a Bazel project.
|
||||||
|
|
||||||
|
The following file structure is assumed:
|
||||||
|
|
||||||
|
```
|
||||||
|
example
|
||||||
|
├── BUILD.bazel
|
||||||
|
├── main.cpp
|
||||||
|
└── WORKSPACE.bazel
|
||||||
|
```
|
||||||
|
|
||||||
|
*main.cpp*:
|
||||||
|
|
||||||
|
```c++
|
||||||
|
#include "fmt/core.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
fmt::print("The answer is {}\n", 42);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The expected output of this example is `The answer is 42`.
|
||||||
|
|
||||||
|
*WORKSPACE.bazel*:
|
||||||
|
|
||||||
|
```python
|
||||||
|
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
|
||||||
|
|
||||||
|
git_repository(
|
||||||
|
name = "fmt",
|
||||||
|
branch = "master",
|
||||||
|
remote = "https://github.com/fmtlib/fmt",
|
||||||
|
patch_cmds = [
|
||||||
|
"mv support/bazel/.bazelrc .bazelrc",
|
||||||
|
"mv support/bazel/.bazelversion .bazelversion",
|
||||||
|
"mv support/bazel/BUILD.bazel BUILD.bazel",
|
||||||
|
"mv support/bazel/WORKSPACE.bazel WORKSPACE.bazel",
|
||||||
|
],
|
||||||
|
# Windows-related patch commands are only needed in the case MSYS2 is not installed.
|
||||||
|
# More details about the installation process of MSYS2 on Windows systems can be found here:
|
||||||
|
# https://docs.bazel.build/versions/main/install-windows.html#installing-compilers-and-language-runtimes
|
||||||
|
# Even if MSYS2 is installed the Windows related patch commands can still be used.
|
||||||
|
patch_cmds_win = [
|
||||||
|
"Move-Item -Path support/bazel/.bazelrc -Destination .bazelrc",
|
||||||
|
"Move-Item -Path support/bazel/.bazelversion -Destination .bazelversion",
|
||||||
|
"Move-Item -Path support/bazel/BUILD.bazel -Destination BUILD.bazel",
|
||||||
|
"Move-Item -Path support/bazel/WORKSPACE.bazel -Destination WORKSPACE.bazel",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
In the *WORKSPACE* file, the {fmt} GitHub repository is fetched. Using the attribute `patch_cmds` the files `BUILD.bazel`, `WORKSPACE.bazel`, `.bazelrc`, and `.bazelversion` are moved to the root of the {fmt} repository. This way the {fmt} repository is recognized as a bazelized workspace.
|
||||||
|
|
||||||
|
*BUILD.bazel*:
|
||||||
|
|
||||||
|
```python
|
||||||
|
cc_binary(
|
||||||
|
name = "Demo",
|
||||||
|
srcs = ["main.cpp"],
|
||||||
|
deps = ["@fmt"],
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
The *BUILD* file defines a binary named `Demo` that has a dependency to {fmt}.
|
||||||
|
|
||||||
|
To execute the binary you can run `bazel run //:Demo`.
|
||||||
|
|
1
vendor/Fmt/support/bazel/WORKSPACE.bazel
vendored
Normal file
1
vendor/Fmt/support/bazel/WORKSPACE.bazel
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
workspace(name = "fmt")
|
10
vendor/Fmt/support/manage.py
vendored
10
vendor/Fmt/support/manage.py
vendored
@ -240,7 +240,7 @@ def release(args):
|
|||||||
# Update the version in the changelog.
|
# Update the version in the changelog.
|
||||||
title_len = 0
|
title_len = 0
|
||||||
for line in fileinput.input(changelog_path, inplace=True):
|
for line in fileinput.input(changelog_path, inplace=True):
|
||||||
if line.decode('utf-8').startswith(version + ' - TBD'):
|
if line.startswith(version + ' - TBD'):
|
||||||
line = version + ' - ' + datetime.date.today().isoformat()
|
line = version + ' - ' + datetime.date.today().isoformat()
|
||||||
title_len = len(line)
|
title_len = len(line)
|
||||||
line += '\n'
|
line += '\n'
|
||||||
@ -270,9 +270,9 @@ def release(args):
|
|||||||
|
|
||||||
# Create a release on GitHub.
|
# Create a release on GitHub.
|
||||||
fmt_repo.push('origin', 'release')
|
fmt_repo.push('origin', 'release')
|
||||||
params = {'access_token': os.getenv('FMT_TOKEN')}
|
auth_headers = {'Authorization': 'token ' + os.getenv('FMT_TOKEN')}
|
||||||
r = requests.post('https://api.github.com/repos/fmtlib/fmt/releases',
|
r = requests.post('https://api.github.com/repos/fmtlib/fmt/releases',
|
||||||
params=params,
|
headers=auth_headers,
|
||||||
data=json.dumps({'tag_name': version,
|
data=json.dumps({'tag_name': version,
|
||||||
'target_commitish': 'release',
|
'target_commitish': 'release',
|
||||||
'body': changes, 'draft': True}))
|
'body': changes, 'draft': True}))
|
||||||
@ -283,8 +283,8 @@ def release(args):
|
|||||||
package = 'fmt-{}.zip'.format(version)
|
package = 'fmt-{}.zip'.format(version)
|
||||||
r = requests.post(
|
r = requests.post(
|
||||||
'{}/{}/assets?name={}'.format(uploads_url, id, package),
|
'{}/{}/assets?name={}'.format(uploads_url, id, package),
|
||||||
headers={'Content-Type': 'application/zip'},
|
headers={'Content-Type': 'application/zip'} | auth_headers,
|
||||||
params=params, data=open('build/fmt/' + package, 'rb'))
|
data=open('build/fmt/' + package, 'rb'))
|
||||||
if r.status_code != 201:
|
if r.status_code != 201:
|
||||||
raise Exception('Failed to upload an asset ' + str(r))
|
raise Exception('Failed to upload an asset ' + str(r))
|
||||||
|
|
||||||
|
59
vendor/Fmt/support/printable.py
vendored
59
vendor/Fmt/support/printable.py
vendored
@ -171,66 +171,31 @@ def main():
|
|||||||
normal1 = compress_normal(normal1)
|
normal1 = compress_normal(normal1)
|
||||||
|
|
||||||
print("""\
|
print("""\
|
||||||
struct singleton {
|
FMT_FUNC auto is_printable(uint32_t cp) -> bool {\
|
||||||
unsigned char upper;
|
|
||||||
unsigned char lowercount;
|
|
||||||
};
|
|
||||||
|
|
||||||
inline auto check(uint16_t x, const singleton* singletonuppers,
|
|
||||||
size_t singletonuppers_size,
|
|
||||||
const unsigned char* singletonlowers,
|
|
||||||
const unsigned char* normal, size_t normal_size) -> bool {
|
|
||||||
auto xupper = x >> 8;
|
|
||||||
auto lowerstart = 0;
|
|
||||||
for (size_t i = 0; i < singletonuppers_size; ++i) {
|
|
||||||
auto su = singletonuppers[i];
|
|
||||||
auto lowerend = lowerstart + su.lowercount;
|
|
||||||
if (xupper < su.upper) break;
|
|
||||||
if (xupper == su.upper) {
|
|
||||||
for (auto j = lowerstart; j < lowerend; ++j) {
|
|
||||||
if (singletonlowers[j] == x) return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lowerstart = lowerend;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto xsigned = static_cast<int>(x);
|
|
||||||
auto current = true;
|
|
||||||
for (size_t i = 0; i < normal_size; ++i) {
|
|
||||||
auto v = static_cast<int>(normal[i]);
|
|
||||||
auto len = v & 0x80 != 0 ? (v & 0x7f) << 8 | normal[i++] : v;
|
|
||||||
xsigned -= len;
|
|
||||||
if (xsigned < 0) break;
|
|
||||||
current = !current;
|
|
||||||
}
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline auto is_printable(uint32_t cp) -> bool {\
|
|
||||||
""")
|
""")
|
||||||
print_singletons(singletons0u, singletons0l, 'singletons0u', 'singletons0l')
|
print_singletons(singletons0u, singletons0l, 'singletons0', 'singletons0_lower')
|
||||||
print_singletons(singletons1u, singletons1l, 'singletons1u', 'singletons1l')
|
print_singletons(singletons1u, singletons1l, 'singletons1', 'singletons1_lower')
|
||||||
print_normal(normal0, 'normal0')
|
print_normal(normal0, 'normal0')
|
||||||
print_normal(normal1, 'normal1')
|
print_normal(normal1, 'normal1')
|
||||||
print("""\
|
print("""\
|
||||||
auto lower = static_cast<uint16_t>(cp);
|
auto lower = static_cast<uint16_t>(cp);
|
||||||
if (cp < 0x10000) {
|
if (cp < 0x10000) {
|
||||||
return check(lower, singletons0u,
|
return is_printable(lower, singletons0,
|
||||||
sizeof(singletons0u) / sizeof(*singletons0u), singletons0l,
|
sizeof(singletons0) / sizeof(*singletons0),
|
||||||
normal0, sizeof(normal0));
|
singletons0_lower, normal0, sizeof(normal0));
|
||||||
}
|
}
|
||||||
if (cp < 0x20000) {
|
if (cp < 0x20000) {
|
||||||
return check(lower, singletons1u,
|
return is_printable(lower, singletons1,
|
||||||
sizeof(singletons1u) / sizeof(*singletons1u), singletons1l,
|
sizeof(singletons1) / sizeof(*singletons1),
|
||||||
normal1, sizeof(normal1));
|
singletons1_lower, normal1, sizeof(normal1));
|
||||||
}\
|
}\
|
||||||
""")
|
""")
|
||||||
for a, b in extra:
|
for a, b in extra:
|
||||||
print(" if (0x{:x} <= cp && cp < 0x{:x}) return false;".format(a, a + b))
|
print(" if (0x{:x} <= cp && cp < 0x{:x}) return false;".format(a, a + b))
|
||||||
print("""\
|
print("""\
|
||||||
return true;
|
return cp < 0x{:x};
|
||||||
}\
|
}}\
|
||||||
""")
|
""".format(NUM_CODEPOINTS))
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
46
vendor/Fmt/test/CMakeLists.txt
vendored
46
vendor/Fmt/test/CMakeLists.txt
vendored
@ -4,23 +4,10 @@ set(TEST_MAIN_SRC test-main.cc gtest-extra.cc gtest-extra.h util.cc)
|
|||||||
add_library(test-main STATIC ${TEST_MAIN_SRC})
|
add_library(test-main STATIC ${TEST_MAIN_SRC})
|
||||||
target_include_directories(test-main PUBLIC
|
target_include_directories(test-main PUBLIC
|
||||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>)
|
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>)
|
||||||
target_link_libraries(test-main gtest)
|
target_link_libraries(test-main gtest fmt)
|
||||||
|
|
||||||
include(CheckCXXCompilerFlag)
|
include(CheckCXXCompilerFlag)
|
||||||
|
|
||||||
# Workaround GTest bug https://github.com/google/googletest/issues/705.
|
|
||||||
check_cxx_compiler_flag(
|
|
||||||
-fno-delete-null-pointer-checks HAVE_FNO_DELETE_NULL_POINTER_CHECKS)
|
|
||||||
if (HAVE_FNO_DELETE_NULL_POINTER_CHECKS)
|
|
||||||
target_compile_options(test-main PUBLIC -fno-delete-null-pointer-checks)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
# Use less strict pedantic flags for the tests because GMock doesn't compile
|
|
||||||
# cleanly with -pedantic and -std=c++98.
|
|
||||||
if (CMAKE_COMPILER_IS_GNUCXX OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
|
|
||||||
#set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -Wno-long-long -Wno-variadic-macros)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
function(add_fmt_executable name)
|
function(add_fmt_executable name)
|
||||||
add_executable(${name} ${ARGN})
|
add_executable(${name} ${ARGN})
|
||||||
if (MINGW)
|
if (MINGW)
|
||||||
@ -84,8 +71,13 @@ if (NOT (MSVC AND BUILD_SHARED_LIBS))
|
|||||||
endif ()
|
endif ()
|
||||||
add_fmt_test(ostream-test)
|
add_fmt_test(ostream-test)
|
||||||
add_fmt_test(compile-test)
|
add_fmt_test(compile-test)
|
||||||
|
add_fmt_test(compile-fp-test HEADER_ONLY)
|
||||||
|
if (MSVC)
|
||||||
|
# Without this option, MSVC returns 199711L for the __cplusplus macro.
|
||||||
|
target_compile_options(compile-fp-test PRIVATE /Zc:__cplusplus)
|
||||||
|
endif()
|
||||||
add_fmt_test(printf-test)
|
add_fmt_test(printf-test)
|
||||||
add_fmt_test(ranges-test)
|
add_fmt_test(ranges-test ranges-odr-test.cc)
|
||||||
add_fmt_test(scan-test)
|
add_fmt_test(scan-test)
|
||||||
add_fmt_test(unicode-test HEADER_ONLY)
|
add_fmt_test(unicode-test HEADER_ONLY)
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
@ -136,29 +128,20 @@ if (NOT MSVC_STATIC_RUNTIME)
|
|||||||
if (FMT_PEDANTIC)
|
if (FMT_PEDANTIC)
|
||||||
target_compile_options(posix-mock-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
|
target_compile_options(posix-mock-test PRIVATE ${PEDANTIC_COMPILE_FLAGS})
|
||||||
endif ()
|
endif ()
|
||||||
if (HAVE_STRTOD_L)
|
|
||||||
target_compile_definitions(posix-mock-test PRIVATE FMT_LOCALE)
|
|
||||||
endif ()
|
|
||||||
add_test(NAME posix-mock-test COMMAND posix-mock-test)
|
add_test(NAME posix-mock-test COMMAND posix-mock-test)
|
||||||
add_fmt_test(os-test)
|
add_fmt_test(os-test)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
message(STATUS "FMT_PEDANTIC: ${FMT_PEDANTIC}")
|
message(STATUS "FMT_PEDANTIC: ${FMT_PEDANTIC}")
|
||||||
|
|
||||||
if (FMT_PEDANTIC AND CXX_STANDARD LESS 20)
|
if (FMT_PEDANTIC)
|
||||||
# MSVC fails to compile GMock when C++17 is enabled.
|
|
||||||
if (FMT_HAS_VARIANT AND NOT MSVC)
|
|
||||||
add_fmt_test(std-format-test)
|
|
||||||
set_property(TARGET std-format-test PROPERTY CXX_STANDARD 17)
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
# Test that the library can be compiled with exceptions disabled.
|
# Test that the library can be compiled with exceptions disabled.
|
||||||
# -fno-exception is broken in icc: https://github.com/fmtlib/fmt/issues/822.
|
# -fno-exception is broken in icc: https://github.com/fmtlib/fmt/issues/822.
|
||||||
if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
|
if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
|
||||||
check_cxx_compiler_flag(-fno-exceptions HAVE_FNO_EXCEPTIONS_FLAG)
|
check_cxx_compiler_flag(-fno-exceptions HAVE_FNO_EXCEPTIONS_FLAG)
|
||||||
endif ()
|
endif ()
|
||||||
if (HAVE_FNO_EXCEPTIONS_FLAG)
|
if (HAVE_FNO_EXCEPTIONS_FLAG)
|
||||||
add_library(noexception-test ../src/format.cc)
|
add_library(noexception-test ../src/format.cc noexception-test.cc)
|
||||||
target_include_directories(
|
target_include_directories(
|
||||||
noexception-test PRIVATE ${PROJECT_SOURCE_DIR}/include)
|
noexception-test PRIVATE ${PROJECT_SOURCE_DIR}/include)
|
||||||
target_compile_options(noexception-test PRIVATE -fno-exceptions)
|
target_compile_options(noexception-test PRIVATE -fno-exceptions)
|
||||||
@ -173,7 +156,11 @@ if (FMT_PEDANTIC AND CXX_STANDARD LESS 20)
|
|||||||
nolocale-test PRIVATE ${PROJECT_SOURCE_DIR}/include)
|
nolocale-test PRIVATE ${PROJECT_SOURCE_DIR}/include)
|
||||||
target_compile_definitions(
|
target_compile_definitions(
|
||||||
nolocale-test PRIVATE FMT_STATIC_THOUSANDS_SEPARATOR=1)
|
nolocale-test PRIVATE FMT_STATIC_THOUSANDS_SEPARATOR=1)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
# These tests are disabled on Windows because they take too long.
|
||||||
|
if (FMT_PEDANTIC AND NOT WIN32)
|
||||||
|
# Test if incorrect API usages produce compilation error.
|
||||||
add_test(compile-error-test ${CMAKE_CTEST_COMMAND}
|
add_test(compile-error-test ${CMAKE_CTEST_COMMAND}
|
||||||
--build-and-test
|
--build-and-test
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/compile-error-test"
|
"${CMAKE_CURRENT_SOURCE_DIR}/compile-error-test"
|
||||||
@ -182,14 +169,11 @@ if (FMT_PEDANTIC AND CXX_STANDARD LESS 20)
|
|||||||
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
|
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
|
||||||
--build-options
|
--build-options
|
||||||
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
|
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
|
||||||
|
"-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}"
|
||||||
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
|
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
|
||||||
"-DCXX_STANDARD_FLAG=${CXX_STANDARD_FLAG}"
|
"-DFMT_DIR=${CMAKE_SOURCE_DIR}"
|
||||||
"-DPEDANTIC_COMPILE_FLAGS=${PEDANTIC_COMPILE_FLAGS}"
|
|
||||||
"-DSUPPORTS_USER_DEFINED_LITERALS=${SUPPORTS_USER_DEFINED_LITERALS}")
|
"-DSUPPORTS_USER_DEFINED_LITERALS=${SUPPORTS_USER_DEFINED_LITERALS}")
|
||||||
endif ()
|
|
||||||
|
|
||||||
# These tests are disabled on Windows because they take too long.
|
|
||||||
if (FMT_PEDANTIC AND NOT WIN32)
|
|
||||||
# Test if the targets are found from the build directory.
|
# Test if the targets are found from the build directory.
|
||||||
add_test(find-package-test ${CMAKE_CTEST_COMMAND}
|
add_test(find-package-test ${CMAKE_CTEST_COMMAND}
|
||||||
-C ${CMAKE_BUILD_TYPE}
|
-C ${CMAKE_BUILD_TYPE}
|
||||||
|
44
vendor/Fmt/test/args-test.cc
vendored
44
vendor/Fmt/test/args-test.cc
vendored
@ -7,10 +7,12 @@
|
|||||||
|
|
||||||
#include "fmt/args.h"
|
#include "fmt/args.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
TEST(args_test, basic) {
|
TEST(args_test, basic) {
|
||||||
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||||
store.push_back(42);
|
store.push_back(42);
|
||||||
store.push_back("abc1");
|
store.push_back("abc1");
|
||||||
store.push_back(1.5f);
|
store.push_back(1.5f);
|
||||||
@ -19,7 +21,7 @@ TEST(args_test, basic) {
|
|||||||
|
|
||||||
TEST(args_test, strings_and_refs) {
|
TEST(args_test, strings_and_refs) {
|
||||||
// Unfortunately the tests are compiled with old ABI so strings use COW.
|
// Unfortunately the tests are compiled with old ABI so strings use COW.
|
||||||
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||||
char str[] = "1234567890";
|
char str[] = "1234567890";
|
||||||
store.push_back(str);
|
store.push_back(str);
|
||||||
store.push_back(std::cref(str));
|
store.push_back(std::cref(str));
|
||||||
@ -48,7 +50,7 @@ template <> struct formatter<custom_type> {
|
|||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
TEST(args_test, custom_format) {
|
TEST(args_test, custom_format) {
|
||||||
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||||
auto c = custom_type();
|
auto c = custom_type();
|
||||||
store.push_back(c);
|
store.push_back(c);
|
||||||
++c.i;
|
++c.i;
|
||||||
@ -77,7 +79,7 @@ template <> struct formatter<to_stringable> {
|
|||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
TEST(args_test, to_string_and_formatter) {
|
TEST(args_test, to_string_and_formatter) {
|
||||||
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||||
auto s = to_stringable();
|
auto s = to_stringable();
|
||||||
store.push_back(s);
|
store.push_back(s);
|
||||||
store.push_back(std::cref(s));
|
store.push_back(std::cref(s));
|
||||||
@ -85,13 +87,13 @@ TEST(args_test, to_string_and_formatter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(args_test, named_int) {
|
TEST(args_test, named_int) {
|
||||||
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||||
store.push_back(fmt::arg("a1", 42));
|
store.push_back(fmt::arg("a1", 42));
|
||||||
EXPECT_EQ("42", fmt::vformat("{a1}", store));
|
EXPECT_EQ("42", fmt::vformat("{a1}", store));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(args_test, named_strings) {
|
TEST(args_test, named_strings) {
|
||||||
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||||
char str[] = "1234567890";
|
char str[] = "1234567890";
|
||||||
store.push_back(fmt::arg("a1", str));
|
store.push_back(fmt::arg("a1", str));
|
||||||
store.push_back(fmt::arg("a2", std::cref(str)));
|
store.push_back(fmt::arg("a2", std::cref(str)));
|
||||||
@ -100,7 +102,7 @@ TEST(args_test, named_strings) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(args_test, named_arg_by_ref) {
|
TEST(args_test, named_arg_by_ref) {
|
||||||
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||||
char band[] = "Rolling Stones";
|
char band[] = "Rolling Stones";
|
||||||
store.push_back(fmt::arg("band", std::cref(band)));
|
store.push_back(fmt::arg("band", std::cref(band)));
|
||||||
band[9] = 'c'; // Changing band affects the output.
|
band[9] = 'c'; // Changing band affects the output.
|
||||||
@ -108,7 +110,7 @@ TEST(args_test, named_arg_by_ref) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(args_test, named_custom_format) {
|
TEST(args_test, named_custom_format) {
|
||||||
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||||
auto c = custom_type();
|
auto c = custom_type();
|
||||||
store.push_back(fmt::arg("c1", c));
|
store.push_back(fmt::arg("c1", c));
|
||||||
++c.i;
|
++c.i;
|
||||||
@ -121,7 +123,7 @@ TEST(args_test, named_custom_format) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(args_test, clear) {
|
TEST(args_test, clear) {
|
||||||
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||||
store.push_back(42);
|
store.push_back(42);
|
||||||
|
|
||||||
auto result = fmt::vformat("{}", store);
|
auto result = fmt::vformat("{}", store);
|
||||||
@ -138,7 +140,7 @@ TEST(args_test, clear) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(args_test, reserve) {
|
TEST(args_test, reserve) {
|
||||||
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||||
store.reserve(2, 1);
|
store.reserve(2, 1);
|
||||||
store.push_back(1.5f);
|
store.push_back(1.5f);
|
||||||
store.push_back(fmt::arg("a1", 42));
|
store.push_back(fmt::arg("a1", 42));
|
||||||
@ -163,7 +165,7 @@ template <> struct formatter<copy_throwable> {
|
|||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
TEST(args_test, throw_on_copy) {
|
TEST(args_test, throw_on_copy) {
|
||||||
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
fmt::dynamic_format_arg_store<fmt::format_context> store;
|
||||||
store.push_back(std::string("foo"));
|
store.push_back(std::string("foo"));
|
||||||
try {
|
try {
|
||||||
store.push_back(copy_throwable());
|
store.push_back(copy_throwable());
|
||||||
@ -172,15 +174,13 @@ TEST(args_test, throw_on_copy) {
|
|||||||
EXPECT_EQ(fmt::vformat("{}", store), "foo");
|
EXPECT_EQ(fmt::vformat("{}", store), "foo");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(args_test, copy_constructor) {
|
TEST(args_test, move_constructor) {
|
||||||
auto store = fmt::dynamic_format_arg_store<fmt::format_context>();
|
using store_type = fmt::dynamic_format_arg_store<fmt::format_context>;
|
||||||
store.push_back(fmt::arg("test1", "value1"));
|
auto store = std::unique_ptr<store_type>(new store_type());
|
||||||
store.push_back(fmt::arg("test2", "value2"));
|
store->push_back(42);
|
||||||
store.push_back(fmt::arg("test3", "value3"));
|
store->push_back(std::string("foo"));
|
||||||
|
store->push_back(fmt::arg("a1", "foo"));
|
||||||
auto store2 = store;
|
auto moved_store = std::move(*store);
|
||||||
store2.push_back(fmt::arg("test4", "value4"));
|
store.reset();
|
||||||
|
EXPECT_EQ(fmt::vformat("{} {} {a1}", moved_store), "42 foo foo");
|
||||||
auto result = fmt::vformat("{test1} {test2} {test3} {test4}", store2);
|
|
||||||
EXPECT_EQ(result, "value1 value2 value3 value4");
|
|
||||||
}
|
}
|
||||||
|
325
vendor/Fmt/test/chrono-test.cc
vendored
325
vendor/Fmt/test/chrono-test.cc
vendored
@ -7,6 +7,9 @@
|
|||||||
|
|
||||||
#include "fmt/chrono.h"
|
#include "fmt/chrono.h"
|
||||||
|
|
||||||
|
#include <ctime>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "gtest-extra.h" // EXPECT_THROW_MSG
|
#include "gtest-extra.h" // EXPECT_THROW_MSG
|
||||||
#include "util.h" // get_locale
|
#include "util.h" // get_locale
|
||||||
|
|
||||||
@ -38,6 +41,36 @@ auto make_second(int s) -> std::tm {
|
|||||||
return time;
|
return time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string system_strftime(const std::string& format, const std::tm* timeptr,
|
||||||
|
std::locale* locptr = nullptr) {
|
||||||
|
auto loc = locptr ? *locptr : std::locale::classic();
|
||||||
|
auto& facet = std::use_facet<std::time_put<char>>(loc);
|
||||||
|
std::ostringstream os;
|
||||||
|
os.imbue(loc);
|
||||||
|
facet.put(os, os, ' ', timeptr, format.c_str(),
|
||||||
|
format.c_str() + format.size());
|
||||||
|
#ifdef _WIN32
|
||||||
|
// Workaround a bug in older versions of Universal CRT.
|
||||||
|
auto str = os.str();
|
||||||
|
if (str == "-0000") str = "+0000";
|
||||||
|
return str;
|
||||||
|
#else
|
||||||
|
return os.str();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
FMT_CONSTEXPR std::tm make_tm(int year, int mon, int mday, int hour, int min,
|
||||||
|
int sec) {
|
||||||
|
auto tm = std::tm();
|
||||||
|
tm.tm_sec = sec;
|
||||||
|
tm.tm_min = min;
|
||||||
|
tm.tm_hour = hour;
|
||||||
|
tm.tm_mday = mday;
|
||||||
|
tm.tm_mon = mon - 1;
|
||||||
|
tm.tm_year = year - 1900;
|
||||||
|
return tm;
|
||||||
|
}
|
||||||
|
|
||||||
TEST(chrono_test, format_tm) {
|
TEST(chrono_test, format_tm) {
|
||||||
auto tm = std::tm();
|
auto tm = std::tm();
|
||||||
tm.tm_year = 116;
|
tm.tm_year = 116;
|
||||||
@ -48,14 +81,132 @@ TEST(chrono_test, format_tm) {
|
|||||||
tm.tm_sec = 33;
|
tm.tm_sec = 33;
|
||||||
EXPECT_EQ(fmt::format("The date is {:%Y-%m-%d %H:%M:%S}.", tm),
|
EXPECT_EQ(fmt::format("The date is {:%Y-%m-%d %H:%M:%S}.", tm),
|
||||||
"The date is 2016-04-25 11:22:33.");
|
"The date is 2016-04-25 11:22:33.");
|
||||||
|
EXPECT_EQ(fmt::format("{:%Y}", tm), "2016");
|
||||||
|
EXPECT_EQ(fmt::format("{:%C}", tm), "20");
|
||||||
|
EXPECT_EQ(fmt::format("{:%C%y}", tm), fmt::format("{:%Y}", tm));
|
||||||
|
EXPECT_EQ(fmt::format("{:%e}", tm), "25");
|
||||||
|
EXPECT_EQ(fmt::format("{:%D}", tm), "04/25/16");
|
||||||
|
EXPECT_EQ(fmt::format("{:%F}", tm), "2016-04-25");
|
||||||
|
EXPECT_EQ(fmt::format("{:%T}", tm), "11:22:33");
|
||||||
|
|
||||||
|
// Short year
|
||||||
|
tm.tm_year = 999 - 1900;
|
||||||
|
tm.tm_mon = 0; // for %G
|
||||||
|
tm.tm_mday = 2; // for %G
|
||||||
|
tm.tm_wday = 3; // for %G
|
||||||
|
tm.tm_yday = 1; // for %G
|
||||||
|
EXPECT_EQ(fmt::format("{:%Y}", tm), "0999");
|
||||||
|
EXPECT_EQ(fmt::format("{:%C%y}", tm), "0999");
|
||||||
|
EXPECT_EQ(fmt::format("{:%G}", tm), "0999");
|
||||||
|
|
||||||
|
tm.tm_year = 27 - 1900;
|
||||||
|
EXPECT_EQ(fmt::format("{:%Y}", tm), "0027");
|
||||||
|
EXPECT_EQ(fmt::format("{:%C%y}", tm), "0027");
|
||||||
|
|
||||||
|
// Overflow year
|
||||||
|
tm.tm_year = 2147483647;
|
||||||
|
EXPECT_EQ(fmt::format("{:%Y}", tm), "2147485547");
|
||||||
|
|
||||||
|
tm.tm_year = -2147483648;
|
||||||
|
EXPECT_EQ(fmt::format("{:%Y}", tm), "-2147481748");
|
||||||
|
|
||||||
|
// for week on the year
|
||||||
|
// https://www.cl.cam.ac.uk/~mgk25/iso-time.html
|
||||||
|
std::vector<std::tm> tm_list = {
|
||||||
|
make_tm(1975, 12, 29, 12, 14, 16), // W01
|
||||||
|
make_tm(1977, 1, 2, 12, 14, 16), // W53
|
||||||
|
make_tm(1999, 12, 27, 12, 14, 16), // W52
|
||||||
|
make_tm(1999, 12, 31, 12, 14, 16), // W52
|
||||||
|
make_tm(2000, 1, 1, 12, 14, 16), // W52
|
||||||
|
make_tm(2000, 1, 2, 12, 14, 16), // W52
|
||||||
|
make_tm(2000, 1, 3, 12, 14, 16) // W1
|
||||||
|
};
|
||||||
|
const std::string iso_week_spec = "%Y-%m-%d: %G %g %V";
|
||||||
|
for (auto ctm : tm_list) {
|
||||||
|
// Calculate tm_yday, tm_wday, etc.
|
||||||
|
std::time_t t = std::mktime(&ctm);
|
||||||
|
tm = *std::localtime(&t);
|
||||||
|
|
||||||
|
auto fmt_spec = fmt::format("{{:{}}}", iso_week_spec);
|
||||||
|
EXPECT_EQ(system_strftime(iso_week_spec, &tm),
|
||||||
|
fmt::format(fmt::runtime(fmt_spec), tm));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Every day from 1970-01-01
|
||||||
|
std::time_t time_now = std::time(nullptr);
|
||||||
|
for (std::time_t t = 6 * 3600; t < time_now; t += 86400) {
|
||||||
|
tm = *std::localtime(&t);
|
||||||
|
|
||||||
|
auto fmt_spec = fmt::format("{{:{}}}", iso_week_spec);
|
||||||
|
EXPECT_EQ(system_strftime(iso_week_spec, &tm),
|
||||||
|
fmt::format(fmt::runtime(fmt_spec), tm));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MSVC:
|
||||||
|
// minkernel\crts\ucrt\src\appcrt\time\wcsftime.cpp(971) : Assertion failed:
|
||||||
|
// timeptr->tm_year >= -1900 && timeptr->tm_year <= 8099
|
||||||
|
#ifndef _WIN32
|
||||||
|
TEST(chrono_test, format_tm_future) {
|
||||||
|
auto tm = std::tm();
|
||||||
|
tm.tm_year = 10445; // 10000+ years
|
||||||
|
tm.tm_mon = 3;
|
||||||
|
tm.tm_mday = 25;
|
||||||
|
tm.tm_hour = 11;
|
||||||
|
tm.tm_min = 22;
|
||||||
|
tm.tm_sec = 33;
|
||||||
|
EXPECT_EQ(fmt::format("The date is {:%Y-%m-%d %H:%M:%S}.", tm),
|
||||||
|
"The date is 12345-04-25 11:22:33.");
|
||||||
|
EXPECT_EQ(fmt::format("{:%Y}", tm), "12345");
|
||||||
|
EXPECT_EQ(fmt::format("{:%C}", tm), "123");
|
||||||
|
EXPECT_EQ(fmt::format("{:%C%y}", tm), fmt::format("{:%Y}", tm));
|
||||||
|
EXPECT_EQ(fmt::format("{:%D}", tm), "04/25/45");
|
||||||
|
EXPECT_EQ(fmt::format("{:%F}", tm), "12345-04-25");
|
||||||
|
EXPECT_EQ(fmt::format("{:%T}", tm), "11:22:33");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(chrono_test, format_tm_past) {
|
||||||
|
auto tm = std::tm();
|
||||||
|
tm.tm_year = -2001;
|
||||||
|
tm.tm_mon = 3;
|
||||||
|
tm.tm_mday = 25;
|
||||||
|
tm.tm_hour = 11;
|
||||||
|
tm.tm_min = 22;
|
||||||
|
tm.tm_sec = 33;
|
||||||
|
EXPECT_EQ(fmt::format("The date is {:%Y-%m-%d %H:%M:%S}.", tm),
|
||||||
|
"The date is -101-04-25 11:22:33.");
|
||||||
|
EXPECT_EQ(fmt::format("{:%Y}", tm), "-101");
|
||||||
|
|
||||||
|
// macOS %C - "-1"
|
||||||
|
// Linux %C - "-2"
|
||||||
|
// fmt %C - "-1"
|
||||||
|
EXPECT_EQ(fmt::format("{:%C}", tm), "-1");
|
||||||
|
EXPECT_EQ(fmt::format("{:%C%y}", tm), fmt::format("{:%Y}", tm));
|
||||||
|
|
||||||
|
// macOS %D - "04/25/01" (%y)
|
||||||
|
// Linux %D - "04/25/99" (%y)
|
||||||
|
// fmt %D - "04/25/01" (%y)
|
||||||
|
EXPECT_EQ(fmt::format("{:%D}", tm), "04/25/01");
|
||||||
|
|
||||||
|
EXPECT_EQ(fmt::format("{:%F}", tm), "-101-04-25");
|
||||||
|
EXPECT_EQ(fmt::format("{:%T}", tm), "11:22:33");
|
||||||
|
|
||||||
|
tm.tm_year = -1901; // -1
|
||||||
|
EXPECT_EQ(fmt::format("{:%Y}", tm), "-001");
|
||||||
|
EXPECT_EQ(fmt::format("{:%C%y}", tm), fmt::format("{:%Y}", tm));
|
||||||
|
|
||||||
|
tm.tm_year = -1911; // -11
|
||||||
|
EXPECT_EQ(fmt::format("{:%Y}", tm), "-011");
|
||||||
|
EXPECT_EQ(fmt::format("{:%C%y}", tm), fmt::format("{:%Y}", tm));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
TEST(chrono_test, grow_buffer) {
|
TEST(chrono_test, grow_buffer) {
|
||||||
auto s = std::string("{:");
|
auto s = std::string("{:");
|
||||||
for (int i = 0; i < 30; ++i) s += "%c";
|
for (int i = 0; i < 30; ++i) s += "%c";
|
||||||
s += "}\n";
|
s += "}\n";
|
||||||
auto t = std::time(nullptr);
|
auto t = std::time(nullptr);
|
||||||
fmt::format(fmt::runtime(s), *std::localtime(&t));
|
(void)fmt::format(fmt::runtime(s), *std::localtime(&t));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(chrono_test, format_to_empty_container) {
|
TEST(chrono_test, format_to_empty_container) {
|
||||||
@ -88,22 +239,45 @@ TEST(chrono_test, gmtime) {
|
|||||||
EXPECT_TRUE(equal(tm, fmt::gmtime(t)));
|
EXPECT_TRUE(equal(tm, fmt::gmtime(t)));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TimePoint> auto strftime(TimePoint tp) -> std::string {
|
template <typename TimePoint> auto strftime_full(TimePoint tp) -> std::string {
|
||||||
auto t = std::chrono::system_clock::to_time_t(tp);
|
auto t = std::chrono::system_clock::to_time_t(tp);
|
||||||
auto tm = *std::localtime(&t);
|
auto tm = *std::localtime(&t);
|
||||||
char output[256] = {};
|
return system_strftime("%Y-%m-%d %H:%M:%S", &tm);
|
||||||
std::strftime(output, sizeof(output), "%Y-%m-%d %H:%M:%S", &tm);
|
|
||||||
return output;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(chrono_test, time_point) {
|
TEST(chrono_test, time_point) {
|
||||||
auto t1 = std::chrono::system_clock::now();
|
auto t1 = std::chrono::system_clock::now();
|
||||||
EXPECT_EQ(strftime(t1), fmt::format("{:%Y-%m-%d %H:%M:%S}", t1));
|
EXPECT_EQ(strftime_full(t1), fmt::format("{:%Y-%m-%d %H:%M:%S}", t1));
|
||||||
EXPECT_EQ(strftime(t1), fmt::format("{}", t1));
|
EXPECT_EQ(strftime_full(t1), fmt::format("{}", t1));
|
||||||
using time_point =
|
using time_point =
|
||||||
std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>;
|
std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>;
|
||||||
auto t2 = time_point(std::chrono::seconds(42));
|
auto t2 = time_point(std::chrono::seconds(42));
|
||||||
EXPECT_EQ(strftime(t2), fmt::format("{:%Y-%m-%d %H:%M:%S}", t2));
|
EXPECT_EQ(strftime_full(t2), fmt::format("{:%Y-%m-%d %H:%M:%S}", t2));
|
||||||
|
|
||||||
|
std::vector<std::string> spec_list = {
|
||||||
|
"%%", "%n", "%t", "%Y", "%EY", "%y", "%Oy", "%Ey", "%C",
|
||||||
|
"%EC", "%G", "%g", "%b", "%h", "%B", "%m", "%Om", "%U",
|
||||||
|
"%OU", "%W", "%OW", "%V", "%OV", "%j", "%d", "%Od", "%e",
|
||||||
|
"%Oe", "%a", "%A", "%w", "%Ow", "%u", "%Ou", "%H", "%OH",
|
||||||
|
"%I", "%OI", "%M", "%OM", "%S", "%OS", "%x", "%Ex", "%X",
|
||||||
|
"%EX", "%D", "%F", "%R", "%T", "%p", "%z", "%Z"};
|
||||||
|
spec_list.push_back("%Y-%m-%d %H:%M:%S");
|
||||||
|
#ifndef _WIN32
|
||||||
|
// Disabled on Windows because these formats are not consistent among
|
||||||
|
// platforms.
|
||||||
|
spec_list.insert(spec_list.end(), {"%c", "%Ec", "%r"});
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (const auto& spec : spec_list) {
|
||||||
|
auto t = std::chrono::system_clock::to_time_t(t1);
|
||||||
|
auto tm = *std::localtime(&t);
|
||||||
|
|
||||||
|
auto sys_output = system_strftime(spec, &tm);
|
||||||
|
|
||||||
|
auto fmt_spec = fmt::format("{{:{}}}", spec);
|
||||||
|
EXPECT_EQ(sys_output, fmt::format(fmt::runtime(fmt_spec), t1));
|
||||||
|
EXPECT_EQ(sys_output, fmt::format(fmt::runtime(fmt_spec), tm));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
|
#ifndef FMT_STATIC_THOUSANDS_SEPARATOR
|
||||||
@ -197,41 +371,41 @@ TEST(chrono_test, format_specs) {
|
|||||||
|
|
||||||
TEST(chrono_test, invalid_specs) {
|
TEST(chrono_test, invalid_specs) {
|
||||||
auto sec = std::chrono::seconds(0);
|
auto sec = std::chrono::seconds(0);
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{:%a}"), sec), fmt::format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%a}"), sec), fmt::format_error,
|
||||||
"no date");
|
"no date");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{:%A}"), sec), fmt::format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%A}"), sec), fmt::format_error,
|
||||||
"no date");
|
"no date");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{:%c}"), sec), fmt::format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%c}"), sec), fmt::format_error,
|
||||||
"no date");
|
"no date");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{:%x}"), sec), fmt::format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%x}"), sec), fmt::format_error,
|
||||||
"no date");
|
"no date");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{:%Ex}"), sec), fmt::format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%Ex}"), sec), fmt::format_error,
|
||||||
"no date");
|
"no date");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{:%X}"), sec), fmt::format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%X}"), sec), fmt::format_error,
|
||||||
"no date");
|
"no date");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{:%EX}"), sec), fmt::format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%EX}"), sec), fmt::format_error,
|
||||||
"no date");
|
"no date");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{:%D}"), sec), fmt::format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%D}"), sec), fmt::format_error,
|
||||||
"no date");
|
"no date");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{:%F}"), sec), fmt::format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%F}"), sec), fmt::format_error,
|
||||||
"no date");
|
"no date");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{:%Ec}"), sec), fmt::format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%Ec}"), sec), fmt::format_error,
|
||||||
"no date");
|
"no date");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{:%w}"), sec), fmt::format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%w}"), sec), fmt::format_error,
|
||||||
"no date");
|
"no date");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{:%u}"), sec), fmt::format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%u}"), sec), fmt::format_error,
|
||||||
"no date");
|
"no date");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{:%b}"), sec), fmt::format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%b}"), sec), fmt::format_error,
|
||||||
"no date");
|
"no date");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{:%B}"), sec), fmt::format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%B}"), sec), fmt::format_error,
|
||||||
"no date");
|
"no date");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{:%z}"), sec), fmt::format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%z}"), sec), fmt::format_error,
|
||||||
"no date");
|
"no date");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{:%Z}"), sec), fmt::format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%Z}"), sec), fmt::format_error,
|
||||||
"no date");
|
"no date");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{:%Eq}"), sec), fmt::format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%Eq}"), sec), fmt::format_error,
|
||||||
"invalid format");
|
"invalid format");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{:%Oq}"), sec), fmt::format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{:%Oq}"), sec), fmt::format_error,
|
||||||
"invalid format");
|
"invalid format");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -279,20 +453,33 @@ TEST(chrono_test, format_default_fp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(chrono_test, format_precision) {
|
TEST(chrono_test, format_precision) {
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{:.2}"), std::chrono::seconds(42)),
|
EXPECT_THROW_MSG(
|
||||||
fmt::format_error,
|
(void)fmt::format(runtime("{:.2}"), std::chrono::seconds(42)),
|
||||||
"precision not allowed for this argument type");
|
fmt::format_error, "precision not allowed for this argument type");
|
||||||
|
EXPECT_EQ("1ms", fmt::format("{:.0}", dms(1.234)));
|
||||||
EXPECT_EQ("1.2ms", fmt::format("{:.1}", dms(1.234)));
|
EXPECT_EQ("1.2ms", fmt::format("{:.1}", dms(1.234)));
|
||||||
EXPECT_EQ("1.23ms", fmt::format("{:.{}}", dms(1.234), 2));
|
EXPECT_EQ("1.23ms", fmt::format("{:.{}}", dms(1.234), 2));
|
||||||
|
|
||||||
|
EXPECT_EQ("13ms", fmt::format("{:.0}", dms(12.56)));
|
||||||
|
EXPECT_EQ("12.6ms", fmt::format("{:.1}", dms(12.56)));
|
||||||
|
EXPECT_EQ("12.56ms", fmt::format("{:.2}", dms(12.56)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(chrono_test, format_full_specs) {
|
TEST(chrono_test, format_full_specs) {
|
||||||
|
EXPECT_EQ("1ms ", fmt::format("{:6.0}", dms(1.234)));
|
||||||
EXPECT_EQ("1.2ms ", fmt::format("{:6.1}", dms(1.234)));
|
EXPECT_EQ("1.2ms ", fmt::format("{:6.1}", dms(1.234)));
|
||||||
EXPECT_EQ(" 1.23ms", fmt::format("{:>8.{}}", dms(1.234), 2));
|
EXPECT_EQ(" 1.23ms", fmt::format("{:>8.{}}", dms(1.234), 2));
|
||||||
EXPECT_EQ(" 1.2ms ", fmt::format("{:^{}.{}}", dms(1.234), 7, 1));
|
EXPECT_EQ(" 1.2ms ", fmt::format("{:^{}.{}}", dms(1.234), 7, 1));
|
||||||
EXPECT_EQ(" 1.23ms ", fmt::format("{0:^{2}.{1}}", dms(1.234), 2, 8));
|
EXPECT_EQ(" 1.23ms ", fmt::format("{0:^{2}.{1}}", dms(1.234), 2, 8));
|
||||||
EXPECT_EQ("=1.234ms=", fmt::format("{:=^{}.{}}", dms(1.234), 9, 3));
|
EXPECT_EQ("=1.234ms=", fmt::format("{:=^{}.{}}", dms(1.234), 9, 3));
|
||||||
EXPECT_EQ("*1.2340ms*", fmt::format("{:*^10.4}", dms(1.234)));
|
EXPECT_EQ("*1.2340ms*", fmt::format("{:*^10.4}", dms(1.234)));
|
||||||
|
|
||||||
|
EXPECT_EQ("13ms ", fmt::format("{:6.0}", dms(12.56)));
|
||||||
|
EXPECT_EQ(" 13ms", fmt::format("{:>8.{}}", dms(12.56), 0));
|
||||||
|
EXPECT_EQ(" 13ms ", fmt::format("{:^{}.{}}", dms(12.56), 6, 0));
|
||||||
|
EXPECT_EQ(" 13ms ", fmt::format("{0:^{2}.{1}}", dms(12.56), 0, 8));
|
||||||
|
EXPECT_EQ("==13ms===", fmt::format("{:=^{}.{}}", dms(12.56), 9, 0));
|
||||||
|
EXPECT_EQ("***13ms***", fmt::format("{:*^10.0}", dms(12.56)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(chrono_test, format_simple_q) {
|
TEST(chrono_test, format_simple_q) {
|
||||||
@ -306,29 +493,37 @@ TEST(chrono_test, format_simple_q) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(chrono_test, format_precision_q) {
|
TEST(chrono_test, format_precision_q) {
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{:.2%Q %q}"), std::chrono::seconds(42)),
|
EXPECT_THROW_MSG(
|
||||||
fmt::format_error,
|
(void)fmt::format(runtime("{:.2%Q %q}"), std::chrono::seconds(42)),
|
||||||
"precision not allowed for this argument type");
|
fmt::format_error, "precision not allowed for this argument type");
|
||||||
EXPECT_EQ("1.2 ms", fmt::format("{:.1%Q %q}", dms(1.234)));
|
EXPECT_EQ("1.2 ms", fmt::format("{:.1%Q %q}", dms(1.234)));
|
||||||
EXPECT_EQ("1.23 ms", fmt::format("{:.{}%Q %q}", dms(1.234), 2));
|
EXPECT_EQ("1.23 ms", fmt::format("{:.{}%Q %q}", dms(1.234), 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(chrono_test, format_full_specs_q) {
|
TEST(chrono_test, format_full_specs_q) {
|
||||||
|
EXPECT_EQ("1 ms ", fmt::format("{:7.0%Q %q}", dms(1.234)));
|
||||||
EXPECT_EQ("1.2 ms ", fmt::format("{:7.1%Q %q}", dms(1.234)));
|
EXPECT_EQ("1.2 ms ", fmt::format("{:7.1%Q %q}", dms(1.234)));
|
||||||
EXPECT_EQ(" 1.23 ms", fmt::format("{:>8.{}%Q %q}", dms(1.234), 2));
|
EXPECT_EQ(" 1.23 ms", fmt::format("{:>8.{}%Q %q}", dms(1.234), 2));
|
||||||
EXPECT_EQ(" 1.2 ms ", fmt::format("{:^{}.{}%Q %q}", dms(1.234), 8, 1));
|
EXPECT_EQ(" 1.2 ms ", fmt::format("{:^{}.{}%Q %q}", dms(1.234), 8, 1));
|
||||||
EXPECT_EQ(" 1.23 ms ", fmt::format("{0:^{2}.{1}%Q %q}", dms(1.234), 2, 9));
|
EXPECT_EQ(" 1.23 ms ", fmt::format("{0:^{2}.{1}%Q %q}", dms(1.234), 2, 9));
|
||||||
EXPECT_EQ("=1.234 ms=", fmt::format("{:=^{}.{}%Q %q}", dms(1.234), 10, 3));
|
EXPECT_EQ("=1.234 ms=", fmt::format("{:=^{}.{}%Q %q}", dms(1.234), 10, 3));
|
||||||
EXPECT_EQ("*1.2340 ms*", fmt::format("{:*^11.4%Q %q}", dms(1.234)));
|
EXPECT_EQ("*1.2340 ms*", fmt::format("{:*^11.4%Q %q}", dms(1.234)));
|
||||||
|
|
||||||
|
EXPECT_EQ("13 ms ", fmt::format("{:7.0%Q %q}", dms(12.56)));
|
||||||
|
EXPECT_EQ(" 13 ms", fmt::format("{:>8.{}%Q %q}", dms(12.56), 0));
|
||||||
|
EXPECT_EQ(" 13 ms ", fmt::format("{:^{}.{}%Q %q}", dms(12.56), 8, 0));
|
||||||
|
EXPECT_EQ(" 13 ms ", fmt::format("{0:^{2}.{1}%Q %q}", dms(12.56), 0, 9));
|
||||||
|
EXPECT_EQ("==13 ms==", fmt::format("{:=^{}.{}%Q %q}", dms(12.56), 9, 0));
|
||||||
|
EXPECT_EQ("***13 ms***", fmt::format("{:*^11.0%Q %q}", dms(12.56)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(chrono_test, invalid_width_id) {
|
TEST(chrono_test, invalid_width_id) {
|
||||||
EXPECT_THROW(fmt::format(runtime("{:{o}"), std::chrono::seconds(0)),
|
EXPECT_THROW((void)fmt::format(runtime("{:{o}"), std::chrono::seconds(0)),
|
||||||
fmt::format_error);
|
fmt::format_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(chrono_test, invalid_colons) {
|
TEST(chrono_test, invalid_colons) {
|
||||||
EXPECT_THROW(fmt::format(runtime("{0}=:{0::"), std::chrono::seconds(0)),
|
EXPECT_THROW((void)fmt::format(runtime("{0}=:{0::"), std::chrono::seconds(0)),
|
||||||
fmt::format_error);
|
fmt::format_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,15 +543,12 @@ TEST(chrono_test, negative_durations) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(chrono_test, special_durations) {
|
TEST(chrono_test, special_durations) {
|
||||||
EXPECT_EQ(
|
auto value = fmt::format("{:%S}", std::chrono::duration<double>(1e20));
|
||||||
"40.",
|
EXPECT_EQ(value, "40");
|
||||||
fmt::format("{:%S}", std::chrono::duration<double>(1e20)).substr(0, 3));
|
|
||||||
auto nan = std::numeric_limits<double>::quiet_NaN();
|
auto nan = std::numeric_limits<double>::quiet_NaN();
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
"nan nan nan nan nan:nan nan",
|
"nan nan nan nan nan:nan nan",
|
||||||
fmt::format("{:%I %H %M %S %R %r}", std::chrono::duration<double>(nan)));
|
fmt::format("{:%I %H %M %S %R %r}", std::chrono::duration<double>(nan)));
|
||||||
fmt::format("{:%S}",
|
|
||||||
std::chrono::duration<float, std::atto>(1.79400457e+31f));
|
|
||||||
EXPECT_EQ(fmt::format("{}", std::chrono::duration<float, std::exa>(1)),
|
EXPECT_EQ(fmt::format("{}", std::chrono::duration<float, std::exa>(1)),
|
||||||
"1Es");
|
"1Es");
|
||||||
EXPECT_EQ(fmt::format("{}", std::chrono::duration<float, std::atto>(1)),
|
EXPECT_EQ(fmt::format("{}", std::chrono::duration<float, std::atto>(1)),
|
||||||
@ -365,6 +557,9 @@ TEST(chrono_test, special_durations) {
|
|||||||
"03:33");
|
"03:33");
|
||||||
EXPECT_EQ(fmt::format("{:%T}", std::chrono::duration<char, std::mega>{2}),
|
EXPECT_EQ(fmt::format("{:%T}", std::chrono::duration<char, std::mega>{2}),
|
||||||
"03:33:20");
|
"03:33:20");
|
||||||
|
EXPECT_EQ("44.000000000000",
|
||||||
|
fmt::format("{:%S}", std::chrono::duration<float, std::pico>(
|
||||||
|
1.54213895E+26)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(chrono_test, unsigned_duration) {
|
TEST(chrono_test, unsigned_duration) {
|
||||||
@ -375,11 +570,63 @@ TEST(chrono_test, weekday) {
|
|||||||
auto loc = get_locale("ru_RU.UTF-8");
|
auto loc = get_locale("ru_RU.UTF-8");
|
||||||
std::locale::global(loc);
|
std::locale::global(loc);
|
||||||
auto mon = fmt::weekday(1);
|
auto mon = fmt::weekday(1);
|
||||||
|
|
||||||
|
auto tm = std::tm();
|
||||||
|
tm.tm_wday = static_cast<int>(mon.c_encoding());
|
||||||
|
|
||||||
EXPECT_EQ(fmt::format("{}", mon), "Mon");
|
EXPECT_EQ(fmt::format("{}", mon), "Mon");
|
||||||
|
EXPECT_EQ(fmt::format("{:%a}", tm), "Mon");
|
||||||
|
|
||||||
if (loc != std::locale::classic()) {
|
if (loc != std::locale::classic()) {
|
||||||
EXPECT_THAT((std::vector<std::string>{"пн", "Пн", "пнд", "Пнд"}),
|
EXPECT_THAT((std::vector<std::string>{"пн", "Пн", "пнд", "Пнд"}),
|
||||||
Contains(fmt::format(loc, "{:L}", mon)));
|
Contains(fmt::format(loc, "{:L}", mon)));
|
||||||
|
EXPECT_THAT((std::vector<std::string>{"пн", "Пн", "пнд", "Пнд"}),
|
||||||
|
Contains(fmt::format(loc, "{:%a}", tm)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(chrono_test, cpp20_duration_subsecond_support) {
|
||||||
|
using attoseconds = std::chrono::duration<long long, std::atto>;
|
||||||
|
// Check that 18 digits of subsecond precision are supported.
|
||||||
|
EXPECT_EQ(fmt::format("{:%S}", attoseconds{999999999999999999}),
|
||||||
|
"00.999999999999999999");
|
||||||
|
EXPECT_EQ(fmt::format("{:%S}", attoseconds{673231113420148734}),
|
||||||
|
"00.673231113420148734");
|
||||||
|
EXPECT_EQ(fmt::format("{:%S}", attoseconds{-673231113420148734}),
|
||||||
|
"-00.673231113420148734");
|
||||||
|
EXPECT_EQ(fmt::format("{:%S}", std::chrono::nanoseconds{13420148734}),
|
||||||
|
"13.420148734");
|
||||||
|
EXPECT_EQ(fmt::format("{:%S}", std::chrono::nanoseconds{-13420148734}),
|
||||||
|
"-13.420148734");
|
||||||
|
EXPECT_EQ(fmt::format("{:%S}", std::chrono::milliseconds{1234}), "01.234");
|
||||||
|
{
|
||||||
|
// Check that {:%H:%M:%S} is equivalent to {:%T}.
|
||||||
|
auto dur = std::chrono::milliseconds{3601234};
|
||||||
|
auto formatted_dur = fmt::format("{:%T}", dur);
|
||||||
|
EXPECT_EQ(formatted_dur, "01:00:01.234");
|
||||||
|
EXPECT_EQ(fmt::format("{:%H:%M:%S}", dur), formatted_dur);
|
||||||
|
}
|
||||||
|
using nanoseconds_dbl = std::chrono::duration<double, std::nano>;
|
||||||
|
EXPECT_EQ(fmt::format("{:%S}", nanoseconds_dbl{-123456789}), "-00.123456789");
|
||||||
|
EXPECT_EQ(fmt::format("{:%S}", nanoseconds_dbl{9123456789}), "09.123456789");
|
||||||
|
// Verify that only the seconds part is extracted and printed.
|
||||||
|
EXPECT_EQ(fmt::format("{:%S}", nanoseconds_dbl{99123456789}), "39.123456789");
|
||||||
|
EXPECT_EQ(fmt::format("{:%S}", nanoseconds_dbl{99123000000}), "39.123000000");
|
||||||
|
{
|
||||||
|
// Now the hour is printed, and we also test if negative doubles work.
|
||||||
|
auto dur = nanoseconds_dbl{-99123456789};
|
||||||
|
auto formatted_dur = fmt::format("{:%T}", dur);
|
||||||
|
EXPECT_EQ(formatted_dur, "-00:01:39.123456789");
|
||||||
|
EXPECT_EQ(fmt::format("{:%H:%M:%S}", dur), formatted_dur);
|
||||||
|
}
|
||||||
|
// Check that durations with precision greater than std::chrono::seconds have
|
||||||
|
// fixed precision, and print zeros even if there is no fractional part.
|
||||||
|
EXPECT_EQ(fmt::format("{:%S}", std::chrono::microseconds{7000000}),
|
||||||
|
"07.000000");
|
||||||
|
EXPECT_EQ(fmt::format("{:%S}", std::chrono::duration<long long, std::ratio<1, 3>>(1)),
|
||||||
|
"00.333333");
|
||||||
|
EXPECT_EQ(fmt::format("{:%S}", std::chrono::duration<long long, std::ratio<1, 7>>(1)),
|
||||||
|
"00.142857");
|
||||||
|
}
|
||||||
|
|
||||||
#endif // FMT_STATIC_THOUSANDS_SEPARATOR
|
#endif // FMT_STATIC_THOUSANDS_SEPARATOR
|
||||||
|
6
vendor/Fmt/test/color-test.cc
vendored
6
vendor/Fmt/test/color-test.cc
vendored
@ -50,6 +50,12 @@ TEST(color_test, format) {
|
|||||||
"\x1b[105mtbmagenta\x1b[0m");
|
"\x1b[105mtbmagenta\x1b[0m");
|
||||||
EXPECT_EQ(fmt::format(fg(fmt::terminal_color::red), "{}", "foo"),
|
EXPECT_EQ(fmt::format(fg(fmt::terminal_color::red), "{}", "foo"),
|
||||||
"\x1b[31mfoo\x1b[0m");
|
"\x1b[31mfoo\x1b[0m");
|
||||||
|
EXPECT_EQ(fmt::format("{}{}", fmt::styled("red", fg(fmt::color::red)),
|
||||||
|
fmt::styled("bold", fmt::emphasis::bold)),
|
||||||
|
"\x1b[38;2;255;000;000mred\x1b[0m\x1b[1mbold\x1b[0m");
|
||||||
|
EXPECT_EQ(fmt::format("{}", fmt::styled("bar", fg(fmt::color::blue) |
|
||||||
|
fmt::emphasis::underline)),
|
||||||
|
"\x1b[4m\x1b[38;2;000;000;255mbar\x1b[0m");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(color_test, format_to) {
|
TEST(color_test, format_to) {
|
||||||
|
208
vendor/Fmt/test/compile-error-test/CMakeLists.txt
vendored
208
vendor/Fmt/test/compile-error-test/CMakeLists.txt
vendored
@ -1,71 +1,158 @@
|
|||||||
# Test if compile errors are produced where necessary.
|
# Test if compile errors are produced where necessary.
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.1...3.18)
|
cmake_minimum_required(VERSION 3.1...3.18)
|
||||||
|
project(compile-error-test CXX)
|
||||||
|
|
||||||
include(CheckCXXSourceCompiles)
|
set(fmt_headers "
|
||||||
include(CheckCXXCompilerFlag)
|
#include <fmt/format.h>
|
||||||
|
#include <fmt/xchar.h>
|
||||||
|
")
|
||||||
|
|
||||||
set(CMAKE_REQUIRED_INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/../../include)
|
set(error_test_names "")
|
||||||
set(CMAKE_REQUIRED_FLAGS ${CXX_STANDARD_FLAG} ${PEDANTIC_COMPILE_FLAGS})
|
set(non_error_test_content "")
|
||||||
|
|
||||||
function (generate_source result fragment)
|
# For error tests (we expect them to produce compilation error):
|
||||||
set(${result} "
|
# * adds a name of test into `error_test_names` list
|
||||||
#define FMT_HEADER_ONLY 1
|
# * generates a single source file (with the same name) for each test
|
||||||
#include \"fmt/format.h\"
|
# For non-error tests (we expect them to compile successfully):
|
||||||
int main() {
|
# * adds a code segment as separate function to `non_error_test_content`
|
||||||
${fragment}
|
function (expect_compile name code_fragment)
|
||||||
|
cmake_parse_arguments(EXPECT_COMPILE "ERROR" "" "" ${ARGN})
|
||||||
|
string(MAKE_C_IDENTIFIER "${name}" test_name)
|
||||||
|
|
||||||
|
if (EXPECT_COMPILE_ERROR)
|
||||||
|
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/${test_name}.cc" "
|
||||||
|
${fmt_headers}
|
||||||
|
void ${test_name}() {
|
||||||
|
${code_fragment}
|
||||||
}
|
}
|
||||||
" PARENT_SCOPE)
|
")
|
||||||
endfunction ()
|
set(error_test_names_copy "${error_test_names}")
|
||||||
|
list(APPEND error_test_names_copy "${test_name}")
|
||||||
function (expect_compile code)
|
set(error_test_names "${error_test_names_copy}" PARENT_SCOPE)
|
||||||
generate_source(source "${code}")
|
else()
|
||||||
check_cxx_source_compiles("${source}" compiles)
|
set(non_error_test_content "
|
||||||
if (NOT compiles)
|
${non_error_test_content}
|
||||||
set(error_msg "Compile error for: ${code}")
|
void ${test_name}() {
|
||||||
endif ()
|
${code_fragment}
|
||||||
# Unset the CMake cache variable compiles. Otherwise the compile test will
|
}" PARENT_SCOPE)
|
||||||
# just use cached information next time it runs.
|
|
||||||
unset(compiles CACHE)
|
|
||||||
if (error_msg)
|
|
||||||
message(FATAL_ERROR ${error_msg})
|
|
||||||
endif()
|
endif()
|
||||||
endfunction ()
|
endfunction ()
|
||||||
|
|
||||||
function (expect_compile_error code)
|
# Generates a source file for non-error test with `non_error_test_content` and
|
||||||
generate_source(source "${code}")
|
# CMake project file with all error and single non-error test targets.
|
||||||
check_cxx_source_compiles("${source}" compiles)
|
function (run_tests)
|
||||||
if (compiles)
|
set(cmake_targets "")
|
||||||
set(error_msg "No compile error for: ${code}")
|
foreach(test_name IN LISTS error_test_names)
|
||||||
|
set(cmake_targets "
|
||||||
|
${cmake_targets}
|
||||||
|
add_library(test-${test_name} ${test_name}.cc)
|
||||||
|
target_link_libraries(test-${test_name} PRIVATE fmt::fmt)
|
||||||
|
")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/non_error_test.cc" "
|
||||||
|
${fmt_headers}
|
||||||
|
${non_error_test_content}
|
||||||
|
")
|
||||||
|
set(cmake_targets "
|
||||||
|
${cmake_targets}
|
||||||
|
add_library(non-error-test non_error_test.cc)
|
||||||
|
target_link_libraries(non-error-test PRIVATE fmt::fmt)
|
||||||
|
")
|
||||||
|
|
||||||
|
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/CMakeLists.txt" "
|
||||||
|
cmake_minimum_required(VERSION 3.1...3.18)
|
||||||
|
project(tests CXX)
|
||||||
|
add_subdirectory(${FMT_DIR} fmt)
|
||||||
|
${cmake_targets}
|
||||||
|
")
|
||||||
|
|
||||||
|
set(build_directory "${CMAKE_CURRENT_BINARY_DIR}/test/build")
|
||||||
|
file(MAKE_DIRECTORY "${build_directory}")
|
||||||
|
execute_process(
|
||||||
|
COMMAND
|
||||||
|
"${CMAKE_COMMAND}"
|
||||||
|
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
|
||||||
|
"-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}"
|
||||||
|
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
|
||||||
|
"-DCMAKE_GENERATOR=${CMAKE_GENERATOR}"
|
||||||
|
"-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}"
|
||||||
|
"-DFMT_DIR=${FMT_DIR}"
|
||||||
|
"${CMAKE_CURRENT_BINARY_DIR}/test"
|
||||||
|
WORKING_DIRECTORY "${build_directory}"
|
||||||
|
RESULT_VARIABLE result_var
|
||||||
|
OUTPUT_VARIABLE output_var
|
||||||
|
ERROR_VARIABLE output_var)
|
||||||
|
if (NOT result_var EQUAL 0)
|
||||||
|
message(FATAL_ERROR "Unable to configure:\n${output_var}")
|
||||||
endif()
|
endif()
|
||||||
# Unset the CMake cache variable compiles. Otherwise the compile test will
|
|
||||||
# just use cached information next time it runs.
|
foreach(test_name IN LISTS error_test_names)
|
||||||
unset(compiles CACHE)
|
execute_process(
|
||||||
if (error_msg)
|
COMMAND
|
||||||
message(FATAL_ERROR ${error_msg})
|
"${CMAKE_COMMAND}" --build "${build_directory}" --target "test-${test_name}"
|
||||||
|
WORKING_DIRECTORY "${build_directory}"
|
||||||
|
RESULT_VARIABLE result_var
|
||||||
|
OUTPUT_VARIABLE output_var
|
||||||
|
ERROR_QUIET)
|
||||||
|
if (result_var EQUAL 0)
|
||||||
|
message(SEND_ERROR "No compile error for \"${test_name}\":\n${output_var}")
|
||||||
|
endif ()
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND
|
||||||
|
"${CMAKE_COMMAND}" --build "${build_directory}" --target "non-error-test"
|
||||||
|
WORKING_DIRECTORY "${build_directory}"
|
||||||
|
RESULT_VARIABLE result_var
|
||||||
|
OUTPUT_VARIABLE output_var
|
||||||
|
ERROR_VARIABLE output_var)
|
||||||
|
if (NOT result_var EQUAL 0)
|
||||||
|
message(SEND_ERROR "Compile error for combined non-error test:\n${output_var}")
|
||||||
endif ()
|
endif ()
|
||||||
endfunction ()
|
endfunction ()
|
||||||
|
|
||||||
|
|
||||||
# check if the source file skeleton compiles
|
# check if the source file skeleton compiles
|
||||||
expect_compile("")
|
expect_compile(check "")
|
||||||
|
expect_compile(check-error "compilation_error" ERROR)
|
||||||
|
|
||||||
# Formatting a wide character with a narrow format string is forbidden.
|
# Formatting a wide character with a narrow format string is forbidden.
|
||||||
expect_compile_error("fmt::format(\"{}\", L'a');")
|
expect_compile(wide-character-narrow-format-string "fmt::format(L\"{}\", L'a');")
|
||||||
|
expect_compile(wide-character-narrow-format-string-error "fmt::format(\"{}\", L'a');" ERROR)
|
||||||
|
|
||||||
# Formatting a wide string with a narrow format string is forbidden.
|
# Formatting a wide string with a narrow format string is forbidden.
|
||||||
expect_compile_error("fmt::format(\"{}\", L\"foo\");")
|
expect_compile(wide-string-narrow-format-string "fmt::format(L\"{}\", L\"foo\");")
|
||||||
|
expect_compile(wide-string-narrow-format-string-error "fmt::format(\"{}\", L\"foo\");" ERROR)
|
||||||
|
|
||||||
# Formatting a narrow string with a wide format string is forbidden because
|
# Formatting a narrow string with a wide format string is forbidden because
|
||||||
# mixing UTF-8 with UTF-16/32 can result in an invalid output.
|
# mixing UTF-8 with UTF-16/32 can result in an invalid output.
|
||||||
expect_compile_error("fmt::format(L\"{}\", \"foo\");")
|
expect_compile(narrow-string-wide-format-string "fmt::format(L\"{}\", L\"foo\");")
|
||||||
|
expect_compile(narrow-string-wide-format-string-error "fmt::format(L\"{}\", \"foo\");" ERROR)
|
||||||
|
|
||||||
# Formatting a wide string with a narrow format string is forbidden.
|
expect_compile(cast-to-string "
|
||||||
expect_compile_error("
|
struct S {
|
||||||
|
operator std::string() const { return std::string(); }
|
||||||
|
};
|
||||||
|
fmt::format(\"{}\", std::string(S()));
|
||||||
|
")
|
||||||
|
expect_compile(cast-to-string-error "
|
||||||
struct S {
|
struct S {
|
||||||
operator std::string() const { return std::string(); }
|
operator std::string() const { return std::string(); }
|
||||||
};
|
};
|
||||||
fmt::format(\"{}\", S());
|
fmt::format(\"{}\", S());
|
||||||
|
" ERROR)
|
||||||
|
|
||||||
|
# Formatting a function
|
||||||
|
expect_compile(format-function "
|
||||||
|
void (*f)();
|
||||||
|
fmt::format(\"{}\", fmt::ptr(f));
|
||||||
")
|
")
|
||||||
|
expect_compile(format-function-error "
|
||||||
|
void (*f)();
|
||||||
|
fmt::format(\"{}\", f);
|
||||||
|
" ERROR)
|
||||||
|
|
||||||
# Make sure that compiler features detected in the header
|
# Make sure that compiler features detected in the header
|
||||||
# match the features detected in CMake.
|
# match the features detected in CMake.
|
||||||
@ -74,6 +161,43 @@ if (SUPPORTS_USER_DEFINED_LITERALS)
|
|||||||
else ()
|
else ()
|
||||||
set(supports_udl 0)
|
set(supports_udl 0)
|
||||||
endif ()
|
endif ()
|
||||||
expect_compile("#if FMT_USE_USER_DEFINED_LITERALS != ${supports_udl}
|
expect_compile(udl-check "
|
||||||
|
#if FMT_USE_USER_DEFINED_LITERALS != ${supports_udl}
|
||||||
# error
|
# error
|
||||||
#endif")
|
#endif
|
||||||
|
")
|
||||||
|
|
||||||
|
if (CMAKE_CXX_STANDARD GREATER_EQUAL 20)
|
||||||
|
# Compile-time argument type check
|
||||||
|
expect_compile(format-string-number-spec "
|
||||||
|
#ifdef FMT_HAS_CONSTEVAL
|
||||||
|
fmt::format(\"{:d}\", 42);
|
||||||
|
#endif
|
||||||
|
")
|
||||||
|
expect_compile(format-string-number-spec-error "
|
||||||
|
#ifdef FMT_HAS_CONSTEVAL
|
||||||
|
fmt::format(\"{:d}\", \"I am not a number\");
|
||||||
|
#else
|
||||||
|
#error
|
||||||
|
#endif
|
||||||
|
" ERROR)
|
||||||
|
|
||||||
|
# Compile-time argument name check
|
||||||
|
expect_compile(format-string-name "
|
||||||
|
#if defined(FMT_HAS_CONSTEVAL) && FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
||||||
|
using namespace fmt::literals;
|
||||||
|
fmt::print(\"{foo}\", \"foo\"_a=42);
|
||||||
|
#endif
|
||||||
|
")
|
||||||
|
expect_compile(format-string-name-error "
|
||||||
|
#if defined(FMT_HAS_CONSTEVAL) && FMT_USE_NONTYPE_TEMPLATE_PARAMETERS
|
||||||
|
using namespace fmt::literals;
|
||||||
|
fmt::print(\"{foo}\", \"bar\"_a=42);
|
||||||
|
#else
|
||||||
|
#error
|
||||||
|
#endif
|
||||||
|
" ERROR)
|
||||||
|
endif ()
|
||||||
|
|
||||||
|
# Run all tests
|
||||||
|
run_tests()
|
||||||
|
62
vendor/Fmt/test/compile-fp-test.cc
vendored
Normal file
62
vendor/Fmt/test/compile-fp-test.cc
vendored
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// Formatting library for C++ - formatting library tests
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
|
#include "fmt/compile.h"
|
||||||
|
#include "gmock/gmock.h"
|
||||||
|
|
||||||
|
#if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806 && \
|
||||||
|
defined(__cpp_constexpr) && __cpp_constexpr >= 201907 && \
|
||||||
|
defined(__cpp_constexpr_dynamic_alloc) && \
|
||||||
|
__cpp_constexpr_dynamic_alloc >= 201907 && __cplusplus >= 202002L
|
||||||
|
template <size_t max_string_length, typename Char = char> struct test_string {
|
||||||
|
template <typename T> constexpr bool operator==(const T& rhs) const noexcept {
|
||||||
|
return fmt::basic_string_view<Char>(rhs).compare(buffer) == 0;
|
||||||
|
}
|
||||||
|
Char buffer[max_string_length]{};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <size_t max_string_length, typename Char = char, typename... Args>
|
||||||
|
consteval auto test_format(auto format, const Args&... args) {
|
||||||
|
test_string<max_string_length, Char> string{};
|
||||||
|
fmt::format_to(string.buffer, format, args...);
|
||||||
|
return string;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(compile_time_formatting_test, floating_point) {
|
||||||
|
EXPECT_EQ("0", test_format<2>(FMT_COMPILE("{}"), 0.0f));
|
||||||
|
EXPECT_EQ("392.500000", test_format<11>(FMT_COMPILE("{0:f}"), 392.5f));
|
||||||
|
|
||||||
|
EXPECT_EQ("0", test_format<2>(FMT_COMPILE("{:}"), 0.0));
|
||||||
|
EXPECT_EQ("0.000000", test_format<9>(FMT_COMPILE("{:f}"), 0.0));
|
||||||
|
EXPECT_EQ("0", test_format<2>(FMT_COMPILE("{:g}"), 0.0));
|
||||||
|
EXPECT_EQ("392.65", test_format<7>(FMT_COMPILE("{:}"), 392.65));
|
||||||
|
EXPECT_EQ("392.65", test_format<7>(FMT_COMPILE("{:g}"), 392.65));
|
||||||
|
EXPECT_EQ("392.65", test_format<7>(FMT_COMPILE("{:G}"), 392.65));
|
||||||
|
EXPECT_EQ("4.9014e+06", test_format<11>(FMT_COMPILE("{:g}"), 4.9014e6));
|
||||||
|
EXPECT_EQ("-392.650000", test_format<12>(FMT_COMPILE("{:f}"), -392.65));
|
||||||
|
EXPECT_EQ("-392.650000", test_format<12>(FMT_COMPILE("{:F}"), -392.65));
|
||||||
|
|
||||||
|
EXPECT_EQ("3.926500e+02", test_format<13>(FMT_COMPILE("{0:e}"), 392.65));
|
||||||
|
EXPECT_EQ("3.926500E+02", test_format<13>(FMT_COMPILE("{0:E}"), 392.65));
|
||||||
|
EXPECT_EQ("+0000392.6", test_format<11>(FMT_COMPILE("{0:+010.4g}"), 392.65));
|
||||||
|
EXPECT_EQ("9223372036854775808.000000",
|
||||||
|
test_format<27>(FMT_COMPILE("{:f}"), 9223372036854775807.0));
|
||||||
|
|
||||||
|
constexpr double nan = std::numeric_limits<double>::quiet_NaN();
|
||||||
|
EXPECT_EQ("nan", test_format<4>(FMT_COMPILE("{}"), nan));
|
||||||
|
EXPECT_EQ("+nan", test_format<5>(FMT_COMPILE("{:+}"), nan));
|
||||||
|
if (std::signbit(-nan))
|
||||||
|
EXPECT_EQ("-nan", test_format<5>(FMT_COMPILE("{}"), -nan));
|
||||||
|
else
|
||||||
|
fmt::print("Warning: compiler doesn't handle negative NaN correctly");
|
||||||
|
|
||||||
|
constexpr double inf = std::numeric_limits<double>::infinity();
|
||||||
|
EXPECT_EQ("inf", test_format<4>(FMT_COMPILE("{}"), inf));
|
||||||
|
EXPECT_EQ("+inf", test_format<5>(FMT_COMPILE("{:+}"), inf));
|
||||||
|
EXPECT_EQ("-inf", test_format<5>(FMT_COMPILE("{}"), -inf));
|
||||||
|
}
|
||||||
|
#endif
|
24
vendor/Fmt/test/compile-test.cc
vendored
24
vendor/Fmt/test/compile-test.cc
vendored
@ -59,7 +59,24 @@ TEST(compile_test, compile_fallback) {
|
|||||||
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), 42));
|
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), 42));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cpp_if_constexpr
|
struct type_with_get {
|
||||||
|
template <int> friend void get(type_with_get);
|
||||||
|
};
|
||||||
|
|
||||||
|
FMT_BEGIN_NAMESPACE
|
||||||
|
template <> struct formatter<type_with_get> : formatter<int> {
|
||||||
|
template <typename FormatContext>
|
||||||
|
auto format(type_with_get, FormatContext& ctx) -> decltype(ctx.out()) {
|
||||||
|
return formatter<int>::format(42, ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
TEST(compile_test, compile_type_with_get) {
|
||||||
|
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), type_with_get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction)
|
||||||
struct test_formattable {};
|
struct test_formattable {};
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
@ -184,6 +201,11 @@ TEST(compile_test, named) {
|
|||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(compile_test, join) {
|
||||||
|
unsigned char data[] = {0x1, 0x2, 0xaf};
|
||||||
|
EXPECT_EQ("0102af", fmt::format(FMT_COMPILE("{:02x}"), fmt::join(data, "")));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(compile_test, format_to) {
|
TEST(compile_test, format_to) {
|
||||||
char buf[8];
|
char buf[8];
|
||||||
auto end = fmt::format_to(buf, FMT_COMPILE("{}"), 42);
|
auto end = fmt::format_to(buf, FMT_COMPILE("{}"), 42);
|
||||||
|
182
vendor/Fmt/test/core-test.cc
vendored
182
vendor/Fmt/test/core-test.cc
vendored
@ -408,15 +408,7 @@ TYPED_TEST(numeric_arg_test, make_and_visit) {
|
|||||||
CHECK_ARG_SIMPLE(std::numeric_limits<TypeParam>::max());
|
CHECK_ARG_SIMPLE(std::numeric_limits<TypeParam>::max());
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace fmt {
|
TEST(arg_test, char_arg) { CHECK_ARG(char, 'a', 'a'); }
|
||||||
template <> struct is_char<wchar_t> : std::true_type {};
|
|
||||||
} // namespace fmt
|
|
||||||
|
|
||||||
TEST(arg_test, char_arg) {
|
|
||||||
CHECK_ARG(char, 'a', 'a');
|
|
||||||
CHECK_ARG(wchar_t, L'a', 'a');
|
|
||||||
CHECK_ARG(wchar_t, L'a', L'a');
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(arg_test, string_arg) {
|
TEST(arg_test, string_arg) {
|
||||||
char str_data[] = "test";
|
char str_data[] = "test";
|
||||||
@ -532,7 +524,7 @@ struct test_format_specs_handler {
|
|||||||
fmt::detail::arg_ref<char> width_ref;
|
fmt::detail::arg_ref<char> width_ref;
|
||||||
int precision = 0;
|
int precision = 0;
|
||||||
fmt::detail::arg_ref<char> precision_ref;
|
fmt::detail::arg_ref<char> precision_ref;
|
||||||
char type = 0;
|
fmt::presentation_type type = fmt::presentation_type::none;
|
||||||
|
|
||||||
// Workaround for MSVC2017 bug that results in "expression did not evaluate
|
// Workaround for MSVC2017 bug that results in "expression did not evaluate
|
||||||
// to a constant" with compiler-generated copy ctor.
|
// to a constant" with compiler-generated copy ctor.
|
||||||
@ -558,14 +550,14 @@ struct test_format_specs_handler {
|
|||||||
constexpr void on_dynamic_precision(string_view) {}
|
constexpr void on_dynamic_precision(string_view) {}
|
||||||
|
|
||||||
constexpr void end_precision() {}
|
constexpr void end_precision() {}
|
||||||
constexpr void on_type(char t) { type = t; }
|
constexpr void on_type(fmt::presentation_type t) { type = t; }
|
||||||
constexpr void on_error(const char*) { res = error; }
|
constexpr void on_error(const char*) { res = error; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <size_t N>
|
template <size_t N>
|
||||||
constexpr test_format_specs_handler parse_test_specs(const char (&s)[N]) {
|
constexpr test_format_specs_handler parse_test_specs(const char (&s)[N]) {
|
||||||
auto h = test_format_specs_handler();
|
auto h = test_format_specs_handler();
|
||||||
fmt::detail::parse_format_specs(s, s + N, h);
|
fmt::detail::parse_format_specs(s, s + N - 1, h);
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -583,7 +575,7 @@ TEST(core_test, constexpr_parse_format_specs) {
|
|||||||
static_assert(parse_test_specs("{42}").width_ref.val.index == 42, "");
|
static_assert(parse_test_specs("{42}").width_ref.val.index == 42, "");
|
||||||
static_assert(parse_test_specs(".42").precision == 42, "");
|
static_assert(parse_test_specs(".42").precision == 42, "");
|
||||||
static_assert(parse_test_specs(".{42}").precision_ref.val.index == 42, "");
|
static_assert(parse_test_specs(".{42}").precision_ref.val.index == 42, "");
|
||||||
static_assert(parse_test_specs("d").type == 'd', "");
|
static_assert(parse_test_specs("d").type == fmt::presentation_type::dec, "");
|
||||||
static_assert(parse_test_specs("{<").res == handler::error, "");
|
static_assert(parse_test_specs("{<").res == handler::error, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -605,7 +597,7 @@ constexpr fmt::detail::dynamic_format_specs<char> parse_dynamic_specs(
|
|||||||
auto specs = fmt::detail::dynamic_format_specs<char>();
|
auto specs = fmt::detail::dynamic_format_specs<char>();
|
||||||
auto ctx = test_parse_context();
|
auto ctx = test_parse_context();
|
||||||
auto h = fmt::detail::dynamic_specs_handler<test_parse_context>(specs, ctx);
|
auto h = fmt::detail::dynamic_specs_handler<test_parse_context>(specs, ctx);
|
||||||
parse_format_specs(s, s + N, h);
|
parse_format_specs(s, s + N - 1, h);
|
||||||
return specs;
|
return specs;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -623,14 +615,15 @@ TEST(format_test, constexpr_dynamic_specs_handler) {
|
|||||||
static_assert(parse_dynamic_specs(".42").precision == 42, "");
|
static_assert(parse_dynamic_specs(".42").precision == 42, "");
|
||||||
static_assert(parse_dynamic_specs(".{}").precision_ref.val.index == 11, "");
|
static_assert(parse_dynamic_specs(".{}").precision_ref.val.index == 11, "");
|
||||||
static_assert(parse_dynamic_specs(".{42}").precision_ref.val.index == 42, "");
|
static_assert(parse_dynamic_specs(".{42}").precision_ref.val.index == 42, "");
|
||||||
static_assert(parse_dynamic_specs("d").type == 'd', "");
|
static_assert(parse_dynamic_specs("d").type == fmt::presentation_type::dec,
|
||||||
|
"");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t N>
|
template <size_t N>
|
||||||
constexpr test_format_specs_handler check_specs(const char (&s)[N]) {
|
constexpr test_format_specs_handler check_specs(const char (&s)[N]) {
|
||||||
fmt::detail::specs_checker<test_format_specs_handler> checker(
|
fmt::detail::specs_checker<test_format_specs_handler> checker(
|
||||||
test_format_specs_handler(), fmt::detail::type::double_type);
|
test_format_specs_handler(), fmt::detail::type::double_type);
|
||||||
parse_format_specs(s, s + N, checker);
|
parse_format_specs(s, s + N - 1, checker);
|
||||||
return checker;
|
return checker;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -647,7 +640,7 @@ TEST(format_test, constexpr_specs_checker) {
|
|||||||
static_assert(check_specs("{42}").width_ref.val.index == 42, "");
|
static_assert(check_specs("{42}").width_ref.val.index == 42, "");
|
||||||
static_assert(check_specs(".42").precision == 42, "");
|
static_assert(check_specs(".42").precision == 42, "");
|
||||||
static_assert(check_specs(".{42}").precision_ref.val.index == 42, "");
|
static_assert(check_specs(".{42}").precision_ref.val.index == 42, "");
|
||||||
static_assert(check_specs("d").type == 'd', "");
|
static_assert(check_specs("d").type == fmt::presentation_type::dec, "");
|
||||||
static_assert(check_specs("{<").res == handler::error, "");
|
static_assert(check_specs("{<").res == handler::error, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -711,10 +704,110 @@ TEST(core_test, has_formatter) {
|
|||||||
"");
|
"");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct const_formattable {};
|
||||||
|
struct nonconst_formattable {};
|
||||||
|
|
||||||
|
FMT_BEGIN_NAMESPACE
|
||||||
|
template <> struct formatter<const_formattable> {
|
||||||
|
auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
|
||||||
|
return ctx.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto format(const const_formattable&, format_context& ctx)
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
auto test = string_view("test");
|
||||||
|
return std::copy_n(test.data(), test.size(), ctx.out());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <> struct formatter<nonconst_formattable> {
|
||||||
|
auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
|
||||||
|
return ctx.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto format(nonconst_formattable&, format_context& ctx)
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
auto test = string_view("test");
|
||||||
|
return std::copy_n(test.data(), test.size(), ctx.out());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
struct convertible_to_pointer {
|
||||||
|
operator const int*() const { return nullptr; }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct convertible_to_pointer_formattable {
|
||||||
|
operator const int*() const { return nullptr; }
|
||||||
|
};
|
||||||
|
|
||||||
|
FMT_BEGIN_NAMESPACE
|
||||||
|
template <> struct formatter<convertible_to_pointer_formattable> {
|
||||||
|
auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
|
||||||
|
return ctx.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto format(convertible_to_pointer_formattable, format_context& ctx) const
|
||||||
|
-> decltype(ctx.out()) {
|
||||||
|
auto test = string_view("test");
|
||||||
|
return std::copy_n(test.data(), test.size(), ctx.out());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
enum class unformattable_scoped_enum {};
|
||||||
|
|
||||||
|
namespace test {
|
||||||
|
enum class formattable_scoped_enum {};
|
||||||
|
auto format_as(formattable_scoped_enum) -> int { return 42; }
|
||||||
|
|
||||||
|
struct convertible_to_enum {
|
||||||
|
operator formattable_scoped_enum() const { return {}; }
|
||||||
|
};
|
||||||
|
} // namespace test
|
||||||
|
|
||||||
TEST(core_test, is_formattable) {
|
TEST(core_test, is_formattable) {
|
||||||
|
#if 0
|
||||||
|
// This should be enabled once corresponding map overloads are gone.
|
||||||
|
static_assert(fmt::is_formattable<signed char*>::value, "");
|
||||||
|
static_assert(fmt::is_formattable<unsigned char*>::value, "");
|
||||||
|
static_assert(fmt::is_formattable<const signed char*>::value, "");
|
||||||
|
static_assert(fmt::is_formattable<const unsigned char*>::value, "");
|
||||||
|
#endif
|
||||||
|
static_assert(!fmt::is_formattable<wchar_t>::value, "");
|
||||||
|
#ifdef __cpp_char8_t
|
||||||
|
static_assert(!fmt::is_formattable<char8_t>::value, "");
|
||||||
|
#endif
|
||||||
|
static_assert(!fmt::is_formattable<char16_t>::value, "");
|
||||||
|
static_assert(!fmt::is_formattable<char32_t>::value, "");
|
||||||
|
static_assert(!fmt::is_formattable<const wchar_t*>::value, "");
|
||||||
|
static_assert(!fmt::is_formattable<const wchar_t[3]>::value, "");
|
||||||
|
static_assert(!fmt::is_formattable<fmt::basic_string_view<wchar_t>>::value,
|
||||||
|
"");
|
||||||
static_assert(fmt::is_formattable<enabled_formatter>::value, "");
|
static_assert(fmt::is_formattable<enabled_formatter>::value, "");
|
||||||
static_assert(!fmt::is_formattable<disabled_formatter>::value, "");
|
static_assert(!fmt::is_formattable<disabled_formatter>::value, "");
|
||||||
static_assert(fmt::is_formattable<disabled_formatter_convertible>::value, "");
|
static_assert(fmt::is_formattable<disabled_formatter_convertible>::value, "");
|
||||||
|
|
||||||
|
static_assert(fmt::is_formattable<const_formattable&>::value, "");
|
||||||
|
static_assert(fmt::is_formattable<const const_formattable&>::value, "");
|
||||||
|
|
||||||
|
static_assert(fmt::is_formattable<nonconst_formattable&>::value, "");
|
||||||
|
#if !FMT_MSC_VER || FMT_MSC_VER >= 1910
|
||||||
|
static_assert(!fmt::is_formattable<const nonconst_formattable&>::value, "");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static_assert(!fmt::is_formattable<convertible_to_pointer>::value, "");
|
||||||
|
const auto f = convertible_to_pointer_formattable();
|
||||||
|
EXPECT_EQ(fmt::format("{}", f), "test");
|
||||||
|
|
||||||
|
static_assert(!fmt::is_formattable<void (*)()>::value, "");
|
||||||
|
|
||||||
|
struct s;
|
||||||
|
static_assert(!fmt::is_formattable<int(s::*)>::value, "");
|
||||||
|
static_assert(!fmt::is_formattable<int (s::*)()>::value, "");
|
||||||
|
static_assert(!fmt::is_formattable<unformattable_scoped_enum>::value, "");
|
||||||
|
static_assert(fmt::is_formattable<test::formattable_scoped_enum>::value, "");
|
||||||
|
static_assert(!fmt::is_formattable<test::convertible_to_enum>::value, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(core_test, format) { EXPECT_EQ(fmt::format("{}", 42), "42"); }
|
TEST(core_test, format) { EXPECT_EQ(fmt::format("{}", 42), "42"); }
|
||||||
@ -725,6 +818,10 @@ TEST(core_test, format_to) {
|
|||||||
EXPECT_EQ(s, "42");
|
EXPECT_EQ(s, "42");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(core_test, format_as) {
|
||||||
|
EXPECT_EQ(fmt::format("{}", test::formattable_scoped_enum()), "42");
|
||||||
|
}
|
||||||
|
|
||||||
struct convertible_to_int {
|
struct convertible_to_int {
|
||||||
operator int() const { return 42; }
|
operator int() const { return 42; }
|
||||||
};
|
};
|
||||||
@ -793,7 +890,10 @@ struct explicitly_convertible_to_string_view {
|
|||||||
};
|
};
|
||||||
|
|
||||||
TEST(core_test, format_explicitly_convertible_to_string_view) {
|
TEST(core_test, format_explicitly_convertible_to_string_view) {
|
||||||
EXPECT_EQ("foo", fmt::format("{}", explicitly_convertible_to_string_view()));
|
// Types explicitly convertible to string_view are not formattable by
|
||||||
|
// default because it may introduce ODR violations.
|
||||||
|
static_assert(
|
||||||
|
!fmt::is_formattable<explicitly_convertible_to_string_view>::value, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
# ifdef FMT_USE_STRING_VIEW
|
# ifdef FMT_USE_STRING_VIEW
|
||||||
@ -802,8 +902,11 @@ struct explicitly_convertible_to_std_string_view {
|
|||||||
};
|
};
|
||||||
|
|
||||||
TEST(core_test, format_explicitly_convertible_to_std_string_view) {
|
TEST(core_test, format_explicitly_convertible_to_std_string_view) {
|
||||||
EXPECT_EQ("foo",
|
// Types explicitly convertible to string_view are not formattable by
|
||||||
fmt::format("{}", explicitly_convertible_to_std_string_view()));
|
// default because it may introduce ODR violations.
|
||||||
|
static_assert(
|
||||||
|
!fmt::is_formattable<explicitly_convertible_to_std_string_view>::value,
|
||||||
|
"");
|
||||||
}
|
}
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
@ -840,47 +943,18 @@ TEST(core_test, adl) {
|
|||||||
if (fmt::detail::const_check(true)) return;
|
if (fmt::detail::const_check(true)) return;
|
||||||
auto s = adl_test::string();
|
auto s = adl_test::string();
|
||||||
char buf[10];
|
char buf[10];
|
||||||
fmt::format("{}", s);
|
(void)fmt::format("{}", s);
|
||||||
fmt::format_to(buf, "{}", s);
|
fmt::format_to(buf, "{}", s);
|
||||||
fmt::format_to_n(buf, 10, "{}", s);
|
fmt::format_to_n(buf, 10, "{}", s);
|
||||||
fmt::formatted_size("{}", s);
|
(void)fmt::formatted_size("{}", s);
|
||||||
fmt::print("{}", s);
|
fmt::print("{}", s);
|
||||||
fmt::print(stdout, "{}", s);
|
fmt::print(stdout, "{}", s);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct const_formattable {};
|
TEST(core_test, has_const_formatter) {
|
||||||
struct nonconst_formattable {};
|
EXPECT_TRUE((fmt::detail::has_const_formatter<const_formattable,
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
|
||||||
template <> struct formatter<const_formattable> {
|
|
||||||
auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
|
|
||||||
return ctx.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto format(const const_formattable&, format_context& ctx)
|
|
||||||
-> decltype(ctx.out()) {
|
|
||||||
auto test = string_view("test");
|
|
||||||
return std::copy_n(test.data(), test.size(), ctx.out());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <> struct formatter<nonconst_formattable> {
|
|
||||||
auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) {
|
|
||||||
return ctx.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto format(nonconst_formattable&, format_context& ctx)
|
|
||||||
-> decltype(ctx.out()) {
|
|
||||||
auto test = string_view("test");
|
|
||||||
return std::copy_n(test.data(), test.size(), ctx.out());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
FMT_END_NAMESPACE
|
|
||||||
|
|
||||||
TEST(core_test, is_const_formattable) {
|
|
||||||
EXPECT_TRUE((fmt::detail::is_const_formattable<const_formattable,
|
|
||||||
fmt::format_context>()));
|
fmt::format_context>()));
|
||||||
EXPECT_FALSE((fmt::detail::is_const_formattable<nonconst_formattable,
|
EXPECT_FALSE((fmt::detail::has_const_formatter<nonconst_formattable,
|
||||||
fmt::format_context>()));
|
fmt::format_context>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
19
vendor/Fmt/test/enforce-checks-test.cc
vendored
19
vendor/Fmt/test/enforce-checks-test.cc
vendored
@ -17,12 +17,12 @@
|
|||||||
|
|
||||||
// Exercise the API to verify that everything we expect to can compile.
|
// Exercise the API to verify that everything we expect to can compile.
|
||||||
void test_format_api() {
|
void test_format_api() {
|
||||||
fmt::format(FMT_STRING("{}"), 42);
|
(void)fmt::format(FMT_STRING("{}"), 42);
|
||||||
fmt::format(FMT_STRING(L"{}"), 42);
|
(void)fmt::format(FMT_STRING(L"{}"), 42);
|
||||||
fmt::format(FMT_STRING("noop"));
|
(void)fmt::format(FMT_STRING("noop"));
|
||||||
|
|
||||||
fmt::to_string(42);
|
(void)fmt::to_string(42);
|
||||||
fmt::to_wstring(42);
|
(void)fmt::to_wstring(42);
|
||||||
|
|
||||||
std::vector<char> out;
|
std::vector<char> out;
|
||||||
fmt::format_to(std::back_inserter(out), FMT_STRING("{}"), 42);
|
fmt::format_to(std::back_inserter(out), FMT_STRING("{}"), 42);
|
||||||
@ -35,13 +35,14 @@ void test_format_api() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void test_chrono() {
|
void test_chrono() {
|
||||||
fmt::format(FMT_STRING("{}"), std::chrono::seconds(42));
|
(void)fmt::format(FMT_STRING("{}"), std::chrono::seconds(42));
|
||||||
fmt::format(FMT_STRING(L"{}"), std::chrono::seconds(42));
|
(void)fmt::format(FMT_STRING(L"{}"), std::chrono::seconds(42));
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_text_style() {
|
void test_text_style() {
|
||||||
fmt::print(fg(fmt::rgb(255, 20, 30)), FMT_STRING("{}"), "rgb(255,20,30)");
|
fmt::print(fg(fmt::rgb(255, 20, 30)), FMT_STRING("{}"), "rgb(255,20,30)");
|
||||||
fmt::format(fg(fmt::rgb(255, 20, 30)), FMT_STRING("{}"), "rgb(255,20,30)");
|
(void)fmt::format(fg(fmt::rgb(255, 20, 30)), FMT_STRING("{}"),
|
||||||
|
"rgb(255,20,30)");
|
||||||
|
|
||||||
fmt::text_style ts = fg(fmt::rgb(255, 20, 30));
|
fmt::text_style ts = fg(fmt::rgb(255, 20, 30));
|
||||||
std::string out;
|
std::string out;
|
||||||
@ -51,7 +52,7 @@ void test_text_style() {
|
|||||||
|
|
||||||
void test_range() {
|
void test_range() {
|
||||||
std::vector<char> hello = {'h', 'e', 'l', 'l', 'o'};
|
std::vector<char> hello = {'h', 'e', 'l', 'l', 'o'};
|
||||||
fmt::format(FMT_STRING("{}"), hello);
|
(void)fmt::format(FMT_STRING("{}"), hello);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
3
vendor/Fmt/test/find-package-test/main.cc
vendored
3
vendor/Fmt/test/find-package-test/main.cc
vendored
@ -1,6 +1,5 @@
|
|||||||
#include "fmt/format.h"
|
#include "fmt/format.h"
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
for(int i = 0; i < argc; ++i)
|
for (int i = 0; i < argc; ++i) fmt::print("{}: {}\n", i, argv[i]);
|
||||||
fmt::print("{}: {}\n", i, argv[i]);
|
|
||||||
}
|
}
|
||||||
|
856
vendor/Fmt/test/format
vendored
856
vendor/Fmt/test/format
vendored
@ -1,856 +0,0 @@
|
|||||||
// Formatting library for C++ - the standard API implementation
|
|
||||||
//
|
|
||||||
// Copyright (c) 2012 - present, Victor Zverovich
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// For the license information refer to format.h.
|
|
||||||
|
|
||||||
#ifndef FMT_FORMAT_
|
|
||||||
#define FMT_FORMAT_
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cassert>
|
|
||||||
#include <variant>
|
|
||||||
#include "fmt/format.h"
|
|
||||||
|
|
||||||
// This implementation verifies the correctness of the standard API proposed in
|
|
||||||
// P0645 Text Formatting and is optimized for copy-pasting from the paper, not
|
|
||||||
// for efficiency or readability. An efficient implementation should not use
|
|
||||||
// std::variant and should store packed argument type tags separately from
|
|
||||||
// values in basic_format_args for small number of arguments.
|
|
||||||
|
|
||||||
namespace std {
|
|
||||||
template<class T>
|
|
||||||
constexpr bool Integral = is_integral_v<T>;
|
|
||||||
|
|
||||||
template <class O>
|
|
||||||
using iter_difference_t = ptrdiff_t;
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://fmt.dev/Text%20Formatting.html#format.syn
|
|
||||||
namespace std {
|
|
||||||
// [format.error], class format_error
|
|
||||||
class format_error;
|
|
||||||
|
|
||||||
// [format.formatter], formatter
|
|
||||||
template<class charT> class basic_format_parse_context;
|
|
||||||
using format_parse_context = basic_format_parse_context<char>;
|
|
||||||
using wformat_parse_context = basic_format_parse_context<wchar_t>;
|
|
||||||
|
|
||||||
template<class Out, class charT> class basic_format_context;
|
|
||||||
using format_context = basic_format_context<
|
|
||||||
/* unspecified */ fmt::detail::buffer_appender<char>, char>;
|
|
||||||
using wformat_context = basic_format_context<
|
|
||||||
/* unspecified */ fmt::detail::buffer_appender<wchar_t>, wchar_t>;
|
|
||||||
|
|
||||||
template<class T, class charT = char> struct formatter {
|
|
||||||
formatter() = delete;
|
|
||||||
};
|
|
||||||
|
|
||||||
// [format.arguments], arguments
|
|
||||||
template<class Context> class basic_format_arg;
|
|
||||||
|
|
||||||
template<class Visitor, class Context>
|
|
||||||
/* see below */ auto visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg);
|
|
||||||
|
|
||||||
template<class Context, class... Args> struct format_arg_store; // exposition only
|
|
||||||
|
|
||||||
template<class Context> class basic_format_args;
|
|
||||||
using format_args = basic_format_args<format_context>;
|
|
||||||
using wformat_args = basic_format_args<wformat_context>;
|
|
||||||
|
|
||||||
template<class Out, class charT>
|
|
||||||
using format_args_t = basic_format_args<basic_format_context<Out, charT>>;
|
|
||||||
|
|
||||||
template<class Context = format_context, class... Args>
|
|
||||||
format_arg_store<Context, Args...>
|
|
||||||
make_format_args(const Args&... args);
|
|
||||||
template<class... Args>
|
|
||||||
format_arg_store<wformat_context, Args...>
|
|
||||||
make_wformat_args(const Args&... args);
|
|
||||||
|
|
||||||
// [format.functions], formatting functions
|
|
||||||
template<class... Args>
|
|
||||||
string format(string_view fmt, const Args&... args);
|
|
||||||
template<class... Args>
|
|
||||||
wstring format(wstring_view fmt, const Args&... args);
|
|
||||||
|
|
||||||
string vformat(string_view fmt, format_args args);
|
|
||||||
wstring vformat(wstring_view fmt, wformat_args args);
|
|
||||||
|
|
||||||
template<class Out, class... Args>
|
|
||||||
Out format_to(Out out, string_view fmt, const Args&... args);
|
|
||||||
template<class Out, class... Args>
|
|
||||||
Out format_to(Out out, wstring_view fmt, const Args&... args);
|
|
||||||
|
|
||||||
template<class Out>
|
|
||||||
Out vformat_to(Out out, string_view fmt, format_args_t<fmt::type_identity_t<Out>, char> args);
|
|
||||||
template<class Out>
|
|
||||||
Out vformat_to(Out out, wstring_view fmt, format_args_t<fmt::type_identity_t<Out>, wchar_t> args);
|
|
||||||
|
|
||||||
template<class Out>
|
|
||||||
struct format_to_n_result {
|
|
||||||
Out out;
|
|
||||||
iter_difference_t<Out> size;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class Out, class... Args>
|
|
||||||
format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
|
|
||||||
string_view fmt, const Args&... args);
|
|
||||||
template<class Out, class... Args>
|
|
||||||
format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
|
|
||||||
wstring_view fmt, const Args&... args);
|
|
||||||
|
|
||||||
template<class... Args>
|
|
||||||
size_t formatted_size(string_view fmt, const Args&... args);
|
|
||||||
template<class... Args>
|
|
||||||
size_t formatted_size(wstring_view fmt, const Args&... args);
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://fmt.dev/Text%20Formatting.html#format.error
|
|
||||||
namespace std {
|
|
||||||
class format_error : public runtime_error {
|
|
||||||
public:
|
|
||||||
explicit format_error(const string& what_arg) : runtime_error(what_arg) {}
|
|
||||||
explicit format_error(const char* what_arg) : runtime_error(what_arg) {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace std {
|
|
||||||
namespace detail {
|
|
||||||
struct error_handler {
|
|
||||||
// This function is intentionally not constexpr to give a compile-time error.
|
|
||||||
void on_error(const char* message) {
|
|
||||||
throw std::format_error(message);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://fmt.dev/Text%20Formatting.html#format.parse_context
|
|
||||||
namespace std {
|
|
||||||
template<class charT>
|
|
||||||
class basic_format_parse_context {
|
|
||||||
public:
|
|
||||||
using char_type = charT;
|
|
||||||
using const_iterator = typename basic_string_view<charT>::const_iterator;
|
|
||||||
using iterator = const_iterator;
|
|
||||||
|
|
||||||
private:
|
|
||||||
iterator begin_; // exposition only
|
|
||||||
iterator end_; // exposition only
|
|
||||||
enum indexing { unknown, manual, automatic }; // exposition only
|
|
||||||
indexing indexing_; // exposition only
|
|
||||||
size_t next_arg_id_; // exposition only
|
|
||||||
size_t num_args_; // exposition only
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit constexpr basic_format_parse_context(basic_string_view<charT> fmt,
|
|
||||||
size_t num_args = 0) noexcept;
|
|
||||||
basic_format_parse_context(const basic_format_parse_context&) = delete;
|
|
||||||
basic_format_parse_context& operator=(const basic_format_parse_context&) = delete;
|
|
||||||
|
|
||||||
constexpr const_iterator begin() const noexcept;
|
|
||||||
constexpr const_iterator end() const noexcept;
|
|
||||||
constexpr void advance_to(const_iterator it);
|
|
||||||
|
|
||||||
constexpr size_t next_arg_id();
|
|
||||||
constexpr void check_arg_id(size_t id);
|
|
||||||
|
|
||||||
// Implementation detail:
|
|
||||||
constexpr void check_arg_id(fmt::string_view) {}
|
|
||||||
detail::error_handler error_handler() const { return {}; }
|
|
||||||
void on_error(const char* msg) { error_handler().on_error(msg); }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace std {
|
|
||||||
template<class charT>
|
|
||||||
/* explicit */ constexpr basic_format_parse_context<charT>::
|
|
||||||
basic_format_parse_context(basic_string_view<charT> fmt,
|
|
||||||
size_t num_args) noexcept
|
|
||||||
: begin_(fmt.begin()), end_(fmt.end()), indexing_(unknown), next_arg_id_(0), num_args_(num_args) {}
|
|
||||||
|
|
||||||
template<class charT>
|
|
||||||
constexpr typename basic_format_parse_context<charT>::const_iterator basic_format_parse_context<charT>::begin() const noexcept { return begin_; }
|
|
||||||
|
|
||||||
template<class charT>
|
|
||||||
constexpr typename basic_format_parse_context<charT>::const_iterator basic_format_parse_context<charT>::end() const noexcept { return end_; }
|
|
||||||
|
|
||||||
template<class charT>
|
|
||||||
constexpr void basic_format_parse_context<charT>::advance_to(typename basic_format_parse_context<charT>::iterator it) { begin_ = it; }
|
|
||||||
|
|
||||||
template<class charT>
|
|
||||||
constexpr size_t basic_format_parse_context<charT>::next_arg_id() {
|
|
||||||
if (indexing_ == manual)
|
|
||||||
throw format_error("manual to automatic indexing");
|
|
||||||
if (indexing_ == unknown)
|
|
||||||
indexing_ = automatic;
|
|
||||||
return next_arg_id_++;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class charT>
|
|
||||||
constexpr void basic_format_parse_context<charT>::check_arg_id(size_t id) {
|
|
||||||
// clang doesn't support __builtin_is_constant_evaluated yet
|
|
||||||
//if (!(!__builtin_is_constant_evaluated() || id < num_args_))
|
|
||||||
// throw format_error(invalid index is out of range");
|
|
||||||
if (indexing_ == automatic)
|
|
||||||
throw format_error("automatic to manual indexing");
|
|
||||||
if (indexing_ == unknown)
|
|
||||||
indexing_ = manual;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://fmt.dev/Text%20Formatting.html#format.context
|
|
||||||
namespace std {
|
|
||||||
template<class Out, class charT>
|
|
||||||
class basic_format_context {
|
|
||||||
basic_format_args<basic_format_context> args_; // exposition only
|
|
||||||
Out out_; // exposition only
|
|
||||||
|
|
||||||
public:
|
|
||||||
using iterator = Out;
|
|
||||||
using char_type = charT;
|
|
||||||
template<class T> using formatter_type = formatter<T, charT>;
|
|
||||||
|
|
||||||
basic_format_arg<basic_format_context> arg(size_t id) const;
|
|
||||||
|
|
||||||
iterator out();
|
|
||||||
void advance_to(iterator it);
|
|
||||||
|
|
||||||
// Implementation details:
|
|
||||||
using format_arg = basic_format_arg<basic_format_context>;
|
|
||||||
basic_format_context(Out out, basic_format_args<basic_format_context> args, fmt::detail::locale_ref)
|
|
||||||
: args_(args), out_(out) {}
|
|
||||||
detail::error_handler error_handler() const { return {}; }
|
|
||||||
basic_format_arg<basic_format_context> arg(fmt::basic_string_view<charT>) const {
|
|
||||||
return {}; // unused: named arguments are not supported yet
|
|
||||||
}
|
|
||||||
void on_error(const char* msg) { error_handler().on_error(msg); }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace std {
|
|
||||||
template<class O, class charT>
|
|
||||||
basic_format_arg<basic_format_context<O, charT>> basic_format_context<O, charT>::arg(size_t id) const { return args_.get(id); }
|
|
||||||
|
|
||||||
template<class O, class charT>
|
|
||||||
typename basic_format_context<O, charT>::iterator basic_format_context<O, charT>::out() { return out_; }
|
|
||||||
|
|
||||||
template<class O, class charT>
|
|
||||||
void basic_format_context<O, charT>::advance_to(typename basic_format_context<O, charT>::iterator it) { out_ = it; }
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace std {
|
|
||||||
namespace detail {
|
|
||||||
template <typename T>
|
|
||||||
constexpr bool is_standard_integer_v =
|
|
||||||
std::is_same_v<T, signed char> ||
|
|
||||||
std::is_same_v<T, short int> ||
|
|
||||||
std::is_same_v<T, int> ||
|
|
||||||
std::is_same_v<T, long int> ||
|
|
||||||
std::is_same_v<T, long long int>;
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
constexpr bool is_standard_unsigned_integer_v =
|
|
||||||
std::is_same_v<T, unsigned char> ||
|
|
||||||
std::is_same_v<T, unsigned short int> ||
|
|
||||||
std::is_same_v<T, unsigned int> ||
|
|
||||||
std::is_same_v<T, unsigned long int> ||
|
|
||||||
std::is_same_v<T, unsigned long long int>;
|
|
||||||
|
|
||||||
template <typename T, typename Char> struct formatter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://fmt.dev/Text%20Formatting.html#format.arg
|
|
||||||
namespace std {
|
|
||||||
template<class Context>
|
|
||||||
class basic_format_arg {
|
|
||||||
public:
|
|
||||||
class handle;
|
|
||||||
|
|
||||||
private:
|
|
||||||
using char_type = typename Context::char_type; // exposition only
|
|
||||||
|
|
||||||
variant<monostate, bool, char_type,
|
|
||||||
int, unsigned int, long long int, unsigned long long int,
|
|
||||||
double, long double,
|
|
||||||
const char_type*, basic_string_view<char_type>,
|
|
||||||
const void*, handle> value; // exposition only
|
|
||||||
|
|
||||||
template<typename T,
|
|
||||||
typename = enable_if_t<
|
|
||||||
std::is_same_v<T, bool> ||
|
|
||||||
std::is_same_v<T, char_type> ||
|
|
||||||
(std::is_same_v<T, char> && std::is_same_v<char_type, wchar_t>) ||
|
|
||||||
detail::is_standard_integer_v<T> ||
|
|
||||||
detail::is_standard_unsigned_integer_v<T> ||
|
|
||||||
sizeof(typename Context::template formatter_type<T>().format(declval<const T&>(), declval<Context&>())) != 0
|
|
||||||
>> explicit basic_format_arg(const T& v) noexcept; // exposition only
|
|
||||||
explicit basic_format_arg(float n) noexcept; // exposition only
|
|
||||||
explicit basic_format_arg(double n) noexcept; // exposition only
|
|
||||||
explicit basic_format_arg(long double n) noexcept; // exposition only
|
|
||||||
explicit basic_format_arg(const char_type* s); // exposition only
|
|
||||||
|
|
||||||
template<class traits>
|
|
||||||
explicit basic_format_arg(
|
|
||||||
basic_string_view<char_type, traits> s) noexcept; // exposition only
|
|
||||||
|
|
||||||
template<class traits, class Allocator>
|
|
||||||
explicit basic_format_arg(
|
|
||||||
const basic_string<char_type, traits, Allocator>& s) noexcept; // exposition only
|
|
||||||
|
|
||||||
explicit basic_format_arg(nullptr_t) noexcept; // exposition only
|
|
||||||
|
|
||||||
template<class T, typename = enable_if_t<is_void_v<T>>>
|
|
||||||
explicit basic_format_arg(const T* p) noexcept; // exposition only
|
|
||||||
|
|
||||||
// Fails due to a bug in clang
|
|
||||||
//template<class Visitor, class Ctx>
|
|
||||||
// friend auto visit_format_arg(Visitor&& vis,
|
|
||||||
// basic_format_arg<Ctx> arg); // exposition only
|
|
||||||
|
|
||||||
friend auto get_value(basic_format_arg arg) {
|
|
||||||
return arg.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T, typename Char> friend struct detail::formatter;
|
|
||||||
|
|
||||||
template<class Ctx, class... Args>
|
|
||||||
friend format_arg_store<Ctx, Args...>
|
|
||||||
make_format_args(const Args&... args); // exposition only
|
|
||||||
|
|
||||||
public:
|
|
||||||
basic_format_arg() noexcept;
|
|
||||||
|
|
||||||
explicit operator bool() const noexcept;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace std {
|
|
||||||
template<class Context>
|
|
||||||
basic_format_arg<Context>::basic_format_arg() noexcept {}
|
|
||||||
|
|
||||||
template<class Context>
|
|
||||||
template<class T, typename> /* explicit */ basic_format_arg<Context>::basic_format_arg(const T& v) noexcept {
|
|
||||||
if constexpr (std::is_same_v<T, bool> || std::is_same_v<T, char_type>)
|
|
||||||
value = v;
|
|
||||||
else if constexpr (std::is_same_v<T, char> && std::is_same_v<char_type, wchar_t>)
|
|
||||||
value = static_cast<wchar_t>(v);
|
|
||||||
else if constexpr (detail::is_standard_integer_v<T> && sizeof(T) <= sizeof(int))
|
|
||||||
value = static_cast<int>(v);
|
|
||||||
else if constexpr (detail::is_standard_unsigned_integer_v<T> && sizeof(T) <= sizeof(unsigned))
|
|
||||||
value = static_cast<unsigned>(v);
|
|
||||||
else if constexpr (detail::is_standard_integer_v<T>)
|
|
||||||
value = static_cast<long long int>(v);
|
|
||||||
else if constexpr (detail::is_standard_unsigned_integer_v<T>)
|
|
||||||
value = static_cast<unsigned long long int>(v);
|
|
||||||
else if constexpr (sizeof(typename Context::template formatter_type<T>().format(declval<const T&>(), declval<Context&>())) != 0)
|
|
||||||
value = handle(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Context>
|
|
||||||
/* explicit */ basic_format_arg<Context>::basic_format_arg(float n) noexcept
|
|
||||||
: value(static_cast<double>(n)) {}
|
|
||||||
|
|
||||||
template<class Context>
|
|
||||||
/* explicit */ basic_format_arg<Context>::basic_format_arg(double n) noexcept
|
|
||||||
: value(n) {}
|
|
||||||
|
|
||||||
template<class Context>
|
|
||||||
/* explicit */ basic_format_arg<Context>::basic_format_arg(long double n) noexcept
|
|
||||||
: value(n) {}
|
|
||||||
|
|
||||||
template<class Context>
|
|
||||||
/* explicit */ basic_format_arg<Context>::basic_format_arg(const typename basic_format_arg<Context>::char_type* s)
|
|
||||||
: value(s) {
|
|
||||||
assert(s != nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Context>
|
|
||||||
template<class traits>
|
|
||||||
/* explicit */ basic_format_arg<Context>::basic_format_arg(basic_string_view<char_type, traits> s) noexcept
|
|
||||||
: value(s) {}
|
|
||||||
|
|
||||||
template<class Context>
|
|
||||||
template<class traits, class Allocator>
|
|
||||||
/* explicit */ basic_format_arg<Context>::basic_format_arg(
|
|
||||||
const basic_string<char_type, traits, Allocator>& s) noexcept
|
|
||||||
: value(basic_string_view<char_type>(s.data(), s.size())) {}
|
|
||||||
|
|
||||||
|
|
||||||
template<class Context>
|
|
||||||
/* explicit */ basic_format_arg<Context>::basic_format_arg(nullptr_t) noexcept
|
|
||||||
: value(static_cast<const void*>(nullptr)) {}
|
|
||||||
|
|
||||||
template<class Context>
|
|
||||||
template<class T, typename> /* explicit */ basic_format_arg<Context>::basic_format_arg(const T* p) noexcept
|
|
||||||
: value(p) {}
|
|
||||||
|
|
||||||
template<class Context>
|
|
||||||
/* explicit */ basic_format_arg<Context>::operator bool() const noexcept {
|
|
||||||
return !holds_alternative<monostate>(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace std {
|
|
||||||
template<class Context>
|
|
||||||
class basic_format_arg<Context>::handle {
|
|
||||||
const void* ptr_; // exposition only
|
|
||||||
void (*format_)(basic_format_parse_context<char_type>&,
|
|
||||||
Context&, const void*); // exposition only
|
|
||||||
|
|
||||||
template<class T> explicit handle(const T& val) noexcept; // exposition only
|
|
||||||
|
|
||||||
friend class basic_format_arg<Context>; // exposition only
|
|
||||||
|
|
||||||
public:
|
|
||||||
void format(basic_format_parse_context<char_type>&, Context& ctx) const;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace std {
|
|
||||||
template<class Context>
|
|
||||||
template<class T> /* explicit */ basic_format_arg<Context>::handle::handle(const T& val) noexcept
|
|
||||||
: ptr_(&val), format_([](basic_format_parse_context<char_type>& parse_ctx, Context& format_ctx, const void* ptr) {
|
|
||||||
typename Context::template formatter_type<T> f;
|
|
||||||
parse_ctx.advance_to(f.parse(parse_ctx));
|
|
||||||
format_ctx.advance_to(f.format(*static_cast<const T*>(ptr), format_ctx));
|
|
||||||
}) {}
|
|
||||||
|
|
||||||
template<class Context>
|
|
||||||
void basic_format_arg<Context>::handle::format(basic_format_parse_context<char_type>& parse_ctx, Context& format_ctx) const {
|
|
||||||
format_(parse_ctx, format_ctx, ptr_);
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://fmt.dev/Text%20Formatting.html#format.visit
|
|
||||||
template<class Visitor, class Context>
|
|
||||||
auto visit_format_arg(Visitor&& vis, basic_format_arg<Context> arg) {
|
|
||||||
return visit(vis, get_value(arg));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://fmt.dev/Text%20Formatting.html#format.store
|
|
||||||
namespace std {
|
|
||||||
template<class Context, class... Args>
|
|
||||||
struct format_arg_store { // exposition only
|
|
||||||
array<basic_format_arg<Context>, sizeof...(Args)> args;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://fmt.dev/Text%20Formatting.html#format.basic_args
|
|
||||||
namespace std {
|
|
||||||
template<class Context>
|
|
||||||
class basic_format_args {
|
|
||||||
size_t size_; // exposition only
|
|
||||||
const basic_format_arg<Context>* data_; // exposition only
|
|
||||||
|
|
||||||
public:
|
|
||||||
basic_format_args() noexcept;
|
|
||||||
|
|
||||||
template<class... Args>
|
|
||||||
basic_format_args(const format_arg_store<Context, Args...>& store) noexcept;
|
|
||||||
|
|
||||||
basic_format_arg<Context> get(size_t i) const noexcept;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace std {
|
|
||||||
|
|
||||||
template<class Context>
|
|
||||||
basic_format_args<Context>::basic_format_args() noexcept : size_(0) {}
|
|
||||||
|
|
||||||
template<class Context>
|
|
||||||
template<class... Args>
|
|
||||||
basic_format_args<Context>::basic_format_args(const format_arg_store<Context, Args...>& store) noexcept
|
|
||||||
: size_(sizeof...(Args)), data_(store.args.data()) {}
|
|
||||||
|
|
||||||
template<class Context>
|
|
||||||
basic_format_arg<Context> basic_format_args<Context>::get(size_t i) const noexcept {
|
|
||||||
return i < size_ ? data_[i] : basic_format_arg<Context>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace std {
|
|
||||||
// https://fmt.dev/Text%20Formatting.html#format.make_args
|
|
||||||
template<class Context /*= format_context*/, class... Args>
|
|
||||||
format_arg_store<Context, Args...> make_format_args(const Args&... args) {
|
|
||||||
return {basic_format_arg<Context>(args)...};
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://fmt.dev/Text%20Formatting.html#format.make_wargs
|
|
||||||
template<class... Args>
|
|
||||||
format_arg_store<wformat_context, Args...> make_wformat_args(const Args&... args) {
|
|
||||||
return make_format_args<wformat_context>(args...);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace std {
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
template <typename OutputIt, typename Char>
|
|
||||||
class arg_formatter
|
|
||||||
: public fmt::detail::arg_formatter_base<OutputIt, Char, error_handler> {
|
|
||||||
private:
|
|
||||||
using char_type = Char;
|
|
||||||
using base = fmt::detail::arg_formatter_base<OutputIt, Char, error_handler>;
|
|
||||||
using format_context = std::basic_format_context<OutputIt, Char>;
|
|
||||||
using parse_context = basic_format_parse_context<Char>;
|
|
||||||
|
|
||||||
parse_context* parse_ctx_;
|
|
||||||
format_context& ctx_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
using iterator = OutputIt;
|
|
||||||
using format_specs = typename base::format_specs;
|
|
||||||
|
|
||||||
/**
|
|
||||||
\rst
|
|
||||||
Constructs an argument formatter object.
|
|
||||||
*ctx* is a reference to the formatting context,
|
|
||||||
*spec* contains format specifier information for standard argument types.
|
|
||||||
\endrst
|
|
||||||
*/
|
|
||||||
arg_formatter(format_context& ctx, parse_context* parse_ctx = nullptr, fmt::format_specs* spec = nullptr)
|
|
||||||
: base(ctx.out(), spec, {}), parse_ctx_(parse_ctx), ctx_(ctx) {}
|
|
||||||
|
|
||||||
using base::operator();
|
|
||||||
|
|
||||||
/** Formats an argument of a user-defined type. */
|
|
||||||
iterator operator()(typename std::basic_format_arg<format_context>::handle handle) {
|
|
||||||
handle.format(*parse_ctx_, ctx_);
|
|
||||||
return this->out();
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator operator()(monostate) {
|
|
||||||
throw format_error("");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Context>
|
|
||||||
inline fmt::detail::type get_type(basic_format_arg<Context> arg) {
|
|
||||||
return visit_format_arg([&] (auto val) {
|
|
||||||
using char_type = typename Context::char_type;
|
|
||||||
using T = decltype(val);
|
|
||||||
if (std::is_same_v<T, monostate>)
|
|
||||||
return fmt::detail::type::none_type;
|
|
||||||
if (std::is_same_v<T, bool>)
|
|
||||||
return fmt::detail::type::bool_type;
|
|
||||||
if (std::is_same_v<T, char_type>)
|
|
||||||
return fmt::detail::type::char_type;
|
|
||||||
if (std::is_same_v<T, int>)
|
|
||||||
return fmt::detail::type::int_type;
|
|
||||||
if (std::is_same_v<T, unsigned int>)
|
|
||||||
return fmt::detail::type::uint_type;
|
|
||||||
if (std::is_same_v<T, long long int>)
|
|
||||||
return fmt::detail::type::long_long_type;
|
|
||||||
if (std::is_same_v<T, unsigned long long int>)
|
|
||||||
return fmt::detail::type::ulong_long_type;
|
|
||||||
if (std::is_same_v<T, double>)
|
|
||||||
return fmt::detail::type::double_type;
|
|
||||||
if (std::is_same_v<T, long double>)
|
|
||||||
return fmt::detail::type::long_double_type;
|
|
||||||
if (std::is_same_v<T, const char_type*>)
|
|
||||||
return fmt::detail::type::cstring_type;
|
|
||||||
if (std::is_same_v<T, basic_string_view<char_type>>)
|
|
||||||
return fmt::detail::type::string_type;
|
|
||||||
if (std::is_same_v<T, const void*>)
|
|
||||||
return fmt::detail::type::pointer_type;
|
|
||||||
assert(get_value(arg).index() == 12);
|
|
||||||
return fmt::detail::type::custom_type;
|
|
||||||
}, arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Context>
|
|
||||||
class custom_formatter {
|
|
||||||
private:
|
|
||||||
using parse_context = basic_format_parse_context<typename Context::char_type>;
|
|
||||||
parse_context& parse_ctx_;
|
|
||||||
Context& format_ctx_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
custom_formatter(parse_context& parse_ctx, Context& ctx) : parse_ctx_(parse_ctx), format_ctx_(ctx) {}
|
|
||||||
|
|
||||||
bool operator()(typename basic_format_arg<Context>::handle h) const {
|
|
||||||
h.format(parse_ctx_, format_ctx_);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T> bool operator()(T) const { return false; }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename ArgFormatter, typename Char, typename Context>
|
|
||||||
struct format_handler : detail::error_handler {
|
|
||||||
using iterator = typename ArgFormatter::iterator;
|
|
||||||
|
|
||||||
format_handler(iterator out, basic_string_view<Char> str,
|
|
||||||
basic_format_args<Context> format_args,
|
|
||||||
fmt::detail::locale_ref loc)
|
|
||||||
: parse_ctx(str), context(out, format_args, loc) {}
|
|
||||||
|
|
||||||
void on_text(const Char* begin, const Char* end) {
|
|
||||||
auto size = fmt::detail::to_unsigned(end - begin);
|
|
||||||
auto out = context.out();
|
|
||||||
auto&& it = fmt::detail::reserve(out, size);
|
|
||||||
it = std::copy_n(begin, size, it);
|
|
||||||
context.advance_to(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
int on_arg_id() { return parse_ctx.next_arg_id(); }
|
|
||||||
int on_arg_id(unsigned id) { return parse_ctx.check_arg_id(id), id; }
|
|
||||||
int on_arg_id(fmt::basic_string_view<Char>) { return 0; }
|
|
||||||
|
|
||||||
void on_replacement_field(int id, const Char* p) {
|
|
||||||
auto arg = context.arg(id);
|
|
||||||
parse_ctx.advance_to(parse_ctx.begin() + (p - &*parse_ctx.begin()));
|
|
||||||
custom_formatter<Context> f(parse_ctx, context);
|
|
||||||
if (!visit_format_arg(f, arg))
|
|
||||||
context.advance_to(visit_format_arg(ArgFormatter(context, &parse_ctx), arg));
|
|
||||||
}
|
|
||||||
|
|
||||||
const Char* on_format_specs(int id, const Char* begin, const Char* end) {
|
|
||||||
auto arg = context.arg(id);
|
|
||||||
parse_ctx.advance_to(parse_ctx.begin() + (begin - &*parse_ctx.begin()));
|
|
||||||
custom_formatter<Context> f(parse_ctx, context);
|
|
||||||
if (visit_format_arg(f, arg)) return &*parse_ctx.begin();
|
|
||||||
fmt::basic_format_specs<Char> specs;
|
|
||||||
using fmt::detail::specs_handler;
|
|
||||||
using parse_context = basic_format_parse_context<Char>;
|
|
||||||
fmt::detail::specs_checker<specs_handler<parse_context, Context>> handler(
|
|
||||||
specs_handler<parse_context, Context>(specs, parse_ctx, context), get_type(arg));
|
|
||||||
begin = parse_format_specs(begin, end, handler);
|
|
||||||
if (begin == end || *begin != '}') on_error("missing '}' in format string");
|
|
||||||
parse_ctx.advance_to(parse_ctx.begin() + (begin - &*parse_ctx.begin()));
|
|
||||||
context.advance_to(visit_format_arg(ArgFormatter(context, &parse_ctx, &specs), arg));
|
|
||||||
return begin;
|
|
||||||
}
|
|
||||||
|
|
||||||
basic_format_parse_context<Char> parse_ctx;
|
|
||||||
Context context;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T, typename Char>
|
|
||||||
struct formatter {
|
|
||||||
// Parses format specifiers stopping either at the end of the range or at the
|
|
||||||
// terminating '}'.
|
|
||||||
template <typename ParseContext>
|
|
||||||
FMT_CONSTEXPR typename ParseContext::iterator parse(ParseContext& ctx) {
|
|
||||||
namespace detail = fmt::detail;
|
|
||||||
typedef detail::dynamic_specs_handler<ParseContext> handler_type;
|
|
||||||
auto type = detail::mapped_type_constant<T, fmt::buffer_context<Char>>::value;
|
|
||||||
detail::specs_checker<handler_type> handler(handler_type(specs_, ctx),
|
|
||||||
type);
|
|
||||||
auto it = parse_format_specs(ctx.begin(), ctx.end(), handler);
|
|
||||||
auto type_spec = specs_.type;
|
|
||||||
auto eh = ctx.error_handler();
|
|
||||||
switch (type) {
|
|
||||||
case detail::type::none_type:
|
|
||||||
FMT_ASSERT(false, "invalid argument type");
|
|
||||||
break;
|
|
||||||
case detail::type::int_type:
|
|
||||||
case detail::type::uint_type:
|
|
||||||
case detail::type::long_long_type:
|
|
||||||
case detail::type::ulong_long_type:
|
|
||||||
case detail::type::bool_type:
|
|
||||||
handle_int_type_spec(type_spec,
|
|
||||||
detail::int_type_checker<decltype(eh)>(eh));
|
|
||||||
break;
|
|
||||||
case detail::type::char_type:
|
|
||||||
handle_char_specs(
|
|
||||||
&specs_, detail::char_specs_checker<decltype(eh)>(type_spec, eh));
|
|
||||||
break;
|
|
||||||
case detail::type::double_type:
|
|
||||||
case detail::type::long_double_type:
|
|
||||||
detail::parse_float_type_spec(specs_, eh);
|
|
||||||
break;
|
|
||||||
case detail::type::cstring_type:
|
|
||||||
detail::handle_cstring_type_spec(
|
|
||||||
type_spec, detail::cstring_type_checker<decltype(eh)>(eh));
|
|
||||||
break;
|
|
||||||
case detail::type::string_type:
|
|
||||||
detail::check_string_type_spec(type_spec, eh);
|
|
||||||
break;
|
|
||||||
case detail::type::pointer_type:
|
|
||||||
detail::check_pointer_type_spec(type_spec, eh);
|
|
||||||
break;
|
|
||||||
case detail::type::custom_type:
|
|
||||||
// Custom format specifiers should be checked in parse functions of
|
|
||||||
// formatter specializations.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename FormatContext>
|
|
||||||
auto format(const T& val, FormatContext& ctx) -> decltype(ctx.out()) {
|
|
||||||
fmt::detail::handle_dynamic_spec<fmt::detail::width_checker>(
|
|
||||||
specs_.width, specs_.width_ref, ctx);
|
|
||||||
fmt::detail::handle_dynamic_spec<fmt::detail::precision_checker>(
|
|
||||||
specs_.precision, specs_.precision_ref, ctx);
|
|
||||||
using af = arg_formatter<typename FormatContext::iterator,
|
|
||||||
typename FormatContext::char_type>;
|
|
||||||
return visit_format_arg(af(ctx, nullptr, &specs_),
|
|
||||||
basic_format_arg<FormatContext>(val));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
fmt::detail::dynamic_format_specs<Char> specs_;
|
|
||||||
};
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
// https://fmt.dev/Text%20Formatting.html#format.functions
|
|
||||||
template<class... Args>
|
|
||||||
string format(string_view fmt, const Args&... args) {
|
|
||||||
return vformat(fmt, make_format_args(args...));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class... Args>
|
|
||||||
wstring format(wstring_view fmt, const Args&... args) {
|
|
||||||
return vformat(fmt, make_wformat_args(args...));
|
|
||||||
}
|
|
||||||
|
|
||||||
string vformat(string_view fmt, format_args args) {
|
|
||||||
fmt::memory_buffer mbuf;
|
|
||||||
fmt::detail::buffer<char>& buf = mbuf;
|
|
||||||
using af = detail::arg_formatter<fmt::format_context::iterator, char>;
|
|
||||||
detail::format_handler<af, char, format_context>
|
|
||||||
h(fmt::detail::buffer_appender<char>(buf), fmt, args, {});
|
|
||||||
fmt::detail::parse_format_string<false>(fmt::to_string_view(fmt), h);
|
|
||||||
return to_string(mbuf);
|
|
||||||
}
|
|
||||||
|
|
||||||
wstring vformat(wstring_view fmt, wformat_args args);
|
|
||||||
|
|
||||||
template<class Out, class... Args>
|
|
||||||
Out format_to(Out out, string_view fmt, const Args&... args) {
|
|
||||||
using context = basic_format_context<Out, decltype(fmt)::value_type>;
|
|
||||||
return vformat_to(out, fmt, make_format_args<context>(args...));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Out, class... Args>
|
|
||||||
Out format_to(Out out, wstring_view fmt, const Args&... args) {
|
|
||||||
using context = basic_format_context<Out, decltype(fmt)::value_type>;
|
|
||||||
return vformat_to(out, fmt, make_format_args<context>(args...));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Out>
|
|
||||||
Out vformat_to(Out out, string_view fmt, format_args_t<fmt::type_identity_t<Out>, char> args) {
|
|
||||||
using af = detail::arg_formatter<Out, char>;
|
|
||||||
detail::format_handler<af, char, basic_format_context<Out, char>>
|
|
||||||
h(out, fmt, args, {});
|
|
||||||
fmt::detail::parse_format_string<false>(fmt::to_string_view(fmt), h);
|
|
||||||
return h.context.out();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Out>
|
|
||||||
Out vformat_to(Out out, wstring_view fmt, format_args_t<fmt::type_identity_t<Out>, wchar_t> args);
|
|
||||||
|
|
||||||
template<class Out, class... Args>
|
|
||||||
format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
|
|
||||||
string_view fmt, const Args&... args);
|
|
||||||
template<class Out, class... Args>
|
|
||||||
format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
|
|
||||||
wstring_view fmt, const Args&... args);
|
|
||||||
|
|
||||||
template<class... Args>
|
|
||||||
size_t formatted_size(string_view fmt, const Args&... args);
|
|
||||||
template<class... Args>
|
|
||||||
size_t formatted_size(wstring_view fmt, const Args&... args);
|
|
||||||
|
|
||||||
#define charT char
|
|
||||||
|
|
||||||
template<> struct formatter<charT, charT> : detail::formatter<charT, charT> {};
|
|
||||||
|
|
||||||
template<> struct formatter<char, wchar_t>;
|
|
||||||
|
|
||||||
template<> struct formatter<charT*, charT> : detail::formatter<const charT*, charT> {};
|
|
||||||
|
|
||||||
template<> struct formatter<const charT*, charT> : detail::formatter<const charT*, charT> {};
|
|
||||||
|
|
||||||
template<size_t N> struct formatter<const charT[N], charT>
|
|
||||||
: detail::formatter<std::basic_string_view<charT>, charT> {};
|
|
||||||
|
|
||||||
template<class traits, class Allocator>
|
|
||||||
struct formatter<basic_string<charT, traits, Allocator>, charT>
|
|
||||||
: detail::formatter<std::basic_string_view<charT>, charT> {};
|
|
||||||
|
|
||||||
template<class traits>
|
|
||||||
struct formatter<basic_string_view<charT, traits>, charT>
|
|
||||||
: detail::formatter<std::basic_string_view<charT>, charT> {};
|
|
||||||
|
|
||||||
template <> struct formatter<nullptr_t, charT> : detail::formatter<const void*, charT> {};
|
|
||||||
template <> struct formatter<void*, charT> : detail::formatter<const void*, charT> {};
|
|
||||||
template <> struct formatter<const void*, charT> : detail::formatter<const void*, charT> {};
|
|
||||||
template <> struct formatter<bool, charT> : detail::formatter<bool, charT> {};
|
|
||||||
|
|
||||||
template <> struct formatter<signed char, charT> : detail::formatter<int, charT> {};
|
|
||||||
template <> struct formatter<short, charT> : detail::formatter<int, charT> {};
|
|
||||||
template <> struct formatter<int, charT> : detail::formatter<int, charT> {};
|
|
||||||
template <> struct formatter<long, charT>
|
|
||||||
: detail::formatter<std::conditional_t<sizeof(long) == sizeof(int), int, long long>, charT> {};
|
|
||||||
template <> struct formatter<long long, charT> : detail::formatter<long long, charT> {};
|
|
||||||
template <> struct formatter<unsigned char, charT> : detail::formatter<unsigned int, charT> {};
|
|
||||||
template <> struct formatter<unsigned short, charT> : detail::formatter<unsigned int, charT> {};
|
|
||||||
template <> struct formatter<unsigned int, charT> : detail::formatter<unsigned int, charT> {};
|
|
||||||
template <> struct formatter<unsigned long, charT>
|
|
||||||
: detail::formatter<std::conditional_t<sizeof(long) == sizeof(int), unsigned, unsigned long long>, charT> {};
|
|
||||||
template <> struct formatter<unsigned long long, charT> : detail::formatter<unsigned long long, charT> {};
|
|
||||||
|
|
||||||
template <> struct formatter<float, charT> : detail::formatter<double, charT> {};
|
|
||||||
template <> struct formatter<double, charT> : detail::formatter<double, charT> {};
|
|
||||||
template <> struct formatter<long double, charT> : detail::formatter<long double, charT> {};
|
|
||||||
|
|
||||||
#undef charT
|
|
||||||
|
|
||||||
#define charT wchar_t
|
|
||||||
|
|
||||||
template<> struct formatter<charT, charT> : detail::formatter<charT, charT> {};
|
|
||||||
|
|
||||||
template<> struct formatter<char, wchar_t> : detail::formatter<charT, charT> {};
|
|
||||||
|
|
||||||
template<> struct formatter<charT*, charT> : detail::formatter<const charT*, charT> {};
|
|
||||||
|
|
||||||
template<> struct formatter<const charT*, charT> : detail::formatter<const charT*, charT> {};
|
|
||||||
|
|
||||||
template<size_t N> struct formatter<const charT[N], charT>
|
|
||||||
: detail::formatter<std::basic_string_view<charT>, charT> {};
|
|
||||||
|
|
||||||
template<class traits, class Allocator>
|
|
||||||
struct formatter<std::basic_string<charT, traits, Allocator>, charT>
|
|
||||||
: detail::formatter<std::basic_string_view<charT>, charT> {};
|
|
||||||
|
|
||||||
template<class traits>
|
|
||||||
struct formatter<std::basic_string_view<charT, traits>, charT>
|
|
||||||
: detail::formatter<std::basic_string_view<charT>, charT> {};
|
|
||||||
|
|
||||||
template <> struct formatter<nullptr_t, charT> : detail::formatter<const void*, charT> {};
|
|
||||||
template <> struct formatter<void*, charT> : detail::formatter<const void*, charT> {};
|
|
||||||
template <> struct formatter<const void*, charT> : detail::formatter<const void*, charT> {};
|
|
||||||
template <> struct formatter<bool, charT> : detail::formatter<bool, charT> {};
|
|
||||||
|
|
||||||
template <> struct formatter<signed char, charT> : detail::formatter<int, charT> {};
|
|
||||||
template <> struct formatter<short, charT> : detail::formatter<int, charT> {};
|
|
||||||
template <> struct formatter<int, charT> : detail::formatter<int, charT> {};
|
|
||||||
template <> struct formatter<long, charT>
|
|
||||||
: detail::formatter<std::conditional_t<sizeof(long) == sizeof(int), int, long long>, charT> {};
|
|
||||||
template <> struct formatter<long long, charT> : detail::formatter<long long, charT> {};
|
|
||||||
template <> struct formatter<unsigned char, charT> : detail::formatter<unsigned int, charT> {};
|
|
||||||
template <> struct formatter<unsigned short, charT> : detail::formatter<unsigned int, charT> {};
|
|
||||||
template <> struct formatter<unsigned int, charT> : detail::formatter<unsigned int, charT> {};
|
|
||||||
template <> struct formatter<unsigned long, charT>
|
|
||||||
: detail::formatter<std::conditional_t<sizeof(long) == sizeof(int), unsigned, unsigned long long>, charT> {};
|
|
||||||
template <> struct formatter<unsigned long long, charT> : detail::formatter<unsigned long long, charT> {};
|
|
||||||
|
|
||||||
template <> struct formatter<float, charT> : detail::formatter<double, charT> {};
|
|
||||||
template <> struct formatter<double, charT> : detail::formatter<double, charT> {};
|
|
||||||
template <> struct formatter<long double, charT> : detail::formatter<long double, charT> {};
|
|
||||||
|
|
||||||
#undef charT
|
|
||||||
|
|
||||||
template<> struct formatter<const wchar_t, char> {
|
|
||||||
formatter() = delete;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // FMT_FORMAT_
|
|
69
vendor/Fmt/test/format-impl-test.cc
vendored
69
vendor/Fmt/test/format-impl-test.cc
vendored
@ -96,23 +96,6 @@ TEST(bigint_test, multiply) {
|
|||||||
EXPECT_EQ("fffffffffffffffe0000000000000001", fmt::format("{}", bigmax));
|
EXPECT_EQ("fffffffffffffffe0000000000000001", fmt::format("{}", bigmax));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(bigint_test, accumulator) {
|
|
||||||
fmt::detail::accumulator acc;
|
|
||||||
EXPECT_EQ(acc.lower, 0);
|
|
||||||
EXPECT_EQ(acc.upper, 0);
|
|
||||||
acc.upper = 12;
|
|
||||||
acc.lower = 34;
|
|
||||||
EXPECT_EQ(static_cast<uint32_t>(acc), 34);
|
|
||||||
acc += 56;
|
|
||||||
EXPECT_EQ(acc.lower, 90);
|
|
||||||
acc += max_value<uint64_t>();
|
|
||||||
EXPECT_EQ(acc.upper, 13);
|
|
||||||
EXPECT_EQ(acc.lower, 89);
|
|
||||||
acc >>= 32;
|
|
||||||
EXPECT_EQ(acc.upper, 0);
|
|
||||||
EXPECT_EQ(acc.lower, 13 * 0x100000000);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(bigint_test, square) {
|
TEST(bigint_test, square) {
|
||||||
bigint n0(0);
|
bigint n0(0);
|
||||||
n0.square();
|
n0.square();
|
||||||
@ -207,14 +190,14 @@ TEST(fp_test, get_cached_power) {
|
|||||||
using limits = std::numeric_limits<double>;
|
using limits = std::numeric_limits<double>;
|
||||||
for (auto exp = limits::min_exponent; exp <= limits::max_exponent; ++exp) {
|
for (auto exp = limits::min_exponent; exp <= limits::max_exponent; ++exp) {
|
||||||
int dec_exp = 0;
|
int dec_exp = 0;
|
||||||
auto fp = fmt::detail::get_cached_power(exp, dec_exp);
|
auto power = fmt::detail::get_cached_power(exp, dec_exp);
|
||||||
bigint exact, cache(fp.f);
|
bigint exact, cache(power.f);
|
||||||
if (dec_exp >= 0) {
|
if (dec_exp >= 0) {
|
||||||
exact.assign_pow10(dec_exp);
|
exact.assign_pow10(dec_exp);
|
||||||
if (fp.e <= 0)
|
if (power.e <= 0)
|
||||||
exact <<= -fp.e;
|
exact <<= -power.e;
|
||||||
else
|
else
|
||||||
cache <<= fp.e;
|
cache <<= power.e;
|
||||||
exact.align(cache);
|
exact.align(cache);
|
||||||
cache.align(exact);
|
cache.align(exact);
|
||||||
auto exact_str = fmt::format("{}", exact);
|
auto exact_str = fmt::format("{}", exact);
|
||||||
@ -228,9 +211,9 @@ TEST(fp_test, get_cached_power) {
|
|||||||
EXPECT_EQ(diff, 0);
|
EXPECT_EQ(diff, 0);
|
||||||
} else {
|
} else {
|
||||||
cache.assign_pow10(-dec_exp);
|
cache.assign_pow10(-dec_exp);
|
||||||
cache *= fp.f + 1; // Inexact check.
|
cache *= power.f + 1; // Inexact check.
|
||||||
exact.assign(1);
|
exact.assign(1);
|
||||||
exact <<= -fp.e;
|
exact <<= -power.e;
|
||||||
exact.align(cache);
|
exact.align(cache);
|
||||||
auto exact_str = fmt::format("{}", exact);
|
auto exact_str = fmt::format("{}", exact);
|
||||||
auto cache_str = fmt::format("{}", cache);
|
auto cache_str = fmt::format("{}", cache);
|
||||||
@ -243,14 +226,17 @@ TEST(fp_test, get_cached_power) {
|
|||||||
TEST(fp_test, dragonbox_max_k) {
|
TEST(fp_test, dragonbox_max_k) {
|
||||||
using fmt::detail::dragonbox::floor_log10_pow2;
|
using fmt::detail::dragonbox::floor_log10_pow2;
|
||||||
using float_info = fmt::detail::dragonbox::float_info<float>;
|
using float_info = fmt::detail::dragonbox::float_info<float>;
|
||||||
EXPECT_EQ(fmt::detail::const_check(float_info::max_k),
|
EXPECT_EQ(
|
||||||
float_info::kappa - floor_log10_pow2(float_info::min_exponent -
|
fmt::detail::const_check(float_info::max_k),
|
||||||
float_info::significand_bits));
|
float_info::kappa -
|
||||||
|
floor_log10_pow2(std::numeric_limits<float>::min_exponent -
|
||||||
|
fmt::detail::num_significand_bits<float>() - 1));
|
||||||
using double_info = fmt::detail::dragonbox::float_info<double>;
|
using double_info = fmt::detail::dragonbox::float_info<double>;
|
||||||
EXPECT_EQ(
|
EXPECT_EQ(
|
||||||
fmt::detail::const_check(double_info::max_k),
|
fmt::detail::const_check(double_info::max_k),
|
||||||
double_info::kappa - floor_log10_pow2(double_info::min_exponent -
|
double_info::kappa -
|
||||||
double_info::significand_bits));
|
floor_log10_pow2(std::numeric_limits<double>::min_exponent -
|
||||||
|
fmt::detail::num_significand_bits<double>() - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(fp_test, get_round_direction) {
|
TEST(fp_test, get_round_direction) {
|
||||||
@ -278,25 +264,22 @@ TEST(fp_test, get_round_direction) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(fp_test, fixed_handler) {
|
TEST(fp_test, fixed_handler) {
|
||||||
struct handler : fmt::detail::fixed_handler {
|
struct handler : fmt::detail::gen_digits_handler {
|
||||||
char buffer[10];
|
char buffer[10];
|
||||||
handler(int prec = 0) : fmt::detail::fixed_handler() {
|
handler(int prec = 0) : fmt::detail::gen_digits_handler() {
|
||||||
buf = buffer;
|
buf = buffer;
|
||||||
precision = prec;
|
precision = prec;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
int exp = 0;
|
handler().on_digit('0', 100, 99, 0, false);
|
||||||
handler().on_digit('0', 100, 99, 0, exp, false);
|
EXPECT_THROW(handler().on_digit('0', 100, 100, 0, false), assertion_failure);
|
||||||
EXPECT_THROW(handler().on_digit('0', 100, 100, 0, exp, false),
|
|
||||||
assertion_failure);
|
|
||||||
namespace digits = fmt::detail::digits;
|
namespace digits = fmt::detail::digits;
|
||||||
EXPECT_EQ(handler(1).on_digit('0', 100, 10, 10, exp, false), digits::error);
|
EXPECT_EQ(handler(1).on_digit('0', 100, 10, 10, false), digits::error);
|
||||||
// Check that divisor - error doesn't overflow.
|
// Check that divisor - error doesn't overflow.
|
||||||
EXPECT_EQ(handler(1).on_digit('0', 100, 10, 101, exp, false), digits::error);
|
EXPECT_EQ(handler(1).on_digit('0', 100, 10, 101, false), digits::error);
|
||||||
// Check that 2 * error doesn't overflow.
|
// Check that 2 * error doesn't overflow.
|
||||||
uint64_t max = max_value<uint64_t>();
|
uint64_t max = max_value<uint64_t>();
|
||||||
EXPECT_EQ(handler(1).on_digit('0', max, 10, max - 1, exp, false),
|
EXPECT_EQ(handler(1).on_digit('0', max, 10, max - 1, false), digits::error);
|
||||||
digits::error);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(fp_test, grisu_format_compiles_with_on_ieee_double) {
|
TEST(fp_test, grisu_format_compiles_with_on_ieee_double) {
|
||||||
@ -360,14 +343,6 @@ TEST(format_impl_test, count_digits) {
|
|||||||
test_count_digits<uint64_t>();
|
test_count_digits<uint64_t>();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(format_impl_test, write_fallback_uintptr) {
|
|
||||||
std::string s;
|
|
||||||
fmt::detail::write_ptr<char>(
|
|
||||||
std::back_inserter(s),
|
|
||||||
fmt::detail::fallback_uintptr(reinterpret_cast<void*>(0xface)), nullptr);
|
|
||||||
EXPECT_EQ(s, "0xface");
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
# include <windows.h>
|
# include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
548
vendor/Fmt/test/format-test.cc
vendored
548
vendor/Fmt/test/format-test.cc
vendored
@ -39,6 +39,75 @@ using testing::StrictMock;
|
|||||||
|
|
||||||
enum { buffer_size = 256 };
|
enum { buffer_size = 256 };
|
||||||
|
|
||||||
|
TEST(uint128_test, ctor) {
|
||||||
|
using fmt::detail::uint128_fallback;
|
||||||
|
auto n = uint128_fallback();
|
||||||
|
EXPECT_EQ(n, 0);
|
||||||
|
n = uint128_fallback(42);
|
||||||
|
EXPECT_EQ(n, 42);
|
||||||
|
EXPECT_EQ(static_cast<uint64_t>(n), 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(uint128_test, shift) {
|
||||||
|
auto n = fmt::detail::uint128_fallback(42);
|
||||||
|
n = n << 64;
|
||||||
|
EXPECT_EQ(static_cast<uint64_t>(n), 0);
|
||||||
|
n = n >> 64;
|
||||||
|
EXPECT_EQ(static_cast<uint64_t>(n), 42);
|
||||||
|
n = n << 62;
|
||||||
|
EXPECT_EQ(static_cast<uint64_t>(n >> 64), 0xa);
|
||||||
|
EXPECT_EQ(static_cast<uint64_t>(n), 0x8000000000000000);
|
||||||
|
n = n >> 62;
|
||||||
|
EXPECT_EQ(static_cast<uint64_t>(n), 42);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(uint128_test, minus) {
|
||||||
|
auto n = fmt::detail::uint128_fallback(42);
|
||||||
|
EXPECT_EQ(n - 2, 40);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Float> void check_isfinite() {
|
||||||
|
using fmt::detail::isfinite;
|
||||||
|
EXPECT_TRUE(isfinite(Float(0.0)));
|
||||||
|
EXPECT_TRUE(isfinite(Float(42.0)));
|
||||||
|
EXPECT_TRUE(isfinite(Float(-42.0)));
|
||||||
|
EXPECT_TRUE(isfinite(Float(fmt::detail::max_value<double>())));
|
||||||
|
// Use double because std::numeric_limits is broken for __float128.
|
||||||
|
using limits = std::numeric_limits<double>;
|
||||||
|
EXPECT_FALSE(isfinite(Float(limits::infinity())));
|
||||||
|
EXPECT_FALSE(isfinite(Float(-limits::infinity())));
|
||||||
|
EXPECT_FALSE(isfinite(Float(limits::quiet_NaN())));
|
||||||
|
EXPECT_FALSE(isfinite(Float(-limits::quiet_NaN())));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(float_test, isfinite) {
|
||||||
|
check_isfinite<double>();
|
||||||
|
#ifdef __SIZEOF_FLOAT128__
|
||||||
|
check_isfinite<fmt::detail::float128>();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Float> void check_isnan() {
|
||||||
|
using fmt::detail::isnan;
|
||||||
|
EXPECT_FALSE(isnan(Float(0.0)));
|
||||||
|
EXPECT_FALSE(isnan(Float(42.0)));
|
||||||
|
EXPECT_FALSE(isnan(Float(-42.0)));
|
||||||
|
EXPECT_FALSE(isnan(Float(fmt::detail::max_value<double>())));
|
||||||
|
// Use double because std::numeric_limits is broken for __float128.
|
||||||
|
using limits = std::numeric_limits<double>;
|
||||||
|
EXPECT_FALSE(isnan(Float(limits::infinity())));
|
||||||
|
EXPECT_FALSE(isnan(Float(-limits::infinity())));
|
||||||
|
EXPECT_TRUE(isnan(Float(limits::quiet_NaN())));
|
||||||
|
EXPECT_TRUE(isnan(Float(-limits::quiet_NaN())));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(float_test, isnan) {
|
||||||
|
check_isnan<double>();
|
||||||
|
#ifdef __SIZEOF_FLOAT128__
|
||||||
|
check_isnan<fmt::detail::float128>();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
struct uint32_pair {
|
struct uint32_pair {
|
||||||
uint32_t u[2];
|
uint32_t u[2];
|
||||||
};
|
};
|
||||||
@ -223,8 +292,9 @@ TEST(memory_buffer_test, move_ctor_dynamic_buffer) {
|
|||||||
buffer.push_back('a');
|
buffer.push_back('a');
|
||||||
basic_memory_buffer<char, 4, std_allocator> buffer2(std::move(buffer));
|
basic_memory_buffer<char, 4, std_allocator> buffer2(std::move(buffer));
|
||||||
// Move should rip the guts of the first buffer.
|
// Move should rip the guts of the first buffer.
|
||||||
EXPECT_EQ(inline_buffer_ptr, &buffer[0]);
|
EXPECT_EQ(&buffer[0], inline_buffer_ptr);
|
||||||
EXPECT_EQ("testa", std::string(&buffer2[0], buffer2.size()));
|
EXPECT_EQ(buffer.size(), 0);
|
||||||
|
EXPECT_EQ(std::string(&buffer2[0], buffer2.size()), "testa");
|
||||||
EXPECT_GT(buffer2.capacity(), 4u);
|
EXPECT_GT(buffer2.capacity(), 4u);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -325,7 +395,7 @@ template <typename Allocator, size_t MaxSize>
|
|||||||
class max_size_allocator : public Allocator {
|
class max_size_allocator : public Allocator {
|
||||||
public:
|
public:
|
||||||
using typename Allocator::value_type;
|
using typename Allocator::value_type;
|
||||||
size_t max_size() const FMT_NOEXCEPT { return MaxSize; }
|
size_t max_size() const noexcept { return MaxSize; }
|
||||||
value_type* allocate(size_t n) {
|
value_type* allocate(size_t n) {
|
||||||
if (n > max_size()) {
|
if (n > max_size()) {
|
||||||
throw std::length_error("size > max_size");
|
throw std::length_error("size > max_size");
|
||||||
@ -370,11 +440,11 @@ TEST(format_test, escape) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(format_test, unmatched_braces) {
|
TEST(format_test, unmatched_braces) {
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{")), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{")), format_error,
|
||||||
"invalid format string");
|
"invalid format string");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("}")), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("}")), format_error,
|
||||||
"unmatched '}' in format string");
|
"unmatched '}' in format string");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0{}")), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0{}")), format_error,
|
||||||
"invalid format string");
|
"invalid format string");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -391,30 +461,30 @@ TEST(format_test, args_in_different_positions) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(format_test, arg_errors) {
|
TEST(format_test, arg_errors) {
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{")), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{")), format_error,
|
||||||
"invalid format string");
|
"invalid format string");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{?}")), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{?}")), format_error,
|
||||||
"invalid format string");
|
"invalid format string");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0")), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0")), format_error,
|
||||||
"invalid format string");
|
"invalid format string");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0}")), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0}")), format_error,
|
||||||
"argument not found");
|
"argument not found");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{00}"), 42), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{00}"), 42), format_error,
|
||||||
"invalid format string");
|
"invalid format string");
|
||||||
|
|
||||||
char format_str[buffer_size];
|
char format_str[buffer_size];
|
||||||
safe_sprintf(format_str, "{%u", INT_MAX);
|
safe_sprintf(format_str, "{%u", INT_MAX);
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime(format_str)), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime(format_str)), format_error,
|
||||||
"invalid format string");
|
"invalid format string");
|
||||||
safe_sprintf(format_str, "{%u}", INT_MAX);
|
safe_sprintf(format_str, "{%u}", INT_MAX);
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime(format_str)), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime(format_str)), format_error,
|
||||||
"argument not found");
|
"argument not found");
|
||||||
|
|
||||||
safe_sprintf(format_str, "{%u", INT_MAX + 1u);
|
safe_sprintf(format_str, "{%u", INT_MAX + 1u);
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime(format_str)), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime(format_str)), format_error,
|
||||||
"invalid format string");
|
"invalid format string");
|
||||||
safe_sprintf(format_str, "{%u}", INT_MAX + 1u);
|
safe_sprintf(format_str, "{%u}", INT_MAX + 1u);
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime(format_str)), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime(format_str)), format_error,
|
||||||
"argument not found");
|
"argument not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -458,24 +528,26 @@ TEST(format_test, named_arg) {
|
|||||||
fmt::arg("i", 0), fmt::arg("j", 0), fmt::arg("k", 0),
|
fmt::arg("i", 0), fmt::arg("j", 0), fmt::arg("k", 0),
|
||||||
fmt::arg("l", 0), fmt::arg("m", 0), fmt::arg("n", 0),
|
fmt::arg("l", 0), fmt::arg("m", 0), fmt::arg("n", 0),
|
||||||
fmt::arg("o", 0), fmt::arg("p", 0)));
|
fmt::arg("o", 0), fmt::arg("p", 0)));
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{a}")), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{a}")), format_error,
|
||||||
"argument not found");
|
"argument not found");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{a}"), 42), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{a}"), 42), format_error,
|
||||||
"argument not found");
|
"argument not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(format_test, auto_arg_index) {
|
TEST(format_test, auto_arg_index) {
|
||||||
EXPECT_EQ("abc", fmt::format("{}{}{}", 'a', 'b', 'c'));
|
EXPECT_EQ("abc", fmt::format("{}{}{}", 'a', 'b', 'c'));
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0}{}"), 'a', 'b'), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0}{}"), 'a', 'b'), format_error,
|
||||||
"cannot switch from manual to automatic argument indexing");
|
"cannot switch from manual to automatic argument indexing");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{}{0}"), 'a', 'b'), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{}{0}"), 'a', 'b'), format_error,
|
||||||
"cannot switch from automatic to manual argument indexing");
|
"cannot switch from automatic to manual argument indexing");
|
||||||
EXPECT_EQ("1.2", fmt::format("{:.{}}", 1.2345, 2));
|
EXPECT_EQ("1.2", fmt::format("{:.{}}", 1.2345, 2));
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0}:.{}"), 1.2345, 2), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0}:.{}"), 1.2345, 2),
|
||||||
|
format_error,
|
||||||
"cannot switch from manual to automatic argument indexing");
|
"cannot switch from manual to automatic argument indexing");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{:.{0}}"), 1.2345, 2), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{:.{0}}"), 1.2345, 2),
|
||||||
|
format_error,
|
||||||
"cannot switch from automatic to manual argument indexing");
|
"cannot switch from automatic to manual argument indexing");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{}")), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{}")), format_error,
|
||||||
"argument not found");
|
"argument not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -533,9 +605,9 @@ TEST(format_test, center_align) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(format_test, fill) {
|
TEST(format_test, fill) {
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:{<5}"), 'c'), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{<5}"), 'c'), format_error,
|
||||||
"invalid fill character '{'");
|
"invalid fill character '{'");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:{<5}}"), 'c'), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{<5}}"), 'c'), format_error,
|
||||||
"invalid fill character '{'");
|
"invalid fill character '{'");
|
||||||
EXPECT_EQ("**42", fmt::format("{0:*>4}", 42));
|
EXPECT_EQ("**42", fmt::format("{0:*>4}", 42));
|
||||||
EXPECT_EQ("**-42", fmt::format("{0:*>5}", -42));
|
EXPECT_EQ("**-42", fmt::format("{0:*>5}", -42));
|
||||||
@ -554,31 +626,35 @@ TEST(format_test, fill) {
|
|||||||
EXPECT_EQ(std::string("\0\0\0*", 4),
|
EXPECT_EQ(std::string("\0\0\0*", 4),
|
||||||
fmt::format(string_view("{:\0>4}", 6), '*'));
|
fmt::format(string_view("{:\0>4}", 6), '*'));
|
||||||
EXPECT_EQ("жж42", fmt::format("{0:ж>4}", 42));
|
EXPECT_EQ("жж42", fmt::format("{0:ж>4}", 42));
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{:\x80\x80\x80\x80\x80>}"), 0),
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{:\x80\x80\x80\x80\x80>}"), 0),
|
||||||
format_error, "missing '}' in format string");
|
format_error, "invalid type specifier");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(format_test, plus_sign) {
|
TEST(format_test, plus_sign) {
|
||||||
EXPECT_EQ("+42", fmt::format("{0:+}", 42));
|
EXPECT_EQ("+42", fmt::format("{0:+}", 42));
|
||||||
EXPECT_EQ("-42", fmt::format("{0:+}", -42));
|
EXPECT_EQ("-42", fmt::format("{0:+}", -42));
|
||||||
EXPECT_EQ("+42", fmt::format("{0:+}", 42));
|
EXPECT_EQ("+42", fmt::format("{0:+}", 42));
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:+}"), 42u), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:+}"), 42u), format_error,
|
||||||
"format specifier requires signed argument");
|
"format specifier requires signed argument");
|
||||||
EXPECT_EQ("+42", fmt::format("{0:+}", 42l));
|
EXPECT_EQ("+42", fmt::format("{0:+}", 42l));
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:+}"), 42ul), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:+}"), 42ul), format_error,
|
||||||
"format specifier requires signed argument");
|
"format specifier requires signed argument");
|
||||||
EXPECT_EQ("+42", fmt::format("{0:+}", 42ll));
|
EXPECT_EQ("+42", fmt::format("{0:+}", 42ll));
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:+}"), 42ull), format_error,
|
#if FMT_USE_INT128
|
||||||
|
EXPECT_EQ("+42", fmt::format("{0:+}", __int128_t(42)));
|
||||||
|
#endif
|
||||||
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:+}"), 42ull), format_error,
|
||||||
"format specifier requires signed argument");
|
"format specifier requires signed argument");
|
||||||
EXPECT_EQ("+42", fmt::format("{0:+}", 42.0));
|
EXPECT_EQ("+42", fmt::format("{0:+}", 42.0));
|
||||||
EXPECT_EQ("+42", fmt::format("{0:+}", 42.0l));
|
EXPECT_EQ("+42", fmt::format("{0:+}", 42.0l));
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:+"), 'c'), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:+"), 'c'), format_error,
|
||||||
"missing '}' in format string");
|
"missing '}' in format string");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:+}"), 'c'), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:+}"), 'c'), format_error,
|
||||||
"invalid format specifier for char");
|
"invalid format specifier for char");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:+}"), "abc"), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:+}"), "abc"), format_error,
|
||||||
"format specifier requires numeric argument");
|
"format specifier requires numeric argument");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:+}"), reinterpret_cast<void*>(0x42)),
|
EXPECT_THROW_MSG(
|
||||||
|
(void)fmt::format(runtime("{0:+}"), reinterpret_cast<void*>(0x42)),
|
||||||
format_error, "format specifier requires numeric argument");
|
format_error, "format specifier requires numeric argument");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -586,23 +662,24 @@ TEST(format_test, minus_sign) {
|
|||||||
EXPECT_EQ("42", fmt::format("{0:-}", 42));
|
EXPECT_EQ("42", fmt::format("{0:-}", 42));
|
||||||
EXPECT_EQ("-42", fmt::format("{0:-}", -42));
|
EXPECT_EQ("-42", fmt::format("{0:-}", -42));
|
||||||
EXPECT_EQ("42", fmt::format("{0:-}", 42));
|
EXPECT_EQ("42", fmt::format("{0:-}", 42));
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:-}"), 42u), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:-}"), 42u), format_error,
|
||||||
"format specifier requires signed argument");
|
"format specifier requires signed argument");
|
||||||
EXPECT_EQ("42", fmt::format("{0:-}", 42l));
|
EXPECT_EQ("42", fmt::format("{0:-}", 42l));
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:-}"), 42ul), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:-}"), 42ul), format_error,
|
||||||
"format specifier requires signed argument");
|
"format specifier requires signed argument");
|
||||||
EXPECT_EQ("42", fmt::format("{0:-}", 42ll));
|
EXPECT_EQ("42", fmt::format("{0:-}", 42ll));
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:-}"), 42ull), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:-}"), 42ull), format_error,
|
||||||
"format specifier requires signed argument");
|
"format specifier requires signed argument");
|
||||||
EXPECT_EQ("42", fmt::format("{0:-}", 42.0));
|
EXPECT_EQ("42", fmt::format("{0:-}", 42.0));
|
||||||
EXPECT_EQ("42", fmt::format("{0:-}", 42.0l));
|
EXPECT_EQ("42", fmt::format("{0:-}", 42.0l));
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:-"), 'c'), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:-"), 'c'), format_error,
|
||||||
"missing '}' in format string");
|
"missing '}' in format string");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:-}"), 'c'), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:-}"), 'c'), format_error,
|
||||||
"invalid format specifier for char");
|
"invalid format specifier for char");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:-}"), "abc"), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:-}"), "abc"), format_error,
|
||||||
"format specifier requires numeric argument");
|
"format specifier requires numeric argument");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:-}"), reinterpret_cast<void*>(0x42)),
|
EXPECT_THROW_MSG(
|
||||||
|
(void)fmt::format(runtime("{0:-}"), reinterpret_cast<void*>(0x42)),
|
||||||
format_error, "format specifier requires numeric argument");
|
format_error, "format specifier requires numeric argument");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -610,23 +687,24 @@ TEST(format_test, space_sign) {
|
|||||||
EXPECT_EQ(" 42", fmt::format("{0: }", 42));
|
EXPECT_EQ(" 42", fmt::format("{0: }", 42));
|
||||||
EXPECT_EQ("-42", fmt::format("{0: }", -42));
|
EXPECT_EQ("-42", fmt::format("{0: }", -42));
|
||||||
EXPECT_EQ(" 42", fmt::format("{0: }", 42));
|
EXPECT_EQ(" 42", fmt::format("{0: }", 42));
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0: }"), 42u), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0: }"), 42u), format_error,
|
||||||
"format specifier requires signed argument");
|
"format specifier requires signed argument");
|
||||||
EXPECT_EQ(" 42", fmt::format("{0: }", 42l));
|
EXPECT_EQ(" 42", fmt::format("{0: }", 42l));
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0: }"), 42ul), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0: }"), 42ul), format_error,
|
||||||
"format specifier requires signed argument");
|
"format specifier requires signed argument");
|
||||||
EXPECT_EQ(" 42", fmt::format("{0: }", 42ll));
|
EXPECT_EQ(" 42", fmt::format("{0: }", 42ll));
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0: }"), 42ull), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0: }"), 42ull), format_error,
|
||||||
"format specifier requires signed argument");
|
"format specifier requires signed argument");
|
||||||
EXPECT_EQ(" 42", fmt::format("{0: }", 42.0));
|
EXPECT_EQ(" 42", fmt::format("{0: }", 42.0));
|
||||||
EXPECT_EQ(" 42", fmt::format("{0: }", 42.0l));
|
EXPECT_EQ(" 42", fmt::format("{0: }", 42.0l));
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0: "), 'c'), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0: "), 'c'), format_error,
|
||||||
"missing '}' in format string");
|
"missing '}' in format string");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0: }"), 'c'), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0: }"), 'c'), format_error,
|
||||||
"invalid format specifier for char");
|
"invalid format specifier for char");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0: }"), "abc"), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0: }"), "abc"), format_error,
|
||||||
"format specifier requires numeric argument");
|
"format specifier requires numeric argument");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0: }"), reinterpret_cast<void*>(0x42)),
|
EXPECT_THROW_MSG(
|
||||||
|
(void)fmt::format(runtime("{0: }"), reinterpret_cast<void*>(0x42)),
|
||||||
format_error, "format specifier requires numeric argument");
|
format_error, "format specifier requires numeric argument");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -670,13 +748,14 @@ TEST(format_test, hash_flag) {
|
|||||||
EXPECT_EQ("0.", fmt::format("{:#.0f}", 0.01));
|
EXPECT_EQ("0.", fmt::format("{:#.0f}", 0.01));
|
||||||
EXPECT_EQ("0.50", fmt::format("{:#.2g}", 0.5));
|
EXPECT_EQ("0.50", fmt::format("{:#.2g}", 0.5));
|
||||||
EXPECT_EQ("0.", fmt::format("{:#.0f}", 0.5));
|
EXPECT_EQ("0.", fmt::format("{:#.0f}", 0.5));
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:#"), 'c'), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:#"), 'c'), format_error,
|
||||||
"missing '}' in format string");
|
"missing '}' in format string");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:#}"), 'c'), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:#}"), 'c'), format_error,
|
||||||
"invalid format specifier for char");
|
"invalid format specifier for char");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:#}"), "abc"), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:#}"), "abc"), format_error,
|
||||||
"format specifier requires numeric argument");
|
"format specifier requires numeric argument");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:#}"), reinterpret_cast<void*>(0x42)),
|
EXPECT_THROW_MSG(
|
||||||
|
(void)fmt::format(runtime("{0:#}"), reinterpret_cast<void*>(0x42)),
|
||||||
format_error, "format specifier requires numeric argument");
|
format_error, "format specifier requires numeric argument");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -690,14 +769,14 @@ TEST(format_test, zero_flag) {
|
|||||||
EXPECT_EQ("00042", fmt::format("{0:05}", 42ull));
|
EXPECT_EQ("00042", fmt::format("{0:05}", 42ull));
|
||||||
EXPECT_EQ("-000042", fmt::format("{0:07}", -42.0));
|
EXPECT_EQ("-000042", fmt::format("{0:07}", -42.0));
|
||||||
EXPECT_EQ("-000042", fmt::format("{0:07}", -42.0l));
|
EXPECT_EQ("-000042", fmt::format("{0:07}", -42.0l));
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:0"), 'c'), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:0"), 'c'), format_error,
|
||||||
"missing '}' in format string");
|
"missing '}' in format string");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:05}"), 'c'), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:05}"), 'c'), format_error,
|
||||||
"invalid format specifier for char");
|
"invalid format specifier for char");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:05}"), "abc"), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:05}"), "abc"), format_error,
|
||||||
"format specifier requires numeric argument");
|
"format specifier requires numeric argument");
|
||||||
EXPECT_THROW_MSG(
|
EXPECT_THROW_MSG(
|
||||||
fmt::format(runtime("{0:05}"), reinterpret_cast<void*>(0x42)),
|
(void)fmt::format(runtime("{0:05}"), reinterpret_cast<void*>(0x42)),
|
||||||
format_error, "format specifier requires numeric argument");
|
format_error, "format specifier requires numeric argument");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -705,19 +784,19 @@ TEST(format_test, width) {
|
|||||||
char format_str[buffer_size];
|
char format_str[buffer_size];
|
||||||
safe_sprintf(format_str, "{0:%u", UINT_MAX);
|
safe_sprintf(format_str, "{0:%u", UINT_MAX);
|
||||||
increment(format_str + 3);
|
increment(format_str + 3);
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime(format_str), 0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime(format_str), 0), format_error,
|
||||||
"number is too big");
|
"number is too big");
|
||||||
size_t size = std::strlen(format_str);
|
size_t size = std::strlen(format_str);
|
||||||
format_str[size] = '}';
|
format_str[size] = '}';
|
||||||
format_str[size + 1] = 0;
|
format_str[size + 1] = 0;
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime(format_str), 0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime(format_str), 0), format_error,
|
||||||
"number is too big");
|
"number is too big");
|
||||||
|
|
||||||
safe_sprintf(format_str, "{0:%u", INT_MAX + 1u);
|
safe_sprintf(format_str, "{0:%u", INT_MAX + 1u);
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime(format_str), 0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime(format_str), 0), format_error,
|
||||||
"number is too big");
|
"number is too big");
|
||||||
safe_sprintf(format_str, "{0:%u}", INT_MAX + 1u);
|
safe_sprintf(format_str, "{0:%u}", INT_MAX + 1u);
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime(format_str), 0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime(format_str), 0), format_error,
|
||||||
"number is too big");
|
"number is too big");
|
||||||
EXPECT_EQ(" -42", fmt::format("{0:4}", -42));
|
EXPECT_EQ(" -42", fmt::format("{0:4}", -42));
|
||||||
EXPECT_EQ(" 42", fmt::format("{0:5}", 42u));
|
EXPECT_EQ(" 42", fmt::format("{0:5}", 42u));
|
||||||
@ -742,47 +821,47 @@ TEST(format_test, runtime_width) {
|
|||||||
char format_str[buffer_size];
|
char format_str[buffer_size];
|
||||||
safe_sprintf(format_str, "{0:{%u", UINT_MAX);
|
safe_sprintf(format_str, "{0:{%u", UINT_MAX);
|
||||||
increment(format_str + 4);
|
increment(format_str + 4);
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime(format_str), 0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime(format_str), 0), format_error,
|
||||||
"invalid format string");
|
"invalid format string");
|
||||||
size_t size = std::strlen(format_str);
|
size_t size = std::strlen(format_str);
|
||||||
format_str[size] = '}';
|
format_str[size] = '}';
|
||||||
format_str[size + 1] = 0;
|
format_str[size + 1] = 0;
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime(format_str), 0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime(format_str), 0), format_error,
|
||||||
"argument not found");
|
"argument not found");
|
||||||
format_str[size + 1] = '}';
|
format_str[size + 1] = '}';
|
||||||
format_str[size + 2] = 0;
|
format_str[size + 2] = 0;
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime(format_str), 0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime(format_str), 0), format_error,
|
||||||
"argument not found");
|
"argument not found");
|
||||||
|
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:{"), 0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{"), 0), format_error,
|
||||||
"invalid format string");
|
"invalid format string");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:{}"), 0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{}"), 0), format_error,
|
||||||
"cannot switch from manual to automatic argument indexing");
|
"cannot switch from manual to automatic argument indexing");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:{?}}"), 0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{?}}"), 0), format_error,
|
||||||
"invalid format string");
|
"invalid format string");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:{1}}"), 0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0), format_error,
|
||||||
"argument not found");
|
"argument not found");
|
||||||
|
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:{0:}}"), 0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{0:}}"), 0), format_error,
|
||||||
"invalid format string");
|
"invalid format string");
|
||||||
|
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:{1}}"), 0, -1), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, -1), format_error,
|
||||||
"negative width");
|
"negative width");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:{1}}"), 0, (INT_MAX + 1u)),
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, (INT_MAX + 1u)),
|
||||||
format_error, "number is too big");
|
format_error, "number is too big");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:{1}}"), 0, -1l), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, -1l), format_error,
|
||||||
"negative width");
|
"negative width");
|
||||||
if (fmt::detail::const_check(sizeof(long) > sizeof(int))) {
|
if (fmt::detail::const_check(sizeof(long) > sizeof(int))) {
|
||||||
long value = INT_MAX;
|
long value = INT_MAX;
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:{1}}"), 0, (value + 1)),
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, (value + 1)),
|
||||||
format_error, "number is too big");
|
format_error, "number is too big");
|
||||||
}
|
}
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:{1}}"), 0, (INT_MAX + 1ul)),
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, (INT_MAX + 1ul)),
|
||||||
format_error, "number is too big");
|
format_error, "number is too big");
|
||||||
|
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:{1}}"), 0, '0'), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, '0'), format_error,
|
||||||
"width is not integer");
|
"width is not integer");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:{1}}"), 0, 0.0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{1}}"), 0, 0.0), format_error,
|
||||||
"width is not integer");
|
"width is not integer");
|
||||||
|
|
||||||
EXPECT_EQ(" -42", fmt::format("{0:{1}}", -42, 4));
|
EXPECT_EQ(" -42", fmt::format("{0:{1}}", -42, 4));
|
||||||
@ -803,53 +882,53 @@ TEST(format_test, precision) {
|
|||||||
char format_str[buffer_size];
|
char format_str[buffer_size];
|
||||||
safe_sprintf(format_str, "{0:.%u", UINT_MAX);
|
safe_sprintf(format_str, "{0:.%u", UINT_MAX);
|
||||||
increment(format_str + 4);
|
increment(format_str + 4);
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime(format_str), 0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime(format_str), 0), format_error,
|
||||||
"number is too big");
|
"number is too big");
|
||||||
size_t size = std::strlen(format_str);
|
size_t size = std::strlen(format_str);
|
||||||
format_str[size] = '}';
|
format_str[size] = '}';
|
||||||
format_str[size + 1] = 0;
|
format_str[size + 1] = 0;
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime(format_str), 0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime(format_str), 0), format_error,
|
||||||
"number is too big");
|
"number is too big");
|
||||||
|
|
||||||
safe_sprintf(format_str, "{0:.%u", INT_MAX + 1u);
|
safe_sprintf(format_str, "{0:.%u", INT_MAX + 1u);
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime(format_str), 0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime(format_str), 0), format_error,
|
||||||
"number is too big");
|
"number is too big");
|
||||||
safe_sprintf(format_str, "{0:.%u}", INT_MAX + 1u);
|
safe_sprintf(format_str, "{0:.%u}", INT_MAX + 1u);
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime(format_str), 0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime(format_str), 0), format_error,
|
||||||
"number is too big");
|
"number is too big");
|
||||||
|
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:."), 0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:."), 0), format_error,
|
||||||
"missing precision specifier");
|
"missing precision specifier");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.}"), 0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.}"), 0), format_error,
|
||||||
"missing precision specifier");
|
"missing precision specifier");
|
||||||
|
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.2"), 0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.2"), 0), format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.2}"), 42), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.2}"), 42), format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.2f}"), 42), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.2f}"), 42), format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.2}"), 42u), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.2}"), 42u), format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.2f}"), 42u), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.2f}"), 42u), format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.2}"), 42l), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.2}"), 42l), format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.2f}"), 42l), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.2f}"), 42l), format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.2}"), 42ul), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.2}"), 42ul), format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.2f}"), 42ul), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.2f}"), 42ul), format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.2}"), 42ll), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.2}"), 42ll), format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.2f}"), 42ll), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.2f}"), 42ll), format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.2}"), 42ull), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.2}"), 42ull), format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.2f}"), 42ull), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.2f}"), 42ull), format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:3.0}"), 'x'), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:3.0}"), 'x'), format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
EXPECT_EQ("1.2", fmt::format("{0:.2}", 1.2345));
|
EXPECT_EQ("1.2", fmt::format("{0:.2}", 1.2345));
|
||||||
EXPECT_EQ("1.2", fmt::format("{0:.2}", 1.2345l));
|
EXPECT_EQ("1.2", fmt::format("{0:.2}", 1.2345l));
|
||||||
@ -866,6 +945,23 @@ TEST(format_test, precision) {
|
|||||||
"117102665855668676818703956031062493194527159149245532930545654440112748"
|
"117102665855668676818703956031062493194527159149245532930545654440112748"
|
||||||
"012970999954193198940908041656332452475714786901472678015935523861155013"
|
"012970999954193198940908041656332452475714786901472678015935523861155013"
|
||||||
"480352649347201937902681071074917033322268447533357208324319361e-324");
|
"480352649347201937902681071074917033322268447533357208324319361e-324");
|
||||||
|
EXPECT_EQ(
|
||||||
|
fmt::format("{:.1074f}", 1.1125369292536e-308),
|
||||||
|
"0.0000000000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
"000000000000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
"000000000000000000000111253692925360019747947051741965785554081512200979"
|
||||||
|
"355021686109411883779182127659725163430929750364498219730822952552570601"
|
||||||
|
"152163505899912777129583674906301179059298598412303893909188340988729019"
|
||||||
|
"014361467448914817838555156840459458527907308695109202499990850735085304"
|
||||||
|
"478476991912072201449236975063640913461919914396877093174125167509869762"
|
||||||
|
"482369631100360266123742648159508919592746619553246586039571522788247697"
|
||||||
|
"156360766271842991667238355464496455107749716934387136380536472531224398"
|
||||||
|
"559833794807213172371254492216255558078524900147957309382830827524104234"
|
||||||
|
"530961756787819847850302379672357738807808384667004752163416921762619527"
|
||||||
|
"462847642037420991432005657440259928195996762610375541867198059294212446"
|
||||||
|
"81962777939941034720757232455434770912461317493580281734466552734375");
|
||||||
|
|
||||||
std::string outputs[] = {
|
std::string outputs[] = {
|
||||||
"-0X1.41FE3FFE71C9E000000000000000000000000000000000000000000000000000000"
|
"-0X1.41FE3FFE71C9E000000000000000000000000000000000000000000000000000000"
|
||||||
@ -895,6 +991,11 @@ TEST(format_test, precision) {
|
|||||||
EXPECT_THAT(outputs,
|
EXPECT_THAT(outputs,
|
||||||
testing::Contains(fmt::format("{:.838A}", -2.14001164E+38)));
|
testing::Contains(fmt::format("{:.838A}", -2.14001164E+38)));
|
||||||
|
|
||||||
|
if (std::numeric_limits<long double>::digits == 64) {
|
||||||
|
auto ld = (std::numeric_limits<long double>::min)();
|
||||||
|
EXPECT_EQ(fmt::format("{:.0}", ld), "3e-4932");
|
||||||
|
}
|
||||||
|
|
||||||
EXPECT_EQ("123.", fmt::format("{:#.0f}", 123.0));
|
EXPECT_EQ("123.", fmt::format("{:#.0f}", 123.0));
|
||||||
EXPECT_EQ("1.23", fmt::format("{:.02f}", 1.234));
|
EXPECT_EQ("1.23", fmt::format("{:.02f}", 1.234));
|
||||||
EXPECT_EQ("0.001", fmt::format("{:.1g}", 0.001));
|
EXPECT_EQ("0.001", fmt::format("{:.1g}", 0.001));
|
||||||
@ -903,13 +1004,16 @@ TEST(format_test, precision) {
|
|||||||
EXPECT_EQ("1.0e-34", fmt::format("{:.1e}", 1e-34));
|
EXPECT_EQ("1.0e-34", fmt::format("{:.1e}", 1e-34));
|
||||||
|
|
||||||
EXPECT_THROW_MSG(
|
EXPECT_THROW_MSG(
|
||||||
fmt::format(runtime("{0:.2}"), reinterpret_cast<void*>(0xcafe)),
|
(void)fmt::format(runtime("{0:.2}"), reinterpret_cast<void*>(0xcafe)),
|
||||||
format_error, "precision not allowed for this argument type");
|
format_error, "precision not allowed for this argument type");
|
||||||
EXPECT_THROW_MSG(
|
EXPECT_THROW_MSG(
|
||||||
fmt::format(runtime("{0:.2f}"), reinterpret_cast<void*>(0xcafe)),
|
(void)fmt::format(runtime("{0:.2f}"), reinterpret_cast<void*>(0xcafe)),
|
||||||
format_error, "precision not allowed for this argument type");
|
format_error, "precision not allowed for this argument type");
|
||||||
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{:.{}e}"), 42.0,
|
||||||
|
fmt::detail::max_value<int>()),
|
||||||
|
format_error, "number is too big");
|
||||||
EXPECT_THROW_MSG(
|
EXPECT_THROW_MSG(
|
||||||
fmt::format(runtime("{:.{}e}"), 42.0, fmt::detail::max_value<int>()),
|
(void)fmt::format("{:.2147483646f}", -2.2121295195081227E+304),
|
||||||
format_error, "number is too big");
|
format_error, "number is too big");
|
||||||
|
|
||||||
EXPECT_EQ("st", fmt::format("{0:.2}", "str"));
|
EXPECT_EQ("st", fmt::format("{0:.2}", "str"));
|
||||||
@ -919,86 +1023,97 @@ TEST(format_test, runtime_precision) {
|
|||||||
char format_str[buffer_size];
|
char format_str[buffer_size];
|
||||||
safe_sprintf(format_str, "{0:.{%u", UINT_MAX);
|
safe_sprintf(format_str, "{0:.{%u", UINT_MAX);
|
||||||
increment(format_str + 5);
|
increment(format_str + 5);
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime(format_str), 0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime(format_str), 0), format_error,
|
||||||
"invalid format string");
|
"invalid format string");
|
||||||
size_t size = std::strlen(format_str);
|
size_t size = std::strlen(format_str);
|
||||||
format_str[size] = '}';
|
format_str[size] = '}';
|
||||||
format_str[size + 1] = 0;
|
format_str[size + 1] = 0;
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime(format_str), 0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime(format_str), 0), format_error,
|
||||||
"argument not found");
|
"argument not found");
|
||||||
format_str[size + 1] = '}';
|
format_str[size + 1] = '}';
|
||||||
format_str[size + 2] = 0;
|
format_str[size + 2] = 0;
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime(format_str), 0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime(format_str), 0), format_error,
|
||||||
"argument not found");
|
"argument not found");
|
||||||
|
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.{"), 0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{"), 0), format_error,
|
||||||
"invalid format string");
|
"invalid format string");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.{}"), 0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{}"), 0), format_error,
|
||||||
"cannot switch from manual to automatic argument indexing");
|
"cannot switch from manual to automatic argument indexing");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.{?}}"), 0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{?}}"), 0), format_error,
|
||||||
"invalid format string");
|
"invalid format string");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.{1}"), 0, 0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}"), 0, 0), format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.{1}}"), 0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0), format_error,
|
||||||
"argument not found");
|
"argument not found");
|
||||||
|
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.{0:}}"), 0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{0:}}"), 0), format_error,
|
||||||
"invalid format string");
|
"invalid format string");
|
||||||
|
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.{1}}"), 0, -1), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0, -1), format_error,
|
||||||
"negative precision");
|
"negative precision");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.{1}}"), 0, (INT_MAX + 1u)),
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0, (INT_MAX + 1u)),
|
||||||
format_error, "number is too big");
|
format_error, "number is too big");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.{1}}"), 0, -1l), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0, -1l), format_error,
|
||||||
"negative precision");
|
"negative precision");
|
||||||
if (fmt::detail::const_check(sizeof(long) > sizeof(int))) {
|
if (fmt::detail::const_check(sizeof(long) > sizeof(int))) {
|
||||||
long value = INT_MAX;
|
long value = INT_MAX;
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.{1}}"), 0, (value + 1)),
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0, (value + 1)),
|
||||||
format_error, "number is too big");
|
format_error, "number is too big");
|
||||||
}
|
}
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.{1}}"), 0, (INT_MAX + 1ul)),
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0, (INT_MAX + 1ul)),
|
||||||
format_error, "number is too big");
|
format_error, "number is too big");
|
||||||
|
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.{1}}"), 0, '0'), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0, '0'), format_error,
|
||||||
"precision is not integer");
|
"precision is not integer");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.{1}}"), 0, 0.0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 0, 0.0), format_error,
|
||||||
"precision is not integer");
|
"precision is not integer");
|
||||||
|
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.{1}}"), 42, 2), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 42, 2), format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.{1}f}"), 42, 2), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}f}"), 42, 2), format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.{1}}"), 42u, 2), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 42u, 2), format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.{1}f}"), 42u, 2), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}f}"), 42u, 2),
|
||||||
|
format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.{1}}"), 42l, 2), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 42l, 2), format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.{1}f}"), 42l, 2), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}f}"), 42l, 2),
|
||||||
|
format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.{1}}"), 42ul, 2), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 42ul, 2),
|
||||||
|
format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.{1}f}"), 42ul, 2), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}f}"), 42ul, 2),
|
||||||
|
format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.{1}}"), 42ll, 2), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 42ll, 2),
|
||||||
|
format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.{1}f}"), 42ll, 2), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}f}"), 42ll, 2),
|
||||||
|
format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.{1}}"), 42ull, 2), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"), 42ull, 2),
|
||||||
|
format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:.{1}f}"), 42ull, 2), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}f}"), 42ull, 2),
|
||||||
|
format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:3.{1}}"), 'x', 0), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:3.{1}}"), 'x', 0),
|
||||||
|
format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
EXPECT_EQ("1.2", fmt::format("{0:.{1}}", 1.2345, 2));
|
EXPECT_EQ("1.2", fmt::format("{0:.{1}}", 1.2345, 2));
|
||||||
EXPECT_EQ("1.2", fmt::format("{1:.{0}}", 2, 1.2345l));
|
EXPECT_EQ("1.2", fmt::format("{1:.{0}}", 2, 1.2345l));
|
||||||
|
|
||||||
EXPECT_THROW_MSG(
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}}"),
|
||||||
fmt::format(runtime("{0:.{1}}"), reinterpret_cast<void*>(0xcafe), 2),
|
reinterpret_cast<void*>(0xcafe), 2),
|
||||||
format_error, "precision not allowed for this argument type");
|
format_error,
|
||||||
EXPECT_THROW_MSG(
|
"precision not allowed for this argument type");
|
||||||
fmt::format(runtime("{0:.{1}f}"), reinterpret_cast<void*>(0xcafe), 2),
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:.{1}f}"),
|
||||||
format_error, "precision not allowed for this argument type");
|
reinterpret_cast<void*>(0xcafe), 2),
|
||||||
|
format_error,
|
||||||
|
"precision not allowed for this argument type");
|
||||||
|
|
||||||
EXPECT_EQ("st", fmt::format("{0:.{1}}", "str", 2));
|
EXPECT_EQ("st", fmt::format("{0:.{1}}", "str", 2));
|
||||||
}
|
}
|
||||||
@ -1023,21 +1138,21 @@ TEST(format_test, format_short) {
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
void check_unknown_types(const T& value, const char* types, const char*) {
|
void check_unknown_types(const T& value, const char* types, const char*) {
|
||||||
char format_str[buffer_size];
|
char format_str[buffer_size];
|
||||||
const char* special = ".0123456789L}";
|
const char* special = ".0123456789L?}";
|
||||||
for (int i = CHAR_MIN; i <= CHAR_MAX; ++i) {
|
for (int i = CHAR_MIN; i <= CHAR_MAX; ++i) {
|
||||||
char c = static_cast<char>(i);
|
char c = static_cast<char>(i);
|
||||||
if (std::strchr(types, c) || std::strchr(special, c) || !c) continue;
|
if (std::strchr(types, c) || std::strchr(special, c) || !c) continue;
|
||||||
safe_sprintf(format_str, "{0:10%c}", c);
|
safe_sprintf(format_str, "{0:10%c}", c);
|
||||||
const char* message = "invalid type specifier";
|
const char* message = "invalid type specifier";
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime(format_str), value), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime(format_str), value),
|
||||||
message)
|
format_error, message)
|
||||||
<< format_str << " " << message;
|
<< format_str << " " << message;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(format_test, format_int) {
|
TEST(format_test, format_int) {
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:v"), 42), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:v"), 42), format_error,
|
||||||
"missing '}' in format string");
|
"invalid type specifier");
|
||||||
check_unknown_types(42, "bBdoxXnLc", "integer");
|
check_unknown_types(42, "bBdoxXnLc", "integer");
|
||||||
EXPECT_EQ("x", fmt::format("{:c}", static_cast<int>('x')));
|
EXPECT_EQ("x", fmt::format("{:c}", static_cast<int>('x')));
|
||||||
}
|
}
|
||||||
@ -1192,32 +1307,30 @@ TEST(format_test, format_float) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(format_test, format_double) {
|
TEST(format_test, format_double) {
|
||||||
EXPECT_EQ("0", fmt::format("{}", 0.0));
|
EXPECT_EQ(fmt::format("{}", 0.0), "0");
|
||||||
check_unknown_types(1.2, "eEfFgGaAnL%", "double");
|
check_unknown_types(1.2, "eEfFgGaAnL%", "double");
|
||||||
EXPECT_EQ("0", fmt::format("{:}", 0.0));
|
EXPECT_EQ(fmt::format("{:}", 0.0), "0");
|
||||||
EXPECT_EQ("0.000000", fmt::format("{:f}", 0.0));
|
EXPECT_EQ(fmt::format("{:f}", 0.0), "0.000000");
|
||||||
EXPECT_EQ("0", fmt::format("{:g}", 0.0));
|
EXPECT_EQ(fmt::format("{:g}", 0.0), "0");
|
||||||
EXPECT_EQ("392.65", fmt::format("{:}", 392.65));
|
EXPECT_EQ(fmt::format("{:}", 392.65), "392.65");
|
||||||
EXPECT_EQ("392.65", fmt::format("{:g}", 392.65));
|
EXPECT_EQ(fmt::format("{:g}", 392.65), "392.65");
|
||||||
EXPECT_EQ("392.65", fmt::format("{:G}", 392.65));
|
EXPECT_EQ(fmt::format("{:G}", 392.65), "392.65");
|
||||||
EXPECT_EQ("4.9014e+06", fmt::format("{:g}", 4.9014e6));
|
EXPECT_EQ(fmt::format("{:g}", 4.9014e6), "4.9014e+06");
|
||||||
EXPECT_EQ("392.650000", fmt::format("{:f}", 392.65));
|
EXPECT_EQ(fmt::format("{:f}", 392.65), "392.650000");
|
||||||
EXPECT_EQ("392.650000", fmt::format("{:F}", 392.65));
|
EXPECT_EQ(fmt::format("{:F}", 392.65), "392.650000");
|
||||||
EXPECT_EQ("42", fmt::format("{:L}", 42.0));
|
EXPECT_EQ(fmt::format("{:L}", 42.0), "42");
|
||||||
EXPECT_EQ(" 0x1.0cccccccccccdp+2", fmt::format("{:24a}", 4.2));
|
EXPECT_EQ(fmt::format("{:24a}", 4.2), " 0x1.0cccccccccccdp+2");
|
||||||
EXPECT_EQ("0x1.0cccccccccccdp+2 ", fmt::format("{:<24a}", 4.2));
|
EXPECT_EQ(fmt::format("{:<24a}", 4.2), "0x1.0cccccccccccdp+2 ");
|
||||||
|
EXPECT_EQ(fmt::format("{0:e}", 392.65), "3.926500e+02");
|
||||||
|
EXPECT_EQ(fmt::format("{0:E}", 392.65), "3.926500E+02");
|
||||||
|
EXPECT_EQ(fmt::format("{0:+010.4g}", 392.65), "+0000392.6");
|
||||||
char buffer[buffer_size];
|
char buffer[buffer_size];
|
||||||
safe_sprintf(buffer, "%e", 392.65);
|
|
||||||
EXPECT_EQ(buffer, fmt::format("{0:e}", 392.65));
|
|
||||||
safe_sprintf(buffer, "%E", 392.65);
|
|
||||||
EXPECT_EQ(buffer, fmt::format("{0:E}", 392.65));
|
|
||||||
EXPECT_EQ("+0000392.6", fmt::format("{0:+010.4g}", 392.65));
|
|
||||||
safe_sprintf(buffer, "%a", -42.0);
|
safe_sprintf(buffer, "%a", -42.0);
|
||||||
EXPECT_EQ(buffer, fmt::format("{:a}", -42.0));
|
EXPECT_EQ(fmt::format("{:a}", -42.0), buffer);
|
||||||
safe_sprintf(buffer, "%A", -42.0);
|
safe_sprintf(buffer, "%A", -42.0);
|
||||||
EXPECT_EQ(buffer, fmt::format("{:A}", -42.0));
|
EXPECT_EQ(fmt::format("{:A}", -42.0), buffer);
|
||||||
EXPECT_EQ("9223372036854775808.000000",
|
EXPECT_EQ(fmt::format("{:f}", 9223372036854775807.0),
|
||||||
fmt::format("{:f}", 9223372036854775807.0));
|
"9223372036854775808.000000");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(format_test, precision_rounding) {
|
TEST(format_test, precision_rounding) {
|
||||||
@ -1326,6 +1439,9 @@ TEST(format_test, format_char) {
|
|||||||
<< format_str;
|
<< format_str;
|
||||||
}
|
}
|
||||||
EXPECT_EQ(fmt::format("{:02X}", n), fmt::format("{:02X}", 'x'));
|
EXPECT_EQ(fmt::format("{:02X}", n), fmt::format("{:02X}", 'x'));
|
||||||
|
|
||||||
|
EXPECT_EQ("\n", fmt::format("{}", '\n'));
|
||||||
|
EXPECT_EQ("'\\n'", fmt::format("{:?}", '\n'));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(format_test, format_volatile_char) {
|
TEST(format_test, format_volatile_char) {
|
||||||
@ -1345,26 +1461,10 @@ TEST(format_test, format_cstring) {
|
|||||||
char nonconst[] = "nonconst";
|
char nonconst[] = "nonconst";
|
||||||
EXPECT_EQ("nonconst", fmt::format("{0}", nonconst));
|
EXPECT_EQ("nonconst", fmt::format("{0}", nonconst));
|
||||||
EXPECT_THROW_MSG(
|
EXPECT_THROW_MSG(
|
||||||
fmt::format(runtime("{0}"), static_cast<const char*>(nullptr)),
|
(void)fmt::format(runtime("{0}"), static_cast<const char*>(nullptr)),
|
||||||
format_error, "string pointer is null");
|
format_error, "string pointer is null");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(format_test, format_schar_string) {
|
|
||||||
signed char str[] = "test";
|
|
||||||
EXPECT_EQ("test", fmt::format("{0:s}", str));
|
|
||||||
const signed char* const_str = str;
|
|
||||||
EXPECT_EQ("test", fmt::format("{0:s}", const_str));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(format_test, format_uchar_string) {
|
|
||||||
unsigned char str[] = "test";
|
|
||||||
EXPECT_EQ("test", fmt::format("{0:s}", str));
|
|
||||||
const unsigned char* const_str = str;
|
|
||||||
EXPECT_EQ("test", fmt::format("{0:s}", const_str));
|
|
||||||
unsigned char* ptr = str;
|
|
||||||
EXPECT_EQ("test", fmt::format("{0:s}", ptr));
|
|
||||||
}
|
|
||||||
|
|
||||||
void function_pointer_test(int, double, std::string) {}
|
void function_pointer_test(int, double, std::string) {}
|
||||||
|
|
||||||
TEST(format_test, format_pointer) {
|
TEST(format_test, format_pointer) {
|
||||||
@ -1388,14 +1488,43 @@ TEST(format_test, format_pointer) {
|
|||||||
EXPECT_EQ("0x0", fmt::format("{}", nullptr));
|
EXPECT_EQ("0x0", fmt::format("{}", nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(format_test, write_uintptr_fallback) {
|
||||||
|
// Test that formatting a pointer by converting it to uint128_fallback works.
|
||||||
|
// This is needed to support systems without uintptr_t.
|
||||||
|
auto s = std::string();
|
||||||
|
fmt::detail::write_ptr<char>(
|
||||||
|
std::back_inserter(s),
|
||||||
|
fmt::detail::bit_cast<fmt::detail::uint128_fallback>(
|
||||||
|
reinterpret_cast<void*>(0xface)),
|
||||||
|
nullptr);
|
||||||
|
EXPECT_EQ(s, "0xface");
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class color { red, green, blue };
|
||||||
|
|
||||||
|
namespace test_ns {
|
||||||
|
enum class color { red, green, blue };
|
||||||
|
using fmt::enums::format_as;
|
||||||
|
} // namespace test_ns
|
||||||
|
|
||||||
|
TEST(format_test, format_enum_class) {
|
||||||
|
EXPECT_EQ(fmt::format("{}", fmt::underlying(color::red)), "0");
|
||||||
|
EXPECT_EQ(fmt::format("{}", test_ns::color::red), "0");
|
||||||
|
}
|
||||||
|
|
||||||
TEST(format_test, format_string) {
|
TEST(format_test, format_string) {
|
||||||
EXPECT_EQ("test", fmt::format("{0}", std::string("test")));
|
EXPECT_EQ(fmt::format("{0}", std::string("test")), "test");
|
||||||
EXPECT_THROW(fmt::format(fmt::runtime("{:x}"), std::string("test")),
|
EXPECT_EQ(fmt::format("{0}", std::string("test")), "test");
|
||||||
|
EXPECT_EQ(fmt::format("{:?}", std::string("test")), "\"test\"");
|
||||||
|
EXPECT_EQ(fmt::format("{:*^10?}", std::string("test")), "**\"test\"**");
|
||||||
|
EXPECT_EQ(fmt::format("{:?}", std::string("\test")), "\"\\test\"");
|
||||||
|
EXPECT_THROW((void)fmt::format(fmt::runtime("{:x}"), std::string("test")),
|
||||||
fmt::format_error);
|
fmt::format_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(format_test, format_string_view) {
|
TEST(format_test, format_string_view) {
|
||||||
EXPECT_EQ("test", fmt::format("{}", string_view("test")));
|
EXPECT_EQ("test", fmt::format("{}", string_view("test")));
|
||||||
|
EXPECT_EQ("\"t\\nst\"", fmt::format("{:?}", string_view("t\nst")));
|
||||||
EXPECT_EQ("", fmt::format("{}", string_view()));
|
EXPECT_EQ("", fmt::format("{}", string_view()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1481,7 +1610,7 @@ template <> struct formatter<Answer> : formatter<int> {
|
|||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
TEST(format_test, format_custom) {
|
TEST(format_test, format_custom) {
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{:s}"), date(2012, 12, 9)),
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{:s}"), date(2012, 12, 9)),
|
||||||
format_error, "unknown format specifier");
|
format_error, "unknown format specifier");
|
||||||
EXPECT_EQ("42", fmt::format("{0}", Answer()));
|
EXPECT_EQ("42", fmt::format("{0}", Answer()));
|
||||||
EXPECT_EQ("0042", fmt::format("{:04}", Answer()));
|
EXPECT_EQ("0042", fmt::format("{:04}", Answer()));
|
||||||
@ -1558,7 +1687,8 @@ TEST(format_test, format_examples) {
|
|||||||
fmt::format("int: {0:d}; hex: {0:#x}; oct: {0:#o}", 42));
|
fmt::format("int: {0:d}; hex: {0:#x}; oct: {0:#o}", 42));
|
||||||
|
|
||||||
EXPECT_EQ("The answer is 42", fmt::format("The answer is {}", 42));
|
EXPECT_EQ("The answer is 42", fmt::format("The answer is {}", 42));
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("The answer is {:d}"), "forty-two"),
|
EXPECT_THROW_MSG(
|
||||||
|
(void)fmt::format(runtime("The answer is {:d}"), "forty-two"),
|
||||||
format_error, "invalid type specifier");
|
format_error, "invalid type specifier");
|
||||||
|
|
||||||
EXPECT_WRITE(
|
EXPECT_WRITE(
|
||||||
@ -1595,6 +1725,11 @@ TEST(format_test, bytes) {
|
|||||||
EXPECT_EQ(10, s.size());
|
EXPECT_EQ(10, s.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(format_test, group_digits_view) {
|
||||||
|
EXPECT_EQ(fmt::format("{}", fmt::group_digits(10000000)), "10,000,000");
|
||||||
|
EXPECT_EQ(fmt::format("{:8}", fmt::group_digits(1000)), " 1,000");
|
||||||
|
}
|
||||||
|
|
||||||
enum test_enum { foo, bar };
|
enum test_enum { foo, bar };
|
||||||
|
|
||||||
TEST(format_test, join) {
|
TEST(format_test, join) {
|
||||||
@ -1718,6 +1853,21 @@ TEST(format_test, custom_format_compile_time_string) {
|
|||||||
|
|
||||||
using namespace fmt::literals;
|
using namespace fmt::literals;
|
||||||
|
|
||||||
|
# if FMT_GCC_VERSION
|
||||||
|
# define FMT_CHECK_DEPRECATED_UDL_FORMAT 1
|
||||||
|
# elif FMT_CLANG_VERSION && defined(__has_warning)
|
||||||
|
# if __has_warning("-Wdeprecated-declarations")
|
||||||
|
# define FMT_CHECK_DEPRECATED_UDL_FORMAT 1
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
# ifndef FMT_CHECK_DEPRECATED_UDL_FORMAT
|
||||||
|
# define FMT_CHECK_DEPRECATED_UDL_FORMAT 0
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if FMT_CHECK_DEPRECATED_UDL_FORMAT
|
||||||
|
# pragma GCC diagnostic push
|
||||||
|
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||||
|
|
||||||
TEST(format_test, format_udl) {
|
TEST(format_test, format_udl) {
|
||||||
EXPECT_EQ("{}c{}"_format("ab", 1), fmt::format("{}c{}", "ab", 1));
|
EXPECT_EQ("{}c{}"_format("ab", 1), fmt::format("{}c{}", "ab", 1));
|
||||||
EXPECT_EQ("foo"_format(), "foo");
|
EXPECT_EQ("foo"_format(), "foo");
|
||||||
@ -1725,6 +1875,9 @@ TEST(format_test, format_udl) {
|
|||||||
EXPECT_EQ("{}"_format(date(2015, 10, 21)), "2015-10-21");
|
EXPECT_EQ("{}"_format(date(2015, 10, 21)), "2015-10-21");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# pragma GCC diagnostic pop
|
||||||
|
# endif
|
||||||
|
|
||||||
TEST(format_test, named_arg_udl) {
|
TEST(format_test, named_arg_udl) {
|
||||||
auto udl_a = fmt::format("{first}{second}{first}{third}", "first"_a = "abra",
|
auto udl_a = fmt::format("{first}{second}{first}{third}", "first"_a = "abra",
|
||||||
"second"_a = "cad", "third"_a = 99);
|
"second"_a = "cad", "third"_a = 99);
|
||||||
@ -1777,21 +1930,21 @@ TEST(format_test, dynamic_formatter) {
|
|||||||
EXPECT_EQ("42", fmt::format("{:d}", num));
|
EXPECT_EQ("42", fmt::format("{:d}", num));
|
||||||
EXPECT_EQ("foo", fmt::format("{:s}", str));
|
EXPECT_EQ("foo", fmt::format("{:s}", str));
|
||||||
EXPECT_EQ(" 42 foo ", fmt::format("{:{}} {:{}}", num, 3, str, 4));
|
EXPECT_EQ(" 42 foo ", fmt::format("{:{}} {:{}}", num, 3, str, 4));
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:{}}"), num), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:{}}"), num), format_error,
|
||||||
"cannot switch from manual to automatic argument indexing");
|
"cannot switch from manual to automatic argument indexing");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{:{0}}"), num), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{:{0}}"), num), format_error,
|
||||||
"cannot switch from automatic to manual argument indexing");
|
"cannot switch from automatic to manual argument indexing");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{:+}"), str), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{:+}"), str), format_error,
|
||||||
"format specifier requires numeric argument");
|
"format specifier requires numeric argument");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{:-}"), str), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{:-}"), str), format_error,
|
||||||
"format specifier requires numeric argument");
|
"format specifier requires numeric argument");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{: }"), str), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{: }"), str), format_error,
|
||||||
"format specifier requires numeric argument");
|
"format specifier requires numeric argument");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{:#}"), str), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{:#}"), str), format_error,
|
||||||
"format specifier requires numeric argument");
|
"format specifier requires numeric argument");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{:0}"), str), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{:0}"), str), format_error,
|
||||||
"format specifier requires numeric argument");
|
"format specifier requires numeric argument");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{:.2}"), num), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{:.2}"), num), format_error,
|
||||||
"precision not allowed for this argument type");
|
"precision not allowed for this argument type");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1815,13 +1968,20 @@ struct formatter<adl_test::fmt::detail::foo> : formatter<std::string> {
|
|||||||
};
|
};
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
TEST(format_test, to_string) {
|
struct convertible_to_int {
|
||||||
EXPECT_EQ("42", fmt::to_string(42));
|
operator int() const { return value; }
|
||||||
EXPECT_EQ("0x1234", fmt::to_string(reinterpret_cast<void*>(0x1234)));
|
|
||||||
EXPECT_EQ("foo", fmt::to_string(adl_test::fmt::detail::foo()));
|
|
||||||
|
|
||||||
enum test_enum2 : unsigned char { test_value };
|
int value = 42;
|
||||||
EXPECT_EQ("0", fmt::to_string(test_value));
|
};
|
||||||
|
|
||||||
|
TEST(format_test, to_string) {
|
||||||
|
EXPECT_EQ(fmt::to_string(42), "42");
|
||||||
|
EXPECT_EQ(fmt::to_string(reinterpret_cast<void*>(0x1234)), "0x1234");
|
||||||
|
EXPECT_EQ(fmt::to_string(adl_test::fmt::detail::foo()), "foo");
|
||||||
|
EXPECT_EQ(fmt::to_string(convertible_to_int()), "42");
|
||||||
|
|
||||||
|
enum foo : unsigned char { zero };
|
||||||
|
EXPECT_EQ(fmt::to_string(zero), "0");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(format_test, output_iterators) {
|
TEST(format_test, output_iterators) {
|
||||||
|
2
vendor/Fmt/test/fuzzing/CMakeLists.txt
vendored
2
vendor/Fmt/test/fuzzing/CMakeLists.txt
vendored
@ -25,6 +25,6 @@ function(add_fuzzer source)
|
|||||||
target_compile_features(${name} PRIVATE cxx_generic_lambdas)
|
target_compile_features(${name} PRIVATE cxx_generic_lambdas)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
foreach (source chrono-duration.cc float.cc named-arg.cc one-arg.cc two-args.cc)
|
foreach (source chrono-duration.cc chrono-timepoint.cc float.cc named-arg.cc one-arg.cc two-args.cc)
|
||||||
add_fuzzer(${source})
|
add_fuzzer(${source})
|
||||||
endforeach ()
|
endforeach ()
|
||||||
|
8
vendor/Fmt/test/fuzzing/build.sh
vendored
8
vendor/Fmt/test/fuzzing/build.sh
vendored
@ -22,6 +22,8 @@ here=$(pwd)
|
|||||||
CXXFLAGSALL="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION= -g"
|
CXXFLAGSALL="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION= -g"
|
||||||
CMAKEFLAGSALL="$root -GNinja -DCMAKE_BUILD_TYPE=Debug -DFMT_DOC=Off -DFMT_TEST=Off -DFMT_FUZZ=On -DCMAKE_CXX_STANDARD=17"
|
CMAKEFLAGSALL="$root -GNinja -DCMAKE_BUILD_TYPE=Debug -DFMT_DOC=Off -DFMT_TEST=Off -DFMT_FUZZ=On -DCMAKE_CXX_STANDARD=17"
|
||||||
|
|
||||||
|
CLANG=clang++-11
|
||||||
|
|
||||||
# For performance analysis of the fuzzers.
|
# For performance analysis of the fuzzers.
|
||||||
builddir=$here/build-fuzzers-perfanalysis
|
builddir=$here/build-fuzzers-perfanalysis
|
||||||
mkdir -p $builddir
|
mkdir -p $builddir
|
||||||
@ -37,7 +39,7 @@ cmake --build $builddir
|
|||||||
builddir=$here/build-fuzzers-ossfuzz
|
builddir=$here/build-fuzzers-ossfuzz
|
||||||
mkdir -p $builddir
|
mkdir -p $builddir
|
||||||
cd $builddir
|
cd $builddir
|
||||||
CXX="clang++" \
|
CXX=$CLANG \
|
||||||
CXXFLAGS="$CXXFLAGSALL -fsanitize=fuzzer-no-link" cmake \
|
CXXFLAGS="$CXXFLAGSALL -fsanitize=fuzzer-no-link" cmake \
|
||||||
cmake $CMAKEFLAGSALL \
|
cmake $CMAKEFLAGSALL \
|
||||||
-DFMT_FUZZ_LINKMAIN=Off \
|
-DFMT_FUZZ_LINKMAIN=Off \
|
||||||
@ -50,7 +52,7 @@ cmake --build $builddir
|
|||||||
builddir=$here/build-fuzzers-libfuzzer
|
builddir=$here/build-fuzzers-libfuzzer
|
||||||
mkdir -p $builddir
|
mkdir -p $builddir
|
||||||
cd $builddir
|
cd $builddir
|
||||||
CXX="clang++" \
|
CXX=$CLANG \
|
||||||
CXXFLAGS="$CXXFLAGSALL -fsanitize=fuzzer-no-link,address,undefined" cmake \
|
CXXFLAGS="$CXXFLAGSALL -fsanitize=fuzzer-no-link,address,undefined" cmake \
|
||||||
cmake $CMAKEFLAGSALL \
|
cmake $CMAKEFLAGSALL \
|
||||||
-DFMT_FUZZ_LINKMAIN=Off \
|
-DFMT_FUZZ_LINKMAIN=Off \
|
||||||
@ -62,7 +64,7 @@ cmake --build $builddir
|
|||||||
builddir=$here/build-fuzzers-fast
|
builddir=$here/build-fuzzers-fast
|
||||||
mkdir -p $builddir
|
mkdir -p $builddir
|
||||||
cd $builddir
|
cd $builddir
|
||||||
CXX="clang++" \
|
CXX=$CLANG \
|
||||||
CXXFLAGS="$CXXFLAGSALL -fsanitize=fuzzer-no-link -O3" cmake \
|
CXXFLAGS="$CXXFLAGSALL -fsanitize=fuzzer-no-link -O3" cmake \
|
||||||
cmake $CMAKEFLAGSALL \
|
cmake $CMAKEFLAGSALL \
|
||||||
-DFMT_FUZZ_LINKMAIN=Off \
|
-DFMT_FUZZ_LINKMAIN=Off \
|
||||||
|
3
vendor/Fmt/test/fuzzing/chrono-duration.cc
vendored
3
vendor/Fmt/test/fuzzing/chrono-duration.cc
vendored
@ -1,9 +1,10 @@
|
|||||||
// Copyright (c) 2019, Paul Dreik
|
// Copyright (c) 2019, Paul Dreik
|
||||||
// For the license information refer to format.h.
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <fmt/chrono.h>
|
#include <fmt/chrono.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
#include "fuzzer-common.h"
|
#include "fuzzer-common.h"
|
||||||
|
|
||||||
template <typename Period, typename Rep>
|
template <typename Period, typename Rep>
|
||||||
|
32
vendor/Fmt/test/fuzzing/chrono-timepoint.cc
vendored
Normal file
32
vendor/Fmt/test/fuzzing/chrono-timepoint.cc
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// Copyright (c) 2021, Paul Dreik
|
||||||
|
// For license information refer to format.h.
|
||||||
|
#include <fmt/chrono.h>
|
||||||
|
|
||||||
|
#include "fuzzer-common.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* a fuzzer for the chrono timepoints formatters
|
||||||
|
* C is a clock (std::chrono::system_clock etc)
|
||||||
|
*/
|
||||||
|
template <typename C> void doit(const uint8_t* data, size_t size) {
|
||||||
|
using Rep = typename C::time_point::rep;
|
||||||
|
constexpr auto N = sizeof(Rep);
|
||||||
|
if (size < N) return;
|
||||||
|
|
||||||
|
const auto x = assign_from_buf<Rep>(data);
|
||||||
|
typename C::duration dur{x};
|
||||||
|
typename C::time_point timepoint{dur};
|
||||||
|
data += N;
|
||||||
|
size -= N;
|
||||||
|
data_to_string format_str(data, size);
|
||||||
|
|
||||||
|
std::string message = fmt::format(format_str.get(), timepoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||||
|
try {
|
||||||
|
doit<std::chrono::system_clock>(data, size);
|
||||||
|
} catch (...) {
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
10
vendor/Fmt/test/fuzzing/float.cc
vendored
10
vendor/Fmt/test/fuzzing/float.cc
vendored
@ -1,17 +1,18 @@
|
|||||||
// A fuzzer for floating-point formatter.
|
// A fuzzer for floating-point formatter.
|
||||||
// For the license information refer to format.h.
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <stdexcept>
|
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <fmt/format.h>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include "fuzzer-common.h"
|
#include "fuzzer-common.h"
|
||||||
|
|
||||||
void check_round_trip(fmt::string_view format_str, double value) {
|
void check_round_trip(fmt::string_view format_str, double value) {
|
||||||
auto buffer = fmt::memory_buffer();
|
auto buffer = fmt::memory_buffer();
|
||||||
fmt::format_to(buffer, format_str, value);
|
fmt::format_to(std::back_inserter(buffer), format_str, value);
|
||||||
|
|
||||||
if (std::isnan(value)) {
|
if (std::isnan(value)) {
|
||||||
auto nan = std::signbit(value) ? "-nan" : "nan";
|
auto nan = std::signbit(value) ? "-nan" : "nan";
|
||||||
@ -24,8 +25,7 @@ void check_round_trip(fmt::string_view format_str, double value) {
|
|||||||
char* ptr = nullptr;
|
char* ptr = nullptr;
|
||||||
if (std::strtod(buffer.data(), &ptr) != value)
|
if (std::strtod(buffer.data(), &ptr) != value)
|
||||||
throw std::runtime_error("round trip failure");
|
throw std::runtime_error("round trip failure");
|
||||||
if (ptr + 1 != buffer.end())
|
if (ptr + 1 != buffer.end()) throw std::runtime_error("unparsed output");
|
||||||
throw std::runtime_error("unparsed output");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||||||
|
6
vendor/Fmt/test/fuzzing/fuzzer-common.h
vendored
6
vendor/Fmt/test/fuzzing/fuzzer-common.h
vendored
@ -4,12 +4,12 @@
|
|||||||
#ifndef FUZZER_COMMON_H
|
#ifndef FUZZER_COMMON_H
|
||||||
#define FUZZER_COMMON_H
|
#define FUZZER_COMMON_H
|
||||||
|
|
||||||
|
#include <fmt/core.h>
|
||||||
|
|
||||||
#include <cstdint> // std::uint8_t
|
#include <cstdint> // std::uint8_t
|
||||||
#include <cstring> // memcpy
|
#include <cstring> // memcpy
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <fmt/core.h>
|
|
||||||
|
|
||||||
// One can format to either a string, or a buffer. The latter is faster, but
|
// One can format to either a string, or a buffer. The latter is faster, but
|
||||||
// one may be interested in formatting to a string instead to verify it works
|
// one may be interested in formatting to a string instead to verify it works
|
||||||
// as intended. To avoid a combinatoric explosion, select this at compile time
|
// as intended. To avoid a combinatoric explosion, select this at compile time
|
||||||
@ -56,8 +56,10 @@ struct data_to_string {
|
|||||||
|
|
||||||
data_to_string(const uint8_t* data, size_t size, bool add_terminator = false)
|
data_to_string(const uint8_t* data, size_t size, bool add_terminator = false)
|
||||||
: buffer(size + (add_terminator ? 1 : 0)) {
|
: buffer(size + (add_terminator ? 1 : 0)) {
|
||||||
|
if (size) {
|
||||||
std::memcpy(buffer.data(), data, size);
|
std::memcpy(buffer.data(), data, size);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fmt::string_view get() const { return {buffer.data(), buffer.size()}; }
|
fmt::string_view get() const { return {buffer.data(), buffer.size()}; }
|
||||||
#else
|
#else
|
||||||
|
6
vendor/Fmt/test/fuzzing/named-arg.cc
vendored
6
vendor/Fmt/test/fuzzing/named-arg.cc
vendored
@ -1,10 +1,11 @@
|
|||||||
// Copyright (c) 2019, Paul Dreik
|
// Copyright (c) 2019, Paul Dreik
|
||||||
// For the license information refer to format.h.
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
|
#include <fmt/chrono.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <fmt/chrono.h>
|
|
||||||
|
|
||||||
#include "fuzzer-common.h"
|
#include "fuzzer-common.h"
|
||||||
|
|
||||||
@ -28,7 +29,8 @@ void invoke_fmt(const uint8_t* data, size_t size, unsigned arg_name_size) {
|
|||||||
fmt::format(format_str.get(), fmt::arg(arg_name.data(), value));
|
fmt::format(format_str.get(), fmt::arg(arg_name.data(), value));
|
||||||
#else
|
#else
|
||||||
fmt::memory_buffer out;
|
fmt::memory_buffer out;
|
||||||
fmt::format_to(out, format_str.get(), fmt::arg(arg_name.data(), value));
|
fmt::format_to(std::back_inserter(out), format_str.get(),
|
||||||
|
fmt::arg(arg_name.data(), value));
|
||||||
#endif
|
#endif
|
||||||
} catch (std::exception&) {
|
} catch (std::exception&) {
|
||||||
}
|
}
|
||||||
|
11
vendor/Fmt/test/fuzzing/one-arg.cc
vendored
11
vendor/Fmt/test/fuzzing/one-arg.cc
vendored
@ -1,17 +1,18 @@
|
|||||||
// Copyright (c) 2019, Paul Dreik
|
// Copyright (c) 2019, Paul Dreik
|
||||||
// For the license information refer to format.h.
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
|
#include <fmt/chrono.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <fmt/chrono.h>
|
|
||||||
|
|
||||||
#include "fuzzer-common.h"
|
#include "fuzzer-common.h"
|
||||||
|
|
||||||
template <typename T, typename Repr>
|
template <typename T, typename Repr> const T* from_repr(const Repr& r) {
|
||||||
const T* from_repr(const Repr& r) { return &r; }
|
return &r;
|
||||||
|
}
|
||||||
|
|
||||||
template <>
|
template <> const std::tm* from_repr<std::tm>(const std::time_t& t) {
|
||||||
const std::tm* from_repr<std::tm>(const std::time_t& t) {
|
|
||||||
return std::localtime(&t);
|
return std::localtime(&t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
3
vendor/Fmt/test/fuzzing/two-args.cc
vendored
3
vendor/Fmt/test/fuzzing/two-args.cc
vendored
@ -1,10 +1,11 @@
|
|||||||
// Copyright (c) 2019, Paul Dreik
|
// Copyright (c) 2019, Paul Dreik
|
||||||
// For the license information refer to format.h.
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fmt/format.h>
|
|
||||||
|
|
||||||
#include "fuzzer-common.h"
|
#include "fuzzer-common.h"
|
||||||
|
|
||||||
|
2
vendor/Fmt/test/gtest-extra.cc
vendored
2
vendor/Fmt/test/gtest-extra.cc
vendored
@ -23,7 +23,7 @@ output_redirect::output_redirect(FILE* f) : file_(f) {
|
|||||||
write_end.dup2(fd);
|
write_end.dup2(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
output_redirect::~output_redirect() FMT_NOEXCEPT {
|
output_redirect::~output_redirect() noexcept {
|
||||||
try {
|
try {
|
||||||
restore();
|
restore();
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
|
2
vendor/Fmt/test/gtest-extra.h
vendored
2
vendor/Fmt/test/gtest-extra.h
vendored
@ -83,7 +83,7 @@ class output_redirect {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
explicit output_redirect(FILE* file);
|
explicit output_redirect(FILE* file);
|
||||||
~output_redirect() FMT_NOEXCEPT;
|
~output_redirect() noexcept;
|
||||||
|
|
||||||
output_redirect(const output_redirect&) = delete;
|
output_redirect(const output_redirect&) = delete;
|
||||||
void operator=(const output_redirect&) = delete;
|
void operator=(const output_redirect&) = delete;
|
||||||
|
7
vendor/Fmt/test/gtest/CMakeLists.txt
vendored
7
vendor/Fmt/test/gtest/CMakeLists.txt
vendored
@ -17,6 +17,13 @@ else ()
|
|||||||
target_compile_definitions(gtest PUBLIC GTEST_HAS_PTHREAD=0)
|
target_compile_definitions(gtest PUBLIC GTEST_HAS_PTHREAD=0)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
|
# Workaround GTest bug https://github.com/google/googletest/issues/705.
|
||||||
|
check_cxx_compiler_flag(
|
||||||
|
-fno-delete-null-pointer-checks HAVE_FNO_DELETE_NULL_POINTER_CHECKS)
|
||||||
|
if (HAVE_FNO_DELETE_NULL_POINTER_CHECKS)
|
||||||
|
target_compile_options(gtest PUBLIC -fno-delete-null-pointer-checks)
|
||||||
|
endif ()
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
# Disable MSVC warnings of _CRT_INSECURE_DEPRECATE functions.
|
# Disable MSVC warnings of _CRT_INSECURE_DEPRECATE functions.
|
||||||
target_compile_definitions(gtest PRIVATE _CRT_SECURE_NO_WARNINGS)
|
target_compile_definitions(gtest PRIVATE _CRT_SECURE_NO_WARNINGS)
|
||||||
|
4
vendor/Fmt/test/header-only-test.cc
vendored
4
vendor/Fmt/test/header-only-test.cc
vendored
@ -1,7 +1,11 @@
|
|||||||
// Header-only configuration test
|
// Header-only configuration test
|
||||||
|
|
||||||
#include "fmt/core.h"
|
#include "fmt/core.h"
|
||||||
|
#include "fmt/ostream.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
#ifndef FMT_HEADER_ONLY
|
#ifndef FMT_HEADER_ONLY
|
||||||
# error "Not in the header-only mode."
|
# error "Not in the header-only mode."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
TEST(header_only_test, format) { EXPECT_EQ(fmt::format("foo"), "foo"); }
|
||||||
|
21
vendor/Fmt/test/module-test.cc
vendored
21
vendor/Fmt/test/module-test.cc
vendored
@ -36,7 +36,6 @@
|
|||||||
#else
|
#else
|
||||||
# define FMT_USE_FCNTL 0
|
# define FMT_USE_FCNTL 0
|
||||||
#endif
|
#endif
|
||||||
#define FMT_NOEXCEPT noexcept
|
|
||||||
#if defined(_WIN32) && !defined(__MINGW32__)
|
#if defined(_WIN32) && !defined(__MINGW32__)
|
||||||
# define FMT_POSIX(call) _##call
|
# define FMT_POSIX(call) _##call
|
||||||
#else
|
#else
|
||||||
@ -76,8 +75,10 @@ bool oops_detail_namespace_is_visible;
|
|||||||
namespace fmt {
|
namespace fmt {
|
||||||
bool namespace_detail_invisible() {
|
bool namespace_detail_invisible() {
|
||||||
#if defined(FMT_HIDE_MODULE_BUGS) && defined(_MSC_FULL_VER) && \
|
#if defined(FMT_HIDE_MODULE_BUGS) && defined(_MSC_FULL_VER) && \
|
||||||
_MSC_FULL_VER <= 192930129
|
((_MSC_VER == 1929 && _MSC_FULL_VER <= 192930136) || \
|
||||||
// bug in msvc up to 16.11-pre1:
|
(_MSC_VER == 1930 && _MSC_FULL_VER <= 193030704))
|
||||||
|
// bug in msvc up to 16.11.5 / 17.0-pre5:
|
||||||
|
|
||||||
// the namespace is visible even when it is neither
|
// the namespace is visible even when it is neither
|
||||||
// implicitly nor explicitly exported
|
// implicitly nor explicitly exported
|
||||||
return true;
|
return true;
|
||||||
@ -97,8 +98,8 @@ TEST(module_test, detail_namespace) {
|
|||||||
// macros must not be imported from a *named* module [cpp.import]/5.1
|
// macros must not be imported from a *named* module [cpp.import]/5.1
|
||||||
TEST(module_test, macros) {
|
TEST(module_test, macros) {
|
||||||
#if defined(FMT_HIDE_MODULE_BUGS) && defined(_MSC_FULL_VER) && \
|
#if defined(FMT_HIDE_MODULE_BUGS) && defined(_MSC_FULL_VER) && \
|
||||||
_MSC_FULL_VER <= 192930129
|
_MSC_FULL_VER <= 192930130
|
||||||
// bug in msvc up to 16.11-pre1:
|
// bug in msvc up to 16.11-pre2:
|
||||||
// include-guard macros leak from BMI
|
// include-guard macros leak from BMI
|
||||||
// and even worse: they cannot be #undef-ined
|
// and even worse: they cannot be #undef-ined
|
||||||
macro_leaked = false;
|
macro_leaked = false;
|
||||||
@ -194,13 +195,6 @@ TEST(module_test, wformat_args) {
|
|||||||
EXPECT_TRUE(args.get(0));
|
EXPECT_TRUE(args.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(module_test, checked_format_args) {
|
|
||||||
fmt::basic_format_args args = fmt::make_args_checked<int>("{}", 42);
|
|
||||||
EXPECT_TRUE(args.get(0));
|
|
||||||
fmt::basic_format_args wargs = fmt::make_args_checked<int>(L"{}", 42);
|
|
||||||
EXPECT_TRUE(wargs.get(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(module_test, dynamic_format_args) {
|
TEST(module_test, dynamic_format_args) {
|
||||||
fmt::dynamic_format_arg_store<fmt::format_context> dyn_store;
|
fmt::dynamic_format_arg_store<fmt::format_context> dyn_store;
|
||||||
dyn_store.push_back(fmt::arg("a42", 42));
|
dyn_store.push_back(fmt::arg("a42", 42));
|
||||||
@ -456,8 +450,7 @@ TEST(module_test, time_duration) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(module_test, weekday) {
|
TEST(module_test, weekday) {
|
||||||
EXPECT_EQ("Monday",
|
EXPECT_EQ("Mon", fmt::format(std::locale::classic(), "{}", fmt::weekday(1)));
|
||||||
std::format(std::locale::classic(), "{:%A}", fmt::weekday(1)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(module_test, to_string_view) {
|
TEST(module_test, to_string_view) {
|
||||||
|
18
vendor/Fmt/test/noexception-test.cc
vendored
Normal file
18
vendor/Fmt/test/noexception-test.cc
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// Formatting library for C++ - Noexception tests
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
|
#include "fmt/args.h"
|
||||||
|
#include "fmt/chrono.h"
|
||||||
|
#include "fmt/color.h"
|
||||||
|
#include "fmt/compile.h"
|
||||||
|
#include "fmt/core.h"
|
||||||
|
#include "fmt/format.h"
|
||||||
|
#include "fmt/os.h"
|
||||||
|
#include "fmt/ostream.h"
|
||||||
|
#include "fmt/printf.h"
|
||||||
|
#include "fmt/ranges.h"
|
||||||
|
#include "fmt/xchar.h"
|
9
vendor/Fmt/test/os-test.cc
vendored
9
vendor/Fmt/test/os-test.cc
vendored
@ -548,13 +548,4 @@ TEST(file_test, fdopen) {
|
|||||||
int read_fd = read_end.descriptor();
|
int read_fd = read_end.descriptor();
|
||||||
EXPECT_EQ(read_fd, FMT_POSIX(fileno(read_end.fdopen("r").get())));
|
EXPECT_EQ(read_fd, FMT_POSIX(fileno(read_end.fdopen("r").get())));
|
||||||
}
|
}
|
||||||
|
|
||||||
# ifdef FMT_LOCALE
|
|
||||||
TEST(locale_test, strtod) {
|
|
||||||
fmt::locale loc;
|
|
||||||
const char *start = "4.2", *ptr = start;
|
|
||||||
EXPECT_EQ(4.2, loc.strtod(ptr));
|
|
||||||
EXPECT_EQ(start + 3, ptr);
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
#endif // FMT_USE_FCNTL
|
#endif // FMT_USE_FCNTL
|
||||||
|
114
vendor/Fmt/test/ostream-test.cc
vendored
114
vendor/Fmt/test/ostream-test.cc
vendored
@ -23,6 +23,7 @@ template <> struct formatter<test> : formatter<int> {
|
|||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "fmt/compile.h"
|
||||||
#include "fmt/ostream.h"
|
#include "fmt/ostream.h"
|
||||||
#include "fmt/ranges.h"
|
#include "fmt/ranges.h"
|
||||||
#include "gmock/gmock.h"
|
#include "gmock/gmock.h"
|
||||||
@ -52,6 +53,16 @@ std::ostream& operator<<(std::ostream& os, streamable_enum) {
|
|||||||
|
|
||||||
enum unstreamable_enum {};
|
enum unstreamable_enum {};
|
||||||
|
|
||||||
|
struct empty_test {};
|
||||||
|
std::ostream& operator<<(std::ostream& os, empty_test) { return os << ""; }
|
||||||
|
|
||||||
|
namespace fmt {
|
||||||
|
template <> struct formatter<test_string> : ostream_formatter {};
|
||||||
|
template <> struct formatter<date> : ostream_formatter {};
|
||||||
|
template <> struct formatter<streamable_enum> : ostream_formatter {};
|
||||||
|
template <> struct formatter<empty_test> : ostream_formatter {};
|
||||||
|
} // namespace fmt
|
||||||
|
|
||||||
TEST(ostream_test, enum) {
|
TEST(ostream_test, enum) {
|
||||||
EXPECT_EQ("streamable_enum", fmt::format("{}", streamable_enum()));
|
EXPECT_EQ("streamable_enum", fmt::format("{}", streamable_enum()));
|
||||||
EXPECT_EQ("0", fmt::format("{}", unstreamable_enum()));
|
EXPECT_EQ("0", fmt::format("{}", unstreamable_enum()));
|
||||||
@ -69,25 +80,22 @@ TEST(ostream_test, format_specs) {
|
|||||||
EXPECT_EQ(" def", fmt::format("{0:>5}", test_string("def")));
|
EXPECT_EQ(" def", fmt::format("{0:>5}", test_string("def")));
|
||||||
EXPECT_EQ(" def ", fmt::format("{0:^5}", test_string("def")));
|
EXPECT_EQ(" def ", fmt::format("{0:^5}", test_string("def")));
|
||||||
EXPECT_EQ("def**", fmt::format("{0:*<5}", test_string("def")));
|
EXPECT_EQ("def**", fmt::format("{0:*<5}", test_string("def")));
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:+}"), test_string()), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:+}"), test_string()),
|
||||||
"format specifier requires numeric argument");
|
format_error, "format specifier requires numeric argument");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:-}"), test_string()), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:-}"), test_string()),
|
||||||
"format specifier requires numeric argument");
|
format_error, "format specifier requires numeric argument");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0: }"), test_string()), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0: }"), test_string()),
|
||||||
"format specifier requires numeric argument");
|
format_error, "format specifier requires numeric argument");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:#}"), test_string()), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:#}"), test_string()),
|
||||||
"format specifier requires numeric argument");
|
format_error, "format specifier requires numeric argument");
|
||||||
EXPECT_THROW_MSG(fmt::format(runtime("{0:05}"), test_string()), format_error,
|
EXPECT_THROW_MSG((void)fmt::format(runtime("{0:05}"), test_string()),
|
||||||
"format specifier requires numeric argument");
|
format_error, "format specifier requires numeric argument");
|
||||||
EXPECT_EQ("test ", fmt::format("{0:13}", test_string("test")));
|
EXPECT_EQ("test ", fmt::format("{0:13}", test_string("test")));
|
||||||
EXPECT_EQ("test ", fmt::format("{0:{1}}", test_string("test"), 13));
|
EXPECT_EQ("test ", fmt::format("{0:{1}}", test_string("test"), 13));
|
||||||
EXPECT_EQ("te", fmt::format("{0:.2}", test_string("test")));
|
EXPECT_EQ("te", fmt::format("{0:.2}", test_string("test")));
|
||||||
EXPECT_EQ("te", fmt::format("{0:.{1}}", test_string("test"), 2));
|
EXPECT_EQ("te", fmt::format("{0:.{1}}", test_string("test"), 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct empty_test {};
|
|
||||||
std::ostream& operator<<(std::ostream& os, empty_test) { return os << ""; }
|
|
||||||
|
|
||||||
TEST(ostream_test, empty_custom_output) {
|
TEST(ostream_test, empty_custom_output) {
|
||||||
EXPECT_EQ("", fmt::format("{}", empty_test()));
|
EXPECT_EQ("", fmt::format("{}", empty_test()));
|
||||||
}
|
}
|
||||||
@ -183,6 +191,8 @@ template <typename T> struct formatter<test_template<T>> : formatter<int> {
|
|||||||
return formatter<int>::format(2, ctx);
|
return formatter<int>::format(2, ctx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <> struct formatter<fmt_test::abc> : ostream_formatter {};
|
||||||
} // namespace fmt
|
} // namespace fmt
|
||||||
|
|
||||||
TEST(ostream_test, template) {
|
TEST(ostream_test, template) {
|
||||||
@ -213,41 +223,6 @@ TEST(ostream_test, disable_builtin_ostream_operators) {
|
|||||||
EXPECT_EQ("foo", fmt::format("{}", convertible<const char*>("foo")));
|
EXPECT_EQ("foo", fmt::format("{}", convertible<const char*>("foo")));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct explicitly_convertible_to_string_like {
|
|
||||||
template <typename String,
|
|
||||||
typename = typename std::enable_if<std::is_constructible<
|
|
||||||
String, const char*, size_t>::value>::type>
|
|
||||||
explicit operator String() const {
|
|
||||||
return String("foo", 3u);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os,
|
|
||||||
explicitly_convertible_to_string_like) {
|
|
||||||
return os << "bar";
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(ostream_test, format_explicitly_convertible_to_string_like) {
|
|
||||||
EXPECT_EQ("bar", fmt::format("{}", explicitly_convertible_to_string_like()));
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef FMT_USE_STRING_VIEW
|
|
||||||
struct explicitly_convertible_to_std_string_view {
|
|
||||||
explicit operator fmt::detail::std_string_view<char>() const {
|
|
||||||
return {"foo", 3u};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os,
|
|
||||||
explicitly_convertible_to_std_string_view) {
|
|
||||||
return os << "bar";
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(ostream_test, format_explicitly_convertible_to_std_string_view) {
|
|
||||||
EXPECT_EQ("bar", fmt::format("{}", explicitly_convertible_to_string_like()));
|
|
||||||
}
|
|
||||||
#endif // FMT_USE_STRING_VIEW
|
|
||||||
|
|
||||||
struct streamable_and_convertible_to_bool {
|
struct streamable_and_convertible_to_bool {
|
||||||
operator bool() const { return true; }
|
operator bool() const { return true; }
|
||||||
};
|
};
|
||||||
@ -257,7 +232,23 @@ std::ostream& operator<<(std::ostream& os, streamable_and_convertible_to_bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(ostream_test, format_convertible_to_bool) {
|
TEST(ostream_test, format_convertible_to_bool) {
|
||||||
EXPECT_EQ("foo", fmt::format("{}", streamable_and_convertible_to_bool()));
|
// operator<< is intentionally not used because of potential ODR violations.
|
||||||
|
EXPECT_EQ(fmt::format("{}", streamable_and_convertible_to_bool()), "true");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct streamable_and_convertible_to_string_view {
|
||||||
|
operator fmt::string_view() const { return "foo"; }
|
||||||
|
};
|
||||||
|
|
||||||
|
std::ostream& operator<<(std::ostream& os,
|
||||||
|
streamable_and_convertible_to_string_view) {
|
||||||
|
return os << "bar";
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ostream_test, format_convertible_to_string_vew) {
|
||||||
|
// operator<< is intentionally not used because of potential ODR violations.
|
||||||
|
EXPECT_EQ(fmt::format("{}", streamable_and_convertible_to_string_view()),
|
||||||
|
"foo");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct copyfmt_test {};
|
struct copyfmt_test {};
|
||||||
@ -268,6 +259,10 @@ std::ostream& operator<<(std::ostream& os, copyfmt_test) {
|
|||||||
return os << "foo";
|
return os << "foo";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace fmt {
|
||||||
|
template <> struct formatter<copyfmt_test> : ostream_formatter {};
|
||||||
|
} // namespace fmt
|
||||||
|
|
||||||
TEST(ostream_test, copyfmt) {
|
TEST(ostream_test, copyfmt) {
|
||||||
EXPECT_EQ("foo", fmt::format("{}", copyfmt_test()));
|
EXPECT_EQ("foo", fmt::format("{}", copyfmt_test()));
|
||||||
}
|
}
|
||||||
@ -280,3 +275,24 @@ TEST(ostream_test, range) {
|
|||||||
auto strs = std::vector<test_string>{test_string("foo"), test_string("bar")};
|
auto strs = std::vector<test_string>{test_string("foo"), test_string("bar")};
|
||||||
EXPECT_EQ("[foo, bar]", fmt::format("{}", strs));
|
EXPECT_EQ("[foo, bar]", fmt::format("{}", strs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct abstract {
|
||||||
|
virtual ~abstract() = default;
|
||||||
|
virtual void f() = 0;
|
||||||
|
friend std::ostream& operator<<(std::ostream& os, const abstract&) {
|
||||||
|
return os;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace fmt {
|
||||||
|
template <> struct formatter<abstract> : ostream_formatter {};
|
||||||
|
} // namespace fmt
|
||||||
|
|
||||||
|
void format_abstract_compiles(const abstract& a) {
|
||||||
|
fmt::format(FMT_COMPILE("{}"), a);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ostream_test, is_formattable) {
|
||||||
|
EXPECT_TRUE(fmt::is_formattable<std::string>());
|
||||||
|
EXPECT_TRUE(fmt::is_formattable<fmt::detail::std_string_view<char>>());
|
||||||
|
}
|
||||||
|
107
vendor/Fmt/test/posix-mock-test.cc
vendored
107
vendor/Fmt/test/posix-mock-test.cc
vendored
@ -457,110 +457,3 @@ TEST(scoped_mock, scope) {
|
|||||||
}
|
}
|
||||||
EXPECT_EQ(nullptr, test_mock::instance);
|
EXPECT_EQ(nullptr, test_mock::instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FMT_LOCALE
|
|
||||||
|
|
||||||
using locale_type = fmt::locale::type;
|
|
||||||
|
|
||||||
struct locale_mock {
|
|
||||||
static locale_mock* instance;
|
|
||||||
MOCK_METHOD3(newlocale, locale_type(int category_mask, const char* locale,
|
|
||||||
locale_type base));
|
|
||||||
MOCK_METHOD1(freelocale, void(locale_type locale));
|
|
||||||
|
|
||||||
MOCK_METHOD3(strtod_l,
|
|
||||||
double(const char* nptr, char** endptr, locale_type locale));
|
|
||||||
} * locale_mock::instance;
|
|
||||||
|
|
||||||
# ifdef _MSC_VER
|
|
||||||
# pragma warning(push)
|
|
||||||
# pragma warning(disable : 4273)
|
|
||||||
# ifdef __clang__
|
|
||||||
# pragma clang diagnostic push
|
|
||||||
# pragma clang diagnostic ignored "-Winconsistent-dllimport"
|
|
||||||
# endif
|
|
||||||
|
|
||||||
_locale_t _create_locale(int category, const char* locale) {
|
|
||||||
return locale_mock::instance->newlocale(category, locale, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _free_locale(_locale_t locale) {
|
|
||||||
locale_mock::instance->freelocale(locale);
|
|
||||||
}
|
|
||||||
|
|
||||||
double _strtod_l(const char* nptr, char** endptr, _locale_t locale) {
|
|
||||||
return locale_mock::instance->strtod_l(nptr, endptr, locale);
|
|
||||||
}
|
|
||||||
# ifdef __clang__
|
|
||||||
# pragma clang diagnostic pop
|
|
||||||
# endif
|
|
||||||
# pragma warning(pop)
|
|
||||||
# endif
|
|
||||||
|
|
||||||
# if defined(__THROW) && \
|
|
||||||
((FMT_GCC_VERSION > 0 && FMT_GCC_VERSION <= 408) || defined(__e2k__))
|
|
||||||
# define FMT_LOCALE_THROW __THROW
|
|
||||||
# else
|
|
||||||
# define FMT_LOCALE_THROW
|
|
||||||
# endif
|
|
||||||
|
|
||||||
# if defined(__APPLE__) || \
|
|
||||||
(defined(__FreeBSD__) && __FreeBSD_version < 1200002)
|
|
||||||
typedef int FreeLocaleResult;
|
|
||||||
# else
|
|
||||||
typedef void FreeLocaleResult;
|
|
||||||
# endif
|
|
||||||
|
|
||||||
FreeLocaleResult freelocale(locale_type locale) FMT_LOCALE_THROW {
|
|
||||||
locale_mock::instance->freelocale(locale);
|
|
||||||
return FreeLocaleResult();
|
|
||||||
}
|
|
||||||
|
|
||||||
double strtod_l(const char* nptr, char** endptr,
|
|
||||||
locale_type locale) FMT_LOCALE_THROW {
|
|
||||||
return locale_mock::instance->strtod_l(nptr, endptr, locale);
|
|
||||||
}
|
|
||||||
|
|
||||||
# undef FMT_LOCALE_THROW
|
|
||||||
|
|
||||||
# ifndef _WIN32
|
|
||||||
locale_t test::newlocale(int category_mask, const char* locale, locale_t base) {
|
|
||||||
return locale_mock::instance->newlocale(category_mask, locale, base);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(locale_test, locale_mock) {
|
|
||||||
scoped_mock<locale_mock> mock;
|
|
||||||
auto locale = reinterpret_cast<locale_type>(11);
|
|
||||||
EXPECT_CALL(mock, newlocale(222, StrEq("foo"), locale));
|
|
||||||
FMT_SYSTEM(newlocale(222, "foo", locale));
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
|
|
||||||
TEST(locale_test, locale) {
|
|
||||||
# ifndef LC_NUMERIC_MASK
|
|
||||||
enum { LC_NUMERIC_MASK = LC_NUMERIC };
|
|
||||||
# endif
|
|
||||||
scoped_mock<locale_mock> mock;
|
|
||||||
auto impl = reinterpret_cast<locale_type>(42);
|
|
||||||
EXPECT_CALL(mock, newlocale(LC_NUMERIC_MASK, StrEq("C"), nullptr))
|
|
||||||
.WillOnce(Return(impl));
|
|
||||||
EXPECT_CALL(mock, freelocale(impl));
|
|
||||||
fmt::locale loc;
|
|
||||||
EXPECT_EQ(impl, loc.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(locale_test, strtod) {
|
|
||||||
scoped_mock<locale_mock> mock;
|
|
||||||
EXPECT_CALL(mock, newlocale(_, _, _))
|
|
||||||
.WillOnce(Return(reinterpret_cast<locale_type>(42)));
|
|
||||||
EXPECT_CALL(mock, freelocale(_));
|
|
||||||
fmt::locale loc;
|
|
||||||
const char* str = "4.2";
|
|
||||||
char end = 'x';
|
|
||||||
EXPECT_CALL(mock, strtod_l(str, _, loc.get()))
|
|
||||||
.WillOnce(testing::DoAll(testing::SetArgPointee<1>(&end), Return(777)));
|
|
||||||
EXPECT_EQ(777, loc.strtod(str));
|
|
||||||
EXPECT_EQ(&end, str);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // FMT_LOCALE
|
|
||||||
|
11
vendor/Fmt/test/printf-test.cc
vendored
11
vendor/Fmt/test/printf-test.cc
vendored
@ -11,7 +11,6 @@
|
|||||||
#include <climits>
|
#include <climits>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#include "fmt/ostream.h"
|
|
||||||
#include "fmt/xchar.h"
|
#include "fmt/xchar.h"
|
||||||
#include "gtest-extra.h"
|
#include "gtest-extra.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
@ -481,12 +480,6 @@ TEST(printf_test, string) {
|
|||||||
EXPECT_PRINTF(L" (null)", L"%10s", null_wstr);
|
EXPECT_PRINTF(L" (null)", L"%10s", null_wstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(printf_test, uchar_string) {
|
|
||||||
unsigned char str[] = "test";
|
|
||||||
unsigned char* pstr = str;
|
|
||||||
EXPECT_EQ("test", fmt::sprintf("%s", pstr));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(printf_test, pointer) {
|
TEST(printf_test, pointer) {
|
||||||
int n;
|
int n;
|
||||||
void* p = &n;
|
void* p = &n;
|
||||||
@ -539,10 +532,6 @@ TEST(printf_test, wide_string) {
|
|||||||
EXPECT_EQ(L"abc", fmt::sprintf(L"%s", L"abc"));
|
EXPECT_EQ(L"abc", fmt::sprintf(L"%s", L"abc"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(printf_test, printf_custom) {
|
|
||||||
EXPECT_EQ("abc", test_sprintf("%s", test_string("abc")));
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(printf_test, vprintf) {
|
TEST(printf_test, vprintf) {
|
||||||
fmt::format_arg_store<fmt::printf_context, int> as{42};
|
fmt::format_arg_store<fmt::printf_context, int> as{42};
|
||||||
fmt::basic_format_args<fmt::printf_context> args(as);
|
fmt::basic_format_args<fmt::printf_context> args(as);
|
||||||
|
17
vendor/Fmt/test/ranges-odr-test.cc
vendored
Normal file
17
vendor/Fmt/test/ranges-odr-test.cc
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Formatting library for C++ - the core API
|
||||||
|
//
|
||||||
|
// Copyright (c) 2012 - present, Victor Zverovich
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// For the license information refer to format.h.
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "fmt/ranges.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
// call fmt::format from another translation unit to test ODR
|
||||||
|
TEST(ranges_odr_test, format_vector) {
|
||||||
|
auto v = std::vector<int>{1, 2, 3, 5, 7, 11};
|
||||||
|
EXPECT_EQ(fmt::format("{}", v), "[1, 2, 3, 5, 7, 11]");
|
||||||
|
}
|
135
vendor/Fmt/test/ranges-test.cc
vendored
135
vendor/Fmt/test/ranges-test.cc
vendored
@ -46,16 +46,42 @@ TEST(ranges_test, format_array_of_literals) {
|
|||||||
TEST(ranges_test, format_vector) {
|
TEST(ranges_test, format_vector) {
|
||||||
auto v = std::vector<int>{1, 2, 3, 5, 7, 11};
|
auto v = std::vector<int>{1, 2, 3, 5, 7, 11};
|
||||||
EXPECT_EQ(fmt::format("{}", v), "[1, 2, 3, 5, 7, 11]");
|
EXPECT_EQ(fmt::format("{}", v), "[1, 2, 3, 5, 7, 11]");
|
||||||
|
EXPECT_EQ(fmt::format("{::#x}", v), "[0x1, 0x2, 0x3, 0x5, 0x7, 0xb]");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ranges_test, format_vector2) {
|
TEST(ranges_test, format_vector2) {
|
||||||
auto v = std::vector<std::vector<int>>{{1, 2}, {3, 5}, {7, 11}};
|
auto v = std::vector<std::vector<int>>{{1, 2}, {3, 5}, {7, 11}};
|
||||||
EXPECT_EQ(fmt::format("{}", v), "[[1, 2], [3, 5], [7, 11]]");
|
EXPECT_EQ(fmt::format("{}", v), "[[1, 2], [3, 5], [7, 11]]");
|
||||||
|
EXPECT_EQ(fmt::format("{:::#x}", v), "[[0x1, 0x2], [0x3, 0x5], [0x7, 0xb]]");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ranges_test, format_map) {
|
TEST(ranges_test, format_map) {
|
||||||
auto m = std::map<std::string, int>{{"one", 1}, {"two", 2}};
|
auto m = std::map<std::string, int>{{"one", 1}, {"two", 2}};
|
||||||
EXPECT_EQ(fmt::format("{}", m), "[(\"one\", 1), (\"two\", 2)]");
|
EXPECT_EQ(fmt::format("{}", m), "{\"one\": 1, \"two\": 2}");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ranges_test, format_set) {
|
||||||
|
EXPECT_EQ(fmt::format("{}", std::set<std::string>{"one", "two"}),
|
||||||
|
"{\"one\", \"two\"}");
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace adl {
|
||||||
|
struct box {
|
||||||
|
int value;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto begin(const box& b) -> const int* {
|
||||||
|
return &b.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto end(const box& b) -> const int* {
|
||||||
|
return &b.value + 1;
|
||||||
|
}
|
||||||
|
} // namespace adl
|
||||||
|
|
||||||
|
TEST(ranges_test, format_adl_begin_end) {
|
||||||
|
auto b = adl::box{42};
|
||||||
|
EXPECT_EQ(fmt::format("{}", b), "[42]");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ranges_test, format_pair) {
|
TEST(ranges_test, format_pair) {
|
||||||
@ -126,8 +152,8 @@ TEST(ranges_test, path_like) {
|
|||||||
struct string_like {
|
struct string_like {
|
||||||
const char* begin();
|
const char* begin();
|
||||||
const char* end();
|
const char* end();
|
||||||
explicit operator fmt::string_view() const { return "foo"; }
|
operator fmt::string_view() const { return "foo"; }
|
||||||
explicit operator std::string_view() const { return "foo"; }
|
operator std::string_view() const { return "foo"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST(ranges_test, format_string_like) {
|
TEST(ranges_test, format_string_like) {
|
||||||
@ -190,7 +216,14 @@ TEST(ranges_test, range) {
|
|||||||
EXPECT_EQ(fmt::format("{}", z), "[0, 0, 0]");
|
EXPECT_EQ(fmt::format("{}", z), "[0, 0, 0]");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !FMT_MSC_VER || FMT_MSC_VER >= 1927
|
enum test_enum { foo };
|
||||||
|
|
||||||
|
TEST(ranges_test, enum_range) {
|
||||||
|
auto v = std::vector<test_enum>{test_enum::foo};
|
||||||
|
EXPECT_EQ(fmt::format("{}", v), "[0]");
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !FMT_MSC_VER
|
||||||
struct unformattable {};
|
struct unformattable {};
|
||||||
|
|
||||||
TEST(ranges_test, unformattable_range) {
|
TEST(ranges_test, unformattable_range) {
|
||||||
@ -217,6 +250,21 @@ TEST(ranges_test, join_tuple) {
|
|||||||
// Single element tuple.
|
// Single element tuple.
|
||||||
auto t4 = std::tuple<float>(4.0f);
|
auto t4 = std::tuple<float>(4.0f);
|
||||||
EXPECT_EQ(fmt::format("{}", fmt::join(t4, "/")), "4");
|
EXPECT_EQ(fmt::format("{}", fmt::join(t4, "/")), "4");
|
||||||
|
|
||||||
|
# if FMT_TUPLE_JOIN_SPECIFIERS
|
||||||
|
// Specs applied to each element.
|
||||||
|
auto t5 = std::tuple<int, int, long>(-3, 100, 1);
|
||||||
|
EXPECT_EQ(fmt::format("{:+03}", fmt::join(t5, ", ")), "-03, +100, +01");
|
||||||
|
|
||||||
|
auto t6 = std::tuple<float, double, long double>(3, 3.14, 3.1415);
|
||||||
|
EXPECT_EQ(fmt::format("{:5.5f}", fmt::join(t6, ", ")),
|
||||||
|
"3.00000, 3.14000, 3.14150");
|
||||||
|
|
||||||
|
// Testing lvalue tuple args.
|
||||||
|
int y = -1;
|
||||||
|
auto t7 = std::tuple<int, int&, const int&>(3, y, y);
|
||||||
|
EXPECT_EQ(fmt::format("{:03}", fmt::join(t7, ", ")), "003, -01, -01");
|
||||||
|
# endif
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ranges_test, join_initializer_list) {
|
TEST(ranges_test, join_initializer_list) {
|
||||||
@ -236,9 +284,40 @@ struct zstring {
|
|||||||
zstring_sentinel end() const { return {}; }
|
zstring_sentinel end() const { return {}; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# ifdef __cpp_lib_ranges
|
||||||
|
struct cpp20_only_range {
|
||||||
|
struct iterator {
|
||||||
|
int val = 0;
|
||||||
|
|
||||||
|
using value_type = int;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using iterator_concept = std::input_iterator_tag;
|
||||||
|
|
||||||
|
iterator() = default;
|
||||||
|
iterator(int i) : val(i) {}
|
||||||
|
int operator*() const { return val; }
|
||||||
|
iterator& operator++() {
|
||||||
|
++val;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
void operator++(int) { ++*this; }
|
||||||
|
bool operator==(const iterator& rhs) const { return val == rhs.val; }
|
||||||
|
};
|
||||||
|
|
||||||
|
int lo;
|
||||||
|
int hi;
|
||||||
|
|
||||||
|
iterator begin() const { return iterator(lo); }
|
||||||
|
iterator end() const { return iterator(hi); }
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(std::input_iterator<cpp20_only_range::iterator>);
|
||||||
|
# endif
|
||||||
|
|
||||||
TEST(ranges_test, join_sentinel) {
|
TEST(ranges_test, join_sentinel) {
|
||||||
auto hello = zstring{"hello"};
|
auto hello = zstring{"hello"};
|
||||||
EXPECT_EQ(fmt::format("{}", hello), "['h', 'e', 'l', 'l', 'o']");
|
EXPECT_EQ(fmt::format("{}", hello), "['h', 'e', 'l', 'l', 'o']");
|
||||||
|
EXPECT_EQ(fmt::format("{::}", hello), "[h, e, l, l, o]");
|
||||||
EXPECT_EQ(fmt::format("{}", fmt::join(hello, "_")), "h_e_l_l_o");
|
EXPECT_EQ(fmt::format("{}", fmt::join(hello, "_")), "h_e_l_l_o");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,18 +339,62 @@ TEST(ranges_test, join_range) {
|
|||||||
|
|
||||||
const auto z = std::vector<int>(3u, 0);
|
const auto z = std::vector<int>(3u, 0);
|
||||||
EXPECT_EQ(fmt::format("{}", fmt::join(z, ",")), "0,0,0");
|
EXPECT_EQ(fmt::format("{}", fmt::join(z, ",")), "0,0,0");
|
||||||
|
|
||||||
|
# ifdef __cpp_lib_ranges
|
||||||
|
EXPECT_EQ(fmt::format("{}", cpp20_only_range{.lo = 0, .hi = 5}),
|
||||||
|
"[0, 1, 2, 3, 4]");
|
||||||
|
EXPECT_EQ(
|
||||||
|
fmt::format("{}", fmt::join(cpp20_only_range{.lo = 0, .hi = 5}, ",")),
|
||||||
|
"0,1,2,3,4");
|
||||||
|
# endif
|
||||||
}
|
}
|
||||||
#endif // FMT_RANGES_TEST_ENABLE_JOIN
|
#endif // FMT_RANGES_TEST_ENABLE_JOIN
|
||||||
|
|
||||||
|
TEST(ranges_test, is_printable) {
|
||||||
|
using fmt::detail::is_printable;
|
||||||
|
EXPECT_TRUE(is_printable(0x0323));
|
||||||
|
EXPECT_FALSE(is_printable(0x0378));
|
||||||
|
EXPECT_FALSE(is_printable(0x110000));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(ranges_test, escape_string) {
|
TEST(ranges_test, escape_string) {
|
||||||
using vec = std::vector<std::string>;
|
using vec = std::vector<std::string>;
|
||||||
EXPECT_EQ(fmt::format("{}", vec{"\n\r\t\"\\"}), "[\"\\n\\r\\t\\\"\\\\\"]");
|
EXPECT_EQ(fmt::format("{}", vec{"\n\r\t\"\\"}), "[\"\\n\\r\\t\\\"\\\\\"]");
|
||||||
EXPECT_EQ(fmt::format("{}", vec{"\x07"}), "[\"\\x07\"]");
|
EXPECT_EQ(fmt::format("{}", vec{"\x07"}), "[\"\\x07\"]");
|
||||||
EXPECT_EQ(fmt::format("{}", vec{"\x7f"}), "[\"\\x7f\"]");
|
EXPECT_EQ(fmt::format("{}", vec{"\x7f"}), "[\"\\x7f\"]");
|
||||||
|
EXPECT_EQ(fmt::format("{}", vec{"n\xcc\x83"}), "[\"n\xcc\x83\"]");
|
||||||
|
|
||||||
// Unassigned Unicode code points.
|
|
||||||
if (fmt::detail::is_utf8()) {
|
if (fmt::detail::is_utf8()) {
|
||||||
|
EXPECT_EQ(fmt::format("{}", vec{"\xcd\xb8"}), "[\"\\u0378\"]");
|
||||||
|
// Unassigned Unicode code points.
|
||||||
EXPECT_EQ(fmt::format("{}", vec{"\xf0\xaa\x9b\x9e"}), "[\"\\U0002a6de\"]");
|
EXPECT_EQ(fmt::format("{}", vec{"\xf0\xaa\x9b\x9e"}), "[\"\\U0002a6de\"]");
|
||||||
EXPECT_EQ(fmt::format("{}", vec{"\xf4\x8f\xbf\xbf"}), "[\"\\U0010ffff\"]");
|
EXPECT_EQ(fmt::format("{}", vec{"\xf4\x8f\xbf\xc0"}),
|
||||||
|
"[\"\\xf4\\x8f\\xbf\\xc0\"]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef FMT_USE_STRING_VIEW
|
||||||
|
struct convertible_to_string_view {
|
||||||
|
operator std::string_view() const { return "foo"; }
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(ranges_test, escape_convertible_to_string_view) {
|
||||||
|
EXPECT_EQ(fmt::format("{}", std::vector<convertible_to_string_view>(1)),
|
||||||
|
"[\"foo\"]");
|
||||||
|
}
|
||||||
|
#endif // FMT_USE_STRING_VIEW
|
||||||
|
|
||||||
|
template <typename R> struct fmt_ref_view {
|
||||||
|
R* r;
|
||||||
|
|
||||||
|
auto begin() const -> decltype(r->begin()) { return r->begin(); }
|
||||||
|
auto end() const -> decltype(r->end()) { return r->end(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST(ranges_test, range_of_range_of_mixed_const) {
|
||||||
|
std::vector<std::vector<int>> v = {{1, 2, 3}, {4, 5}};
|
||||||
|
EXPECT_EQ(fmt::format("{}", v), "[[1, 2, 3], [4, 5]]");
|
||||||
|
|
||||||
|
fmt_ref_view<decltype(v)> r{&v};
|
||||||
|
EXPECT_EQ(fmt::format("{}", r), "[[1, 2, 3], [4, 5]]");
|
||||||
|
}
|
||||||
|
161
vendor/Fmt/test/std-format-test.cc
vendored
161
vendor/Fmt/test/std-format-test.cc
vendored
@ -1,161 +0,0 @@
|
|||||||
#include <format>
|
|
||||||
|
|
||||||
#include "gtest/gtest.h"
|
|
||||||
|
|
||||||
TEST(std_format_test, escaping) {
|
|
||||||
using namespace std;
|
|
||||||
string s = format("{0}-{{", 8); // s == "8-{"
|
|
||||||
EXPECT_EQ(s, "8-{");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(std_format_test, indexing) {
|
|
||||||
using namespace std;
|
|
||||||
string s0 = format("{} to {}", "a", "b"); // OK: automatic indexing
|
|
||||||
string s1 = format("{1} to {0}", "a", "b"); // OK: manual indexing
|
|
||||||
EXPECT_EQ(s0, "a to b");
|
|
||||||
EXPECT_EQ(s1, "b to a");
|
|
||||||
// Error: mixing automatic and manual indexing
|
|
||||||
EXPECT_THROW(string s2 = format("{0} to {}", "a", "b"), std::format_error);
|
|
||||||
// Error: mixing automatic and manual indexing
|
|
||||||
EXPECT_THROW(string s3 = format("{} to {1}", "a", "b"), std::format_error);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(std_format_test, alignment) {
|
|
||||||
using namespace std;
|
|
||||||
char c = 120;
|
|
||||||
string s0 = format("{:6}", 42); // s0 == " 42"
|
|
||||||
string s1 = format("{:6}", 'x'); // s1 == "x "
|
|
||||||
string s2 = format("{:*<6}", 'x'); // s2 == "x*****"
|
|
||||||
string s3 = format("{:*>6}", 'x'); // s3 == "*****x"
|
|
||||||
string s4 = format("{:*^6}", 'x'); // s4 == "**x***"
|
|
||||||
// Error: '=' with charT and no integer presentation type
|
|
||||||
EXPECT_THROW(string s5 = format("{:=6}", 'x'), std::format_error);
|
|
||||||
string s6 = format("{:6d}", c); // s6 == " 120"
|
|
||||||
string s7 = format("{:6}", true); // s9 == "true "
|
|
||||||
EXPECT_EQ(s0, " 42");
|
|
||||||
EXPECT_EQ(s1, "x ");
|
|
||||||
EXPECT_EQ(s2, "x*****");
|
|
||||||
EXPECT_EQ(s3, "*****x");
|
|
||||||
EXPECT_EQ(s4, "**x***");
|
|
||||||
EXPECT_EQ(s6, " 120");
|
|
||||||
EXPECT_EQ(s7, "true ");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(std_format_test, float) {
|
|
||||||
using namespace std;
|
|
||||||
double inf = numeric_limits<double>::infinity();
|
|
||||||
double nan = numeric_limits<double>::quiet_NaN();
|
|
||||||
string s0 = format("{0:} {0:+} {0:-} {0: }", 1); // s0 == "1 +1 1 1"
|
|
||||||
string s1 = format("{0:} {0:+} {0:-} {0: }", -1); // s1 == "-1 -1 -1 -1"
|
|
||||||
string s2 =
|
|
||||||
format("{0:} {0:+} {0:-} {0: }", inf); // s2 == "inf +inf inf inf"
|
|
||||||
string s3 =
|
|
||||||
format("{0:} {0:+} {0:-} {0: }", nan); // s3 == "nan +nan nan nan"
|
|
||||||
EXPECT_EQ(s0, "1 +1 1 1");
|
|
||||||
EXPECT_EQ(s1, "-1 -1 -1 -1");
|
|
||||||
EXPECT_EQ(s2, "inf +inf inf inf");
|
|
||||||
EXPECT_EQ(s3, "nan +nan nan nan");
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(std_format_test, int) {
|
|
||||||
using namespace std;
|
|
||||||
string s0 = format("{}", 42); // s0 == "42"
|
|
||||||
string s1 = format("{0:b} {0:d} {0:o} {0:x}", 42); // s1 == "101010 42 52 2a"
|
|
||||||
string s2 = format("{0:#x} {0:#X}", 42); // s2 == "0x2a 0X2A"
|
|
||||||
string s3 = format("{:L}", 1234); // s3 == "1234" (depends on the locale)
|
|
||||||
EXPECT_EQ(s0, "42");
|
|
||||||
EXPECT_EQ(s1, "101010 42 52 2a");
|
|
||||||
EXPECT_EQ(s2, "0x2a 0X2A");
|
|
||||||
EXPECT_EQ(s3, "1234");
|
|
||||||
}
|
|
||||||
|
|
||||||
#include <format>
|
|
||||||
|
|
||||||
enum color { red, green, blue };
|
|
||||||
|
|
||||||
const char* color_names[] = {"red", "green", "blue"};
|
|
||||||
|
|
||||||
template <> struct std::formatter<color> : std::formatter<const char*> {
|
|
||||||
auto format(color c, format_context& ctx) {
|
|
||||||
return formatter<const char*>::format(color_names[c], ctx);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct err {};
|
|
||||||
|
|
||||||
TEST(std_format_test, formatter) {
|
|
||||||
std::string s0 = std::format("{}", 42); // OK: library-provided formatter
|
|
||||||
// std::string s1 = std::format("{}", L"foo"); // Ill-formed: disabled
|
|
||||||
// formatter
|
|
||||||
std::string s2 = std::format("{}", red); // OK: user-provided formatter
|
|
||||||
// std::string s3 = std::format("{}", err{}); // Ill-formed: disabled
|
|
||||||
// formatter
|
|
||||||
EXPECT_EQ(s0, "42");
|
|
||||||
EXPECT_EQ(s2, "red");
|
|
||||||
}
|
|
||||||
|
|
||||||
struct S {
|
|
||||||
int value;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <> struct std::formatter<S> {
|
|
||||||
size_t width_arg_id = 0;
|
|
||||||
|
|
||||||
// Parses a width argument id in the format { <digit> }.
|
|
||||||
constexpr auto parse(format_parse_context& ctx) {
|
|
||||||
constexpr auto is_ascii_digit = [](const char c) {
|
|
||||||
return c >= '0' && c <= '9';
|
|
||||||
};
|
|
||||||
|
|
||||||
auto iter = ctx.begin();
|
|
||||||
// auto get_char = [&]() { return iter != ctx.end() ? *iter : 0; };
|
|
||||||
auto get_char = [&]() { return iter != ctx.end() ? *iter : '\0'; };
|
|
||||||
if (get_char() != '{') return iter;
|
|
||||||
++iter;
|
|
||||||
char c = get_char();
|
|
||||||
if (!is_ascii_digit(c) || (++iter, get_char()) != '}')
|
|
||||||
throw format_error("invalid format");
|
|
||||||
width_arg_id = fmt::detail::to_unsigned(c - '0');
|
|
||||||
ctx.check_arg_id(width_arg_id);
|
|
||||||
return ++iter;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Formats S with width given by the argument width_arg_id.
|
|
||||||
auto format(S s, format_context& ctx) {
|
|
||||||
int width = visit_format_arg(
|
|
||||||
[](auto value) -> int {
|
|
||||||
using type = decltype(value);
|
|
||||||
if constexpr (!is_integral_v<type> || is_same_v<type, bool>)
|
|
||||||
throw format_error("width is not integral");
|
|
||||||
// else if (value < 0 || value > numeric_limits<int>::max())
|
|
||||||
else if (fmt::detail::is_negative(value) ||
|
|
||||||
value > numeric_limits<int>::max())
|
|
||||||
throw format_error("invalid width");
|
|
||||||
else
|
|
||||||
return static_cast<int>(value);
|
|
||||||
},
|
|
||||||
ctx.arg(width_arg_id));
|
|
||||||
return format_to(ctx.out(), "{0:{1}}", s.value, width);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST(std_format_test, parsing) {
|
|
||||||
std::string s = std::format("{0:{1}}", S{42}, 10); // s == " 42"
|
|
||||||
EXPECT_EQ(s, " 42");
|
|
||||||
}
|
|
||||||
|
|
||||||
#if FMT_USE_INT128
|
|
||||||
template <> struct std::formatter<__int128_t> : std::formatter<long long> {
|
|
||||||
auto format(__int128_t n, format_context& ctx) {
|
|
||||||
// Format as a long long since we only want to check if it is possible to
|
|
||||||
// specialize formatter for __int128_t.
|
|
||||||
return formatter<long long>::format(static_cast<long long>(n), ctx);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST(std_format_test, int128) {
|
|
||||||
__int128_t n = 42;
|
|
||||||
auto s = std::format("{}", n);
|
|
||||||
EXPECT_EQ(s, "42");
|
|
||||||
}
|
|
||||||
#endif // FMT_USE_INT128
|
|
2
vendor/Fmt/test/unicode-test.cc
vendored
2
vendor/Fmt/test/unicode-test.cc
vendored
@ -18,7 +18,7 @@ using testing::Contains;
|
|||||||
TEST(unicode_test, is_utf8) { EXPECT_TRUE(fmt::detail::is_utf8()); }
|
TEST(unicode_test, is_utf8) { EXPECT_TRUE(fmt::detail::is_utf8()); }
|
||||||
|
|
||||||
TEST(unicode_test, legacy_locale) {
|
TEST(unicode_test, legacy_locale) {
|
||||||
auto loc = get_locale("ru_RU.CP1251", "Russian.1251");
|
auto loc = get_locale("ru_RU.CP1251", "Russian_Russia.1251");
|
||||||
if (loc == std::locale::classic()) return;
|
if (loc == std::locale::classic()) return;
|
||||||
|
|
||||||
auto s = std::string();
|
auto s = std::string();
|
||||||
|
95
vendor/Fmt/test/xchar-test.cc
vendored
95
vendor/Fmt/test/xchar-test.cc
vendored
@ -8,14 +8,18 @@
|
|||||||
#include "fmt/xchar.h"
|
#include "fmt/xchar.h"
|
||||||
|
|
||||||
#include <complex>
|
#include <complex>
|
||||||
|
#include <cwchar>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "fmt/chrono.h"
|
#include "fmt/chrono.h"
|
||||||
#include "fmt/color.h"
|
#include "fmt/color.h"
|
||||||
#include "fmt/ostream.h"
|
#include "fmt/ostream.h"
|
||||||
#include "fmt/ranges.h"
|
#include "fmt/ranges.h"
|
||||||
#include "gtest/gtest.h"
|
#include "gtest-extra.h" // Contains
|
||||||
|
#include "util.h" // get_locale
|
||||||
|
|
||||||
using fmt::detail::max_value;
|
using fmt::detail::max_value;
|
||||||
|
using testing::Contains;
|
||||||
|
|
||||||
namespace test_ns {
|
namespace test_ns {
|
||||||
template <typename Char> class test_string {
|
template <typename Char> class test_string {
|
||||||
@ -68,8 +72,10 @@ struct explicitly_convertible_to_wstring_view {
|
|||||||
};
|
};
|
||||||
|
|
||||||
TEST(xchar_test, format_explicitly_convertible_to_wstring_view) {
|
TEST(xchar_test, format_explicitly_convertible_to_wstring_view) {
|
||||||
EXPECT_EQ(L"foo",
|
// Types explicitly convertible to wstring_view are not formattable by
|
||||||
fmt::format(L"{}", explicitly_convertible_to_wstring_view()));
|
// default because it may introduce ODR violations.
|
||||||
|
static_assert(
|
||||||
|
!fmt::is_formattable<explicitly_convertible_to_wstring_view>::value, "");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -87,6 +93,10 @@ TEST(xchar_test, format) {
|
|||||||
EXPECT_EQ(L"abc1", fmt::format(L"{}c{}", L"ab", 1));
|
EXPECT_EQ(L"abc1", fmt::format(L"{}c{}", L"ab", 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(xchar_test, is_formattable) {
|
||||||
|
static_assert(!fmt::is_formattable<const wchar_t*>::value, "");
|
||||||
|
}
|
||||||
|
|
||||||
TEST(xchar_test, compile_time_string) {
|
TEST(xchar_test, compile_time_string) {
|
||||||
#if defined(FMT_USE_STRING_VIEW) && __cplusplus >= 201703L
|
#if defined(FMT_USE_STRING_VIEW) && __cplusplus >= 201703L
|
||||||
EXPECT_EQ(L"42", fmt::format(FMT_STRING(std::wstring_view(L"{}")), 42));
|
EXPECT_EQ(L"42", fmt::format(FMT_STRING(std::wstring_view(L"{}")), 42));
|
||||||
@ -210,6 +220,12 @@ std::wostream& operator<<(std::wostream& os, streamable_enum) {
|
|||||||
return os << L"streamable_enum";
|
return os << L"streamable_enum";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace fmt {
|
||||||
|
template <>
|
||||||
|
struct formatter<streamable_enum, wchar_t> : basic_ostream_formatter<wchar_t> {
|
||||||
|
};
|
||||||
|
} // namespace fmt
|
||||||
|
|
||||||
enum unstreamable_enum {};
|
enum unstreamable_enum {};
|
||||||
|
|
||||||
TEST(xchar_test, enum) {
|
TEST(xchar_test, enum) {
|
||||||
@ -228,14 +244,14 @@ namespace fake_qt {
|
|||||||
class QString {
|
class QString {
|
||||||
public:
|
public:
|
||||||
QString(const wchar_t* s) : s_(s) {}
|
QString(const wchar_t* s) : s_(s) {}
|
||||||
const wchar_t* utf16() const FMT_NOEXCEPT { return s_.data(); }
|
const wchar_t* utf16() const noexcept { return s_.data(); }
|
||||||
int size() const FMT_NOEXCEPT { return static_cast<int>(s_.size()); }
|
int size() const noexcept { return static_cast<int>(s_.size()); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::wstring s_;
|
std::wstring s_;
|
||||||
};
|
};
|
||||||
|
|
||||||
fmt::basic_string_view<wchar_t> to_string_view(const QString& s) FMT_NOEXCEPT {
|
fmt::basic_string_view<wchar_t> to_string_view(const QString& s) noexcept {
|
||||||
return {s.utf16(), static_cast<size_t>(s.size())};
|
return {s.utf16(), static_cast<size_t>(s.size())};
|
||||||
}
|
}
|
||||||
} // namespace fake_qt
|
} // namespace fake_qt
|
||||||
@ -257,6 +273,55 @@ TEST(xchar_test, chrono) {
|
|||||||
EXPECT_EQ(fmt::format("The date is {:%Y-%m-%d %H:%M:%S}.", tm),
|
EXPECT_EQ(fmt::format("The date is {:%Y-%m-%d %H:%M:%S}.", tm),
|
||||||
"The date is 2016-04-25 11:22:33.");
|
"The date is 2016-04-25 11:22:33.");
|
||||||
EXPECT_EQ(L"42s", fmt::format(L"{}", std::chrono::seconds(42)));
|
EXPECT_EQ(L"42s", fmt::format(L"{}", std::chrono::seconds(42)));
|
||||||
|
EXPECT_EQ(fmt::format(L"{:%F}", tm), L"2016-04-25");
|
||||||
|
EXPECT_EQ(fmt::format(L"{:%T}", tm), L"11:22:33");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring system_wcsftime(const std::wstring& format, const std::tm* timeptr,
|
||||||
|
std::locale* locptr = nullptr) {
|
||||||
|
auto loc = locptr ? *locptr : std::locale::classic();
|
||||||
|
auto& facet = std::use_facet<std::time_put<wchar_t>>(loc);
|
||||||
|
std::wostringstream os;
|
||||||
|
os.imbue(loc);
|
||||||
|
facet.put(os, os, L' ', timeptr, format.c_str(),
|
||||||
|
format.c_str() + format.size());
|
||||||
|
#ifdef _WIN32
|
||||||
|
// Workaround a bug in older versions of Universal CRT.
|
||||||
|
auto str = os.str();
|
||||||
|
if (str == L"-0000") str = L"+0000";
|
||||||
|
return str;
|
||||||
|
#else
|
||||||
|
return os.str();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(chrono_test, time_point) {
|
||||||
|
auto t1 = std::chrono::system_clock::now();
|
||||||
|
|
||||||
|
std::vector<std::wstring> spec_list = {
|
||||||
|
L"%%", L"%n", L"%t", L"%Y", L"%EY", L"%y", L"%Oy", L"%Ey", L"%C",
|
||||||
|
L"%EC", L"%G", L"%g", L"%b", L"%h", L"%B", L"%m", L"%Om", L"%U",
|
||||||
|
L"%OU", L"%W", L"%OW", L"%V", L"%OV", L"%j", L"%d", L"%Od", L"%e",
|
||||||
|
L"%Oe", L"%a", L"%A", L"%w", L"%Ow", L"%u", L"%Ou", L"%H", L"%OH",
|
||||||
|
L"%I", L"%OI", L"%M", L"%OM", L"%S", L"%OS", L"%x", L"%Ex", L"%X",
|
||||||
|
L"%EX", L"%D", L"%F", L"%R", L"%T", L"%p", L"%z", L"%Z"};
|
||||||
|
spec_list.push_back(L"%Y-%m-%d %H:%M:%S");
|
||||||
|
#ifndef _WIN32
|
||||||
|
// Disabled on Windows, because these formats is not consistent among
|
||||||
|
// platforms.
|
||||||
|
spec_list.insert(spec_list.end(), {L"%c", L"%Ec", L"%r"});
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (const auto& spec : spec_list) {
|
||||||
|
auto t = std::chrono::system_clock::to_time_t(t1);
|
||||||
|
auto tm = *std::localtime(&t);
|
||||||
|
|
||||||
|
auto sys_output = system_wcsftime(spec, &tm);
|
||||||
|
|
||||||
|
auto fmt_spec = fmt::format(L"{{:{}}}", spec);
|
||||||
|
EXPECT_EQ(sys_output, fmt::format(fmt_spec, t1));
|
||||||
|
EXPECT_EQ(sys_output, fmt::format(fmt_spec, tm));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(xchar_test, color) {
|
TEST(xchar_test, color) {
|
||||||
@ -405,7 +470,7 @@ template <class charT> struct formatter<std::complex<double>, charT> {
|
|||||||
specs_.precision, specs_.precision_ref, ctx);
|
specs_.precision, specs_.precision_ref, ctx);
|
||||||
auto specs = std::string();
|
auto specs = std::string();
|
||||||
if (specs_.precision > 0) specs = fmt::format(".{}", specs_.precision);
|
if (specs_.precision > 0) specs = fmt::format(".{}", specs_.precision);
|
||||||
if (specs_.type) specs += specs_.type;
|
if (specs_.type == presentation_type::fixed_lower) specs += 'f';
|
||||||
auto real = fmt::format(ctx.locale().template get<std::locale>(),
|
auto real = fmt::format(ctx.locale().template get<std::locale>(),
|
||||||
fmt::runtime("{:" + specs + "}"), c.real());
|
fmt::runtime("{:" + specs + "}"), c.real());
|
||||||
auto imag = fmt::format(ctx.locale().template get<std::locale>(),
|
auto imag = fmt::format(ctx.locale().template get<std::locale>(),
|
||||||
@ -426,4 +491,20 @@ TEST(locale_test, complex) {
|
|||||||
EXPECT_EQ(fmt::format("{:8}", std::complex<double>(1, 2)), " (1+2i)");
|
EXPECT_EQ(fmt::format("{:8}", std::complex<double>(1, 2)), " (1+2i)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(locale_test, chrono_weekday) {
|
||||||
|
auto loc = get_locale("ru_RU.UTF-8", "Russian_Russia.1251");
|
||||||
|
auto loc_old = std::locale::global(loc);
|
||||||
|
auto mon = fmt::weekday(1);
|
||||||
|
EXPECT_EQ(fmt::format(L"{}", mon), L"Mon");
|
||||||
|
if (loc != std::locale::classic()) {
|
||||||
|
// {L"\x43F\x43D", L"\x41F\x43D", L"\x43F\x43D\x434", L"\x41F\x43D\x434"}
|
||||||
|
// {L"пн", L"Пн", L"пнд", L"Пнд"}
|
||||||
|
EXPECT_THAT(
|
||||||
|
(std::vector<std::wstring>{L"\x43F\x43D", L"\x41F\x43D",
|
||||||
|
L"\x43F\x43D\x434", L"\x41F\x43D\x434"}),
|
||||||
|
Contains(fmt::format(loc, L"{:L}", mon)));
|
||||||
|
}
|
||||||
|
std::locale::global(loc_old);
|
||||||
|
}
|
||||||
|
|
||||||
#endif // FMT_STATIC_THOUSANDS_SEPARATOR
|
#endif // FMT_STATIC_THOUSANDS_SEPARATOR
|
||||||
|
18805
vendor/POCO/Data/SQLite/src/sqlite3.c
vendored
18805
vendor/POCO/Data/SQLite/src/sqlite3.c
vendored
File diff suppressed because it is too large
Load Diff
509
vendor/POCO/Data/SQLite/src/sqlite3.h
vendored
509
vendor/POCO/Data/SQLite/src/sqlite3.h
vendored
@ -43,7 +43,30 @@ extern "C" {
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Provide the ability to override linkage features of the interface.
|
** Facilitate override of interface linkage and calling conventions.
|
||||||
|
** Be aware that these macros may not be used within this particular
|
||||||
|
** translation of the amalgamation and its associated header file.
|
||||||
|
**
|
||||||
|
** The SQLITE_EXTERN and SQLITE_API macros are used to instruct the
|
||||||
|
** compiler that the target identifier should have external linkage.
|
||||||
|
**
|
||||||
|
** The SQLITE_CDECL macro is used to set the calling convention for
|
||||||
|
** public functions that accept a variable number of arguments.
|
||||||
|
**
|
||||||
|
** The SQLITE_APICALL macro is used to set the calling convention for
|
||||||
|
** public functions that accept a fixed number of arguments.
|
||||||
|
**
|
||||||
|
** The SQLITE_STDCALL macro is no longer used and is now deprecated.
|
||||||
|
**
|
||||||
|
** The SQLITE_CALLBACK macro is used to set the calling convention for
|
||||||
|
** function pointers.
|
||||||
|
**
|
||||||
|
** The SQLITE_SYSAPI macro is used to set the calling convention for
|
||||||
|
** functions provided by the operating system.
|
||||||
|
**
|
||||||
|
** Currently, the SQLITE_CDECL, SQLITE_APICALL, SQLITE_CALLBACK, and
|
||||||
|
** SQLITE_SYSAPI macros are used only when building for environments
|
||||||
|
** that require non-default calling conventions.
|
||||||
*/
|
*/
|
||||||
#ifndef SQLITE_EXTERN
|
#ifndef SQLITE_EXTERN
|
||||||
# define SQLITE_EXTERN extern
|
# define SQLITE_EXTERN extern
|
||||||
@ -123,9 +146,9 @@ extern "C" {
|
|||||||
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
|
||||||
** [sqlite_version()] and [sqlite_source_id()].
|
** [sqlite_version()] and [sqlite_source_id()].
|
||||||
*/
|
*/
|
||||||
#define SQLITE_VERSION "3.36.0"
|
#define SQLITE_VERSION "3.38.1"
|
||||||
#define SQLITE_VERSION_NUMBER 3036000
|
#define SQLITE_VERSION_NUMBER 3038001
|
||||||
#define SQLITE_SOURCE_ID "2021-06-18 18:36:39 5c9a6c06871cb9fe42814af9c039eb6da5427a6ec28f187af7ebfb62eafa66e5"
|
#define SQLITE_SOURCE_ID "2022-03-12 13:37:29 38c210fdd258658321c85ec9c01a072fda3ada94540e3239d29b34dc547a8cbc"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** CAPI3REF: Run-Time Library Version Numbers
|
** CAPI3REF: Run-Time Library Version Numbers
|
||||||
@ -537,12 +560,13 @@ SQLITE_API int sqlite3_exec(
|
|||||||
#define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8))
|
#define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8))
|
||||||
#define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT |(10<<8))
|
#define SQLITE_CONSTRAINT_ROWID (SQLITE_CONSTRAINT |(10<<8))
|
||||||
#define SQLITE_CONSTRAINT_PINNED (SQLITE_CONSTRAINT |(11<<8))
|
#define SQLITE_CONSTRAINT_PINNED (SQLITE_CONSTRAINT |(11<<8))
|
||||||
|
#define SQLITE_CONSTRAINT_DATATYPE (SQLITE_CONSTRAINT |(12<<8))
|
||||||
#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8))
|
#define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8))
|
||||||
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
|
#define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8))
|
||||||
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8))
|
#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8))
|
||||||
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8))
|
#define SQLITE_AUTH_USER (SQLITE_AUTH | (1<<8))
|
||||||
#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8))
|
#define SQLITE_OK_LOAD_PERMANENTLY (SQLITE_OK | (1<<8))
|
||||||
#define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8))
|
#define SQLITE_OK_SYMLINK (SQLITE_OK | (2<<8)) /* internal use only */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** CAPI3REF: Flags For File Open Operations
|
** CAPI3REF: Flags For File Open Operations
|
||||||
@ -550,6 +574,19 @@ SQLITE_API int sqlite3_exec(
|
|||||||
** These bit values are intended for use in the
|
** These bit values are intended for use in the
|
||||||
** 3rd parameter to the [sqlite3_open_v2()] interface and
|
** 3rd parameter to the [sqlite3_open_v2()] interface and
|
||||||
** in the 4th parameter to the [sqlite3_vfs.xOpen] method.
|
** in the 4th parameter to the [sqlite3_vfs.xOpen] method.
|
||||||
|
**
|
||||||
|
** Only those flags marked as "Ok for sqlite3_open_v2()" may be
|
||||||
|
** used as the third argument to the [sqlite3_open_v2()] interface.
|
||||||
|
** The other flags have historically been ignored by sqlite3_open_v2(),
|
||||||
|
** though future versions of SQLite might change so that an error is
|
||||||
|
** raised if any of the disallowed bits are passed into sqlite3_open_v2().
|
||||||
|
** Applications should not depend on the historical behavior.
|
||||||
|
**
|
||||||
|
** Note in particular that passing the SQLITE_OPEN_EXCLUSIVE flag into
|
||||||
|
** [sqlite3_open_v2()] does *not* cause the underlying database file
|
||||||
|
** to be opened using O_EXCL. Passing SQLITE_OPEN_EXCLUSIVE into
|
||||||
|
** [sqlite3_open_v2()] has historically be a no-op and might become an
|
||||||
|
** error in future versions of SQLite.
|
||||||
*/
|
*/
|
||||||
#define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */
|
#define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */
|
||||||
#define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */
|
#define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */
|
||||||
@ -572,6 +609,7 @@ SQLITE_API int sqlite3_exec(
|
|||||||
#define SQLITE_OPEN_PRIVATECACHE 0x00040000 /* Ok for sqlite3_open_v2() */
|
#define SQLITE_OPEN_PRIVATECACHE 0x00040000 /* Ok for sqlite3_open_v2() */
|
||||||
#define SQLITE_OPEN_WAL 0x00080000 /* VFS only */
|
#define SQLITE_OPEN_WAL 0x00080000 /* VFS only */
|
||||||
#define SQLITE_OPEN_NOFOLLOW 0x01000000 /* Ok for sqlite3_open_v2() */
|
#define SQLITE_OPEN_NOFOLLOW 0x01000000 /* Ok for sqlite3_open_v2() */
|
||||||
|
#define SQLITE_OPEN_EXRESCODE 0x02000000 /* Extended result codes */
|
||||||
|
|
||||||
/* Reserved: 0x00F00000 */
|
/* Reserved: 0x00F00000 */
|
||||||
/* Legacy compatibility: */
|
/* Legacy compatibility: */
|
||||||
@ -2464,11 +2502,14 @@ SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64);
|
|||||||
** CAPI3REF: Count The Number Of Rows Modified
|
** CAPI3REF: Count The Number Of Rows Modified
|
||||||
** METHOD: sqlite3
|
** METHOD: sqlite3
|
||||||
**
|
**
|
||||||
** ^This function returns the number of rows modified, inserted or
|
** ^These functions return the number of rows modified, inserted or
|
||||||
** deleted by the most recently completed INSERT, UPDATE or DELETE
|
** deleted by the most recently completed INSERT, UPDATE or DELETE
|
||||||
** statement on the database connection specified by the only parameter.
|
** statement on the database connection specified by the only parameter.
|
||||||
** ^Executing any other type of SQL statement does not modify the value
|
** The two functions are identical except for the type of the return value
|
||||||
** returned by this function.
|
** and that if the number of rows modified by the most recent INSERT, UPDATE
|
||||||
|
** or DELETE is greater than the maximum value supported by type "int", then
|
||||||
|
** the return value of sqlite3_changes() is undefined. ^Executing any other
|
||||||
|
** type of SQL statement does not modify the value returned by these functions.
|
||||||
**
|
**
|
||||||
** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are
|
** ^Only changes made directly by the INSERT, UPDATE or DELETE statement are
|
||||||
** considered - auxiliary changes caused by [CREATE TRIGGER | triggers],
|
** considered - auxiliary changes caused by [CREATE TRIGGER | triggers],
|
||||||
@ -2517,16 +2558,21 @@ SQLITE_API void sqlite3_set_last_insert_rowid(sqlite3*,sqlite3_int64);
|
|||||||
** </ul>
|
** </ul>
|
||||||
*/
|
*/
|
||||||
SQLITE_API int sqlite3_changes(sqlite3*);
|
SQLITE_API int sqlite3_changes(sqlite3*);
|
||||||
|
SQLITE_API sqlite3_int64 sqlite3_changes64(sqlite3*);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** CAPI3REF: Total Number Of Rows Modified
|
** CAPI3REF: Total Number Of Rows Modified
|
||||||
** METHOD: sqlite3
|
** METHOD: sqlite3
|
||||||
**
|
**
|
||||||
** ^This function returns the total number of rows inserted, modified or
|
** ^These functions return the total number of rows inserted, modified or
|
||||||
** deleted by all [INSERT], [UPDATE] or [DELETE] statements completed
|
** deleted by all [INSERT], [UPDATE] or [DELETE] statements completed
|
||||||
** since the database connection was opened, including those executed as
|
** since the database connection was opened, including those executed as
|
||||||
** part of trigger programs. ^Executing any other type of SQL statement
|
** part of trigger programs. The two functions are identical except for the
|
||||||
** does not affect the value returned by sqlite3_total_changes().
|
** type of the return value and that if the number of rows modified by the
|
||||||
|
** connection exceeds the maximum value supported by type "int", then
|
||||||
|
** the return value of sqlite3_total_changes() is undefined. ^Executing
|
||||||
|
** any other type of SQL statement does not affect the value returned by
|
||||||
|
** sqlite3_total_changes().
|
||||||
**
|
**
|
||||||
** ^Changes made as part of [foreign key actions] are included in the
|
** ^Changes made as part of [foreign key actions] are included in the
|
||||||
** count, but those made as part of REPLACE constraint resolution are
|
** count, but those made as part of REPLACE constraint resolution are
|
||||||
@ -2554,6 +2600,7 @@ SQLITE_API int sqlite3_changes(sqlite3*);
|
|||||||
** </ul>
|
** </ul>
|
||||||
*/
|
*/
|
||||||
SQLITE_API int sqlite3_total_changes(sqlite3*);
|
SQLITE_API int sqlite3_total_changes(sqlite3*);
|
||||||
|
SQLITE_API sqlite3_int64 sqlite3_total_changes64(sqlite3*);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** CAPI3REF: Interrupt A Long-Running Query
|
** CAPI3REF: Interrupt A Long-Running Query
|
||||||
@ -3383,6 +3430,14 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
|||||||
** the default shared cache setting provided by
|
** the default shared cache setting provided by
|
||||||
** [sqlite3_enable_shared_cache()].)^
|
** [sqlite3_enable_shared_cache()].)^
|
||||||
**
|
**
|
||||||
|
** [[OPEN_EXRESCODE]] ^(<dt>[SQLITE_OPEN_EXRESCODE]</dt>
|
||||||
|
** <dd>The database connection comes up in "extended result code mode".
|
||||||
|
** In other words, the database behaves has if
|
||||||
|
** [sqlite3_extended_result_codes(db,1)] where called on the database
|
||||||
|
** connection as soon as the connection is created. In addition to setting
|
||||||
|
** the extended result code mode, this flag also causes [sqlite3_open_v2()]
|
||||||
|
** to return an extended result code.</dd>
|
||||||
|
**
|
||||||
** [[OPEN_NOFOLLOW]] ^(<dt>[SQLITE_OPEN_NOFOLLOW]</dt>
|
** [[OPEN_NOFOLLOW]] ^(<dt>[SQLITE_OPEN_NOFOLLOW]</dt>
|
||||||
** <dd>The database filename is not allowed to be a symbolic link</dd>
|
** <dd>The database filename is not allowed to be a symbolic link</dd>
|
||||||
** </dl>)^
|
** </dl>)^
|
||||||
@ -3390,7 +3445,15 @@ SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*);
|
|||||||
** If the 3rd parameter to sqlite3_open_v2() is not one of the
|
** If the 3rd parameter to sqlite3_open_v2() is not one of the
|
||||||
** required combinations shown above optionally combined with other
|
** required combinations shown above optionally combined with other
|
||||||
** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits]
|
** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits]
|
||||||
** then the behavior is undefined.
|
** then the behavior is undefined. Historic versions of SQLite
|
||||||
|
** have silently ignored surplus bits in the flags parameter to
|
||||||
|
** sqlite3_open_v2(), however that behavior might not be carried through
|
||||||
|
** into future versions of SQLite and so applications should not rely
|
||||||
|
** upon it. Note in particular that the SQLITE_OPEN_EXCLUSIVE flag is a no-op
|
||||||
|
** for sqlite3_open_v2(). The SQLITE_OPEN_EXCLUSIVE does *not* cause
|
||||||
|
** the open to fail if the database already exists. The SQLITE_OPEN_EXCLUSIVE
|
||||||
|
** flag is intended for use by the [sqlite3_vfs|VFS interface] only, and not
|
||||||
|
** by sqlite3_open_v2().
|
||||||
**
|
**
|
||||||
** ^The fourth parameter to sqlite3_open_v2() is the name of the
|
** ^The fourth parameter to sqlite3_open_v2() is the name of the
|
||||||
** [sqlite3_vfs] object that defines the operating system interface that
|
** [sqlite3_vfs] object that defines the operating system interface that
|
||||||
@ -3761,13 +3824,14 @@ SQLITE_API void sqlite3_free_filename(char*);
|
|||||||
** sqlite3_extended_errcode() might change with each API call.
|
** sqlite3_extended_errcode() might change with each API call.
|
||||||
** Except, there are some interfaces that are guaranteed to never
|
** Except, there are some interfaces that are guaranteed to never
|
||||||
** change the value of the error code. The error-code preserving
|
** change the value of the error code. The error-code preserving
|
||||||
** interfaces are:
|
** interfaces include the following:
|
||||||
**
|
**
|
||||||
** <ul>
|
** <ul>
|
||||||
** <li> sqlite3_errcode()
|
** <li> sqlite3_errcode()
|
||||||
** <li> sqlite3_extended_errcode()
|
** <li> sqlite3_extended_errcode()
|
||||||
** <li> sqlite3_errmsg()
|
** <li> sqlite3_errmsg()
|
||||||
** <li> sqlite3_errmsg16()
|
** <li> sqlite3_errmsg16()
|
||||||
|
** <li> sqlite3_error_offset()
|
||||||
** </ul>
|
** </ul>
|
||||||
**
|
**
|
||||||
** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language
|
** ^The sqlite3_errmsg() and sqlite3_errmsg16() return English-language
|
||||||
@ -3782,6 +3846,13 @@ SQLITE_API void sqlite3_free_filename(char*);
|
|||||||
** ^(Memory to hold the error message string is managed internally
|
** ^(Memory to hold the error message string is managed internally
|
||||||
** and must not be freed by the application)^.
|
** and must not be freed by the application)^.
|
||||||
**
|
**
|
||||||
|
** ^If the most recent error references a specific token in the input
|
||||||
|
** SQL, the sqlite3_error_offset() interface returns the byte offset
|
||||||
|
** of the start of that token. ^The byte offset returned by
|
||||||
|
** sqlite3_error_offset() assumes that the input SQL is UTF8.
|
||||||
|
** ^If the most recent error does not reference a specific token in the input
|
||||||
|
** SQL, then the sqlite3_error_offset() function returns -1.
|
||||||
|
**
|
||||||
** When the serialized [threading mode] is in use, it might be the
|
** When the serialized [threading mode] is in use, it might be the
|
||||||
** case that a second error occurs on a separate thread in between
|
** case that a second error occurs on a separate thread in between
|
||||||
** the time of the first error and the call to these interfaces.
|
** the time of the first error and the call to these interfaces.
|
||||||
@ -3801,6 +3872,7 @@ SQLITE_API int sqlite3_extended_errcode(sqlite3 *db);
|
|||||||
SQLITE_API const char *sqlite3_errmsg(sqlite3*);
|
SQLITE_API const char *sqlite3_errmsg(sqlite3*);
|
||||||
SQLITE_API const void *sqlite3_errmsg16(sqlite3*);
|
SQLITE_API const void *sqlite3_errmsg16(sqlite3*);
|
||||||
SQLITE_API const char *sqlite3_errstr(int);
|
SQLITE_API const char *sqlite3_errstr(int);
|
||||||
|
SQLITE_API int sqlite3_error_offset(sqlite3 *db);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** CAPI3REF: Prepared Statement Object
|
** CAPI3REF: Prepared Statement Object
|
||||||
@ -4158,12 +4230,17 @@ SQLITE_API int sqlite3_prepare16_v3(
|
|||||||
** are managed by SQLite and are automatically freed when the prepared
|
** are managed by SQLite and are automatically freed when the prepared
|
||||||
** statement is finalized.
|
** statement is finalized.
|
||||||
** ^The string returned by sqlite3_expanded_sql(P), on the other hand,
|
** ^The string returned by sqlite3_expanded_sql(P), on the other hand,
|
||||||
** is obtained from [sqlite3_malloc()] and must be free by the application
|
** is obtained from [sqlite3_malloc()] and must be freed by the application
|
||||||
** by passing it to [sqlite3_free()].
|
** by passing it to [sqlite3_free()].
|
||||||
|
**
|
||||||
|
** ^The sqlite3_normalized_sql() interface is only available if
|
||||||
|
** the [SQLITE_ENABLE_NORMALIZE] compile-time option is defined.
|
||||||
*/
|
*/
|
||||||
SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
|
SQLITE_API const char *sqlite3_sql(sqlite3_stmt *pStmt);
|
||||||
SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt);
|
SQLITE_API char *sqlite3_expanded_sql(sqlite3_stmt *pStmt);
|
||||||
|
#ifdef SQLITE_ENABLE_NORMALIZE
|
||||||
SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt);
|
SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt);
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** CAPI3REF: Determine If An SQL Statement Writes The Database
|
** CAPI3REF: Determine If An SQL Statement Writes The Database
|
||||||
@ -4207,6 +4284,10 @@ SQLITE_API const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt);
|
|||||||
** be false. ^Similarly, a CREATE TABLE IF NOT EXISTS statement is a
|
** be false. ^Similarly, a CREATE TABLE IF NOT EXISTS statement is a
|
||||||
** read-only no-op if the table already exists, but
|
** read-only no-op if the table already exists, but
|
||||||
** sqlite3_stmt_readonly() still returns false for such a statement.
|
** sqlite3_stmt_readonly() still returns false for such a statement.
|
||||||
|
**
|
||||||
|
** ^If prepared statement X is an [EXPLAIN] or [EXPLAIN QUERY PLAN]
|
||||||
|
** statement, then sqlite3_stmt_readonly(X) returns the same value as
|
||||||
|
** if the EXPLAIN or EXPLAIN QUERY PLAN prefix were omitted.
|
||||||
*/
|
*/
|
||||||
SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
|
SQLITE_API int sqlite3_stmt_readonly(sqlite3_stmt *pStmt);
|
||||||
|
|
||||||
@ -4275,6 +4356,8 @@ SQLITE_API int sqlite3_stmt_busy(sqlite3_stmt*);
|
|||||||
**
|
**
|
||||||
** ^The sqlite3_value objects that are passed as parameters into the
|
** ^The sqlite3_value objects that are passed as parameters into the
|
||||||
** implementation of [application-defined SQL functions] are protected.
|
** implementation of [application-defined SQL functions] are protected.
|
||||||
|
** ^The sqlite3_value objects returned by [sqlite3_vtab_rhs_value()]
|
||||||
|
** are protected.
|
||||||
** ^The sqlite3_value object returned by
|
** ^The sqlite3_value object returned by
|
||||||
** [sqlite3_column_value()] is unprotected.
|
** [sqlite3_column_value()] is unprotected.
|
||||||
** Unprotected sqlite3_value objects may only be used as arguments
|
** Unprotected sqlite3_value objects may only be used as arguments
|
||||||
@ -4896,6 +4979,10 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
|
|||||||
** even empty strings, are always zero-terminated. ^The return
|
** even empty strings, are always zero-terminated. ^The return
|
||||||
** value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer.
|
** value from sqlite3_column_blob() for a zero-length BLOB is a NULL pointer.
|
||||||
**
|
**
|
||||||
|
** ^Strings returned by sqlite3_column_text16() always have the endianness
|
||||||
|
** which is native to the platform, regardless of the text encoding set
|
||||||
|
** for the database.
|
||||||
|
**
|
||||||
** <b>Warning:</b> ^The object returned by [sqlite3_column_value()] is an
|
** <b>Warning:</b> ^The object returned by [sqlite3_column_value()] is an
|
||||||
** [unprotected sqlite3_value] object. In a multithreaded environment,
|
** [unprotected sqlite3_value] object. In a multithreaded environment,
|
||||||
** an unprotected sqlite3_value object may only be used safely with
|
** an unprotected sqlite3_value object may only be used safely with
|
||||||
@ -4909,7 +4996,7 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
|
|||||||
** [application-defined SQL functions] or [virtual tables], not within
|
** [application-defined SQL functions] or [virtual tables], not within
|
||||||
** top-level application code.
|
** top-level application code.
|
||||||
**
|
**
|
||||||
** The these routines may attempt to convert the datatype of the result.
|
** These routines may attempt to convert the datatype of the result.
|
||||||
** ^For example, if the internal representation is FLOAT and a text result
|
** ^For example, if the internal representation is FLOAT and a text result
|
||||||
** is requested, [sqlite3_snprintf()] is used internally to perform the
|
** is requested, [sqlite3_snprintf()] is used internally to perform the
|
||||||
** conversion automatically. ^(The following table details the conversions
|
** conversion automatically. ^(The following table details the conversions
|
||||||
@ -4934,7 +5021,7 @@ SQLITE_API int sqlite3_data_count(sqlite3_stmt *pStmt);
|
|||||||
** <tr><td> TEXT <td> BLOB <td> No change
|
** <tr><td> TEXT <td> BLOB <td> No change
|
||||||
** <tr><td> BLOB <td> INTEGER <td> [CAST] to INTEGER
|
** <tr><td> BLOB <td> INTEGER <td> [CAST] to INTEGER
|
||||||
** <tr><td> BLOB <td> FLOAT <td> [CAST] to REAL
|
** <tr><td> BLOB <td> FLOAT <td> [CAST] to REAL
|
||||||
** <tr><td> BLOB <td> TEXT <td> Add a zero terminator if needed
|
** <tr><td> BLOB <td> TEXT <td> [CAST] to TEXT, ensure zero terminator
|
||||||
** </table>
|
** </table>
|
||||||
** </blockquote>)^
|
** </blockquote>)^
|
||||||
**
|
**
|
||||||
@ -6347,6 +6434,72 @@ SQLITE_API sqlite3_stmt *sqlite3_next_stmt(sqlite3 *pDb, sqlite3_stmt *pStmt);
|
|||||||
SQLITE_API void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
|
SQLITE_API void *sqlite3_commit_hook(sqlite3*, int(*)(void*), void*);
|
||||||
SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
|
SQLITE_API void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CAPI3REF: Autovacuum Compaction Amount Callback
|
||||||
|
** METHOD: sqlite3
|
||||||
|
**
|
||||||
|
** ^The sqlite3_autovacuum_pages(D,C,P,X) interface registers a callback
|
||||||
|
** function C that is invoked prior to each autovacuum of the database
|
||||||
|
** file. ^The callback is passed a copy of the generic data pointer (P),
|
||||||
|
** the schema-name of the attached database that is being autovacuumed,
|
||||||
|
** the the size of the database file in pages, the number of free pages,
|
||||||
|
** and the number of bytes per page, respectively. The callback should
|
||||||
|
** return the number of free pages that should be removed by the
|
||||||
|
** autovacuum. ^If the callback returns zero, then no autovacuum happens.
|
||||||
|
** ^If the value returned is greater than or equal to the number of
|
||||||
|
** free pages, then a complete autovacuum happens.
|
||||||
|
**
|
||||||
|
** <p>^If there are multiple ATTACH-ed database files that are being
|
||||||
|
** modified as part of a transaction commit, then the autovacuum pages
|
||||||
|
** callback is invoked separately for each file.
|
||||||
|
**
|
||||||
|
** <p><b>The callback is not reentrant.</b> The callback function should
|
||||||
|
** not attempt to invoke any other SQLite interface. If it does, bad
|
||||||
|
** things may happen, including segmentation faults and corrupt database
|
||||||
|
** files. The callback function should be a simple function that
|
||||||
|
** does some arithmetic on its input parameters and returns a result.
|
||||||
|
**
|
||||||
|
** ^The X parameter to sqlite3_autovacuum_pages(D,C,P,X) is an optional
|
||||||
|
** destructor for the P parameter. ^If X is not NULL, then X(P) is
|
||||||
|
** invoked whenever the database connection closes or when the callback
|
||||||
|
** is overwritten by another invocation of sqlite3_autovacuum_pages().
|
||||||
|
**
|
||||||
|
** <p>^There is only one autovacuum pages callback per database connection.
|
||||||
|
** ^Each call to the sqlite3_autovacuum_pages() interface overrides all
|
||||||
|
** previous invocations for that database connection. ^If the callback
|
||||||
|
** argument (C) to sqlite3_autovacuum_pages(D,C,P,X) is a NULL pointer,
|
||||||
|
** then the autovacuum steps callback is cancelled. The return value
|
||||||
|
** from sqlite3_autovacuum_pages() is normally SQLITE_OK, but might
|
||||||
|
** be some other error code if something goes wrong. The current
|
||||||
|
** implementation will only return SQLITE_OK or SQLITE_MISUSE, but other
|
||||||
|
** return codes might be added in future releases.
|
||||||
|
**
|
||||||
|
** <p>If no autovacuum pages callback is specified (the usual case) or
|
||||||
|
** a NULL pointer is provided for the callback,
|
||||||
|
** then the default behavior is to vacuum all free pages. So, in other
|
||||||
|
** words, the default behavior is the same as if the callback function
|
||||||
|
** were something like this:
|
||||||
|
**
|
||||||
|
** <blockquote><pre>
|
||||||
|
** unsigned int demonstration_autovac_pages_callback(
|
||||||
|
** void *pClientData,
|
||||||
|
** const char *zSchema,
|
||||||
|
** unsigned int nDbPage,
|
||||||
|
** unsigned int nFreePage,
|
||||||
|
** unsigned int nBytePerPage
|
||||||
|
** ){
|
||||||
|
** return nFreePage;
|
||||||
|
** }
|
||||||
|
** </pre></blockquote>
|
||||||
|
*/
|
||||||
|
SQLITE_API int sqlite3_autovacuum_pages(
|
||||||
|
sqlite3 *db,
|
||||||
|
unsigned int(*)(void*,const char*,unsigned int,unsigned int,unsigned int),
|
||||||
|
void*,
|
||||||
|
void(*)(void*)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** CAPI3REF: Data Change Notification Callbacks
|
** CAPI3REF: Data Change Notification Callbacks
|
||||||
** METHOD: sqlite3
|
** METHOD: sqlite3
|
||||||
@ -6988,8 +7141,38 @@ struct sqlite3_index_info {
|
|||||||
**
|
**
|
||||||
** These macros define the allowed values for the
|
** These macros define the allowed values for the
|
||||||
** [sqlite3_index_info].aConstraint[].op field. Each value represents
|
** [sqlite3_index_info].aConstraint[].op field. Each value represents
|
||||||
** an operator that is part of a constraint term in the wHERE clause of
|
** an operator that is part of a constraint term in the WHERE clause of
|
||||||
** a query that uses a [virtual table].
|
** a query that uses a [virtual table].
|
||||||
|
**
|
||||||
|
** ^The left-hand operand of the operator is given by the corresponding
|
||||||
|
** aConstraint[].iColumn field. ^An iColumn of -1 indicates the left-hand
|
||||||
|
** operand is the rowid.
|
||||||
|
** The SQLITE_INDEX_CONSTRAINT_LIMIT and SQLITE_INDEX_CONSTRAINT_OFFSET
|
||||||
|
** operators have no left-hand operand, and so for those operators the
|
||||||
|
** corresponding aConstraint[].iColumn is meaningless and should not be
|
||||||
|
** used.
|
||||||
|
**
|
||||||
|
** All operator values from SQLITE_INDEX_CONSTRAINT_FUNCTION through
|
||||||
|
** value 255 are reserved to represent functions that are overloaded
|
||||||
|
** by the [xFindFunction|xFindFunction method] of the virtual table
|
||||||
|
** implementation.
|
||||||
|
**
|
||||||
|
** The right-hand operands for each constraint might be accessible using
|
||||||
|
** the [sqlite3_vtab_rhs_value()] interface. Usually the right-hand
|
||||||
|
** operand is only available if it appears as a single constant literal
|
||||||
|
** in the input SQL. If the right-hand operand is another column or an
|
||||||
|
** expression (even a constant expression) or a parameter, then the
|
||||||
|
** sqlite3_vtab_rhs_value() probably will not be able to extract it.
|
||||||
|
** ^The SQLITE_INDEX_CONSTRAINT_ISNULL and
|
||||||
|
** SQLITE_INDEX_CONSTRAINT_ISNOTNULL operators have no right-hand operand
|
||||||
|
** and hence calls to sqlite3_vtab_rhs_value() for those operators will
|
||||||
|
** always return SQLITE_NOTFOUND.
|
||||||
|
**
|
||||||
|
** The collating sequence to be used for comparison can be found using
|
||||||
|
** the [sqlite3_vtab_collation()] interface. For most real-world virtual
|
||||||
|
** tables, the collating sequence of constraints does not matter (for example
|
||||||
|
** because the constraints are numeric) and so the sqlite3_vtab_collation()
|
||||||
|
** interface is no commonly needed.
|
||||||
*/
|
*/
|
||||||
#define SQLITE_INDEX_CONSTRAINT_EQ 2
|
#define SQLITE_INDEX_CONSTRAINT_EQ 2
|
||||||
#define SQLITE_INDEX_CONSTRAINT_GT 4
|
#define SQLITE_INDEX_CONSTRAINT_GT 4
|
||||||
@ -7005,6 +7188,8 @@ struct sqlite3_index_info {
|
|||||||
#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70
|
#define SQLITE_INDEX_CONSTRAINT_ISNOTNULL 70
|
||||||
#define SQLITE_INDEX_CONSTRAINT_ISNULL 71
|
#define SQLITE_INDEX_CONSTRAINT_ISNULL 71
|
||||||
#define SQLITE_INDEX_CONSTRAINT_IS 72
|
#define SQLITE_INDEX_CONSTRAINT_IS 72
|
||||||
|
#define SQLITE_INDEX_CONSTRAINT_LIMIT 73
|
||||||
|
#define SQLITE_INDEX_CONSTRAINT_OFFSET 74
|
||||||
#define SQLITE_INDEX_CONSTRAINT_FUNCTION 150
|
#define SQLITE_INDEX_CONSTRAINT_FUNCTION 150
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -7034,7 +7219,7 @@ struct sqlite3_index_info {
|
|||||||
** destructor.
|
** destructor.
|
||||||
**
|
**
|
||||||
** ^If the third parameter (the pointer to the sqlite3_module object) is
|
** ^If the third parameter (the pointer to the sqlite3_module object) is
|
||||||
** NULL then no new module is create and any existing modules with the
|
** NULL then no new module is created and any existing modules with the
|
||||||
** same name are dropped.
|
** same name are dropped.
|
||||||
**
|
**
|
||||||
** See also: [sqlite3_drop_modules()]
|
** See also: [sqlite3_drop_modules()]
|
||||||
@ -7810,7 +7995,8 @@ SQLITE_API int sqlite3_test_control(int op, ...);
|
|||||||
#define SQLITE_TESTCTRL_SEEK_COUNT 30
|
#define SQLITE_TESTCTRL_SEEK_COUNT 30
|
||||||
#define SQLITE_TESTCTRL_TRACEFLAGS 31
|
#define SQLITE_TESTCTRL_TRACEFLAGS 31
|
||||||
#define SQLITE_TESTCTRL_TUNE 32
|
#define SQLITE_TESTCTRL_TUNE 32
|
||||||
#define SQLITE_TESTCTRL_LAST 32 /* Largest TESTCTRL */
|
#define SQLITE_TESTCTRL_LOGEST 33
|
||||||
|
#define SQLITE_TESTCTRL_LAST 33 /* Largest TESTCTRL */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** CAPI3REF: SQL Keyword Checking
|
** CAPI3REF: SQL Keyword Checking
|
||||||
@ -8333,6 +8519,16 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
|
|||||||
** The counter is incremented on the first [sqlite3_step()] call of each
|
** The counter is incremented on the first [sqlite3_step()] call of each
|
||||||
** cycle.
|
** cycle.
|
||||||
**
|
**
|
||||||
|
** [[SQLITE_STMTSTATUS_FILTER_MISS]]
|
||||||
|
** [[SQLITE_STMTSTATUS_FILTER HIT]]
|
||||||
|
** <dt>SQLITE_STMTSTATUS_FILTER_HIT<br>
|
||||||
|
** SQLITE_STMTSTATUS_FILTER_MISS</dt>
|
||||||
|
** <dd>^SQLITE_STMTSTATUS_FILTER_HIT is the number of times that a join
|
||||||
|
** step was bypassed because a Bloom filter returned not-found. The
|
||||||
|
** corresponding SQLITE_STMTSTATUS_FILTER_MISS value is the number of
|
||||||
|
** times that the Bloom filter returned a find, and thus the join step
|
||||||
|
** had to be processed as normal.
|
||||||
|
**
|
||||||
** [[SQLITE_STMTSTATUS_MEMUSED]] <dt>SQLITE_STMTSTATUS_MEMUSED</dt>
|
** [[SQLITE_STMTSTATUS_MEMUSED]] <dt>SQLITE_STMTSTATUS_MEMUSED</dt>
|
||||||
** <dd>^This is the approximate number of bytes of heap memory
|
** <dd>^This is the approximate number of bytes of heap memory
|
||||||
** used to store the prepared statement. ^This value is not actually
|
** used to store the prepared statement. ^This value is not actually
|
||||||
@ -8347,6 +8543,8 @@ SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg);
|
|||||||
#define SQLITE_STMTSTATUS_VM_STEP 4
|
#define SQLITE_STMTSTATUS_VM_STEP 4
|
||||||
#define SQLITE_STMTSTATUS_REPREPARE 5
|
#define SQLITE_STMTSTATUS_REPREPARE 5
|
||||||
#define SQLITE_STMTSTATUS_RUN 6
|
#define SQLITE_STMTSTATUS_RUN 6
|
||||||
|
#define SQLITE_STMTSTATUS_FILTER_MISS 7
|
||||||
|
#define SQLITE_STMTSTATUS_FILTER_HIT 8
|
||||||
#define SQLITE_STMTSTATUS_MEMUSED 99
|
#define SQLITE_STMTSTATUS_MEMUSED 99
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -9010,8 +9208,9 @@ SQLITE_API void sqlite3_log(int iErrCode, const char *zFormat, ...);
|
|||||||
**
|
**
|
||||||
** A single database handle may have at most a single write-ahead log callback
|
** A single database handle may have at most a single write-ahead log callback
|
||||||
** registered at one time. ^Calling [sqlite3_wal_hook()] replaces any
|
** registered at one time. ^Calling [sqlite3_wal_hook()] replaces any
|
||||||
** previously registered write-ahead log callback. ^Note that the
|
** previously registered write-ahead log callback. ^The return value is
|
||||||
** [sqlite3_wal_autocheckpoint()] interface and the
|
** a copy of the third parameter from the previous call, if any, or 0.
|
||||||
|
** ^Note that the [sqlite3_wal_autocheckpoint()] interface and the
|
||||||
** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will
|
** [wal_autocheckpoint pragma] both invoke [sqlite3_wal_hook()] and will
|
||||||
** overwrite any prior [sqlite3_wal_hook()] settings.
|
** overwrite any prior [sqlite3_wal_hook()] settings.
|
||||||
*/
|
*/
|
||||||
@ -9314,19 +9513,269 @@ SQLITE_API int sqlite3_vtab_nochange(sqlite3_context*);
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
** CAPI3REF: Determine The Collation For a Virtual Table Constraint
|
** CAPI3REF: Determine The Collation For a Virtual Table Constraint
|
||||||
|
** METHOD: sqlite3_index_info
|
||||||
**
|
**
|
||||||
** This function may only be called from within a call to the [xBestIndex]
|
** This function may only be called from within a call to the [xBestIndex]
|
||||||
** method of a [virtual table].
|
** method of a [virtual table]. This function returns a pointer to a string
|
||||||
|
** that is the name of the appropriate collation sequence to use for text
|
||||||
|
** comparisons on the constraint identified by its arguments.
|
||||||
**
|
**
|
||||||
** The first argument must be the sqlite3_index_info object that is the
|
** The first argument must be the pointer to the [sqlite3_index_info] object
|
||||||
** first parameter to the xBestIndex() method. The second argument must be
|
** that is the first parameter to the xBestIndex() method. The second argument
|
||||||
** an index into the aConstraint[] array belonging to the sqlite3_index_info
|
** must be an index into the aConstraint[] array belonging to the
|
||||||
** structure passed to xBestIndex. This function returns a pointer to a buffer
|
** sqlite3_index_info structure passed to xBestIndex.
|
||||||
** containing the name of the collation sequence for the corresponding
|
**
|
||||||
** constraint.
|
** Important:
|
||||||
|
** The first parameter must be the same pointer that is passed into the
|
||||||
|
** xBestMethod() method. The first parameter may not be a pointer to a
|
||||||
|
** different [sqlite3_index_info] object, even an exact copy.
|
||||||
|
**
|
||||||
|
** The return value is computed as follows:
|
||||||
|
**
|
||||||
|
** <ol>
|
||||||
|
** <li><p> If the constraint comes from a WHERE clause expression that contains
|
||||||
|
** a [COLLATE operator], then the name of the collation specified by
|
||||||
|
** that COLLATE operator is returned.
|
||||||
|
** <li><p> If there is no COLLATE operator, but the column that is the subject
|
||||||
|
** of the constraint specifies an alternative collating sequence via
|
||||||
|
** a [COLLATE clause] on the column definition within the CREATE TABLE
|
||||||
|
** statement that was passed into [sqlite3_declare_vtab()], then the
|
||||||
|
** name of that alternative collating sequence is returned.
|
||||||
|
** <li><p> Otherwise, "BINARY" is returned.
|
||||||
|
** </ol>
|
||||||
*/
|
*/
|
||||||
SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
|
SQLITE_API SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CAPI3REF: Determine if a virtual table query is DISTINCT
|
||||||
|
** METHOD: sqlite3_index_info
|
||||||
|
**
|
||||||
|
** This API may only be used from within an [xBestIndex|xBestIndex method]
|
||||||
|
** of a [virtual table] implementation. The result of calling this
|
||||||
|
** interface from outside of xBestIndex() is undefined and probably harmful.
|
||||||
|
**
|
||||||
|
** ^The sqlite3_vtab_distinct() interface returns an integer that is
|
||||||
|
** either 0, 1, or 2. The integer returned by sqlite3_vtab_distinct()
|
||||||
|
** gives the virtual table additional information about how the query
|
||||||
|
** planner wants the output to be ordered. As long as the virtual table
|
||||||
|
** can meet the ordering requirements of the query planner, it may set
|
||||||
|
** the "orderByConsumed" flag.
|
||||||
|
**
|
||||||
|
** <ol><li value="0"><p>
|
||||||
|
** ^If the sqlite3_vtab_distinct() interface returns 0, that means
|
||||||
|
** that the query planner needs the virtual table to return all rows in the
|
||||||
|
** sort order defined by the "nOrderBy" and "aOrderBy" fields of the
|
||||||
|
** [sqlite3_index_info] object. This is the default expectation. If the
|
||||||
|
** virtual table outputs all rows in sorted order, then it is always safe for
|
||||||
|
** the xBestIndex method to set the "orderByConsumed" flag, regardless of
|
||||||
|
** the return value from sqlite3_vtab_distinct().
|
||||||
|
** <li value="1"><p>
|
||||||
|
** ^(If the sqlite3_vtab_distinct() interface returns 1, that means
|
||||||
|
** that the query planner does not need the rows to be returned in sorted order
|
||||||
|
** as long as all rows with the same values in all columns identified by the
|
||||||
|
** "aOrderBy" field are adjacent.)^ This mode is used when the query planner
|
||||||
|
** is doing a GROUP BY.
|
||||||
|
** <li value="2"><p>
|
||||||
|
** ^(If the sqlite3_vtab_distinct() interface returns 2, that means
|
||||||
|
** that the query planner does not need the rows returned in any particular
|
||||||
|
** order, as long as rows with the same values in all "aOrderBy" columns
|
||||||
|
** are adjacent.)^ ^(Furthermore, only a single row for each particular
|
||||||
|
** combination of values in the columns identified by the "aOrderBy" field
|
||||||
|
** needs to be returned.)^ ^It is always ok for two or more rows with the same
|
||||||
|
** values in all "aOrderBy" columns to be returned, as long as all such rows
|
||||||
|
** are adjacent. ^The virtual table may, if it chooses, omit extra rows
|
||||||
|
** that have the same value for all columns identified by "aOrderBy".
|
||||||
|
** ^However omitting the extra rows is optional.
|
||||||
|
** This mode is used for a DISTINCT query.
|
||||||
|
** </ol>
|
||||||
|
**
|
||||||
|
** ^For the purposes of comparing virtual table output values to see if the
|
||||||
|
** values are same value for sorting purposes, two NULL values are considered
|
||||||
|
** to be the same. In other words, the comparison operator is "IS"
|
||||||
|
** (or "IS NOT DISTINCT FROM") and not "==".
|
||||||
|
**
|
||||||
|
** If a virtual table implementation is unable to meet the requirements
|
||||||
|
** specified above, then it must not set the "orderByConsumed" flag in the
|
||||||
|
** [sqlite3_index_info] object or an incorrect answer may result.
|
||||||
|
**
|
||||||
|
** ^A virtual table implementation is always free to return rows in any order
|
||||||
|
** it wants, as long as the "orderByConsumed" flag is not set. ^When the
|
||||||
|
** the "orderByConsumed" flag is unset, the query planner will add extra
|
||||||
|
** [bytecode] to ensure that the final results returned by the SQL query are
|
||||||
|
** ordered correctly. The use of the "orderByConsumed" flag and the
|
||||||
|
** sqlite3_vtab_distinct() interface is merely an optimization. ^Careful
|
||||||
|
** use of the sqlite3_vtab_distinct() interface and the "orderByConsumed"
|
||||||
|
** flag might help queries against a virtual table to run faster. Being
|
||||||
|
** overly aggressive and setting the "orderByConsumed" flag when it is not
|
||||||
|
** valid to do so, on the other hand, might cause SQLite to return incorrect
|
||||||
|
** results.
|
||||||
|
*/
|
||||||
|
SQLITE_API int sqlite3_vtab_distinct(sqlite3_index_info*);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CAPI3REF: Identify and handle IN constraints in xBestIndex
|
||||||
|
**
|
||||||
|
** This interface may only be used from within an
|
||||||
|
** [xBestIndex|xBestIndex() method] of a [virtual table] implementation.
|
||||||
|
** The result of invoking this interface from any other context is
|
||||||
|
** undefined and probably harmful.
|
||||||
|
**
|
||||||
|
** ^(A constraint on a virtual table of the form
|
||||||
|
** "[IN operator|column IN (...)]" is
|
||||||
|
** communicated to the xBestIndex method as a
|
||||||
|
** [SQLITE_INDEX_CONSTRAINT_EQ] constraint.)^ If xBestIndex wants to use
|
||||||
|
** this constraint, it must set the corresponding
|
||||||
|
** aConstraintUsage[].argvIndex to a postive integer. ^(Then, under
|
||||||
|
** the usual mode of handling IN operators, SQLite generates [bytecode]
|
||||||
|
** that invokes the [xFilter|xFilter() method] once for each value
|
||||||
|
** on the right-hand side of the IN operator.)^ Thus the virtual table
|
||||||
|
** only sees a single value from the right-hand side of the IN operator
|
||||||
|
** at a time.
|
||||||
|
**
|
||||||
|
** In some cases, however, it would be advantageous for the virtual
|
||||||
|
** table to see all values on the right-hand of the IN operator all at
|
||||||
|
** once. The sqlite3_vtab_in() interfaces facilitates this in two ways:
|
||||||
|
**
|
||||||
|
** <ol>
|
||||||
|
** <li><p>
|
||||||
|
** ^A call to sqlite3_vtab_in(P,N,-1) will return true (non-zero)
|
||||||
|
** if and only if the [sqlite3_index_info|P->aConstraint][N] constraint
|
||||||
|
** is an [IN operator] that can be processed all at once. ^In other words,
|
||||||
|
** sqlite3_vtab_in() with -1 in the third argument is a mechanism
|
||||||
|
** by which the virtual table can ask SQLite if all-at-once processing
|
||||||
|
** of the IN operator is even possible.
|
||||||
|
**
|
||||||
|
** <li><p>
|
||||||
|
** ^A call to sqlite3_vtab_in(P,N,F) with F==1 or F==0 indicates
|
||||||
|
** to SQLite that the virtual table does or does not want to process
|
||||||
|
** the IN operator all-at-once, respectively. ^Thus when the third
|
||||||
|
** parameter (F) is non-negative, this interface is the mechanism by
|
||||||
|
** which the virtual table tells SQLite how it wants to process the
|
||||||
|
** IN operator.
|
||||||
|
** </ol>
|
||||||
|
**
|
||||||
|
** ^The sqlite3_vtab_in(P,N,F) interface can be invoked multiple times
|
||||||
|
** within the same xBestIndex method call. ^For any given P,N pair,
|
||||||
|
** the return value from sqlite3_vtab_in(P,N,F) will always be the same
|
||||||
|
** within the same xBestIndex call. ^If the interface returns true
|
||||||
|
** (non-zero), that means that the constraint is an IN operator
|
||||||
|
** that can be processed all-at-once. ^If the constraint is not an IN
|
||||||
|
** operator or cannot be processed all-at-once, then the interface returns
|
||||||
|
** false.
|
||||||
|
**
|
||||||
|
** ^(All-at-once processing of the IN operator is selected if both of the
|
||||||
|
** following conditions are met:
|
||||||
|
**
|
||||||
|
** <ol>
|
||||||
|
** <li><p> The P->aConstraintUsage[N].argvIndex value is set to a positive
|
||||||
|
** integer. This is how the virtual table tells SQLite that it wants to
|
||||||
|
** use the N-th constraint.
|
||||||
|
**
|
||||||
|
** <li><p> The last call to sqlite3_vtab_in(P,N,F) for which F was
|
||||||
|
** non-negative had F>=1.
|
||||||
|
** </ol>)^
|
||||||
|
**
|
||||||
|
** ^If either or both of the conditions above are false, then SQLite uses
|
||||||
|
** the traditional one-at-a-time processing strategy for the IN constraint.
|
||||||
|
** ^If both conditions are true, then the argvIndex-th parameter to the
|
||||||
|
** xFilter method will be an [sqlite3_value] that appears to be NULL,
|
||||||
|
** but which can be passed to [sqlite3_vtab_in_first()] and
|
||||||
|
** [sqlite3_vtab_in_next()] to find all values on the right-hand side
|
||||||
|
** of the IN constraint.
|
||||||
|
*/
|
||||||
|
SQLITE_API int sqlite3_vtab_in(sqlite3_index_info*, int iCons, int bHandle);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CAPI3REF: Find all elements on the right-hand side of an IN constraint.
|
||||||
|
**
|
||||||
|
** These interfaces are only useful from within the
|
||||||
|
** [xFilter|xFilter() method] of a [virtual table] implementation.
|
||||||
|
** The result of invoking these interfaces from any other context
|
||||||
|
** is undefined and probably harmful.
|
||||||
|
**
|
||||||
|
** The X parameter in a call to sqlite3_vtab_in_first(X,P) or
|
||||||
|
** sqlite3_vtab_in_next(X,P) must be one of the parameters to the
|
||||||
|
** xFilter method which invokes these routines, and specifically
|
||||||
|
** a parameter that was previously selected for all-at-once IN constraint
|
||||||
|
** processing use the [sqlite3_vtab_in()] interface in the
|
||||||
|
** [xBestIndex|xBestIndex method]. ^(If the X parameter is not
|
||||||
|
** an xFilter argument that was selected for all-at-once IN constraint
|
||||||
|
** processing, then these routines return [SQLITE_MISUSE])^ or perhaps
|
||||||
|
** exhibit some other undefined or harmful behavior.
|
||||||
|
**
|
||||||
|
** ^(Use these routines to access all values on the right-hand side
|
||||||
|
** of the IN constraint using code like the following:
|
||||||
|
**
|
||||||
|
** <blockquote><pre>
|
||||||
|
** for(rc=sqlite3_vtab_in_first(pList, &pVal);
|
||||||
|
** rc==SQLITE_OK && pVal
|
||||||
|
** rc=sqlite3_vtab_in_next(pList, &pVal)
|
||||||
|
** ){
|
||||||
|
** // do something with pVal
|
||||||
|
** }
|
||||||
|
** if( rc!=SQLITE_OK ){
|
||||||
|
** // an error has occurred
|
||||||
|
** }
|
||||||
|
** </pre></blockquote>)^
|
||||||
|
**
|
||||||
|
** ^On success, the sqlite3_vtab_in_first(X,P) and sqlite3_vtab_in_next(X,P)
|
||||||
|
** routines return SQLITE_OK and set *P to point to the first or next value
|
||||||
|
** on the RHS of the IN constraint. ^If there are no more values on the
|
||||||
|
** right hand side of the IN constraint, then *P is set to NULL and these
|
||||||
|
** routines return [SQLITE_DONE]. ^The return value might be
|
||||||
|
** some other value, such as SQLITE_NOMEM, in the event of a malfunction.
|
||||||
|
**
|
||||||
|
** The *ppOut values returned by these routines are only valid until the
|
||||||
|
** next call to either of these routines or until the end of the xFilter
|
||||||
|
** method from which these routines were called. If the virtual table
|
||||||
|
** implementation needs to retain the *ppOut values for longer, it must make
|
||||||
|
** copies. The *ppOut values are [protected sqlite3_value|protected].
|
||||||
|
*/
|
||||||
|
SQLITE_API int sqlite3_vtab_in_first(sqlite3_value *pVal, sqlite3_value **ppOut);
|
||||||
|
SQLITE_API int sqlite3_vtab_in_next(sqlite3_value *pVal, sqlite3_value **ppOut);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** CAPI3REF: Constraint values in xBestIndex()
|
||||||
|
** METHOD: sqlite3_index_info
|
||||||
|
**
|
||||||
|
** This API may only be used from within the [xBestIndex|xBestIndex method]
|
||||||
|
** of a [virtual table] implementation. The result of calling this interface
|
||||||
|
** from outside of an xBestIndex method are undefined and probably harmful.
|
||||||
|
**
|
||||||
|
** ^When the sqlite3_vtab_rhs_value(P,J,V) interface is invoked from within
|
||||||
|
** the [xBestIndex] method of a [virtual table] implementation, with P being
|
||||||
|
** a copy of the [sqlite3_index_info] object pointer passed into xBestIndex and
|
||||||
|
** J being a 0-based index into P->aConstraint[], then this routine
|
||||||
|
** attempts to set *V to the value of the right-hand operand of
|
||||||
|
** that constraint if the right-hand operand is known. ^If the
|
||||||
|
** right-hand operand is not known, then *V is set to a NULL pointer.
|
||||||
|
** ^The sqlite3_vtab_rhs_value(P,J,V) interface returns SQLITE_OK if
|
||||||
|
** and only if *V is set to a value. ^The sqlite3_vtab_rhs_value(P,J,V)
|
||||||
|
** inteface returns SQLITE_NOTFOUND if the right-hand side of the J-th
|
||||||
|
** constraint is not available. ^The sqlite3_vtab_rhs_value() interface
|
||||||
|
** can return an result code other than SQLITE_OK or SQLITE_NOTFOUND if
|
||||||
|
** something goes wrong.
|
||||||
|
**
|
||||||
|
** The sqlite3_vtab_rhs_value() interface is usually only successful if
|
||||||
|
** the right-hand operand of a constraint is a literal value in the original
|
||||||
|
** SQL statement. If the right-hand operand is an expression or a reference
|
||||||
|
** to some other column or a [host parameter], then sqlite3_vtab_rhs_value()
|
||||||
|
** will probably return [SQLITE_NOTFOUND].
|
||||||
|
**
|
||||||
|
** ^(Some constraints, such as [SQLITE_INDEX_CONSTRAINT_ISNULL] and
|
||||||
|
** [SQLITE_INDEX_CONSTRAINT_ISNOTNULL], have no right-hand operand. For such
|
||||||
|
** constraints, sqlite3_vtab_rhs_value() always returns SQLITE_NOTFOUND.)^
|
||||||
|
**
|
||||||
|
** ^The [sqlite3_value] object returned in *V is a protected sqlite3_value
|
||||||
|
** and remains valid for the duration of the xBestIndex method call.
|
||||||
|
** ^When xBestIndex returns, the sqlite3_value object returned by
|
||||||
|
** sqlite3_vtab_rhs_value() is automatically deallocated.
|
||||||
|
**
|
||||||
|
** The "_rhs_" in the name of this routine is an abbreviation for
|
||||||
|
** "Right-Hand Side".
|
||||||
|
*/
|
||||||
|
SQLITE_API int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **ppVal);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** CAPI3REF: Conflict resolution modes
|
** CAPI3REF: Conflict resolution modes
|
||||||
** KEYWORDS: {conflict resolution mode}
|
** KEYWORDS: {conflict resolution mode}
|
||||||
@ -9878,6 +10327,10 @@ SQLITE_API unsigned char *sqlite3_serialize(
|
|||||||
** database is currently in a read transaction or is involved in a backup
|
** database is currently in a read transaction or is involved in a backup
|
||||||
** operation.
|
** operation.
|
||||||
**
|
**
|
||||||
|
** It is not possible to deserialized into the TEMP database. If the
|
||||||
|
** S argument to sqlite3_deserialize(D,S,P,N,M,F) is "temp" then the
|
||||||
|
** function returns SQLITE_ERROR.
|
||||||
|
**
|
||||||
** If sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the
|
** If sqlite3_deserialize(D,S,P,N,M,F) fails for any reason and if the
|
||||||
** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then
|
** SQLITE_DESERIALIZE_FREEONCLOSE bit is set in argument F, then
|
||||||
** [sqlite3_free()] is invoked on argument P prior to returning.
|
** [sqlite3_free()] is invoked on argument P prior to returning.
|
||||||
|
Loading…
Reference in New Issue
Block a user