Update {fmt} to 7.1.3

This commit is contained in:
relesgoe 2020-12-13 19:57:35 -08:00
parent fd0979cf3a
commit 71f7b1f518
95 changed files with 10973 additions and 8475 deletions

View file

@ -1,10 +1,8 @@
cmake_minimum_required(VERSION 3.1.0)
cmake_minimum_required(VERSION 3.1...3.18)
# Use newer policies if available, up to most recent tested version of CMake.
if(${CMAKE_VERSION} VERSION_LESS 3.11)
# Fallback for using newer policies on CMake <3.12.
if(${CMAKE_VERSION} VERSION_LESS 3.12)
cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION})
else()
cmake_policy(VERSION 3.11)
endif()
# Determine if fmt is built as a subproject (using add_subdirectory)
@ -55,8 +53,8 @@ endif ()
project(FMT CXX)
include(GNUInstallDirs)
set_verbose(FMT_INC_DIR ${CMAKE_INSTALL_INCLUDEDIR} CACHE STRING
"Installation directory for include files, a relative path "
"that will be joined to ${CMAKE_INSTALL_PREFIX}, or an arbitrary absolute path.")
"Installation directory for include files, a relative path that "
"will be joined with ${CMAKE_INSTALL_PREFIX} or an absolute path.")
option(FMT_PEDANTIC "Enable extra warnings and expensive tests." OFF)
option(FMT_WERROR "Halt the compilation with an error on compiler warnings."
@ -109,11 +107,11 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
-Wold-style-cast -Wundef
-Wredundant-decls -Wwrite-strings -Wpointer-arith
-Wcast-qual -Wformat=2 -Wmissing-include-dirs
-Wcast-align -Wnon-virtual-dtor
-Wcast-align
-Wctor-dtor-privacy -Wdisabled-optimization
-Winvalid-pch -Woverloaded-virtual
-Wconversion -Wswitch-enum
-Wno-ctor-dtor-privacy -Wno-format-nonliteral -Wno-shadow)
-Wconversion -Wswitch-enum -Wundef
-Wno-ctor-dtor-privacy -Wno-format-nonliteral)
if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6)
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wnoexcept
-Wno-dangling-else -Wno-unused-local-typedefs)
@ -131,8 +129,8 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
endif ()
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -pedantic -Wconversion
-Wno-sign-conversion -Wdeprecated -Wweak-vtables)
set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -pedantic -Wconversion -Wundef
-Wdeprecated -Wweak-vtables)
check_cxx_compiler_flag(-Wzero-as-null-pointer-constant HAS_NULLPTR_WARNING)
if (HAS_NULLPTR_WARNING)
set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS}
@ -201,7 +199,10 @@ if (HAVE_STRTOD_L)
endif ()
if (MINGW)
target_compile_options(fmt PUBLIC "-Wa,-mbig-obj")
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)
@ -231,7 +232,8 @@ if (CMAKE_BUILD_TYPE STREQUAL "Debug")
endif ()
if (BUILD_SHARED_LIBS)
if (UNIX AND NOT APPLE AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "SunOS" AND NOT EMSCRIPTEN)
if (UNIX AND NOT APPLE AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "SunOS" AND
NOT EMSCRIPTEN)
# Fix rpmlint warning:
# unused-direct-shlib-dependency /usr/lib/libformat.so.1.1.0 /lib/libm.so.6.
target_link_libraries(fmt -Wl,--as-needed)
@ -256,20 +258,22 @@ target_include_directories(fmt-header-only INTERFACE
if (FMT_INSTALL)
include(CMakePackageConfigHelpers)
set_verbose(FMT_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/fmt CACHE STRING
"Installation directory for cmake files, a relative path "
"that will be joined to ${CMAKE_INSTALL_PREFIX}, or an arbitrary absolute path.")
"Installation directory for cmake files, a relative path that "
"will be joined with ${CMAKE_INSTALL_PREFIX} or an absolute "
"path.")
set(version_config ${PROJECT_BINARY_DIR}/fmt-config-version.cmake)
set(project_config ${PROJECT_BINARY_DIR}/fmt-config.cmake)
set(pkgconfig ${PROJECT_BINARY_DIR}/fmt.pc)
set(targets_export_name fmt-targets)
set_verbose(FMT_LIB_DIR ${CMAKE_INSTALL_LIBDIR} CACHE STRING
"Installation directory for libraries, a relative path "
"that will be joined to ${CMAKE_INSTALL_PREFIX}, or an arbitrary absolute path.")
"Installation directory for libraries, a relative path that "
"will be joined to ${CMAKE_INSTALL_PREFIX} or an absolute path.")
set_verbose(FMT_PKGCONFIG_DIR ${CMAKE_INSTALL_LIBDIR}/pkgconfig CACHE PATH
"Installation directory for pkgconfig (.pc) files, a relative path "
"that will be joined to ${CMAKE_INSTALL_PREFIX}, or an arbitrary absolute path.")
"Installation directory for pkgconfig (.pc) files, a relative "
"path that will be joined with ${CMAKE_INSTALL_PREFIX} or an "
"absolute path.")
# Generate the version, config and target files into the build directory.
write_basic_package_version_file(
@ -326,6 +330,12 @@ endif ()
# Control fuzzing independent of the unit tests.
if (FMT_FUZZ)
add_subdirectory(test/fuzzing)
# The FMT_FUZZ macro is used to prevent resource exhaustion in fuzzing
# mode and make fuzzing practically possible. It is similar to
# FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION but uses a different name to
# avoid interfering with fuzzing of projects that use {fmt}.
# See also https://llvm.org/docs/LibFuzzer.html#fuzzer-friendly-build-mode.
target_compile_definitions(fmt PUBLIC FMT_FUZZ)
endif ()

View file

@ -14,4 +14,7 @@ exceptions:
* snake_case should be used instead of UpperCamelCase for function and type
names
All documentation must adhere to the [Google Developer Documentation Style
Guide](https://developers.google.com/style).
Thanks for contributing!

View file

@ -1,3 +1,428 @@
7.1.3 - 2020-11-24
------------------
* Fixed handling of buffer boundaries in ``format_to_n``
(`#1996 <https://github.com/fmtlib/fmt/issues/1996>`_,
`#2029 <https://github.com/fmtlib/fmt/issues/2029>`_).
* Fixed linkage errors when linking with a shared library
(`#2011 <https://github.com/fmtlib/fmt/issues/2011>`_).
* Reintroduced ostream support to range formatters
(`#2014 <https://github.com/fmtlib/fmt/issues/2014>`_).
* Worked around an issue with mixing std versions in gcc
(`#2017 <https://github.com/fmtlib/fmt/issues/2017>`_).
7.1.2 - 2020-11-04
------------------
* Fixed floating point formatting with large precision
(`#1976 <https://github.com/fmtlib/fmt/issues/1976>`_).
7.1.1 - 2020-11-01
------------------
* Fixed ABI compatibility with 7.0.x
(`#1961 <https://github.com/fmtlib/fmt/issues/1961>`_).
* Added the ``FMT_ARM_ABI_COMPATIBILITY`` macro to work around ABI
incompatibility between GCC and Clang on ARM
(`#1919 <https://github.com/fmtlib/fmt/issues/1919>`_).
* Worked around a SFINAE bug in GCC 8
(`#1957 <https://github.com/fmtlib/fmt/issues/1957>`_).
* Fixed linkage errors when building with GCC's LTO
(`#1955 <https://github.com/fmtlib/fmt/issues/1955>`_).
* Fixed a compilation error when building without ``__builtin_clz`` or equivalent
(`#1968 <https://github.com/fmtlib/fmt/pull/1968>`_).
Thanks `@tohammer (Tobias Hammer) <https://github.com/tohammer>`_.
* Fixed a sign conversion warning
(`#1964 <https://github.com/fmtlib/fmt/pull/1964>`_).
Thanks `@OptoCloud <https://github.com/OptoCloud>`_.
7.1.0 - 2020-10-25
------------------
* Switched from `Grisu3
<https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf>`_
to `Dragonbox <https://github.com/jk-jeon/dragonbox>`_ for the default
floating-point formatting which gives the shortest decimal representation
with round-trip guarantee and correct rounding
(`#1882 <https://github.com/fmtlib/fmt/pull/1882>`_,
`#1887 <https://github.com/fmtlib/fmt/pull/1887>`_,
`#1894 <https://github.com/fmtlib/fmt/pull/1894>`_). This makes {fmt} up to
20-30x faster than common implementations of ``std::ostringstream`` and
``sprintf`` on `dtoa-benchmark <https://github.com/fmtlib/dtoa-benchmark>`_
and faster than double-conversion and Ryū:
.. image:: https://user-images.githubusercontent.com/576385/
95684665-11719600-0ba8-11eb-8e5b-972ff4e49428.png
It is possible to get even better performance at the cost of larger binary
size by compiling with the ``FMT_USE_FULL_CACHE_DRAGONBOX`` macro set to 1.
Thanks `@jk-jeon (Junekey Jeon) <https://github.com/jk-jeon>`_.
* Added an experimental unsynchronized file output API which, together with
`format string compilation <https://fmt.dev/latest/api.html#compile-api>`_,
can give `5-9 times speed up compared to fprintf
<https://www.zverovich.net/2020/08/04/optimal-file-buffer-size.html>`_
on common platforms (`godbolt <https://godbolt.org/z/nsTcG8>`__):
.. code:: c++
#include <fmt/os.h>
int main() {
auto f = fmt::output_file("guide");
f.print("The answer is {}.", 42);
}
* Added a formatter for ``std::chrono::time_point<system_clock>``
(`#1819 <https://github.com/fmtlib/fmt/issues/1819>`_,
`#1837 <https://github.com/fmtlib/fmt/pull/1837>`_). For example
(`godbolt <https://godbolt.org/z/c4M6fh>`__):
.. code:: c++
#include <fmt/chrono.h>
int main() {
auto now = std::chrono::system_clock::now();
fmt::print("The time is {:%H:%M:%S}.\n", now);
}
Thanks `@adamburgess (Adam Burgess) <https://github.com/adamburgess>`_.
* Added support for ranges with non-const ``begin``/``end`` to ``fmt::join``
(`#1784 <https://github.com/fmtlib/fmt/issues/1784>`_,
`#1786 <https://github.com/fmtlib/fmt/pull/1786>`_). For example
(`godbolt <https://godbolt.org/z/jP63Tv>`__):
.. code:: c++
#include <fmt/ranges.h>
#include <range/v3/view/filter.hpp>
int main() {
using std::literals::string_literals::operator""s;
auto strs = std::array{"a"s, "bb"s, "ccc"s};
auto range = strs | ranges::views::filter(
[] (const std::string &x) { return x.size() != 2; }
);
fmt::print("{}\n", fmt::join(range, ""));
}
prints "accc".
Thanks `@tonyelewis (Tony E Lewis) <https://github.com/tonyelewis>`_.
* Added a ``memory_buffer::append`` overload that takes a range
(`#1806 <https://github.com/fmtlib/fmt/pull/1806>`_).
Thanks `@BRevzin (Barry Revzin) <https://github.com/BRevzin>`_.
* Improved handling of single code units in ``FMT_COMPILE``. For example:
.. code:: c++
#include <fmt/compile.h>
char* f(char* buf) {
return fmt::format_to(buf, FMT_COMPILE("x{}"), 42);
}
compiles to just (`godbolt <https://godbolt.org/z/5vncz3>`__):
.. code:: asm
_Z1fPc:
movb $120, (%rdi)
xorl %edx, %edx
cmpl $42, _ZN3fmt2v76detail10basic_dataIvE23zero_or_powers_of_10_32E+8(%rip)
movl $3, %eax
seta %dl
subl %edx, %eax
movzwl _ZN3fmt2v76detail10basic_dataIvE6digitsE+84(%rip), %edx
cltq
addq %rdi, %rax
movw %dx, -2(%rax)
ret
Here a single ``mov`` instruction writes ``'x'`` (``$120``) to the output
buffer.
* Added dynamic width support to format string compilation
(`#1809 <https://github.com/fmtlib/fmt/issues/1809>`_).
* Improved error reporting for unformattable types: now you'll get the type name
directly in the error message instead of the note:
.. code:: c++
#include <fmt/core.h>
struct how_about_no {};
int main() {
fmt::print("{}", how_about_no());
}
Error (`godbolt <https://godbolt.org/z/GoxM4e>`__):
``fmt/core.h:1438:3: error: static_assert failed due to requirement
'fmt::v7::formattable<how_about_no>()' "Cannot format an argument.
To make type T formattable provide a formatter<T> specialization:
https://fmt.dev/latest/api.html#udt"
...``
* Added the `make_args_checked <https://fmt.dev/7.1.0/api.html#argument-lists>`_
function template that allows you to write formatting functions with
compile-time format string checks and avoid binary code bloat
(`godbolt <https://godbolt.org/z/PEf9qr>`__):
.. code:: c++
void vlog(const char* file, int line, fmt::string_view format,
fmt::format_args args) {
fmt::print("{}: {}: ", file, line);
fmt::vprint(format, args);
}
template <typename S, typename... Args>
void log(const char* file, int line, const S& format, Args&&... args) {
vlog(file, line, format,
fmt::make_args_checked<Args...>(format, args...));
}
#define MY_LOG(format, ...) \
log(__FILE__, __LINE__, FMT_STRING(format), __VA_ARGS__)
MY_LOG("invalid squishiness: {}", 42);
* Replaced ``snprintf`` fallback with a faster internal IEEE 754 ``float`` and
``double`` formatter for arbitrary precision. For example
(`godbolt <https://godbolt.org/z/dPhWvj>`__):
.. code:: c++
#include <fmt/core.h>
int main() {
fmt::print("{:.500}\n", 4.9406564584124654E-324);
}
prints
``4.9406564584124654417656879286822137236505980261432476442558568250067550727020875186529983636163599237979656469544571773092665671035593979639877479601078187812630071319031140452784581716784898210368871863605699873072305000638740915356498438731247339727316961514003171538539807412623856559117102665855668676818703956031062493194527159149245532930545654440112748012970999954193198940908041656332452475714786901472678015935523861155013480352649347201937902681071074917033322268447533357208324319360923829e-324``.
* Made ``format_to_n`` and ``formatted_size`` part of the `core API
<https://fmt.dev/latest/api.html#core-api>`__
(`godbolt <https://godbolt.org/z/sPjY1K>`__):
.. code:: c++
#include <fmt/core.h>
int main() {
char buffer[10];
auto result = fmt::format_to_n(buffer, sizeof(buffer), "{}", 42);
}
* Added ``fmt::format_to_n`` overload with format string compilation
(`#1764 <https://github.com/fmtlib/fmt/issues/1764>`_,
`#1767 <https://github.com/fmtlib/fmt/pull/1767>`_,
`#1869 <https://github.com/fmtlib/fmt/pull/1869>`_). For example
(`godbolt <https://godbolt.org/z/93h86q>`__):
.. code:: c++
#include <fmt/compile.h>
int main() {
char buffer[8];
fmt::format_to_n(buffer, sizeof(buffer), FMT_COMPILE("{}"), 42);
}
Thanks `@Kurkin (Dmitry Kurkin) <https://github.com/Kurkin>`_,
`@alexezeder (Alexey Ochapov) <https://github.com/alexezeder>`_.
* Added ``fmt::format_to`` overload that take ``text_style``
(`#1593 <https://github.com/fmtlib/fmt/issues/1593>`_,
`#1842 <https://github.com/fmtlib/fmt/issues/1842>`_,
`#1843 <https://github.com/fmtlib/fmt/pull/1843>`_). For example
(`godbolt <https://godbolt.org/z/91153r>`__):
.. code:: c++
#include <fmt/color.h>
int main() {
std::string out;
fmt::format_to(std::back_inserter(out),
fmt::emphasis::bold | fg(fmt::color::red),
"The answer is {}.", 42);
}
Thanks `@Naios (Denis Blank) <https://github.com/Naios>`_.
* Made the ``#`` specifier emit trailing zeros in addition to the decimal point
(`#1797 <https://github.com/fmtlib/fmt/issues/1797>`_). For example
(`godbolt <https://godbolt.org/z/bhdcW9>`__):
.. code:: c++
#include <fmt/core.h>
int main() {
fmt::print("{:#.2g}", 0.5);
}
prints ``0.50``.
* Changed the default floating point format to not include ``.0`` for
consistency with ``std::format`` and ``std::to_chars``
(`#1893 <https://github.com/fmtlib/fmt/issues/1893>`_,
`#1943 <https://github.com/fmtlib/fmt/issues/1943>`_). It is possible to get
the decimal point and trailing zero with the ``#`` specifier.
* Fixed an issue with floating-point formatting that could result in addition of
a non-significant trailing zero in rare cases e.g. ``1.00e-34`` instead of
``1.0e-34`` (`#1873 <https://github.com/fmtlib/fmt/issues/1873>`_,
`#1917 <https://github.com/fmtlib/fmt/issues/1917>`_).
* Made ``fmt::to_string`` fallback on ``ostream`` insertion operator if
the ``formatter`` specialization is not provided
(`#1815 <https://github.com/fmtlib/fmt/issues/1815>`_,
`#1829 <https://github.com/fmtlib/fmt/pull/1829>`_).
Thanks `@alexezeder (Alexey Ochapov) <https://github.com/alexezeder>`_.
* Added support for the append mode to the experimental file API and
improved ``fcntl.h`` detection.
(`#1847 <https://github.com/fmtlib/fmt/pull/1847>`_,
`#1848 <https://github.com/fmtlib/fmt/pull/1848>`_).
Thanks `@t-wiser <https://github.com/t-wiser>`_.
* Fixed handling of types that have both an implicit conversion operator and
an overloaded ``ostream`` insertion operator
(`#1766 <https://github.com/fmtlib/fmt/issues/1766>`_).
* Fixed a slicing issue in an internal iterator type
(`#1822 <https://github.com/fmtlib/fmt/pull/1822>`_).
Thanks `@BRevzin (Barry Revzin) <https://github.com/BRevzin>`_.
* Fixed an issue in locale-specific integer formatting
(`#1927 <https://github.com/fmtlib/fmt/issues/1927>`_).
* Fixed handling of exotic code unit types
(`#1870 <https://github.com/fmtlib/fmt/issues/1870>`_,
`#1932 <https://github.com/fmtlib/fmt/issues/1932>`_).
* Improved ``FMT_ALWAYS_INLINE``
(`#1878 <https://github.com/fmtlib/fmt/pull/1878>`_).
Thanks `@jk-jeon (Junekey Jeon) <https://github.com/jk-jeon>`_.
* Removed dependency on ``windows.h``
(`#1900 <https://github.com/fmtlib/fmt/pull/1900>`_).
Thanks `@bernd5 (Bernd Baumanns) <https://github.com/bernd5>`_.
* Optimized counting of decimal digits on MSVC
(`#1890 <https://github.com/fmtlib/fmt/pull/1890>`_).
Thanks `@mwinterb <https://github.com/mwinterb>`_.
* Improved documentation
(`#1772 <https://github.com/fmtlib/fmt/issues/1772>`_,
`#1775 <https://github.com/fmtlib/fmt/pull/1775>`_,
`#1792 <https://github.com/fmtlib/fmt/pull/1792>`_,
`#1838 <https://github.com/fmtlib/fmt/pull/1838>`_,
`#1888 <https://github.com/fmtlib/fmt/pull/1888>`_,
`#1918 <https://github.com/fmtlib/fmt/pull/1918>`_,
`#1939 <https://github.com/fmtlib/fmt/pull/1939>`_).
Thanks `@leolchat (Léonard Gérard) <https://github.com/leolchat>`_,
`@pepsiman (Malcolm Parsons) <https://github.com/pepsiman>`_,
`@Klaim (Joël Lamotte) <https://github.com/Klaim>`_,
`@ravijanjam (Ravi J) <https://github.com/ravijanjam>`_,
`@francesco-st <https://github.com/francesco-st>`_,
`@udnaan (Adnan) <https://github.com/udnaan>`_.
* Added the ``FMT_REDUCE_INT_INSTANTIATIONS`` CMake option that reduces the
binary code size at the cost of some integer formatting performance. This can
be useful for extremely memory-constrained embedded systems
(`#1778 <https://github.com/fmtlib/fmt/issues/1778>`_,
`#1781 <https://github.com/fmtlib/fmt/pull/1781>`_).
Thanks `@kammce (Khalil Estell) <https://github.com/kammce>`_.
* Added the ``FMT_USE_INLINE_NAMESPACES`` macro to control usage of inline
namespaces (`#1945 <https://github.com/fmtlib/fmt/pull/1945>`_).
Thanks `@darklukee <https://github.com/darklukee>`_.
* Improved build configuration
(`#1760 <https://github.com/fmtlib/fmt/pull/1760>`_,
`#1770 <https://github.com/fmtlib/fmt/pull/1770>`_,
`#1779 <https://github.com/fmtlib/fmt/issues/1779>`_,
`#1783 <https://github.com/fmtlib/fmt/pull/1783>`_,
`#1823 <https://github.com/fmtlib/fmt/pull/1823>`_).
Thanks `@dvetutnev (Dmitriy Vetutnev) <https://github.com/dvetutnev>`_,
`@xvitaly (Vitaly Zaitsev) <https://github.com/xvitaly>`_,
`@tambry (Raul Tambre) <https://github.com/tambry>`_,
`@medithe <https://github.com/medithe>`_,
`@martinwuehrer (Martin Wührer) <https://github.com/martinwuehrer>`_.
* Fixed various warnings and compilation issues
(`#1790 <https://github.com/fmtlib/fmt/pull/1790>`_,
`#1802 <https://github.com/fmtlib/fmt/pull/1802>`_,
`#1808 <https://github.com/fmtlib/fmt/pull/1808>`_,
`#1810 <https://github.com/fmtlib/fmt/issues/1810>`_,
`#1811 <https://github.com/fmtlib/fmt/issues/1811>`_,
`#1812 <https://github.com/fmtlib/fmt/pull/1812>`_,
`#1814 <https://github.com/fmtlib/fmt/pull/1814>`_,
`#1816 <https://github.com/fmtlib/fmt/pull/1816>`_,
`#1817 <https://github.com/fmtlib/fmt/pull/1817>`_,
`#1818 <https://github.com/fmtlib/fmt/pull/1818>`_,
`#1825 <https://github.com/fmtlib/fmt/issues/1825>`_,
`#1836 <https://github.com/fmtlib/fmt/pull/1836>`_,
`#1855 <https://github.com/fmtlib/fmt/pull/1855>`_,
`#1856 <https://github.com/fmtlib/fmt/pull/1856>`_,
`#1860 <https://github.com/fmtlib/fmt/pull/1860>`_,
`#1877 <https://github.com/fmtlib/fmt/pull/1877>`_,
`#1879 <https://github.com/fmtlib/fmt/pull/1879>`_,
`#1880 <https://github.com/fmtlib/fmt/pull/1880>`_,
`#1896 <https://github.com/fmtlib/fmt/issues/1896>`_,
`#1897 <https://github.com/fmtlib/fmt/pull/1897>`_,
`#1898 <https://github.com/fmtlib/fmt/pull/1898>`_,
`#1904 <https://github.com/fmtlib/fmt/issues/1904>`_,
`#1908 <https://github.com/fmtlib/fmt/pull/1908>`_,
`#1911 <https://github.com/fmtlib/fmt/issues/1911>`_,
`#1912 <https://github.com/fmtlib/fmt/issues/1912>`_,
`#1928 <https://github.com/fmtlib/fmt/issues/1928>`_,
`#1929 <https://github.com/fmtlib/fmt/pull/1929>`_,
`#1935 <https://github.com/fmtlib/fmt/issues/1935>`_
`#1937 <https://github.com/fmtlib/fmt/pull/1937>`_,
`#1942 <https://github.com/fmtlib/fmt/pull/1942>`_,
`#1949 <https://github.com/fmtlib/fmt/issues/1949>`_).
Thanks `@TheQwertiest <https://github.com/TheQwertiest>`_,
`@medithe <https://github.com/medithe>`_,
`@martinwuehrer (Martin Wührer) <https://github.com/martinwuehrer>`_,
`@n16h7hunt3r <https://github.com/n16h7hunt3r>`_,
`@Othereum (Seokjin Lee) <https://github.com/Othereum>`_,
`@gsjaardema (Greg Sjaardema) <https://github.com/gsjaardema>`_,
`@AlexanderLanin (Alexander Lanin) <https://github.com/AlexanderLanin>`_,
`@gcerretani (Giovanni Cerretani) <https://github.com/gcerretani>`_,
`@chronoxor (Ivan Shynkarenka) <https://github.com/chronoxor>`_,
`@noizefloor (Jan Schwers) <https://github.com/noizefloor>`_,
`@akohlmey (Axel Kohlmeyer) <https://github.com/akohlmey>`_,
`@jk-jeon (Junekey Jeon) <https://github.com/jk-jeon>`_,
`@rimathia <https://github.com/rimathia>`_,
`@rglarix (Riccardo Ghetta (larix)) <https://github.com/rglarix>`_,
`@moiwi <https://github.com/moiwi>`_,
`@heckad (Kazantcev Andrey) <https://github.com/heckad>`_,
`@MarcDirven <https://github.com/MarcDirven>`_.
`@BartSiwek (Bart Siwek) <https://github.com/BartSiwek>`_,
`@darklukee <https://github.com/darklukee>`_.
7.0.3 - 2020-08-06
------------------
@ -49,7 +474,7 @@
<http://www.zverovich.net/2020/05/21/reducing-library-size.html>`_.
* Added a simpler and more efficient `format string compilation API
<https://fmt.dev/dev/api.html#compile-api>`_:
<https://fmt.dev/7.0.0/api.html#compile-api>`_:
.. code:: c++
@ -188,7 +613,7 @@
Thanks `@BRevzin (Barry Revzin) <https://github.com/BRevzin>`_.
* Added support for named args, ``clear`` and ``reserve`` to
* Added support for named arguments, ``clear`` and ``reserve`` to
``dynamic_format_arg_store``
(`#1655 <https://github.com/fmtlib/fmt/issues/1655>`_,
`#1663 <https://github.com/fmtlib/fmt/pull/1663>`_,
@ -1705,7 +2130,7 @@
* Implemented ``constexpr`` parsing of format strings and `compile-time format
string checks
<https://fmt.dev/dev/api.html#compile-time-format-string-checks>`_. For
<https://fmt.dev/latest/api.html#compile-time-format-string-checks>`_. For
example
.. code:: c++
@ -1766,7 +2191,7 @@
throw format_error("invalid specifier");
* Added `iterator support
<https://fmt.dev/dev/api.html#output-iterator-support>`_:
<https://fmt.dev/latest/api.html#output-iterator-support>`_:
.. code:: c++
@ -1777,7 +2202,7 @@
fmt::format_to(std::back_inserter(out), "{}", 42);
* Added the `format_to_n
<https://fmt.dev/dev/api.html#_CPPv2N3fmt11format_to_nE8OutputItNSt6size_tE11string_viewDpRK4Args>`_
<https://fmt.dev/latest/api.html#_CPPv2N3fmt11format_to_nE8OutputItNSt6size_tE11string_viewDpRK4Args>`_
function that restricts the output to the specified number of characters
(`#298 <https://github.com/fmtlib/fmt/issues/298>`_):
@ -1788,7 +2213,7 @@
// out == "1234" (without terminating '\0')
* Added the `formatted_size
<https://fmt.dev/dev/api.html#_CPPv2N3fmt14formatted_sizeE11string_viewDpRK4Args>`_
<https://fmt.dev/latest/api.html#_CPPv2N3fmt14formatted_sizeE11string_viewDpRK4Args>`_
function for computing the output size:
.. code:: c++
@ -1798,7 +2223,7 @@
auto size = fmt::formatted_size("{}", 12345); // size == 5
* Improved compile times by reducing dependencies on standard headers and
providing a lightweight `core API <https://fmt.dev/dev/api.html#core-api>`_:
providing a lightweight `core API <https://fmt.dev/latest/api.html#core-api>`_:
.. code:: c++
@ -1810,7 +2235,7 @@
<https://github.com/fmtlib/fmt#compile-time-and-code-bloat>`_.
* Added the `make_format_args
<https://fmt.dev/dev/api.html#_CPPv2N3fmt16make_format_argsEDpRK4Args>`_
<https://fmt.dev/latest/api.html#_CPPv2N3fmt16make_format_argsEDpRK4Args>`_
function for capturing formatting arguments:
.. code:: c++
@ -1892,7 +2317,7 @@
fmt::format("{} {two}", 1, fmt::arg("two", 2));
* Removed the write API in favor of the `format API
<https://fmt.dev/dev/api.html#format-api>`_ with compile-time handling of
<https://fmt.dev/latest/api.html#format-api>`_ with compile-time handling of
format strings.
* Disallowed formatting of multibyte strings into a wide character target

View file

@ -7,48 +7,57 @@
.. image:: https://ci.appveyor.com/api/projects/status/ehjkiefde6gucy1v
:target: https://ci.appveyor.com/project/vitaut/fmt
.. image:: https://oss-fuzz-build-logs.storage.googleapis.com/badges/libfmt.svg
:alt: fmt is continuously fuzzed att oss-fuzz
.. image:: https://oss-fuzz-build-logs.storage.googleapis.com/badges/fmt.svg
:alt: fmt is continuously fuzzed at oss-fuzz
:target: https://bugs.chromium.org/p/oss-fuzz/issues/list?\
colspec=ID%20Type%20Component%20Status%20Proj%20Reported%20Owner%20\
Summary&q=proj%3Dlibfmt&can=1
Summary&q=proj%3Dfmt&can=1
.. image:: https://img.shields.io/badge/stackoverflow-fmt-blue.svg
:alt: Ask questions at StackOverflow with the tag fmt
:target: https://stackoverflow.com/questions/tagged/fmt
**{fmt}** is an open-source formatting library for C++.
It can be used as a safe and fast alternative to (s)printf and iostreams.
**{fmt}** is an open-source formatting library providing a fast and safe
alternative to C stdio and C++ iostreams.
`Documentation <https://fmt.dev/latest/>`__
If you like this project, please consider donating to BYSOL,
an initiative to help victims of political repressions in Belarus:
https://www.facebook.com/donate/759400044849707/108388587646909/.
`Documentation <https://fmt.dev>`__
Q&A: ask questions on `StackOverflow with the tag fmt
<https://stackoverflow.com/questions/tagged/fmt>`_.
Try {fmt} in `Compiler Explorer <https://godbolt.org/z/Eq5763>`_.
Features
--------
* Simple `format API <https://fmt.dev/dev/api.html>`_ with positional arguments
* Simple `format API <https://fmt.dev/latest/api.html>`_ with positional arguments
for localization
* Implementation of `C++20 std::format
<https://en.cppreference.com/w/cpp/utility/format>`__
* `Format string syntax <https://fmt.dev/dev/syntax.html>`_ similar to the one
of Python's
* `Format string syntax <https://fmt.dev/latest/syntax.html>`_ similar to Python's
`format <https://docs.python.org/3/library/stdtypes.html#str.format>`_
* Fast IEEE 754 floating-point formatter with correct rounding, shortness and
round-trip guarantees
* Safe `printf implementation
<https://fmt.dev/latest/api.html#printf-formatting>`_ including
the POSIX extension for positional arguments
* Extensibility: support for user-defined types
<https://fmt.dev/latest/api.html#printf-formatting>`_ including the POSIX
extension for positional arguments
* Extensibility: `support for user-defined types
<https://fmt.dev/latest/api.html#formatting-user-defined-types>`_
* High performance: faster than common standard library implementations of
`printf <https://en.cppreference.com/w/cpp/io/c/fprintf>`_,
iostreams, ``to_string`` and ``to_chars``, see `Speed tests`_ and
`Converting a hundred million integers to strings per second
``(s)printf``, iostreams, ``to_string`` and ``to_chars``, see `Speed tests`_
and `Converting a hundred million integers to strings per second
<http://www.zverovich.net/2020/06/13/fast-int-to-string-revisited.html>`_
* Small code size both in terms of source code (the minimum configuration
consists of just three header files, ``core.h``, ``format.h`` and
``format-inl.h``) and compiled code. See `Compile time and code bloat`_
* Reliability: the library has an extensive set of `unit tests
<https://github.com/fmtlib/fmt/tree/master/test>`_ and is continuously fuzzed
* Small code size both in terms of source code with the minimum configuration
consisting of just three files, ``core.h``, ``format.h`` and ``format-inl.h``,
and compiled code; see `Compile time and code bloat`_
* Reliability: the library has an extensive set of `tests
<https://github.com/fmtlib/fmt/tree/master/test>`_ and is `continuously fuzzed
<https://bugs.chromium.org/p/oss-fuzz/issues/list?colspec=ID%20Type%20
Component%20Status%20Proj%20Reported%20Owner%20Summary&q=proj%3Dfmt&can=1>`_
* Safety: the library is fully type safe, errors in format strings can be
reported at compile time, automatic memory management prevents buffer overflow
errors
@ -57,18 +66,17 @@ Features
<https://github.com/fmtlib/fmt/blob/master/LICENSE.rst>`_
* `Portability <https://fmt.dev/latest/index.html#portability>`_ with
consistent output across platforms and support for older compilers
* Clean warning-free codebase even on high warning levels
(``-Wall -Wextra -pedantic``)
* Clean warning-free codebase even on high warning levels such as
``-Wall -Wextra -pedantic``
* Locale-independence by default
* Support for wide strings
* Optional header-only configuration enabled with the ``FMT_HEADER_ONLY`` macro
See the `documentation <https://fmt.dev/latest/>`_ for more details.
See the `documentation <https://fmt.dev>`_ for more details.
Examples
--------
Print ``Hello, world!`` to ``stdout``:
**Print to stdout** (`run <https://godbolt.org/z/Tevcjh>`_)
.. code:: c++
@ -78,100 +86,95 @@ Print ``Hello, world!`` to ``stdout``:
fmt::print("Hello, world!\n");
}
Format a string:
**Format a string** (`run <https://godbolt.org/z/oK8h33>`_)
.. code:: c++
std::string s = fmt::format("The answer is {}.", 42);
// s == "The answer is 42."
Format a string using positional arguments:
**Format a string using positional arguments** (`run <https://godbolt.org/z/Yn7Txe>`_)
.. code:: c++
std::string s = fmt::format("I'd rather be {1} than {0}.", "right", "happy");
// s == "I'd rather be happy than right."
Print a chrono duration:
**Print chrono durations** (`run <https://godbolt.org/z/K8s4Mc>`_)
.. code:: c++
#include <fmt/chrono.h>
int main() {
using namespace std::chrono_literals;
fmt::print("Elapsed time: {}", 42ms);
using namespace std::literals::chrono_literals;
fmt::print("Default format: {} {}\n", 42s, 100ms);
fmt::print("strftime-like format: {:%H:%M:%S}\n", 3h + 15min + 30s);
}
prints "Elapsed time: 42ms".
Output::
Check a format string at compile time:
Default format: 42s 100ms
strftime-like format: 03:15:30
**Print a container** (`run <https://godbolt.org/z/MjsY7c>`_)
.. code:: c++
// test.cc
#include <fmt/format.h>
std::string s = format(FMT_STRING("{:d}"), "hello");
#include <vector>
#include <fmt/ranges.h>
gives a compile-time error because ``d`` is an invalid format specifier for a
string.
Use {fmt} as a safe portable replacement for ``itoa``
(`godbolt <https://godbolt.org/g/NXmpU4>`_):
.. code:: c++
fmt::memory_buffer buf;
format_to(buf, "{}", 42); // replaces itoa(42, buffer, 10)
format_to(buf, "{:x}", 42); // replaces itoa(42, buffer, 16)
// access the string with to_string(buf) or buf.data()
Format objects of user-defined types via a simple `extension API
<https://fmt.dev/latest/api.html#formatting-user-defined-types>`_:
.. code:: c++
#include <fmt/format.h>
struct date {
int year, month, day;
};
template <>
struct fmt::formatter<date> {
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const date& d, FormatContext& ctx) {
return format_to(ctx.out(), "{}-{}-{}", d.year, d.month, d.day);
}
};
std::string s = fmt::format("The date is {}", date{2012, 12, 9});
// s == "The date is 2012-12-9"
Create your own functions similar to `format
<https://fmt.dev/latest/api.html#format>`_ and
`print <https://fmt.dev/latest/api.html#print>`_
which take arbitrary arguments (`godbolt <https://godbolt.org/g/MHjHVf>`_):
.. code:: c++
// Prints formatted error message.
void vreport_error(const char* format, fmt::format_args args) {
fmt::print("Error: ");
fmt::vprint(format, args);
}
template <typename... Args>
void report_error(const char* format, const Args & ... args) {
vreport_error(format, fmt::make_format_args(args...));
int main() {
std::vector<int> v = {1, 2, 3};
fmt::print("{}\n", v);
}
report_error("file not found: {}", path);
Output::
Note that ``vreport_error`` is not parameterized on argument types which can
improve compile times and reduce code size compared to a fully parameterized
version.
{1, 2, 3}
**Check a format string at compile time**
.. code:: c++
std::string s = fmt::format(FMT_STRING("{:d}"), "don't panic");
This gives a compile-time error because ``d`` is an invalid format specifier for
a string.
**Write a file from a single thread**
.. code:: c++
#include <fmt/os.h>
int main() {
auto out = fmt::output_file("guide.txt");
out.print("Don't {}", "Panic");
}
This can be `5 to 9 times faster than fprintf
<http://www.zverovich.net/2020/08/04/optimal-file-buffer-size.html>`_.
**Print with colors and text styles**
.. code:: c++
#include <fmt/color.h>
int main() {
fmt::print(fg(fmt::color::crimson) | fmt::emphasis::bold,
"Hello, {}!\n", "world");
fmt::print(fg(fmt::color::floral_white) | bg(fmt::color::slate_gray) |
fmt::emphasis::underline, "Hello, {}!\n", "мир");
fmt::print(fg(fmt::color::steel_blue) | fmt::emphasis::italic,
"Hello, {}!\n", "世界");
}
Output on a modern terminal:
.. image:: https://user-images.githubusercontent.com/
576385/88485597-d312f600-cf2b-11ea-9cbe-61f535a86e28.png
Benchmarks
----------
@ -198,12 +201,14 @@ or equivalent is filled 2,000,000 times with output sent to ``/dev/null``; for
further details refer to the `source
<https://github.com/fmtlib/format-benchmark/blob/master/tinyformat_test.cpp>`_.
{fmt} is up to 10x 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>`_)
and faster than `double-conversion <https://github.com/google/double-conversion>`_:
and faster than `double-conversion <https://github.com/google/double-conversion>`_ and
`ryu <https://github.com/ulfjack/ryu>`_:
.. image:: https://user-images.githubusercontent.com/576385/69767160-cdaca400-112f-11ea-9fc5-347c9f83caad.png
:target: https://fmt.dev/unknown_mac64_clang10.0.html
.. image:: https://user-images.githubusercontent.com/576385/
95684665-11719600-0ba8-11eb-8e5b-972ff4e49428.png
:target: https://fmt.dev/unknown_mac64_clang12.0.html
Compile time and code bloat
~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -282,30 +287,33 @@ or the bloat test::
Projects using this library
---------------------------
* `0 A.D. <https://play0ad.com/>`_: A free, open-source, cross-platform
* `0 A.D. <https://play0ad.com/>`_: a free, open-source, cross-platform
real-time strategy game
* `AMPL/MP <https://github.com/ampl/mp>`_:
An open-source library for mathematical programming
an open-source library for mathematical programming
* `Aseprite <https://github.com/aseprite/aseprite>`_:
Animated sprite editor & pixel art tool
animated sprite editor & pixel art tool
* `AvioBook <https://www.aviobook.aero/en>`_: A comprehensive aircraft
* `AvioBook <https://www.aviobook.aero/en>`_: a comprehensive aircraft
operations suite
* `Celestia <https://celestia.space/>`_: Real-time 3D visualization of space
* `Blizzard Battle.net <https://battle.net/>`_: an online gaming platform
* `Celestia <https://celestia.space/>`_: real-time 3D visualization of space
* `Ceph <https://ceph.com/>`_: A scalable distributed storage system
* `Ceph <https://ceph.com/>`_: a scalable distributed storage system
* `ccache <https://ccache.dev/>`_: A compiler cache
* `ccache <https://ccache.dev/>`_: a compiler cache
* `ClickHouse <https://github.com/ClickHouse/ClickHouse>`_: analytical database management system
* `ClickHouse <https://github.com/ClickHouse/ClickHouse>`_: analytical database
management system
* `CUAUV <http://cuauv.org/>`_: Cornell University's autonomous underwater
vehicle
* `Drake <https://drake.mit.edu/>`_: A planning, control, and analysis toolbox
* `Drake <https://drake.mit.edu/>`_: a planning, control, and analysis toolbox
for nonlinear dynamical systems (MIT)
* `Envoy <https://lyft.github.io/envoy/>`_: C++ L7 proxy and communication bus
@ -318,66 +326,70 @@ Projects using this library
* `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_:
Player vs Player Gaming Network with tweaks
* `KBEngine <https://kbengine.org/>`_: An open-source MMOG server engine
* `KBEngine <https://github.com/kbengine/kbengine>`_: an open-source MMOG server
engine
* `Keypirinha <https://keypirinha.com/>`_: A semantic launcher for Windows
* `Keypirinha <https://keypirinha.com/>`_: a semantic launcher for Windows
* `Kodi <https://kodi.tv/>`_ (formerly xbmc): Home theater software
* `Kodi <https://kodi.tv/>`_ (formerly xbmc): home theater software
* `Knuth <https://kth.cash/>`_: High-performance Bitcoin full-node
* `Knuth <https://kth.cash/>`_: high-performance Bitcoin full-node
* `Microsoft Verona <https://github.com/microsoft/verona>`_:
Research programming language for concurrent ownership
research programming language for concurrent ownership
* `MongoDB <https://mongodb.com/>`_: Distributed document database
* `MongoDB <https://mongodb.com/>`_: distributed document database
* `MongoDB Smasher <https://github.com/duckie/mongo_smasher>`_: A small tool to
* `MongoDB Smasher <https://github.com/duckie/mongo_smasher>`_: a small tool to
generate randomized datasets
* `OpenSpace <https://openspaceproject.com/>`_: An open-source
* `OpenSpace <https://openspaceproject.com/>`_: an open-source
astrovisualization framework
* `PenUltima Online (POL) <https://www.polserver.com/>`_:
An MMO server, compatible with most Ultima Online clients
an MMO server, compatible with most Ultima Online clients
* `PyTorch <https://github.com/pytorch/pytorch>`_: An open-source machine
* `PyTorch <https://github.com/pytorch/pytorch>`_: an open-source machine
learning library
* `quasardb <https://www.quasardb.net/>`_: A distributed, high-performance,
* `quasardb <https://www.quasardb.net/>`_: a distributed, high-performance,
associative database
* `Quill <https://github.com/odygrd/quill>`_: asynchronous low-latency logging library
* `readpe <https://bitbucket.org/sys_dev/readpe>`_: Read Portable Executable
* `QKW <https://github.com/ravijanjam/qkw>`_: generalizing aliasing to simplify
navigation, and executing complex multi-line terminal command sequences
* `redis-cerberus <https://github.com/HunanTV/redis-cerberus>`_: A Redis cluster
* `redis-cerberus <https://github.com/HunanTV/redis-cerberus>`_: a Redis cluster
proxy
* `redpanda <https://vectorized.io/redpanda>`_: A 10x faster Kafka® replacement
* `redpanda <https://vectorized.io/redpanda>`_: a 10x faster Kafka® replacement
for mission critical systems written in C++
* `rpclib <http://rpclib.net/>`_: A modern C++ msgpack-RPC server and client
* `rpclib <http://rpclib.net/>`_: a modern C++ msgpack-RPC server and client
library
* `Salesforce Analytics Cloud
<https://www.salesforce.com/analytics-cloud/overview/>`_:
Business intelligence software
business intelligence software
* `Scylla <https://www.scylladb.com/>`_: A Cassandra-compatible NoSQL data store
* `Scylla <https://www.scylladb.com/>`_: a Cassandra-compatible NoSQL data store
that can handle 1 million transactions per second on a single server
* `Seastar <http://www.seastar-project.org/>`_: An advanced, open-source C++
* `Seastar <http://www.seastar-project.org/>`_: an advanced, open-source C++
framework for high-performance server applications on modern hardware
* `spdlog <https://github.com/gabime/spdlog>`_: Super fast C++ logging library
* `spdlog <https://github.com/gabime/spdlog>`_: super fast C++ logging library
* `Stellar <https://www.stellar.org/>`_: Financial platform
* `Stellar <https://www.stellar.org/>`_: financial platform
* `Touch Surgery <https://www.touchsurgery.com/>`_: Surgery simulator
* `Touch Surgery <https://www.touchsurgery.com/>`_: surgery simulator
* `TrinityCore <https://github.com/TrinityCore/TrinityCore>`_: Open-source
* `TrinityCore <https://github.com/TrinityCore/TrinityCore>`_: open-source
MMORPG framework
* `Windows Terminal <https://github.com/microsoft/terminal>`_: The new Windows
Terminal
* `Windows Terminal <https://github.com/microsoft/terminal>`_: the new Windows
terminal
`More... <https://github.com/search?q=fmtlib&type=Code>`_
@ -435,7 +447,7 @@ Boost Format
This is a very powerful library which supports both ``printf``-like format
strings and positional arguments. Its main drawback is performance. According to
various benchmarks it is much slower than other methods considered here. Boost
various, benchmarks it is much slower than other methods considered here. Boost
Format also has excessive build times and severe code bloat issues (see
`Benchmarks`_).

View file

@ -4,10 +4,14 @@ if (NOT DOXYGEN)
return ()
endif ()
find_package(PythonInterp QUIET REQUIRED)
add_custom_target(doc
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/build.py ${FMT_VERSION}
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/build.py
${FMT_VERSION}
SOURCES api.rst syntax.rst usage.rst build.py conf.py _templates/layout.html)
include(GNUInstallDirs)
install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html/
DESTINATION share/doc/fmt OPTIONAL
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/doc/fmt OPTIONAL
PATTERN ".doctrees" EXCLUDE)

View file

@ -15,6 +15,7 @@ The {fmt} library API consists of the following parts:
and tuples
* :ref:`fmt/chrono.h <chrono-api>`: date and time formatting
* :ref:`fmt/compile.h <compile-api>`: format string compilation
* :ref:`fmt/color.h <color-api>`: terminal color and text style
* :ref:`fmt/ostream.h <ostream-api>`: ``std::ostream`` support
* :ref:`fmt/printf.h <printf-api>`: ``printf`` formatting
@ -47,6 +48,10 @@ participate in an overload resolution if the latter is not a string.
.. doxygenfunction:: format(const S&, Args&&...)
.. doxygenfunction:: vformat(const S&, basic_format_args<buffer_context<type_identity_t<Char>>>)
.. doxygenfunction:: fmt::format_to(OutputIt, const S&, Args&&...)
.. doxygenfunction:: fmt::format_to_n(OutputIt, size_t, const S&, const Args&...)
.. doxygenfunction:: fmt::formatted_size(string_view, Args&&...)
.. _print:
.. doxygenfunction:: print(const S&, Args&&...)
@ -65,6 +70,35 @@ Named arguments are not supported in compile-time checks at the moment.
Argument Lists
--------------
You can create your own formatting function with compile-time checks and small
binary footprint, for example (https://godbolt.org/z/oba4Mc):
.. code:: c++
#include <fmt/format.h>
void vlog(const char* file, int line, fmt::string_view format,
fmt::format_args args) {
fmt::print("{}: {}: ", file, line);
fmt::vprint(format, args);
}
template <typename S, typename... Args>
void log(const char* file, int line, const S& format, Args&&... args) {
vlog(file, line, format,
fmt::make_args_checked<Args...>(format, args...));
}
#define MY_LOG(format, ...) \
log(__FILE__, __LINE__, FMT_STRING(format), __VA_ARGS__)
MY_LOG("invalid squishiness: {}", 42);
Note that ``vlog`` is not parameterized on argument types which improves compile
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&...)
.. doxygenclass:: fmt::format_arg_store
@ -93,7 +127,7 @@ Compatibility
Locale
------
All formatting is locale-independent by default. Use the ``'n'`` format
All formatting is locale-independent by default. Use the ``'L'`` format
specifier to insert the appropriate number separator characters from the
locale::
@ -114,12 +148,14 @@ string checks, wide string, output iterator and user-defined type support.
Compile-time Format String Checks
---------------------------------
Compile-time checks are supported for built-in and string types as well as
user-defined types with ``constexpr`` ``parse`` functions in their ``formatter``
specializations.
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``
functions in their ``formatter`` specializations.
.. doxygendefine:: FMT_STRING
.. _udt:
Formatting User-defined Types
-----------------------------
@ -237,6 +273,10 @@ You can also write a formatter for a hierarchy of classes::
fmt::print("{}", a); // prints "B"
}
If a type provides both a ``formatter`` specialization and an implicit
conversion to a formattable type, the specialization takes precedence over the
conversion.
.. doxygenclass:: fmt::basic_format_parse_context
:members:
@ -264,7 +304,9 @@ Utilities
.. doxygentypedef:: fmt::char_t
.. doxygenfunction:: fmt::formatted_size(string_view, const Args&...)
.. doxygenfunction:: fmt::ptr(const T *)
.. doxygenfunction:: fmt::ptr(const std::unique_ptr<T>&)
.. doxygenfunction:: fmt::ptr(const std::shared_ptr<T>&)
.. doxygenfunction:: fmt::to_string(const T&)
@ -272,7 +314,7 @@ Utilities
.. doxygenfunction:: fmt::to_string_view(const Char *)
.. doxygenfunction:: fmt::join(const Range&, string_view)
.. doxygenfunction:: fmt::join(Range&&, string_view)
.. doxygenfunction:: fmt::join(It, Sentinel, string_view)
@ -298,8 +340,6 @@ the value of ``errno`` being preserved by library functions.
.. doxygenclass:: fmt::windows_error
:members:
.. _formatstrings:
Custom Allocators
-----------------
@ -330,10 +370,10 @@ allocator::
return vformat(alloc, format_str, fmt::make_format_args(args...));
}
The allocator will be used for the output container only. If you are using named
arguments, the container that stores pointers to them will be allocated using
the default allocator. Also floating-point formatting falls back on ``sprintf``
which may do allocations.
The allocator will be used for the output container only. Formatting functions
normally don't do any allocations for built-in and string types except for
non-default floating-point formatting that occasionally falls back on
``sprintf``.
.. _ranges-api:
@ -383,9 +423,10 @@ The format string syntax is described in the documentation of
Format string compilation
=========================
``fmt/compile.h`` provides format string compilation support. Format strings
are parsed at compile time and converted into efficient formatting code. This
supports arguments of built-in and string types as well as user-defined types
``fmt/compile.h`` provides format string compilation support when using
``FMT_COMPILE``. Format strings are parsed, checked and converted
into efficient formatting code at compile-time.
This supports arguments of built-in and string types as well as user-defined types
with ``constexpr`` ``parse`` functions in their ``formatter`` specializations.
Format string compilation can generate more binary code compared to the default
API and is only recommended in places where formatting is a performance
@ -393,6 +434,15 @@ bottleneck.
.. doxygendefine:: FMT_COMPILE
.. _color-api:
Terminal color and text style
=============================
``fmt/color.h`` provides support for terminal color and text style output.
.. doxygenfunction:: print(const text_style&, const S&, const Args&...)
.. _ostream-api:
``std::ostream`` Support

View file

@ -6,20 +6,10 @@ import errno, os, shutil, sys, tempfile
from subprocess import check_call, check_output, CalledProcessError, Popen, PIPE
from distutils.version import LooseVersion
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']
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']
def pip_install(package, commit=None, **kwargs):
"Install package using pip."
min_version = kwargs.get('min_version')
if min_version:
from pkg_resources import get_distribution, DistributionNotFound
try:
installed_version = get_distribution(os.path.basename(package)).version
if LooseVersion(installed_version) >= min_version:
print('{} {} already installed'.format(package, min_version))
return
except DistributionNotFound:
pass
if commit:
package = 'git+https://github.com/{0}.git@{1}'.format(package, commit)
print('Installing {0}'.format(package))
@ -52,12 +42,11 @@ def create_build_env(dirname='virtualenv'):
check_call(['pip', 'install', '--upgrade', 'distribute'])
except DistributionNotFound:
pass
# Install Sphinx and Breathe.
pip_install('sphinx-doc/sphinx', '12b83372ac9316e8cbe86e7fed889296a4cc29ee',
min_version='1.4.1.dev20160531')
# Install Sphinx and Breathe. Require the exact version of Sphinx which is
# compatible with Breathe.
pip_install('sphinx-doc/sphinx', '12b83372ac9316e8cbe86e7fed889296a4cc29ee')
pip_install('michaeljones/breathe',
'129222318f7c8f865d2631e7da7b033567e7f56a',
min_version='4.2.0')
'129222318f7c8f865d2631e7da7b033567e7f56a')
def build_docs(version='dev', **kwargs):
doc_dir = kwargs.get('doc_dir', os.path.dirname(os.path.realpath(__file__)))
@ -74,8 +63,8 @@ def build_docs(version='dev', **kwargs):
GENERATE_MAN = NO
GENERATE_RTF = NO
CASE_SENSE_NAMES = NO
INPUT = {0}/core.h {0}/compile.h {0}/format.h {0}/os.h \
{0}/ostream.h {0}/printf.h {0}/time.h
INPUT = {0}/chrono.h {0}/color.h {0}/core.h {0}/compile.h \
{0}/format.h {0}/os.h {0}/ostream.h {0}/printf.h
QUIET = YES
JAVADOC_AUTOBRIEF = YES
AUTOLINK_SUPPORT = NO
@ -95,7 +84,8 @@ def build_docs(version='dev', **kwargs):
"FMT_END_NAMESPACE=}}" \
"FMT_STRING_ALIAS=1" \
"FMT_ENABLE_IF(B)="
EXCLUDE_SYMBOLS = fmt::internal::* StringValue write_str
EXCLUDE_SYMBOLS = fmt::formatter fmt::printf_formatter fmt::arg_join \
fmt::basic_format_arg::handle
'''.format(include_dir, doxyxml_dir).encode('UTF-8'))
if p.returncode != 0:
raise CalledProcessError(p.returncode, cmd)

View file

@ -15,6 +15,7 @@ The {fmt} library API consists of the following parts:
and tuples
* :ref:`fmt/chrono.h <chrono-api>`: date and time formatting
* :ref:`fmt/compile.h <compile-api>`: format string compilation
* :ref:`fmt/color.h <color-api>`: terminal color and text style
* :ref:`fmt/ostream.h <ostream-api>`: ``std::ostream`` support
* :ref:`fmt/printf.h <printf-api>`: ``printf`` formatting
@ -47,6 +48,10 @@ participate in an overload resolution if the latter is not a string.
.. doxygenfunction:: format(const S&, Args&&...)
.. doxygenfunction:: vformat(const S&, basic_format_args<buffer_context<type_identity_t<Char>>>)
.. doxygenfunction:: fmt::format_to(OutputIt, const S&, Args&&...)
.. doxygenfunction:: fmt::format_to_n(OutputIt, size_t, const S&, const Args&...)
.. doxygenfunction:: fmt::formatted_size(string_view, Args&&...)
.. _print:
.. doxygenfunction:: print(const S&, Args&&...)
@ -65,6 +70,35 @@ Named arguments are not supported in compile-time checks at the moment.
Argument Lists
--------------
You can create your own formatting function with compile-time checks and small
binary footprint, for example (https://godbolt.org/z/oba4Mc):
.. code:: c++
#include <fmt/format.h>
void vlog(const char* file, int line, fmt::string_view format,
fmt::format_args args) {
fmt::print("{}: {}: ", file, line);
fmt::vprint(format, args);
}
template <typename S, typename... Args>
void log(const char* file, int line, const S& format, Args&&... args) {
vlog(file, line, format,
fmt::make_args_checked<Args...>(format, args...));
}
#define MY_LOG(format, ...) \
log(__FILE__, __LINE__, FMT_STRING(format), __VA_ARGS__)
MY_LOG("invalid squishiness: {}", 42);
Note that ``vlog`` is not parameterized on argument types which improves compile
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&...)
.. doxygenclass:: fmt::format_arg_store
@ -93,7 +127,7 @@ Compatibility
Locale
------
All formatting is locale-independent by default. Use the ``'n'`` format
All formatting is locale-independent by default. Use the ``'L'`` format
specifier to insert the appropriate number separator characters from the
locale::
@ -114,12 +148,14 @@ string checks, wide string, output iterator and user-defined type support.
Compile-time Format String Checks
---------------------------------
Compile-time checks are supported for built-in and string types as well as
user-defined types with ``constexpr`` ``parse`` functions in their ``formatter``
specializations.
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``
functions in their ``formatter`` specializations.
.. doxygendefine:: FMT_STRING
.. _udt:
Formatting User-defined Types
-----------------------------
@ -237,6 +273,10 @@ You can also write a formatter for a hierarchy of classes::
fmt::print("{}", a); // prints "B"
}
If a type provides both a ``formatter`` specialization and an implicit
conversion to a formattable type, the specialization takes precedence over the
conversion.
.. doxygenclass:: fmt::basic_format_parse_context
:members:
@ -264,7 +304,9 @@ Utilities
.. doxygentypedef:: fmt::char_t
.. doxygenfunction:: fmt::formatted_size(string_view, const Args&...)
.. doxygenfunction:: fmt::ptr(const T *)
.. doxygenfunction:: fmt::ptr(const std::unique_ptr<T>&)
.. doxygenfunction:: fmt::ptr(const std::shared_ptr<T>&)
.. doxygenfunction:: fmt::to_string(const T&)
@ -272,7 +314,7 @@ Utilities
.. doxygenfunction:: fmt::to_string_view(const Char *)
.. doxygenfunction:: fmt::join(const Range&, string_view)
.. doxygenfunction:: fmt::join(Range&&, string_view)
.. doxygenfunction:: fmt::join(It, Sentinel, string_view)
@ -298,8 +340,6 @@ the value of ``errno`` being preserved by library functions.
.. doxygenclass:: fmt::windows_error
:members:
.. _formatstrings:
Custom Allocators
-----------------
@ -330,10 +370,10 @@ allocator::
return vformat(alloc, format_str, fmt::make_format_args(args...));
}
The allocator will be used for the output container only. If you are using named
arguments, the container that stores pointers to them will be allocated using
the default allocator. Also floating-point formatting falls back on ``sprintf``
which may do allocations.
The allocator will be used for the output container only. Formatting functions
normally don't do any allocations for built-in and string types except for
non-default floating-point formatting that occasionally falls back on
``sprintf``.
.. _ranges-api:
@ -383,9 +423,10 @@ The format string syntax is described in the documentation of
Format string compilation
=========================
``fmt/compile.h`` provides format string compilation support. Format strings
are parsed at compile time and converted into efficient formatting code. This
supports arguments of built-in and string types as well as user-defined types
``fmt/compile.h`` provides format string compilation support when using
``FMT_COMPILE``. Format strings are parsed, checked and converted
into efficient formatting code at compile-time.
This supports arguments of built-in and string types as well as user-defined types
with ``constexpr`` ``parse`` functions in their ``formatter`` specializations.
Format string compilation can generate more binary code compared to the default
API and is only recommended in places where formatting is a performance
@ -393,6 +434,15 @@ bottleneck.
.. doxygendefine:: FMT_COMPILE
.. _color-api:
Terminal color and text style
=============================
``fmt/color.h`` provides support for terminal color and text style output.
.. doxygenfunction:: print(const text_style&, const S&, const Args&...)
.. _ostream-api:
``std::ostream`` Support

View file

@ -23,7 +23,7 @@ Format API
The format API is similar in spirit to the C ``printf`` family of function but
is safer, simpler and several times `faster
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_
<https://www.zverovich.net/2020/06/13/fast-int-to-string-revisited.html>`_
than common standard library implementations.
The `format string syntax <syntax.html>`_ is similar to the one used by
`str.format <http://docs.python.org/3/library/stdtypes.html#str.format>`_ in
@ -48,21 +48,19 @@ The ``fmt::print`` function performs formatting and writes the result to a strea
fmt::print(stderr, "System error code = {}\n", errno);
The file argument can be omitted in which case the function prints to
``stdout``:
If you omit the file argument the function will print to ``stdout``:
.. code:: c++
fmt::print("Don't {}\n", "panic");
The Format API also supports positional arguments useful for localization:
The format API also supports positional arguments useful for localization:
.. code:: c++
fmt::print("I'd rather be {1} than {0}.", "right", "happy");
Named arguments can be created with ``fmt::arg``. This makes it easier to track
what goes where when multiple arguments are being formatted:
You can pass named arguments with ``fmt::arg``:
.. code:: c++
@ -91,16 +89,17 @@ time. For example, the code
fmt::format("The answer is {:d}", "forty-two");
throws a ``format_error`` exception with description "unknown format code 'd' for
string", because the argument ``"forty-two"`` is a string while the format code
``d`` only applies to integers, while
throws the ``format_error`` exception because the argument ``"forty-two"`` is a
string while the format code ``d`` only applies to integers.
The code
.. code:: c++
format(FMT_STRING("The answer is {:d}"), "forty-two");
reports a compile-time error for the same reason on compilers that support
relaxed ``constexpr``. See `here <api.html#c.fmt>`_ for details.
reports a compile-time error on compilers that support relaxed ``constexpr``.
See `here <api.html#c.fmt>`_ for details.
The following code
@ -117,13 +116,13 @@ formatted into a narrow string. You can use a wide format string instead:
For comparison, writing a wide character to ``std::ostream`` results in
its numeric value being written to the stream (i.e. 1070 instead of letter 'ю'
which is represented by ``L'\x42e'`` if we use Unicode) which is rarely what is
needed.
which is represented by ``L'\x42e'`` if we use Unicode) which is rarely
desirable.
Compact Binary Code
-------------------
The library is designed to produce compact per-call compiled code. For example
The library produces compact per-call compiled code. For example
(`godbolt <https://godbolt.org/g/TZU4KF>`_),
.. code:: c++
@ -144,8 +143,8 @@ compiles to just
mov rcx, rsp
mov edi, offset .L.str
mov esi, 17
mov edx, 2
call fmt::v5::vprint(fmt::v5::basic_string_view<char>, fmt::v5::format_args)
mov edx, 1
call fmt::v7::vprint(fmt::v7::basic_string_view<char>, fmt::v7::format_args)
xor eax, eax
add rsp, 24
ret
@ -167,20 +166,19 @@ The library is highly portable and relies only on a small set of C++11 features:
* deleted functions
* alias templates
These are available since GCC 4.8, Clang 3.0 and MSVC 19.0 (2015). For older
compilers use {fmt} `version 4.x
<https://github.com/fmtlib/fmt/releases/tag/4.1.0>`_ which continues to be
maintained and only requires C++98.
These are available in GCC 4.8, Clang 3.0, MSVC 19.0 (2015) and more recent
compiler version. For older compilers use {fmt} `version 4.x
<https://github.com/fmtlib/fmt/releases/tag/4.1.0>`_ which is maintained and
only requires C++98.
The output of all formatting functions is consistent across platforms. In
particular, formatting a floating-point infinity always gives ``inf`` while the
output of ``printf`` is platform-dependent. For example,
The output of all formatting functions is consistent across platforms.
For example,
.. code::
fmt::print("{}", std::numeric_limits<double>::infinity());
always prints ``inf``.
always prints ``inf`` while the output of ``printf`` is platform-dependent.
.. _ease-of-use:

View file

@ -52,6 +52,14 @@ To build a `shared library`__ set the ``BUILD_SHARED_LIBS`` CMake variable to
__ http://en.wikipedia.org/wiki/Library_%28computing%29#Shared_libraries
To build a `static library` with position independent code (required if the main
consumer of the fmt library is a shared library i.e. a Python extension) set the
``CMAKE_POSITION_INDEPENDENT_CODE`` CMake variable to ``TRUE``::
cmake -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE ...
Installing the Library
======================
@ -83,6 +91,49 @@ Setting up your target to use a header-only version of ``fmt`` is equally easy::
target_link_libraries(<your-target> PRIVATE fmt::fmt-header-only)
Usage with build2
=================
You can use `build2 <https://build2.org>`_, a dependency manager and a
build-system combined, to use ``fmt``.
Currently this package is available in these package repositories:
- **https://cppget.org/fmt/** for released and published versions.
- `The git repository with the sources of the build2 package of fmt <https://github.com/build2-packaging/fmt.git>`_
for unreleased or custom revisions of ``fmt``.
**Usage:**
- ``build2`` package name: ``fmt``
- Library target name : ``lib{fmt}``
For example, to make your ``build2`` project depend on ``fmt``:
- Add one of the repositories to your configurations, or in your
``repositories.manifest``, if not already there::
:
role: prerequisite
location: https://pkg.cppget.org/1/stable
- Add this package as a dependency to your ``./manifest`` file
(example for ``v7.0.x``)::
depends: fmt ~7.0.0
- Import the target and use it as a prerequisite to your own target
using `fmt` in the appropriate ``buildfile``::
import fmt = fmt%lib{fmt}
lib{mylib} : cxx{**} ... $fmt
Then build your project as usual with `b` or `bdep update`.
For ``build2`` newcomers or to get more details and use cases, you can read the
``build2``
`toolchain introduction <https://build2.org/build2-toolchain/doc/build2-toolchain-intro.xhtml>`_.
Building the Documentation
==========================
@ -130,6 +181,18 @@ The fmt port in vcpkg is kept up to date by Microsoft team members and community
contributors. If the version is out of date, please `create an issue or pull
request <https://github.com/Microsoft/vcpkg>`__ on the vcpkg repository.
LHelper
=======
You can download and install fmt using
`lhelper <https://github.com/franko/lhelper>`__ dependency manager::
lhelper activate <some-environment>
lhelper install fmt
All the recipes for lhelper are kept in the
`lhelper's recipe <https://github.com/franko/lhelper-recipes>`__ repository.
Android NDK
===========

View file

@ -4,7 +4,7 @@
*
* Sphinx stylesheet -- basic theme.
*
* :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
* :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
@ -81,26 +81,14 @@ div.sphinxsidebar input {
font-size: 1em;
}
div.sphinxsidebar #searchbox form.search {
overflow: hidden;
}
div.sphinxsidebar #searchbox input[type="text"] {
float: left;
width: 80%;
padding: 0.25em;
box-sizing: border-box;
width: 170px;
}
div.sphinxsidebar #searchbox input[type="submit"] {
float: left;
width: 20%;
border-left: none;
padding: 0.25em;
box-sizing: border-box;
width: 30px;
}
img {
border: 0;
max-width: 100%;
@ -138,8 +126,6 @@ ul.keywordmatches li.goodmatch a {
table.contentstable {
width: 90%;
margin-left: auto;
margin-right: auto;
}
table.contentstable p.biglink {
@ -167,14 +153,9 @@ table.indextable td {
vertical-align: top;
}
table.indextable ul {
table.indextable dl, table.indextable dd {
margin-top: 0;
margin-bottom: 0;
list-style-type: none;
}
table.indextable > tbody > tr > td > ul {
padding-left: 0em;
}
table.indextable tr.pcap {
@ -206,20 +187,8 @@ div.genindex-jumpbox {
padding: 0.4em;
}
/* -- domain module index --------------------------------------------------- */
table.modindextable td {
padding: 2px;
border-collapse: collapse;
}
/* -- general body styles --------------------------------------------------- */
div.body {
min-width: 450px;
max-width: 800px;
}
div.body p, div.body dd, div.body li, div.body blockquote {
-moz-hyphens: auto;
-ms-hyphens: auto;
@ -252,6 +221,10 @@ div.body td {
text-align: left;
}
.field-list ul {
padding-left: 1em;
}
.first {
margin-top: 0 !important;
}
@ -353,11 +326,6 @@ table.docutils {
border-collapse: collapse;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
table caption span.caption-number {
font-style: italic;
}
@ -373,6 +341,10 @@ table.docutils td, table.docutils th {
border-bottom: 1px solid #aaa;
}
table.field-list td, table.field-list th {
border: 0 !important;
}
table.footnote td, table.footnote th {
border: 0 !important;
}
@ -409,34 +381,6 @@ div.figure p.caption span.caption-number {
div.figure p.caption span.caption-text {
}
/* -- field list styles ----------------------------------------------------- */
table.field-list td, table.field-list th {
border: 0 !important;
}
.field-list ul {
margin: 0;
padding-left: 1em;
}
.field-list p {
margin: 0;
}
.field-name {
-moz-hyphens: manual;
-ms-hyphens: manual;
-webkit-hyphens: manual;
hyphens: manual;
}
/* -- hlist styles ---------------------------------------------------------- */
table.hlist td {
vertical-align: top;
}
/* -- other body styles ----------------------------------------------------- */
@ -478,19 +422,24 @@ dd {
margin-left: 30px;
}
dt:target, span.highlighted {
dt:target, .highlighted {
background-color: #fbe54e;
}
rect.highlighted {
fill: #fbe54e;
}
dl.glossary dt {
font-weight: bold;
font-size: 1.1em;
}
.field-list ul {
margin: 0;
padding-left: 1em;
}
.field-list p {
margin: 0;
}
.optional {
font-size: 1.3em;
}
@ -549,13 +498,6 @@ pre {
overflow-y: hidden; /* fixes display issues on Chrome browsers */
}
span.pre {
-moz-hyphens: none;
-ms-hyphens: none;
-webkit-hyphens: none;
hyphens: none;
}
td.linenos pre {
padding: 5px 0px;
border: 0;
@ -647,16 +589,6 @@ span.eqno {
float: right;
}
span.eqno a.headerlink {
position: relative;
left: 0px;
z-index: 1;
}
div.math:hover a.headerlink {
visibility: visible;
}
/* -- printout stylesheet --------------------------------------------------- */
@media print {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 756 B

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 829 B

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 641 B

After

Width:  |  Height:  |  Size: 3.4 KiB

View file

@ -4,7 +4,7 @@
*
* Sphinx JavaScript utilities for all documentation.
*
* :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
* :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
@ -45,7 +45,7 @@ jQuery.urlencode = encodeURIComponent;
* it will always return arrays of strings for the value parts.
*/
jQuery.getQueryParameters = function(s) {
if (typeof s === 'undefined')
if (typeof s == 'undefined')
s = document.location.search;
var parts = s.substr(s.indexOf('?') + 1).split('&');
var result = {};
@ -66,55 +66,29 @@ jQuery.getQueryParameters = function(s) {
* span elements with the given class name.
*/
jQuery.fn.highlightText = function(text, className) {
function highlight(node, addItems) {
if (node.nodeType === 3) {
function highlight(node) {
if (node.nodeType == 3) {
var val = node.nodeValue;
var pos = val.toLowerCase().indexOf(text);
if (pos >= 0 &&
!jQuery(node.parentNode).hasClass(className) &&
!jQuery(node.parentNode).hasClass("nohighlight")) {
var span;
var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg");
if (isInSVG) {
span = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
} else {
span = document.createElement("span");
span.className = className;
}
if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) {
var span = document.createElement("span");
span.className = className;
span.appendChild(document.createTextNode(val.substr(pos, text.length)));
node.parentNode.insertBefore(span, node.parentNode.insertBefore(
document.createTextNode(val.substr(pos + text.length)),
node.nextSibling));
node.nodeValue = val.substr(0, pos);
if (isInSVG) {
var bbox = span.getBBox();
var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
rect.x.baseVal.value = bbox.x;
rect.y.baseVal.value = bbox.y;
rect.width.baseVal.value = bbox.width;
rect.height.baseVal.value = bbox.height;
rect.setAttribute('class', className);
var parentOfText = node.parentNode.parentNode;
addItems.push({
"parent": node.parentNode,
"target": rect});
}
}
}
else if (!jQuery(node).is("button, select, textarea")) {
jQuery.each(node.childNodes, function() {
highlight(this, addItems);
highlight(this);
});
}
}
var addItems = [];
var result = this.each(function() {
highlight(this, addItems);
return this.each(function() {
highlight(this);
});
for (var i = 0; i < addItems.length; ++i) {
jQuery(addItems[i].parent).before(addItems[i].target);
}
return result;
};
/*
@ -150,30 +124,28 @@ var Documentation = {
this.fixFirefoxAnchorBug();
this.highlightSearchWords();
this.initIndexTable();
if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) {
this.initOnKeyListeners();
}
},
/**
* i18n support
*/
TRANSLATIONS : {},
PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; },
PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; },
LOCALE : 'unknown',
// gettext and ngettext don't access this so that the functions
// can safely bound to a different name (_ = Documentation.gettext)
gettext : function(string) {
var translated = Documentation.TRANSLATIONS[string];
if (typeof translated === 'undefined')
if (typeof translated == 'undefined')
return string;
return (typeof translated === 'string') ? translated : translated[0];
return (typeof translated == 'string') ? translated : translated[0];
},
ngettext : function(singular, plural, n) {
var translated = Documentation.TRANSLATIONS[singular];
if (typeof translated === 'undefined')
if (typeof translated == 'undefined')
return (n == 1) ? singular : plural;
return translated[Documentation.PLURALEXPR(n)];
},
@ -208,7 +180,7 @@ var Documentation = {
* see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075
*/
fixFirefoxAnchorBug : function() {
if (document.location.hash && $.browser.mozilla)
if (document.location.hash)
window.setTimeout(function() {
document.location.href += '';
}, 10);
@ -244,7 +216,7 @@ var Documentation = {
var src = $(this).attr('src');
var idnum = $(this).attr('id').substr(7);
$('tr.cg-' + idnum).toggle();
if (src.substr(-9) === 'minus.png')
if (src.substr(-9) == 'minus.png')
$(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
else
$(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
@ -276,7 +248,7 @@ var Documentation = {
var path = document.location.pathname;
var parts = path.split(/\//);
$.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() {
if (this === '..')
if (this == '..')
parts.pop();
});
var url = parts.join('/');
@ -312,4 +284,4 @@ _ = Documentation.gettext;
$(document).ready(function() {
Documentation.init();
});
});

View file

@ -1,10 +0,0 @@
var DOCUMENTATION_OPTIONS = {
URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
VERSION: '7.0.3',
LANGUAGE: 'None',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true,
SOURCELINK_SUFFIX: '.txt',
NAVIGATION_WITH_KEYS: false,
};

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 B

After

Width:  |  Height:  |  Size: 347 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 B

After

Width:  |  Height:  |  Size: 347 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 286 B

After

Width:  |  Height:  |  Size: 358 B

File diff suppressed because one or more lines are too long

View file

@ -1,297 +0,0 @@
/*
* language_data.js
* ~~~~~~~~~~~~~~~~
*
* This script contains the language-specific data used by searchtools.js,
* namely the list of stopwords, stemmer, scorer and splitter.
*
* :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
var stopwords = ["a","and","are","as","at","be","but","by","for","if","in","into","is","it","near","no","not","of","on","or","such","that","the","their","then","there","these","they","this","to","was","will","with"];
/* Non-minified version JS is _stemmer.js if file is provided */
/**
* Porter Stemmer
*/
var Stemmer = function() {
var step2list = {
ational: 'ate',
tional: 'tion',
enci: 'ence',
anci: 'ance',
izer: 'ize',
bli: 'ble',
alli: 'al',
entli: 'ent',
eli: 'e',
ousli: 'ous',
ization: 'ize',
ation: 'ate',
ator: 'ate',
alism: 'al',
iveness: 'ive',
fulness: 'ful',
ousness: 'ous',
aliti: 'al',
iviti: 'ive',
biliti: 'ble',
logi: 'log'
};
var step3list = {
icate: 'ic',
ative: '',
alize: 'al',
iciti: 'ic',
ical: 'ic',
ful: '',
ness: ''
};
var c = "[^aeiou]"; // consonant
var v = "[aeiouy]"; // vowel
var C = c + "[^aeiouy]*"; // consonant sequence
var V = v + "[aeiou]*"; // vowel sequence
var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0
var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1
var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1
var s_v = "^(" + C + ")?" + v; // vowel in stem
this.stemWord = function (w) {
var stem;
var suffix;
var firstch;
var origword = w;
if (w.length < 3)
return w;
var re;
var re2;
var re3;
var re4;
firstch = w.substr(0,1);
if (firstch == "y")
w = firstch.toUpperCase() + w.substr(1);
// Step 1a
re = /^(.+?)(ss|i)es$/;
re2 = /^(.+?)([^s])s$/;
if (re.test(w))
w = w.replace(re,"$1$2");
else if (re2.test(w))
w = w.replace(re2,"$1$2");
// Step 1b
re = /^(.+?)eed$/;
re2 = /^(.+?)(ed|ing)$/;
if (re.test(w)) {
var fp = re.exec(w);
re = new RegExp(mgr0);
if (re.test(fp[1])) {
re = /.$/;
w = w.replace(re,"");
}
}
else if (re2.test(w)) {
var fp = re2.exec(w);
stem = fp[1];
re2 = new RegExp(s_v);
if (re2.test(stem)) {
w = stem;
re2 = /(at|bl|iz)$/;
re3 = new RegExp("([^aeiouylsz])\\1$");
re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
if (re2.test(w))
w = w + "e";
else if (re3.test(w)) {
re = /.$/;
w = w.replace(re,"");
}
else if (re4.test(w))
w = w + "e";
}
}
// Step 1c
re = /^(.+?)y$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = new RegExp(s_v);
if (re.test(stem))
w = stem + "i";
}
// Step 2
re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
suffix = fp[2];
re = new RegExp(mgr0);
if (re.test(stem))
w = stem + step2list[suffix];
}
// Step 3
re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
suffix = fp[2];
re = new RegExp(mgr0);
if (re.test(stem))
w = stem + step3list[suffix];
}
// Step 4
re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
re2 = /^(.+?)(s|t)(ion)$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = new RegExp(mgr1);
if (re.test(stem))
w = stem;
}
else if (re2.test(w)) {
var fp = re2.exec(w);
stem = fp[1] + fp[2];
re2 = new RegExp(mgr1);
if (re2.test(stem))
w = stem;
}
// Step 5
re = /^(.+?)e$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = new RegExp(mgr1);
re2 = new RegExp(meq1);
re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
w = stem;
}
re = /ll$/;
re2 = new RegExp(mgr1);
if (re.test(w) && re2.test(w)) {
re = /.$/;
w = w.replace(re,"");
}
// and turn initial Y back to y
if (firstch == "y")
w = firstch.toLowerCase() + w.substr(1);
return w;
}
}
var splitChars = (function() {
var result = {};
var singles = [96, 180, 187, 191, 215, 247, 749, 885, 903, 907, 909, 930, 1014, 1648,
1748, 1809, 2416, 2473, 2481, 2526, 2601, 2609, 2612, 2615, 2653, 2702,
2706, 2729, 2737, 2740, 2857, 2865, 2868, 2910, 2928, 2948, 2961, 2971,
2973, 3085, 3089, 3113, 3124, 3213, 3217, 3241, 3252, 3295, 3341, 3345,
3369, 3506, 3516, 3633, 3715, 3721, 3736, 3744, 3748, 3750, 3756, 3761,
3781, 3912, 4239, 4347, 4681, 4695, 4697, 4745, 4785, 4799, 4801, 4823,
4881, 5760, 5901, 5997, 6313, 7405, 8024, 8026, 8028, 8030, 8117, 8125,
8133, 8181, 8468, 8485, 8487, 8489, 8494, 8527, 11311, 11359, 11687, 11695,
11703, 11711, 11719, 11727, 11735, 12448, 12539, 43010, 43014, 43019, 43587,
43696, 43713, 64286, 64297, 64311, 64317, 64319, 64322, 64325, 65141];
var i, j, start, end;
for (i = 0; i < singles.length; i++) {
result[singles[i]] = true;
}
var ranges = [[0, 47], [58, 64], [91, 94], [123, 169], [171, 177], [182, 184], [706, 709],
[722, 735], [741, 747], [751, 879], [888, 889], [894, 901], [1154, 1161],
[1318, 1328], [1367, 1368], [1370, 1376], [1416, 1487], [1515, 1519], [1523, 1568],
[1611, 1631], [1642, 1645], [1750, 1764], [1767, 1773], [1789, 1790], [1792, 1807],
[1840, 1868], [1958, 1968], [1970, 1983], [2027, 2035], [2038, 2041], [2043, 2047],
[2070, 2073], [2075, 2083], [2085, 2087], [2089, 2307], [2362, 2364], [2366, 2383],
[2385, 2391], [2402, 2405], [2419, 2424], [2432, 2436], [2445, 2446], [2449, 2450],
[2483, 2485], [2490, 2492], [2494, 2509], [2511, 2523], [2530, 2533], [2546, 2547],
[2554, 2564], [2571, 2574], [2577, 2578], [2618, 2648], [2655, 2661], [2672, 2673],
[2677, 2692], [2746, 2748], [2750, 2767], [2769, 2783], [2786, 2789], [2800, 2820],
[2829, 2830], [2833, 2834], [2874, 2876], [2878, 2907], [2914, 2917], [2930, 2946],
[2955, 2957], [2966, 2968], [2976, 2978], [2981, 2983], [2987, 2989], [3002, 3023],
[3025, 3045], [3059, 3076], [3130, 3132], [3134, 3159], [3162, 3167], [3170, 3173],
[3184, 3191], [3199, 3204], [3258, 3260], [3262, 3293], [3298, 3301], [3312, 3332],
[3386, 3388], [3390, 3423], [3426, 3429], [3446, 3449], [3456, 3460], [3479, 3481],
[3518, 3519], [3527, 3584], [3636, 3647], [3655, 3663], [3674, 3712], [3717, 3718],
[3723, 3724], [3726, 3731], [3752, 3753], [3764, 3772], [3774, 3775], [3783, 3791],
[3802, 3803], [3806, 3839], [3841, 3871], [3892, 3903], [3949, 3975], [3980, 4095],
[4139, 4158], [4170, 4175], [4182, 4185], [4190, 4192], [4194, 4196], [4199, 4205],
[4209, 4212], [4226, 4237], [4250, 4255], [4294, 4303], [4349, 4351], [4686, 4687],
[4702, 4703], [4750, 4751], [4790, 4791], [4806, 4807], [4886, 4887], [4955, 4968],
[4989, 4991], [5008, 5023], [5109, 5120], [5741, 5742], [5787, 5791], [5867, 5869],
[5873, 5887], [5906, 5919], [5938, 5951], [5970, 5983], [6001, 6015], [6068, 6102],
[6104, 6107], [6109, 6111], [6122, 6127], [6138, 6159], [6170, 6175], [6264, 6271],
[6315, 6319], [6390, 6399], [6429, 6469], [6510, 6511], [6517, 6527], [6572, 6592],
[6600, 6607], [6619, 6655], [6679, 6687], [6741, 6783], [6794, 6799], [6810, 6822],
[6824, 6916], [6964, 6980], [6988, 6991], [7002, 7042], [7073, 7085], [7098, 7167],
[7204, 7231], [7242, 7244], [7294, 7400], [7410, 7423], [7616, 7679], [7958, 7959],
[7966, 7967], [8006, 8007], [8014, 8015], [8062, 8063], [8127, 8129], [8141, 8143],
[8148, 8149], [8156, 8159], [8173, 8177], [8189, 8303], [8306, 8307], [8314, 8318],
[8330, 8335], [8341, 8449], [8451, 8454], [8456, 8457], [8470, 8472], [8478, 8483],
[8506, 8507], [8512, 8516], [8522, 8525], [8586, 9311], [9372, 9449], [9472, 10101],
[10132, 11263], [11493, 11498], [11503, 11516], [11518, 11519], [11558, 11567],
[11622, 11630], [11632, 11647], [11671, 11679], [11743, 11822], [11824, 12292],
[12296, 12320], [12330, 12336], [12342, 12343], [12349, 12352], [12439, 12444],
[12544, 12548], [12590, 12592], [12687, 12689], [12694, 12703], [12728, 12783],
[12800, 12831], [12842, 12880], [12896, 12927], [12938, 12976], [12992, 13311],
[19894, 19967], [40908, 40959], [42125, 42191], [42238, 42239], [42509, 42511],
[42540, 42559], [42592, 42593], [42607, 42622], [42648, 42655], [42736, 42774],
[42784, 42785], [42889, 42890], [42893, 43002], [43043, 43055], [43062, 43071],
[43124, 43137], [43188, 43215], [43226, 43249], [43256, 43258], [43260, 43263],
[43302, 43311], [43335, 43359], [43389, 43395], [43443, 43470], [43482, 43519],
[43561, 43583], [43596, 43599], [43610, 43615], [43639, 43641], [43643, 43647],
[43698, 43700], [43703, 43704], [43710, 43711], [43715, 43738], [43742, 43967],
[44003, 44015], [44026, 44031], [55204, 55215], [55239, 55242], [55292, 55295],
[57344, 63743], [64046, 64047], [64110, 64111], [64218, 64255], [64263, 64274],
[64280, 64284], [64434, 64466], [64830, 64847], [64912, 64913], [64968, 65007],
[65020, 65135], [65277, 65295], [65306, 65312], [65339, 65344], [65371, 65381],
[65471, 65473], [65480, 65481], [65488, 65489], [65496, 65497]];
for (i = 0; i < ranges.length; i++) {
start = ranges[i][0];
end = ranges[i][1];
for (j = start; j <= end; j++) {
result[j] = true;
}
}
return result;
})();
function splitQuery(query) {
var result = [];
var start = -1;
for (var i = 0; i < query.length; i++) {
if (splitChars[query.charCodeAt(i)]) {
if (start !== -1) {
result.push(query.slice(start, i));
start = -1;
}
} else if (start === -1) {
start = i;
}
}
if (start !== -1) {
result.push(query.slice(start));
}
return result;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 B

After

Width:  |  Height:  |  Size: 173 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 B

After

Width:  |  Height:  |  Size: 173 B

View file

@ -1,52 +1,231 @@
/*
* searchtools.js
* searchtools.js_t
* ~~~~~~~~~~~~~~~~
*
* Sphinx JavaScript utilities for the full-text search.
*
* :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
* :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
if (!Scorer) {
/**
* Simple result scoring code.
*/
var Scorer = {
// Implement the following function to further tweak the score for each result
// The function takes a result array [filename, title, anchor, descr, score]
// and returns the new score.
/*
score: function(result) {
return result[4];
},
*/
// query matches the full name of an object
objNameMatch: 11,
// or matches in the last dotted part of the object name
objPartialMatch: 6,
// Additive scores depending on the priority of the object
objPrio: {0: 15, // used to be importantResults
1: 5, // used to be objectResults
2: -5}, // used to be unimportantResults
// Used when the priority is not in the mapping.
objPrioDefault: 0,
/* Non-minified version JS is _stemmer.js if file is provided */
/**
* Porter Stemmer
*/
var Stemmer = function() {
// query found in title
title: 15,
// query found in terms
term: 5
var step2list = {
ational: 'ate',
tional: 'tion',
enci: 'ence',
anci: 'ance',
izer: 'ize',
bli: 'ble',
alli: 'al',
entli: 'ent',
eli: 'e',
ousli: 'ous',
ization: 'ize',
ation: 'ate',
ator: 'ate',
alism: 'al',
iveness: 'ive',
fulness: 'ful',
ousness: 'ous',
aliti: 'al',
iviti: 'ive',
biliti: 'ble',
logi: 'log'
};
}
if (!splitQuery) {
function splitQuery(query) {
return query.split(/\s+/);
var step3list = {
icate: 'ic',
ative: '',
alize: 'al',
iciti: 'ic',
ical: 'ic',
ful: '',
ness: ''
};
var c = "[^aeiou]"; // consonant
var v = "[aeiouy]"; // vowel
var C = c + "[^aeiouy]*"; // consonant sequence
var V = v + "[aeiou]*"; // vowel sequence
var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0
var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1
var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1
var s_v = "^(" + C + ")?" + v; // vowel in stem
this.stemWord = function (w) {
var stem;
var suffix;
var firstch;
var origword = w;
if (w.length < 3)
return w;
var re;
var re2;
var re3;
var re4;
firstch = w.substr(0,1);
if (firstch == "y")
w = firstch.toUpperCase() + w.substr(1);
// Step 1a
re = /^(.+?)(ss|i)es$/;
re2 = /^(.+?)([^s])s$/;
if (re.test(w))
w = w.replace(re,"$1$2");
else if (re2.test(w))
w = w.replace(re2,"$1$2");
// Step 1b
re = /^(.+?)eed$/;
re2 = /^(.+?)(ed|ing)$/;
if (re.test(w)) {
var fp = re.exec(w);
re = new RegExp(mgr0);
if (re.test(fp[1])) {
re = /.$/;
w = w.replace(re,"");
}
}
else if (re2.test(w)) {
var fp = re2.exec(w);
stem = fp[1];
re2 = new RegExp(s_v);
if (re2.test(stem)) {
w = stem;
re2 = /(at|bl|iz)$/;
re3 = new RegExp("([^aeiouylsz])\\1$");
re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
if (re2.test(w))
w = w + "e";
else if (re3.test(w)) {
re = /.$/;
w = w.replace(re,"");
}
else if (re4.test(w))
w = w + "e";
}
}
// Step 1c
re = /^(.+?)y$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = new RegExp(s_v);
if (re.test(stem))
w = stem + "i";
}
// Step 2
re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
suffix = fp[2];
re = new RegExp(mgr0);
if (re.test(stem))
w = stem + step2list[suffix];
}
// Step 3
re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
suffix = fp[2];
re = new RegExp(mgr0);
if (re.test(stem))
w = stem + step3list[suffix];
}
// Step 4
re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
re2 = /^(.+?)(s|t)(ion)$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = new RegExp(mgr1);
if (re.test(stem))
w = stem;
}
else if (re2.test(w)) {
var fp = re2.exec(w);
stem = fp[1] + fp[2];
re2 = new RegExp(mgr1);
if (re2.test(stem))
w = stem;
}
// Step 5
re = /^(.+?)e$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = new RegExp(mgr1);
re2 = new RegExp(meq1);
re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
w = stem;
}
re = /ll$/;
re2 = new RegExp(mgr1);
if (re.test(w) && re2.test(w)) {
re = /.$/;
w = w.replace(re,"");
}
// and turn initial Y back to y
if (firstch == "y")
w = firstch.toLowerCase() + w.substr(1);
return w;
}
}
/**
* Simple result scoring code.
*/
var Scorer = {
// Implement the following function to further tweak the score for each result
// The function takes a result array [filename, title, anchor, descr, score]
// and returns the new score.
/*
score: function(result) {
return result[4];
},
*/
// query matches the full name of an object
objNameMatch: 11,
// or matches in the last dotted part of the object name
objPartialMatch: 6,
// Additive scores depending on the priority of the object
objPrio: {0: 15, // used to be importantResults
1: 5, // used to be objectResults
2: -5}, // used to be unimportantResults
// Used when the priority is not in the mapping.
objPrioDefault: 0,
// query found in title
title: 15,
// query found in terms
term: 5
};
/**
* Search Module
*/
@ -138,13 +317,14 @@ var Search = {
*/
query : function(query) {
var i;
var stopwords = ["a","and","are","as","at","be","but","by","for","if","in","into","is","it","near","no","not","of","on","or","such","that","the","their","then","there","these","they","this","to","was","will","with"];
// stem the searchterms and add them to the correct list
var stemmer = new Stemmer();
var searchterms = [];
var excluded = [];
var hlterms = [];
var tmp = splitQuery(query);
var tmp = query.split(/\s+/);
var objectterms = [];
for (i = 0; i < tmp.length; i++) {
if (tmp[i] !== "") {
@ -158,10 +338,6 @@ var Search = {
}
// stem the word
var word = stemmer.stemWord(tmp[i].toLowerCase());
// prevent stemmer from cutting word smaller than two chars
if(word.length < 3 && tmp[i].length >= 3) {
word = tmp[i];
}
var toAppend;
// select the correct list
if (word[0] == '-') {
@ -259,11 +435,7 @@ var Search = {
displayNextItem();
});
} else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) {
var suffix = DOCUMENTATION_OPTIONS.SOURCELINK_SUFFIX;
if (suffix === undefined) {
suffix = '.txt';
}
$.ajax({url: DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' + item[5] + (item[5].slice(-suffix.length) === suffix ? '' : suffix),
$.ajax({url: DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' + item[0] + '.txt',
dataType: "text",
complete: function(jqxhr, textstatus) {
var data = jqxhr.responseText;
@ -302,7 +474,6 @@ var Search = {
*/
performObjectSearch : function(object, otherterms) {
var filenames = this._index.filenames;
var docnames = this._index.docnames;
var objects = this._index.objects;
var objnames = this._index.objnames;
var titles = this._index.titles;
@ -356,7 +527,7 @@ var Search = {
} else {
score += Scorer.objPrioDefault;
}
results.push([docnames[match[0]], fullname, '#'+anchor, descr, score, filenames[match[0]]]);
results.push([filenames[match[0]], fullname, '#'+anchor, descr, score]);
}
}
}
@ -368,7 +539,6 @@ var Search = {
* search for full-text terms in the index
*/
performTermsSearch : function(searchterms, excluded, terms, titleterms) {
var docnames = this._index.docnames;
var filenames = this._index.filenames;
var titles = this._index.titles;
@ -443,7 +613,7 @@ var Search = {
// select one (max) score for the file.
// for better ranking, we should calculate ranking by using words statistics like basic tf-idf...
var score = $u.max($u.map(fileMap[file], function(w){return scoreMap[file][w]}));
results.push([docnames[file], titles[file], '', null, score, filenames[file]]);
results.push([filenames[file], titles[file], '', null, score]);
}
}
return results;
@ -478,4 +648,4 @@ var Search = {
$(document).ready(function() {
Search.init();
});
});

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 B

After

Width:  |  Height:  |  Size: 345 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 B

After

Width:  |  Height:  |  Size: 345 B

View file

@ -4,7 +4,7 @@
*
* sphinx.websupport utilities for all documentation.
*
* :copyright: Copyright 2007-2019 by the Sphinx team, see AUTHORS.
* :copyright: Copyright 2007-2016 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
@ -301,7 +301,7 @@
li.hide();
// Determine where in the parents children list to insert this comment.
for(var i=0; i < siblings.length; i++) {
for(i=0; i < siblings.length; i++) {
if (comp(comment, siblings[i]) <= 0) {
$('#cd' + siblings[i].id)
.parent()

File diff suppressed because it is too large Load diff

View file

@ -8,7 +8,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Contents &mdash; fmt 7.0.3 documentation</title>
<title>Contents &mdash; fmt 7.1.3 documentation</title>
<link rel="stylesheet" href="_static/basic.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
@ -17,19 +17,16 @@
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '7.0.3',
VERSION: '7.1.3',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true,
SOURCELINK_SUFFIX: '.txt'
SOURCELINK_SUFFIX: ''
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<script type="text/javascript" src="_static/language_data.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="Usage" href="usage.html" />
<meta name="description" content="Small, safe and fast formatting library">
<meta name="keywords" content="C++, formatting, printf, string, library">
@ -68,15 +65,15 @@
<ul class="nav navbar-nav">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown"
role="button" aria-expanded="false">7.0.3
role="button" aria-expanded="false">7.1.3
<span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="https://fmt.dev/7.0.3">7.0.3</a></li>
<li><a href="https://fmt.dev/7.1.3">7.1.3</a></li>
<li><a href="https://fmt.dev/7.0.2">7.0.2</a></li>
<li><a href="https://fmt.dev/7.1.2">7.1.2</a></li>
<li><a href="https://fmt.dev/7.0.1">7.0.1</a></li>
<li><a href="https://fmt.dev/7.1.1">7.1.1</a></li>
</ul>
</li>
@ -134,9 +131,11 @@
<li class="toctree-l2"><a class="reference internal" href="usage.html#building-the-library">Building the Library</a></li>
<li class="toctree-l2"><a class="reference internal" href="usage.html#installing-the-library">Installing the Library</a></li>
<li class="toctree-l2"><a class="reference internal" href="usage.html#usage-with-cmake">Usage with CMake</a></li>
<li class="toctree-l2"><a class="reference internal" href="usage.html#usage-with-build2">Usage with build2</a></li>
<li class="toctree-l2"><a class="reference internal" href="usage.html#building-the-documentation">Building the Documentation</a></li>
<li class="toctree-l2"><a class="reference internal" href="usage.html#conda">Conda</a></li>
<li class="toctree-l2"><a class="reference internal" href="usage.html#vcpkg">Vcpkg</a></li>
<li class="toctree-l2"><a class="reference internal" href="usage.html#lhelper">LHelper</a></li>
<li class="toctree-l2"><a class="reference internal" href="usage.html#android-ndk">Android NDK</a></li>
<li class="toctree-l2"><a class="reference internal" href="usage.html#homebrew">Homebrew</a></li>
</ul>
@ -147,9 +146,10 @@
<li class="toctree-l2"><a class="reference internal" href="api.html#ranges-and-tuple-formatting">Ranges and Tuple Formatting</a></li>
<li class="toctree-l2"><a class="reference internal" href="api.html#date-and-time-formatting">Date and Time Formatting</a></li>
<li class="toctree-l2"><a class="reference internal" href="api.html#format-string-compilation">Format string compilation</a></li>
<li class="toctree-l2"><a class="reference internal" href="api.html#std-ostream-support"><code class="docutils literal notranslate"><span class="pre">std::ostream</span></code> Support</a></li>
<li class="toctree-l2"><a class="reference internal" href="api.html#printf-formatting"><code class="docutils literal notranslate"><span class="pre">printf</span></code> Formatting</a></li>
<li class="toctree-l2"><a class="reference internal" href="api.html#compatibility-with-c-20-std-format">Compatibility with C++20 <code class="docutils literal notranslate"><span class="pre">std::format</span></code></a></li>
<li class="toctree-l2"><a class="reference internal" href="api.html#terminal-color-and-text-style">Terminal color and text style</a></li>
<li class="toctree-l2"><a class="reference internal" href="api.html#std-ostream-support"><code class="docutils literal"><span class="pre">std::ostream</span></code> Support</a></li>
<li class="toctree-l2"><a class="reference internal" href="api.html#printf-formatting"><code class="docutils literal"><span class="pre">printf</span></code> Formatting</a></li>
<li class="toctree-l2"><a class="reference internal" href="api.html#compatibility-with-c-20-std-format">Compatibility with C++20 <code class="docutils literal"><span class="pre">std::format</span></code></a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="syntax.html">Format String Syntax</a><ul>
@ -170,7 +170,7 @@
<div class="footer" role="contentinfo">
&copy; Copyright 2012-present, Victor Zverovich.
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.5.
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.4.1+.
</div>
<script src="_static/bootstrap.min.js"></script>

View file

@ -9,7 +9,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Index &mdash; fmt 7.0.3 documentation</title>
<title>Index &mdash; fmt 7.1.3 documentation</title>
<link rel="stylesheet" href="_static/basic.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
@ -18,19 +18,16 @@
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '7.0.3',
VERSION: '7.1.3',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true,
SOURCELINK_SUFFIX: '.txt'
SOURCELINK_SUFFIX: ''
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<script type="text/javascript" src="_static/language_data.js"></script>
<link rel="index" title="Index" href="#" />
<link rel="search" title="Search" href="search.html" />
<meta name="description" content="Small, safe and fast formatting library">
<meta name="keywords" content="C++, formatting, printf, string, library">
<meta name="author" content="Victor Zverovich">
@ -68,15 +65,15 @@
<ul class="nav navbar-nav">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown"
role="button" aria-expanded="false">7.0.3
role="button" aria-expanded="false">7.1.3
<span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="https://fmt.dev/7.0.3">7.0.3</a></li>
<li><a href="https://fmt.dev/7.1.3">7.1.3</a></li>
<li><a href="https://fmt.dev/7.0.2">7.0.2</a></li>
<li><a href="https://fmt.dev/7.1.2">7.1.2</a></li>
<li><a href="https://fmt.dev/7.0.1">7.0.1</a></li>
<li><a href="https://fmt.dev/7.1.1">7.1.1</a></li>
</ul>
</li>
@ -134,134 +131,266 @@
</div>
<h2 id="F">F</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.html#_CPPv4N3fmt3argEPK4CharRK1T">fmt::arg (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt16basic_format_argE">fmt::basic_format_arg (C++ class)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt17basic_format_argsE">fmt::basic_format_args (C++ class)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt17basic_format_args17basic_format_argsEPK10format_argi">fmt::basic_format_args::basic_format_args (C++ function)</a>, <a href="api.html#_CPPv4N3fmt17basic_format_args17basic_format_argsERK16format_arg_storeI7ContextDp4ArgsE">[1]</a>, <a href="api.html#_CPPv4N3fmt17basic_format_args17basic_format_argsERK24dynamic_format_arg_storeI7ContextE">[2]</a>
</li>
<li><a href="api.html#_CPPv4NK3fmt17basic_format_args3getEi">fmt::basic_format_args::get (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt26basic_format_parse_contextE">fmt::basic_format_parse_context (C++ class)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt26basic_format_parse_context10advance_toE8iterator">fmt::basic_format_parse_context::advance_to (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4NK3fmt26basic_format_parse_context5beginEv">fmt::basic_format_parse_context::begin (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt26basic_format_parse_context12check_arg_idEi">fmt::basic_format_parse_context::check_arg_id (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4NK3fmt26basic_format_parse_context3endEv">fmt::basic_format_parse_context::end (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt26basic_format_parse_context11next_arg_idEv">fmt::basic_format_parse_context::next_arg_id (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt19basic_memory_bufferE">fmt::basic_memory_buffer (C++ class)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt19basic_memory_buffer19basic_memory_bufferERR19basic_memory_buffer">fmt::basic_memory_buffer::basic_memory_buffer (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt19basic_memory_buffer4growE6size_t">fmt::basic_memory_buffer::grow (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt19basic_memory_bufferaSERR19basic_memory_buffer">fmt::basic_memory_buffer::operator= (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt17basic_string_viewE">fmt::basic_string_view (C++ class)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt17basic_string_view17basic_string_viewEPK4Char">fmt::basic_string_view::basic_string_view (C++ function)</a>, <a href="api.html#_CPPv4N3fmt17basic_string_view17basic_string_viewEPK4Char6size_t">[1]</a>, <a href="api.html#_CPPv4N3fmt17basic_string_view17basic_string_viewERKNSt12basic_stringI4Char6Traits5AllocEE">[2]</a>
</li>
<li><a href="api.html#_CPPv4NK3fmt17basic_string_view4dataEv">fmt::basic_string_view::data (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4NK3fmt17basic_string_view4sizeEv">fmt::basic_string_view::size (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt13buffered_file6vprintE11string_view11format_args">fmt::buffered_file::vprint (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt6detail6bufferE">fmt::detail::buffer (C++ class)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt6detail6buffer6appendEPK1UPK1U">fmt::detail::buffer::append (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4NK3fmt6detail6buffer8capacityEv">fmt::detail::buffer::capacity (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt6detail6buffer5clearEv">fmt::detail::buffer::clear (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt6detail6buffer4dataEv">fmt::detail::buffer::data (C++ function)</a>, <a href="api.html#_CPPv4NK3fmt6detail6buffer4dataEv">[1]</a>
</li>
<li><a href="api.html#_CPPv4N3fmt6detail6buffer7reserveE6size_t">fmt::detail::buffer::reserve (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt6detail6buffer6resizeE6size_t">fmt::detail::buffer::resize (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4NK3fmt6detail6buffer4sizeEv">fmt::detail::buffer::size (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt24dynamic_format_arg_storeE">fmt::dynamic_format_arg_store (C++ class)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt24dynamic_format_arg_store5clearEv">fmt::dynamic_format_arg_store::clear (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt24dynamic_format_arg_store9push_backENSt17reference_wrapperI1TEE">fmt::dynamic_format_arg_store::push_back (C++ function)</a>, <a href="api.html#_CPPv4N3fmt24dynamic_format_arg_store9push_backERK1T">[1]</a>, <a href="api.html#_CPPv4N3fmt24dynamic_format_arg_store9push_backERKN6detail9named_argI9char_type1TEE">[2]</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.html#_CPPv4N3fmt24dynamic_format_arg_store7reserveE6size_t6size_t">fmt::dynamic_format_arg_store::reserve (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt6formatERK1SDpRR4Args">fmt::format (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt16format_arg_storeE">fmt::format_arg_store (C++ class)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt11format_argsE">fmt::format_args (C++ class)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt19format_system_errorERN6detail6bufferIcEEi11string_view">fmt::format_system_error (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt9format_toE8OutputItRK1SDpRR4Args">fmt::format_to (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt11format_to_nE8OutputIt6size_tRK1SDpRK4Args">fmt::format_to_n (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt18format_to_n_resultE">fmt::format_to_n_result (C++ class)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt18format_to_n_result3outE">fmt::format_to_n_result::out (C++ member)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt18format_to_n_result4sizeE">fmt::format_to_n_result::size (C++ member)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt14formatted_sizeE11string_viewDpRK4Args">fmt::formatted_size (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt7fprintfEPNSt4FILEERK1SDpRK4Args">fmt::fprintf (C++ function)</a>, <a href="api.html#_CPPv4N3fmt7fprintfERNSt13basic_ostreamI4CharEERK1SDpRK4Args">[1]</a>
</li>
<li><a href="api.html#_CPPv4N3fmt7is_charE">fmt::is_char (C++ class)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt4joinE2It8Sentinel11string_view">fmt::join (C++ function)</a>, <a href="api.html#_CPPv4N3fmt4joinERK5Range11string_view">[1]</a>
</li>
<li><a href="api.html#_CPPv4N3fmt8literalsli2_aEPKc6size_t">fmt::literals::operator&#34;&#34;_a (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt8literalsli7_formatEPKc6size_t">fmt::literals::operator&#34;&#34;_format (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt16make_format_argsEDpRK4Args">fmt::make_format_args (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt5printEPNSt4FILEERK1SDpRR4Args">fmt::print (C++ function)</a>, <a href="api.html#_CPPv4N3fmt5printERK1SDpRR4Args">[1]</a>, <a href="api.html#_CPPv4N3fmt5printERNSt13basic_ostreamI4CharEERK1SDpRR4Args">[2]</a>
</li>
<li><a href="api.html#_CPPv4N3fmt6printfERK1SDpRK4Args">fmt::printf (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt7sprintfERK1SDpRK4Args">fmt::sprintf (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt12system_errorE">fmt::system_error (C++ class)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt12system_error12system_errorEi11string_viewDpRK4Args">fmt::system_error::system_error (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt9to_stringERK1T">fmt::to_string (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt14to_string_viewEPK4Char">fmt::to_string_view (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt10to_wstringERK1T">fmt::to_wstring (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt7vformatERK1S17basic_format_argsI14buffer_contextI15type_identity_tI4CharEEE">fmt::vformat (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt6vprintEPNSt4FILEE11string_view11format_args">fmt::vprint (C++ function)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt13windows_errorE">fmt::windows_error (C++ class)</a>
</li>
<li><a href="api.html#_CPPv4N3fmt13windows_error13windows_errorEi11string_viewDpRK4Args">fmt::windows_error::windows_error (C++ function)</a>
</li>
<li><a href="api.html#c.FMT_COMPILE">FMT_COMPILE (C macro)</a>
</li>
<li><a href="api.html#c.FMT_STRING">FMT_STRING (C macro)</a>
</li>
</ul></td>
<td style="width: 33%" valign="top"><dl>
<dt><a href="api.html#_CPPv2N3fmt3argEPK4CharRK1T">fmt::arg (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt16basic_format_argE">fmt::basic_format_arg (C++ class)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt17basic_format_argsE">fmt::basic_format_args (C++ class)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt17basic_format_args17basic_format_argsEPK10format_argi">fmt::basic_format_args::basic_format_args (C++ function)</a>, <a href="api.html#_CPPv2N3fmt17basic_format_args17basic_format_argsERK16format_arg_storeI7ContextDp4ArgsE">[1]</a>, <a href="api.html#_CPPv2N3fmt17basic_format_args17basic_format_argsERK24dynamic_format_arg_storeI7ContextE">[2]</a>
</dt>
<dt><a href="api.html#_CPPv2NK3fmt17basic_format_args3getEi">fmt::basic_format_args::get (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt26basic_format_parse_contextE">fmt::basic_format_parse_context (C++ class)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt26basic_format_parse_context10advance_toE8iterator">fmt::basic_format_parse_context::advance_to (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2NK3fmt26basic_format_parse_context5beginEv">fmt::basic_format_parse_context::begin (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt26basic_format_parse_context12check_arg_idEi">fmt::basic_format_parse_context::check_arg_id (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2NK3fmt26basic_format_parse_context3endEv">fmt::basic_format_parse_context::end (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt26basic_format_parse_context11next_arg_idEv">fmt::basic_format_parse_context::next_arg_id (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt19basic_memory_bufferE">fmt::basic_memory_buffer (C++ class)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt19basic_memory_buffer19basic_memory_bufferERR19basic_memory_buffer">fmt::basic_memory_buffer::basic_memory_buffer (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt19basic_memory_buffer4growE6size_t">fmt::basic_memory_buffer::grow (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt19basic_memory_bufferaSERR19basic_memory_buffer">fmt::basic_memory_buffer::operator= (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt19basic_memory_buffer7reserveE6size_t">fmt::basic_memory_buffer::reserve (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt19basic_memory_buffer6resizeE6size_t">fmt::basic_memory_buffer::resize (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt17basic_string_viewE">fmt::basic_string_view (C++ class)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt17basic_string_view17basic_string_viewEPK4Char">fmt::basic_string_view::basic_string_view (C++ function)</a>, <a href="api.html#_CPPv2N3fmt17basic_string_view17basic_string_viewEPK4Char6size_t">[1]</a>, <a href="api.html#_CPPv2N3fmt17basic_string_view17basic_string_viewERKNSt12basic_stringI4Char6Traits5AllocEE">[2]</a>
</dt>
<dt><a href="api.html#_CPPv2NK3fmt17basic_string_view4dataEv">fmt::basic_string_view::data (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2NK3fmt17basic_string_view4sizeEv">fmt::basic_string_view::size (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt13buffered_file6vprintE11string_view11format_args">fmt::buffered_file::vprint (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt6detail6bufferE">fmt::detail::buffer (C++ class)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt6detail6buffer6appendEPK1UPK1U">fmt::detail::buffer::append (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2NK3fmt6detail6buffer8capacityEv">fmt::detail::buffer::capacity (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt6detail6buffer5clearEv">fmt::detail::buffer::clear (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt6detail6buffer4dataEv">fmt::detail::buffer::data (C++ function)</a>, <a href="api.html#_CPPv2NK3fmt6detail6buffer4dataEv">[1]</a>
</dt>
<dt><a href="api.html#_CPPv2NK3fmt6detail6buffer4sizeEv">fmt::detail::buffer::size (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt24dynamic_format_arg_storeE">fmt::dynamic_format_arg_store (C++ class)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt24dynamic_format_arg_store5clearEv">fmt::dynamic_format_arg_store::clear (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt24dynamic_format_arg_store9push_backENSt17reference_wrapperI1TEE">fmt::dynamic_format_arg_store::push_back (C++ function)</a>, <a href="api.html#_CPPv2N3fmt24dynamic_format_arg_store9push_backERK1T">[1]</a>, <a href="api.html#_CPPv2N3fmt24dynamic_format_arg_store9push_backERKN6detail9named_argI9char_type1TEE">[2]</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt24dynamic_format_arg_store7reserveE6size_t6size_t">fmt::dynamic_format_arg_store::reserve (C++ function)</a>
</dt>
</dl></td>
<td style="width: 33%" valign="top"><dl>
<dt><a href="api.html#_CPPv2N3fmt6formatERK1SDpRR4Args">fmt::format (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt16format_arg_storeE">fmt::format_arg_store (C++ class)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt11format_argsE">fmt::format_args (C++ class)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt19format_system_errorERN6detail6bufferIcEEi11string_view">fmt::format_system_error (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt9format_toE8OutputItRK1SDpRR4Args">fmt::format_to (C++ function)</a>, <a href="api.html#_CPPv2N3fmt9format_toE8OutputItRK1SDpRR4Args">[1]</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt11format_to_nE8OutputIt6size_tRK1SDpRK4Args">fmt::format_to_n (C++ function)</a>, <a href="api.html#_CPPv2N3fmt11format_to_nE8OutputIt6size_tRK1SDpRK4Args">[1]</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt18format_to_n_resultE">fmt::format_to_n_result (C++ class)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt18format_to_n_result3outE">fmt::format_to_n_result::out (C++ member)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt18format_to_n_result4sizeE">fmt::format_to_n_result::size (C++ member)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt14formatted_sizeE11string_viewDpRR4Args">fmt::formatted_size (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt7fprintfEPNSt4FILEERK1SDpRK4Args">fmt::fprintf (C++ function)</a>, <a href="api.html#_CPPv2N3fmt7fprintfERNSt13basic_ostreamI4CharEERK1SDpRK4Args">[1]</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt7is_charE">fmt::is_char (C++ class)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt4joinE2It8Sentinel11string_view">fmt::join (C++ function)</a>, <a href="api.html#_CPPv2N3fmt4joinERR5Range11string_view">[1]</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt8literalsli2_aEPKc6size_t">fmt::literals::operator&#34;&#34;_a (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt8literalsli7_formatEPKc6size_t">fmt::literals::operator&#34;&#34;_format (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt17make_args_checkedERK1SDpRK18remove_reference_tI4ArgsE">fmt::make_args_checked (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt16make_format_argsEDpRK4Args">fmt::make_format_args (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt5printEPNSt4FILEERK1SDpRR4Args">fmt::print (C++ function)</a>, <a href="api.html#_CPPv2N3fmt5printERK10text_styleRK1SDpRK4Args">[1]</a>, <a href="api.html#_CPPv2N3fmt5printERK1SDpRR4Args">[2]</a>, <a href="api.html#_CPPv2N3fmt5printERNSt13basic_ostreamI4CharEERK1SDpRR4Args">[3]</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt6printfERK1SDpRK4Args">fmt::printf (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt3ptrEPK1T">fmt::ptr (C++ function)</a>, <a href="api.html#_CPPv2N3fmt3ptrERKNSt10shared_ptrI1TEE">[1]</a>, <a href="api.html#_CPPv2N3fmt3ptrERKNSt10unique_ptrI1TEE">[2]</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt7sprintfERK1SDpRK4Args">fmt::sprintf (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt12system_errorE">fmt::system_error (C++ class)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt12system_error12system_errorEi11string_viewDpRK4Args">fmt::system_error::system_error (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt9to_stringERK1T">fmt::to_string (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt14to_string_viewEPK4Char">fmt::to_string_view (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt10to_wstringERK1T">fmt::to_wstring (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt7vformatERK1S17basic_format_argsI14buffer_contextI15type_identity_tI4CharEEE">fmt::vformat (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt6vprintEPNSt4FILEE11string_view11format_args">fmt::vprint (C++ function)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt13windows_errorE">fmt::windows_error (C++ class)</a>
</dt>
<dt><a href="api.html#_CPPv2N3fmt13windows_error13windows_errorEi11string_viewDpRK4Args">fmt::windows_error::windows_error (C++ function)</a>
</dt>
<dt><a href="api.html#c.FMT_COMPILE">FMT_COMPILE (C macro)</a>
</dt>
<dt><a href="api.html#c.FMT_STRING">FMT_STRING (C macro)</a>
</dt>
</dl></td>
</tr></table>
@ -274,7 +403,7 @@
<div class="footer" role="contentinfo">
&copy; Copyright 2012-present, Victor Zverovich.
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.5.
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.4.1+.
</div>
<script src="_static/bootstrap.min.js"></script>

View file

@ -8,7 +8,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Overview &mdash; fmt 7.0.3 documentation</title>
<title>Overview &mdash; fmt 7.1.3 documentation</title>
<link rel="stylesheet" href="_static/basic.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
@ -17,19 +17,16 @@
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '7.0.3',
VERSION: '7.1.3',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true,
SOURCELINK_SUFFIX: '.txt'
SOURCELINK_SUFFIX: ''
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<script type="text/javascript" src="_static/language_data.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<meta name="description" content="Small, safe and fast formatting library">
<meta name="keywords" content="C++, formatting, printf, string, library">
<meta name="author" content="Victor Zverovich">
@ -67,15 +64,15 @@
<ul class="nav navbar-nav">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown"
role="button" aria-expanded="false">7.0.3
role="button" aria-expanded="false">7.1.3
<span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="https://fmt.dev/7.0.3">7.0.3</a></li>
<li><a href="https://fmt.dev/7.1.3">7.1.3</a></li>
<li><a href="https://fmt.dev/7.0.2">7.0.2</a></li>
<li><a href="https://fmt.dev/7.1.2">7.1.2</a></li>
<li><a href="https://fmt.dev/7.0.1">7.0.1</a></li>
<li><a href="https://fmt.dev/7.1.1">7.1.1</a></li>
</ul>
</li>
@ -124,7 +121,7 @@
<div class="btn-group" role="group">
<a class="btn btn-success"
href="https://github.com/fmtlib/fmt/releases/download/7.0.3/fmt-7.0.3.zip">
href="https://github.com/fmtlib/fmt/releases/download/7.1.3/fmt-7.1.3.zip">
<span class="glyphicon glyphicon-download"></span> Download
</a>
<button type="button" class="btn btn-success dropdown-toggle"
@ -132,15 +129,15 @@
<ul class="dropdown-menu">
<li><a href="https://github.com/fmtlib/fmt/releases/download/7.0.3/fmt-7.0.3.zip">Version 7.0.3
<li><a href="https://github.com/fmtlib/fmt/releases/download/7.1.3/fmt-7.1.3.zip">Version 7.1.3
</a></li>
<li><a href="https://github.com/fmtlib/fmt/releases/download/7.0.2/fmt-7.0.2.zip">Version 7.0.2
<li><a href="https://github.com/fmtlib/fmt/releases/download/7.1.2/fmt-7.1.2.zip">Version 7.1.2
</a></li>
<li><a href="https://github.com/fmtlib/fmt/releases/download/7.0.1/fmt-7.0.1.zip">Version 7.0.1
<li><a href="https://github.com/fmtlib/fmt/releases/download/7.1.1/fmt-7.1.1.zip">Version 7.1.1
</a></li>
</ul>
@ -170,44 +167,42 @@ alternative to C stdio and C++ iostreams.</p>
</div>
</div><div class="section" id="format-api">
<span id="format-api-intro"></span><h2>Format API<a class="headerlink" href="#format-api" title="Permalink to this headline"></a></h2>
<p>The format API is similar in spirit to the C <code class="docutils literal notranslate"><span class="pre">printf</span></code> family of function but
is safer, simpler and several times <a class="reference external" href="http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html">faster</a>
<p>The format API is similar in spirit to the C <code class="docutils literal"><span class="pre">printf</span></code> family of function but
is safer, simpler and several times <a class="reference external" href="https://www.zverovich.net/2020/06/13/fast-int-to-string-revisited.html">faster</a>
than common standard library implementations.
The <a class="reference external" href="syntax.html">format string syntax</a> is similar to the one used by
<a class="reference external" href="http://docs.python.org/3/library/stdtypes.html#str.format">str.format</a> in
Python:</p>
<div class="code c++ highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">&quot;The answer is {}.&quot;</span><span class="p">,</span> <span class="mi">42</span><span class="p">);</span>
<div class="code c++ highlight-c++"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">&quot;The answer is {}.&quot;</span><span class="p">,</span> <span class="mi">42</span><span class="p">);</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">fmt::format</span></code> function returns a string “The answer is 42.”. You can use
<code class="docutils literal notranslate"><span class="pre">fmt::memory_buffer</span></code> to avoid constructing <code class="docutils literal notranslate"><span class="pre">std::string</span></code>:</p>
<div class="code c++ highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">memory_buffer</span> <span class="n">out</span><span class="p">;</span>
<p>The <code class="docutils literal"><span class="pre">fmt::format</span></code> function returns a string &#8220;The answer is 42.&#8221;. You can use
<code class="docutils literal"><span class="pre">fmt::memory_buffer</span></code> to avoid constructing <code class="docutils literal"><span class="pre">std::string</span></code>:</p>
<div class="code c++ highlight-c++"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">memory_buffer</span> <span class="n">out</span><span class="p">;</span>
<span class="n">format_to</span><span class="p">(</span><span class="n">out</span><span class="p">,</span> <span class="s">&quot;For a moment, {} happened.&quot;</span><span class="p">,</span> <span class="s">&quot;nothing&quot;</span><span class="p">);</span>
<span class="n">out</span><span class="p">.</span><span class="n">data</span><span class="p">();</span> <span class="c1">// returns a pointer to the formatted data</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">fmt::print</span></code> function performs formatting and writes the result to a stream:</p>
<div class="code c++ highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">&quot;System error code = {}</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">errno</span><span class="p">);</span>
<p>The <code class="docutils literal"><span class="pre">fmt::print</span></code> function performs formatting and writes the result to a stream:</p>
<div class="code c++ highlight-c++"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">&quot;System error code = {}</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="n">errno</span><span class="p">);</span>
</pre></div>
</div>
<p>The file argument can be omitted in which case the function prints to
<code class="docutils literal notranslate"><span class="pre">stdout</span></code>:</p>
<div class="code c++ highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&quot;Don&#39;t {}</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="s">&quot;panic&quot;</span><span class="p">);</span>
<p>If you omit the file argument the function will print to <code class="docutils literal"><span class="pre">stdout</span></code>:</p>
<div class="code c++ highlight-c++"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&quot;Don&#39;t {}</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="s">&quot;panic&quot;</span><span class="p">);</span>
</pre></div>
</div>
<p>The Format API also supports positional arguments useful for localization:</p>
<div class="code c++ highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&quot;I&#39;d rather be {1} than {0}.&quot;</span><span class="p">,</span> <span class="s">&quot;right&quot;</span><span class="p">,</span> <span class="s">&quot;happy&quot;</span><span class="p">);</span>
<p>The format API also supports positional arguments useful for localization:</p>
<div class="code c++ highlight-c++"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&quot;I&#39;d rather be {1} than {0}.&quot;</span><span class="p">,</span> <span class="s">&quot;right&quot;</span><span class="p">,</span> <span class="s">&quot;happy&quot;</span><span class="p">);</span>
</pre></div>
</div>
<p>Named arguments can be created with <code class="docutils literal notranslate"><span class="pre">fmt::arg</span></code>. This makes it easier to track
what goes where when multiple arguments are being formatted:</p>
<div class="code c++ highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&quot;Hello, {name}! The answer is {number}. Goodbye, {name}.&quot;</span><span class="p">,</span>
<p>You can pass named arguments with <code class="docutils literal"><span class="pre">fmt::arg</span></code>:</p>
<div class="code c++ highlight-c++"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&quot;Hello, {name}! The answer is {number}. Goodbye, {name}.&quot;</span><span class="p">,</span>
<span class="n">fmt</span><span class="o">::</span><span class="n">arg</span><span class="p">(</span><span class="s">&quot;name&quot;</span><span class="p">,</span> <span class="s">&quot;World&quot;</span><span class="p">),</span> <span class="n">fmt</span><span class="o">::</span><span class="n">arg</span><span class="p">(</span><span class="s">&quot;number&quot;</span><span class="p">,</span> <span class="mi">42</span><span class="p">));</span>
</pre></div>
</div>
<p>If your compiler supports C++11 user-defined literals, the suffix <code class="docutils literal notranslate"><span class="pre">_a</span></code> offers
<p>If your compiler supports C++11 user-defined literals, the suffix <code class="docutils literal"><span class="pre">_a</span></code> offers
an alternative, slightly terser syntax for named arguments:</p>
<div class="code c++ highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="k">using</span> <span class="k">namespace</span> <span class="n">fmt</span><span class="o">::</span><span class="n">literals</span><span class="p">;</span>
<div class="code c++ highlight-c++"><div class="highlight"><pre><span></span><span class="k">using</span> <span class="k">namespace</span> <span class="n">fmt</span><span class="o">::</span><span class="n">literals</span><span class="p">;</span>
<span class="n">fmt</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&quot;Hello, {name}! The answer is {number}. Goodbye, {name}.&quot;</span><span class="p">,</span>
<span class="s">&quot;name&quot;</span><span class="n">_a</span><span class="o">=</span><span class="s">&quot;World&quot;</span><span class="p">,</span> <span class="s">&quot;number&quot;</span><span class="n">_a</span><span class="o">=</span><span class="mi">42</span><span class="p">);</span>
</pre></div>
@ -218,36 +213,36 @@ an alternative, slightly terser syntax for named arguments:</p>
<p>The library is fully type safe, automatic memory management prevents buffer
overflow, errors in format strings are reported using exceptions or at compile
time. For example, the code</p>
<div class="code c++ highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">&quot;The answer is {:d}&quot;</span><span class="p">,</span> <span class="s">&quot;forty-two&quot;</span><span class="p">);</span>
<div class="code c++ highlight-c++"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">&quot;The answer is {:d}&quot;</span><span class="p">,</span> <span class="s">&quot;forty-two&quot;</span><span class="p">);</span>
</pre></div>
</div>
<p>throws a <code class="docutils literal notranslate"><span class="pre">format_error</span></code> exception with description “unknown format code d for
string”, because the argument <code class="docutils literal notranslate"><span class="pre">&quot;forty-two&quot;</span></code> is a string while the format code
<code class="docutils literal notranslate"><span class="pre">d</span></code> only applies to integers, while</p>
<div class="code c++ highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">format</span><span class="p">(</span><span class="n">FMT_STRING</span><span class="p">(</span><span class="s">&quot;The answer is {:d}&quot;</span><span class="p">),</span> <span class="s">&quot;forty-two&quot;</span><span class="p">);</span>
<p>throws the <code class="docutils literal"><span class="pre">format_error</span></code> exception because the argument <code class="docutils literal"><span class="pre">&quot;forty-two&quot;</span></code> is a
string while the format code <code class="docutils literal"><span class="pre">d</span></code> only applies to integers.</p>
<p>The code</p>
<div class="code c++ highlight-c++"><div class="highlight"><pre><span></span><span class="n">format</span><span class="p">(</span><span class="n">FMT_STRING</span><span class="p">(</span><span class="s">&quot;The answer is {:d}&quot;</span><span class="p">),</span> <span class="s">&quot;forty-two&quot;</span><span class="p">);</span>
</pre></div>
</div>
<p>reports a compile-time error for the same reason on compilers that support
relaxed <code class="docutils literal notranslate"><span class="pre">constexpr</span></code>. See <a class="reference external" href="api.html#c.fmt">here</a> for details.</p>
<p>reports a compile-time error on compilers that support relaxed <code class="docutils literal"><span class="pre">constexpr</span></code>.
See <a class="reference external" href="api.html#c.fmt">here</a> for details.</p>
<p>The following code</p>
<div class="code c++ highlight-c++ notranslate"><div class="highlight"><pre><span></span>fmt::format(&quot;Cyrillic letter {}&quot;, L&#39;\x42e&#39;);
<div class="code c++ highlight-c++"><div class="highlight"><pre><span></span>fmt::format(&quot;Cyrillic letter {}&quot;, L&#39;\x42e&#39;);
</pre></div>
</div>
<p>produces a compile-time error because wide character <code class="docutils literal notranslate"><span class="pre">L'\x42e'</span></code> cannot be
<p>produces a compile-time error because wide character <code class="docutils literal"><span class="pre">L'\x42e'</span></code> cannot be
formatted into a narrow string. You can use a wide format string instead:</p>
<div class="code c++ highlight-c++ notranslate"><div class="highlight"><pre><span></span>fmt::format(L&quot;Cyrillic letter {}&quot;, L&#39;\x42e&#39;);
<div class="code c++ highlight-c++"><div class="highlight"><pre><span></span>fmt::format(L&quot;Cyrillic letter {}&quot;, L&#39;\x42e&#39;);
</pre></div>
</div>
<p>For comparison, writing a wide character to <code class="docutils literal notranslate"><span class="pre">std::ostream</span></code> results in
its numeric value being written to the stream (i.e. 1070 instead of letter ‘ю’
which is represented by <code class="docutils literal notranslate"><span class="pre">L'\x42e'</span></code> if we use Unicode) which is rarely what is
needed.</p>
<p>For comparison, writing a wide character to <code class="docutils literal"><span class="pre">std::ostream</span></code> results in
its numeric value being written to the stream (i.e. 1070 instead of letter &#8216;ю&#8217;
which is represented by <code class="docutils literal"><span class="pre">L'\x42e'</span></code> if we use Unicode) which is rarely
desirable.</p>
</div>
<div class="section" id="compact-binary-code">
<h2>Compact Binary Code<a class="headerlink" href="#compact-binary-code" title="Permalink to this headline"></a></h2>
<p>The library is designed to produce compact per-call compiled code. For example
<p>The library produces compact per-call compiled code. For example
(<a class="reference external" href="https://godbolt.org/g/TZU4KF">godbolt</a>),</p>
<div class="code c++ highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf">&lt;fmt/core.h&gt;</span><span class="cp"></span>
<div class="code c++ highlight-c++"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf">&lt;fmt/core.h&gt;</span><span class="cp"></span>
<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="n">fmt</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&quot;The answer is {}.&quot;</span><span class="p">,</span> <span class="mi">42</span><span class="p">);</span>
@ -255,14 +250,14 @@ needed.</p>
</pre></div>
</div>
<p>compiles to just</p>
<div class="code asm highlight-c++ notranslate"><div class="highlight"><pre><span></span>main: # @main
<div class="code asm highlight-c++"><div class="highlight"><pre><span></span>main: # @main
sub rsp, 24
mov qword ptr [rsp], 42
mov rcx, rsp
mov edi, offset .L.str
mov esi, 17
mov edx, 2
call fmt::v5::vprint(fmt::v5::basic_string_view&lt;char&gt;, fmt::v5::format_args)
mov edx, 1
call fmt::v7::vprint(fmt::v7::basic_string_view&lt;char&gt;, fmt::v7::format_args)
xor eax, eax
add rsp, 24
ret
@ -283,16 +278,15 @@ needed.</p>
<li>deleted functions</li>
<li>alias templates</li>
</ul>
<p>These are available since GCC 4.8, Clang 3.0 and MSVC 19.0 (2015). For older
compilers use {fmt} <a class="reference external" href="https://github.com/fmtlib/fmt/releases/tag/4.1.0">version 4.x</a> which continues to be
maintained and only requires C++98.</p>
<p>The output of all formatting functions is consistent across platforms. In
particular, formatting a floating-point infinity always gives <code class="docutils literal notranslate"><span class="pre">inf</span></code> while the
output of <code class="docutils literal notranslate"><span class="pre">printf</span></code> is platform-dependent. For example,</p>
<div class="code highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&quot;{}&quot;</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">numeric_limits</span><span class="o">&lt;</span><span class="kt">double</span><span class="o">&gt;::</span><span class="n">infinity</span><span class="p">());</span>
<p>These are available in GCC 4.8, Clang 3.0, MSVC 19.0 (2015) and more recent
compiler version. For older compilers use {fmt} <a class="reference external" href="https://github.com/fmtlib/fmt/releases/tag/4.1.0">version 4.x</a> which is maintained and
only requires C++98.</p>
<p>The output of all formatting functions is consistent across platforms.
For example,</p>
<div class="code highlight-c++"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">print</span><span class="p">(</span><span class="s">&quot;{}&quot;</span><span class="p">,</span> <span class="n">std</span><span class="o">::</span><span class="n">numeric_limits</span><span class="o">&lt;</span><span class="kt">double</span><span class="o">&gt;::</span><span class="n">infinity</span><span class="p">());</span>
</pre></div>
</div>
<p>always prints <code class="docutils literal notranslate"><span class="pre">inf</span></code>.</p>
<p>always prints <code class="docutils literal"><span class="pre">inf</span></code> while the output of <code class="docutils literal"><span class="pre">printf</span></code> is platform-dependent.</p>
</div>
<div class="section" id="ease-of-use">
<span id="id3"></span><h2>Ease of Use<a class="headerlink" href="#ease-of-use" title="Permalink to this headline"></a></h2>
@ -317,7 +311,7 @@ using the library both in open-source and commercial projects.</p>
<div class="footer" role="contentinfo">
&copy; Copyright 2012-present, Victor Zverovich.
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.5.
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.4.1+.
</div>
<script src="_static/bootstrap.min.js"></script>

Binary file not shown.

View file

@ -8,7 +8,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Search &mdash; fmt 7.0.3 documentation</title>
<title>Search &mdash; fmt 7.1.3 documentation</title>
<link rel="stylesheet" href="_static/basic.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
@ -17,20 +17,17 @@
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '7.0.3',
VERSION: '7.1.3',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true,
SOURCELINK_SUFFIX: '.txt'
SOURCELINK_SUFFIX: ''
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<script type="text/javascript" src="_static/language_data.js"></script>
<script type="text/javascript" src="_static/searchtools.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="#" />
<script type="text/javascript">
jQuery(function() { Search.loadIndex("searchindex.js"); });
</script>
@ -75,15 +72,15 @@
<ul class="nav navbar-nav">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown"
role="button" aria-expanded="false">7.0.3
role="button" aria-expanded="false">7.1.3
<span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="https://fmt.dev/7.0.3">7.0.3</a></li>
<li><a href="https://fmt.dev/7.1.3">7.1.3</a></li>
<li><a href="https://fmt.dev/7.0.2">7.0.2</a></li>
<li><a href="https://fmt.dev/7.1.2">7.1.2</a></li>
<li><a href="https://fmt.dev/7.0.1">7.0.1</a></li>
<li><a href="https://fmt.dev/7.1.1">7.1.1</a></li>
</ul>
</li>
@ -160,7 +157,7 @@
<div class="footer" role="contentinfo">
&copy; Copyright 2012-present, Victor Zverovich.
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.5.
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.4.1+.
</div>
<script src="_static/bootstrap.min.js"></script>

File diff suppressed because one or more lines are too long

View file

@ -8,7 +8,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Format String Syntax &mdash; fmt 7.0.3 documentation</title>
<title>Format String Syntax &mdash; fmt 7.1.3 documentation</title>
<link rel="stylesheet" href="_static/basic.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
@ -17,19 +17,16 @@
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '7.0.3',
VERSION: '7.1.3',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true,
SOURCELINK_SUFFIX: '.txt'
SOURCELINK_SUFFIX: ''
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<script type="text/javascript" src="_static/language_data.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="prev" title="API Reference" href="api.html" />
<meta name="description" content="Small, safe and fast formatting library">
<meta name="keywords" content="C++, formatting, printf, string, library">
@ -68,15 +65,15 @@
<ul class="nav navbar-nav">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown"
role="button" aria-expanded="false">7.0.3
role="button" aria-expanded="false">7.1.3
<span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="https://fmt.dev/7.0.3">7.0.3</a></li>
<li><a href="https://fmt.dev/7.1.3">7.1.3</a></li>
<li><a href="https://fmt.dev/7.0.2">7.0.2</a></li>
<li><a href="https://fmt.dev/7.1.2">7.1.2</a></li>
<li><a href="https://fmt.dev/7.0.1">7.0.1</a></li>
<li><a href="https://fmt.dev/7.1.1">7.1.1</a></li>
</ul>
</li>
@ -131,40 +128,40 @@
<p>Formatting functions such as <a class="reference internal" href="api.html#format"><span class="std std-ref">fmt::format()</span></a> and
<a class="reference internal" href="api.html#print"><span class="std std-ref">fmt::print()</span></a> use the same format string syntax described in this
section.</p>
<p>Format strings contain “replacement fields” surrounded by curly braces <code class="docutils literal notranslate"><span class="pre">{}</span></code>.
<p>Format strings contain &#8220;replacement fields&#8221; surrounded by curly braces <code class="docutils literal"><span class="pre">{}</span></code>.
Anything that is not contained in braces is considered literal text, which is
copied unchanged to the output. If you need to include a brace character in the
literal text, it can be escaped by doubling: <code class="docutils literal notranslate"><span class="pre">{{</span></code> and <code class="docutils literal notranslate"><span class="pre">}}</span></code>.</p>
literal text, it can be escaped by doubling: <code class="docutils literal"><span class="pre">{{</span></code> and <code class="docutils literal"><span class="pre">}}</span></code>.</p>
<p>The grammar for a replacement field is as follows:</p>
<pre>
<strong id="grammar-token-replacement-field">replacement_field</strong> ::= &quot;{&quot; [<a class="reference internal" href="#grammar-token-arg-id"><code class="xref docutils literal notranslate"><span class="pre">arg_id</span></code></a>] [&quot;:&quot; <a class="reference internal" href="#grammar-token-format-spec"><code class="xref docutils literal notranslate"><span class="pre">format_spec</span></code></a>] &quot;}&quot;
<strong id="grammar-token-arg-id">arg_id </strong> ::= <a class="reference internal" href="#grammar-token-integer"><code class="xref docutils literal notranslate"><span class="pre">integer</span></code></a> | <a class="reference internal" href="#grammar-token-identifier"><code class="xref docutils literal notranslate"><span class="pre">identifier</span></code></a>
<strong id="grammar-token-integer">integer </strong> ::= <a class="reference internal" href="#grammar-token-digit"><code class="xref docutils literal notranslate"><span class="pre">digit</span></code></a>+
<strong id="grammar-token-replacement_field">replacement_field</strong> ::= &quot;{&quot; [<a class="reference internal" href="#grammar-token-arg_id"><code class="xref docutils literal"><span class="pre">arg_id</span></code></a>] [&quot;:&quot; <a class="reference internal" href="#grammar-token-format_spec"><code class="xref docutils literal"><span class="pre">format_spec</span></code></a>] &quot;}&quot;
<strong id="grammar-token-arg_id">arg_id </strong> ::= <a class="reference internal" href="#grammar-token-integer"><code class="xref docutils literal"><span class="pre">integer</span></code></a> | <a class="reference internal" href="#grammar-token-identifier"><code class="xref docutils literal"><span class="pre">identifier</span></code></a>
<strong id="grammar-token-integer">integer </strong> ::= <a class="reference internal" href="#grammar-token-digit"><code class="xref docutils literal"><span class="pre">digit</span></code></a>+
<strong id="grammar-token-digit">digit </strong> ::= &quot;0&quot;...&quot;9&quot;
<strong id="grammar-token-identifier">identifier </strong> ::= <a class="reference internal" href="#grammar-token-id-start"><code class="xref docutils literal notranslate"><span class="pre">id_start</span></code></a> <a class="reference internal" href="#grammar-token-id-continue"><code class="xref docutils literal notranslate"><span class="pre">id_continue</span></code></a>*
<strong id="grammar-token-id-start">id_start </strong> ::= &quot;a&quot;...&quot;z&quot; | &quot;A&quot;...&quot;Z&quot; | &quot;_&quot;
<strong id="grammar-token-id-continue">id_continue </strong> ::= <a class="reference internal" href="#grammar-token-id-start"><code class="xref docutils literal notranslate"><span class="pre">id_start</span></code></a> | <a class="reference internal" href="#grammar-token-digit"><code class="xref docutils literal notranslate"><span class="pre">digit</span></code></a>
<strong id="grammar-token-identifier">identifier </strong> ::= <a class="reference internal" href="#grammar-token-id_start"><code class="xref docutils literal"><span class="pre">id_start</span></code></a> <a class="reference internal" href="#grammar-token-id_continue"><code class="xref docutils literal"><span class="pre">id_continue</span></code></a>*
<strong id="grammar-token-id_start">id_start </strong> ::= &quot;a&quot;...&quot;z&quot; | &quot;A&quot;...&quot;Z&quot; | &quot;_&quot;
<strong id="grammar-token-id_continue">id_continue </strong> ::= <a class="reference internal" href="#grammar-token-id_start"><code class="xref docutils literal"><span class="pre">id_start</span></code></a> | <a class="reference internal" href="#grammar-token-digit"><code class="xref docutils literal"><span class="pre">digit</span></code></a>
</pre>
<p>In less formal terms, the replacement field can start with an <em>arg_id</em>
that specifies the argument whose value is to be formatted and inserted into
the output instead of the replacement field.
The <em>arg_id</em> is optionally followed by a <em>format_spec</em>, which is preceded
by a colon <code class="docutils literal notranslate"><span class="pre">':'</span></code>. These specify a non-default format for the replacement value.</p>
by a colon <code class="docutils literal"><span class="pre">':'</span></code>. These specify a non-default format for the replacement value.</p>
<p>See also the <a class="reference internal" href="#formatspec"><span class="std std-ref">Format Specification Mini-Language</span></a> section.</p>
<p>If the numerical arg_ids in a format string are 0, 1, 2, in sequence,
they can all be omitted (not just some) and the numbers 0, 1, 2, will be
<p>If the numerical arg_ids in a format string are 0, 1, 2, ... in sequence,
they can all be omitted (not just some) and the numbers 0, 1, 2, ... will be
automatically inserted in that order.</p>
<p>Named arguments can be referred to by their names or indices.</p>
<p>Some simple format string examples:</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="s">&quot;First, thou shalt count to {0}&quot;</span> <span class="c1">// References the first argument</span>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="s">&quot;First, thou shalt count to {0}&quot;</span> <span class="c1">// References the first argument</span>
<span class="s">&quot;Bring me a {}&quot;</span> <span class="c1">// Implicitly references the first argument</span>
<span class="s">&quot;From {} to {}&quot;</span> <span class="c1">// Same as &quot;From {0} to {1}&quot;</span>
</pre></div>
</div>
<p>The <em>format_spec</em> field contains a specification of how the value should be
presented, including such details as field width, alignment, padding, decimal
precision and so on. Each value type can define its own formatting
mini-language or interpretation of the <em>format_spec</em>.</p>
precision and so on. Each value type can define its own &#8220;formatting
mini-language&#8221; or interpretation of the <em>format_spec</em>.</p>
<p>Most built-in types support a common formatting mini-language, which is
described in the next section.</p>
<p>A <em>format_spec</em> field can also include nested replacement fields in certain
@ -174,7 +171,7 @@ of a value to be dynamically specified.</p>
<p>See the <a class="reference internal" href="#formatexamples"><span class="std std-ref">Format Examples</span></a> section for some examples.</p>
<div class="section" id="format-specification-mini-language">
<span id="formatspec"></span><h2>Format Specification Mini-Language<a class="headerlink" href="#format-specification-mini-language" title="Permalink to this headline"></a></h2>
<p>“Format specifications” are used within replacement fields contained within a
<p>&#8220;Format specifications&#8221; are used within replacement fields contained within a
format string to define how individual values are presented (see
<a class="reference internal" href="#syntax"><span class="std std-ref">Format String Syntax</span></a>). Each formattable type may define how the format
specification is to be interpreted.</p>
@ -182,17 +179,17 @@ specification is to be interpreted.</p>
although some of the formatting options are only supported by the numeric types.</p>
<p>The general form of a <em>standard format specifier</em> is:</p>
<pre>
<strong id="grammar-token-format-spec">format_spec</strong> ::= [[<a class="reference internal" href="#grammar-token-fill"><code class="xref docutils literal notranslate"><span class="pre">fill</span></code></a>]<a class="reference internal" href="#grammar-token-align"><code class="xref docutils literal notranslate"><span class="pre">align</span></code></a>][<a class="reference internal" href="#grammar-token-sign"><code class="xref docutils literal notranslate"><span class="pre">sign</span></code></a>][&quot;#&quot;][&quot;0&quot;][<a class="reference internal" href="#grammar-token-width"><code class="xref docutils literal notranslate"><span class="pre">width</span></code></a>][&quot;.&quot; <a class="reference internal" href="#grammar-token-precision"><code class="xref docutils literal notranslate"><span class="pre">precision</span></code></a>][<a class="reference internal" href="#grammar-token-type"><code class="xref docutils literal notranslate"><span class="pre">type</span></code></a>]
<strong id="grammar-token-format_spec">format_spec</strong> ::= [[<a class="reference internal" href="#grammar-token-fill"><code class="xref docutils literal"><span class="pre">fill</span></code></a>]<a class="reference internal" href="#grammar-token-align"><code class="xref docutils literal"><span class="pre">align</span></code></a>][<a class="reference internal" href="#grammar-token-sign"><code class="xref docutils literal"><span class="pre">sign</span></code></a>][&quot;#&quot;][&quot;0&quot;][<a class="reference internal" href="#grammar-token-width"><code class="xref docutils literal"><span class="pre">width</span></code></a>][&quot;.&quot; <a class="reference internal" href="#grammar-token-precision"><code class="xref docutils literal"><span class="pre">precision</span></code></a>][<a class="reference internal" href="#grammar-token-type"><code class="xref docutils literal"><span class="pre">type</span></code></a>]
<strong id="grammar-token-fill">fill </strong> ::= &lt;a character other than '{' or '}'&gt;
<strong id="grammar-token-align">align </strong> ::= &quot;&lt;&quot; | &quot;&gt;&quot; | &quot;^&quot;
<strong id="grammar-token-sign">sign </strong> ::= &quot;+&quot; | &quot;-&quot; | &quot; &quot;
<strong id="grammar-token-width">width </strong> ::= <a class="reference internal" href="#grammar-token-integer"><code class="xref docutils literal notranslate"><span class="pre">integer</span></code></a> | &quot;{&quot; [<a class="reference internal" href="#grammar-token-arg-id"><code class="xref docutils literal notranslate"><span class="pre">arg_id</span></code></a>] &quot;}&quot;
<strong id="grammar-token-precision">precision </strong> ::= <a class="reference internal" href="#grammar-token-integer"><code class="xref docutils literal notranslate"><span class="pre">integer</span></code></a> | &quot;{&quot; [<a class="reference internal" href="#grammar-token-arg-id"><code class="xref docutils literal notranslate"><span class="pre">arg_id</span></code></a>] &quot;}&quot;
<strong id="grammar-token-type">type </strong> ::= <a class="reference internal" href="#grammar-token-int-type"><code class="xref docutils literal notranslate"><span class="pre">int_type</span></code></a> | &quot;a&quot; | &quot;A&quot; | &quot;c&quot; | &quot;e&quot; | &quot;E&quot; | &quot;f&quot; | &quot;F&quot; | &quot;g&quot; | &quot;G&quot; | &quot;L&quot; | &quot;p&quot; | &quot;s&quot;
<strong id="grammar-token-int-type">int_type </strong> ::= &quot;b&quot; | &quot;B&quot; | &quot;d&quot; | &quot;o&quot; | &quot;x&quot; | &quot;X&quot;
<strong id="grammar-token-width">width </strong> ::= <a class="reference internal" href="#grammar-token-integer"><code class="xref docutils literal"><span class="pre">integer</span></code></a> | &quot;{&quot; [<a class="reference internal" href="#grammar-token-arg_id"><code class="xref docutils literal"><span class="pre">arg_id</span></code></a>] &quot;}&quot;
<strong id="grammar-token-precision">precision </strong> ::= <a class="reference internal" href="#grammar-token-integer"><code class="xref docutils literal"><span class="pre">integer</span></code></a> | &quot;{&quot; [<a class="reference internal" href="#grammar-token-arg_id"><code class="xref docutils literal"><span class="pre">arg_id</span></code></a>] &quot;}&quot;
<strong id="grammar-token-type">type </strong> ::= <a class="reference internal" href="#grammar-token-int_type"><code class="xref docutils literal"><span class="pre">int_type</span></code></a> | &quot;a&quot; | &quot;A&quot; | &quot;c&quot; | &quot;e&quot; | &quot;E&quot; | &quot;f&quot; | &quot;F&quot; | &quot;g&quot; | &quot;G&quot; | &quot;L&quot; | &quot;p&quot; | &quot;s&quot;
<strong id="grammar-token-int_type">int_type </strong> ::= &quot;b&quot; | &quot;B&quot; | &quot;d&quot; | &quot;o&quot; | &quot;x&quot; | &quot;X&quot;
</pre>
<p>The <em>fill</em> character can be any Unicode code point other than <code class="docutils literal notranslate"><span class="pre">'{'</span></code> or
<code class="docutils literal notranslate"><span class="pre">'}'</span></code>. The presence of a fill character is signaled by the character following
<p>The <em>fill</em> character can be any Unicode code point other than <code class="docutils literal"><span class="pre">'{'</span></code> or
<code class="docutils literal"><span class="pre">'}'</span></code>. The presence of a fill character is signaled by the character following
it, which must be one of the alignment options. If the second character of
<em>format_spec</em> is not a valid alignment option, then it is assumed that both the
fill character and the alignment option are absent.</p>
@ -208,15 +205,15 @@ fill character and the alignment option are absent.</p>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">'&lt;'</span></code></td>
<tr class="row-even"><td><code class="docutils literal"><span class="pre">'&lt;'</span></code></td>
<td>Forces the field to be left-aligned within the available
space (this is the default for most objects).</td>
</tr>
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">'&gt;'</span></code></td>
<tr class="row-odd"><td><code class="docutils literal"><span class="pre">'&gt;'</span></code></td>
<td>Forces the field to be right-aligned within the
available space (this is the default for numbers).</td>
</tr>
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">'^'</span></code></td>
<tr class="row-even"><td><code class="docutils literal"><span class="pre">'^'</span></code></td>
<td>Forces the field to be centered within the available
space.</td>
</tr>
@ -238,11 +235,11 @@ following:</p>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">'+'</span></code></td>
<tr class="row-even"><td><code class="docutils literal"><span class="pre">'+'</span></code></td>
<td>indicates that a sign should be used for both
positive as well as negative numbers.</td>
</tr>
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">'-'</span></code></td>
<tr class="row-odd"><td><code class="docutils literal"><span class="pre">'-'</span></code></td>
<td>indicates that a sign should be used only for negative
numbers (this is the default behavior).</td>
</tr>
@ -252,31 +249,31 @@ positive numbers, and a minus sign on negative numbers.</td>
</tr>
</tbody>
</table>
<p>The <code class="docutils literal notranslate"><span class="pre">'#'</span></code> option causes the “alternate form” to be used for the
<p>The <code class="docutils literal"><span class="pre">'#'</span></code> option causes the &#8220;alternate form&#8221; to be used for the
conversion. The alternate form is defined differently for different
types. This option is only valid for integer and floating-point types.
For integers, when binary, octal, or hexadecimal output is used, this
option adds the prefix respective <code class="docutils literal notranslate"><span class="pre">&quot;0b&quot;</span></code> (<code class="docutils literal notranslate"><span class="pre">&quot;0B&quot;</span></code>), <code class="docutils literal notranslate"><span class="pre">&quot;0&quot;</span></code>, or
<code class="docutils literal notranslate"><span class="pre">&quot;0x&quot;</span></code> (<code class="docutils literal notranslate"><span class="pre">&quot;0X&quot;</span></code>) to the output value. Whether the prefix is
option adds the prefix respective <code class="docutils literal"><span class="pre">&quot;0b&quot;</span></code> (<code class="docutils literal"><span class="pre">&quot;0B&quot;</span></code>), <code class="docutils literal"><span class="pre">&quot;0&quot;</span></code>, or
<code class="docutils literal"><span class="pre">&quot;0x&quot;</span></code> (<code class="docutils literal"><span class="pre">&quot;0X&quot;</span></code>) to the output value. Whether the prefix is
lower-case or upper-case is determined by the case of the type
specifier, for example, the prefix <code class="docutils literal notranslate"><span class="pre">&quot;0x&quot;</span></code> is used for the type <code class="docutils literal notranslate"><span class="pre">'x'</span></code>
and <code class="docutils literal notranslate"><span class="pre">&quot;0X&quot;</span></code> is used for <code class="docutils literal notranslate"><span class="pre">'X'</span></code>. For floating-point numbers the
specifier, for example, the prefix <code class="docutils literal"><span class="pre">&quot;0x&quot;</span></code> is used for the type <code class="docutils literal"><span class="pre">'x'</span></code>
and <code class="docutils literal"><span class="pre">&quot;0X&quot;</span></code> is used for <code class="docutils literal"><span class="pre">'X'</span></code>. For floating-point numbers the
alternate form causes the result of the conversion to always contain a
decimal-point character, even if no digits follow it. Normally, a
decimal-point character appears in the result of these conversions
only if a digit follows it. In addition, for <code class="docutils literal notranslate"><span class="pre">'g'</span></code> and <code class="docutils literal notranslate"><span class="pre">'G'</span></code>
only if a digit follows it. In addition, for <code class="docutils literal"><span class="pre">'g'</span></code> and <code class="docutils literal"><span class="pre">'G'</span></code>
conversions, trailing zeros are not removed from the result.</p>
<p><em>width</em> is a decimal integer defining the minimum field width. If not
specified, then the field width will be determined by the content.</p>
<p>Preceding the <em>width</em> field by a zero (<code class="docutils literal notranslate"><span class="pre">'0'</span></code>) character enables sign-aware
<p>Preceding the <em>width</em> field by a zero (<code class="docutils literal"><span class="pre">'0'</span></code>) character enables sign-aware
zero-padding for numeric types. It forces the padding to be placed after the
sign or base (if any) but before the digits. This is used for printing fields in
the form +000000120. This option is only valid for numeric types and it has no
the form &#8216;+000000120&#8217;. This option is only valid for numeric types and it has no
effect on formatting of infinity and NaN.</p>
<p>The <em>precision</em> is a decimal number indicating how many digits should be
displayed after the decimal point for a floating-point value formatted with
<code class="docutils literal notranslate"><span class="pre">'f'</span></code> and <code class="docutils literal notranslate"><span class="pre">'F'</span></code>, or before and after the decimal point for a floating-point
value formatted with <code class="docutils literal notranslate"><span class="pre">'g'</span></code> or <code class="docutils literal notranslate"><span class="pre">'G'</span></code>. For non-number types the field
<code class="docutils literal"><span class="pre">'f'</span></code> and <code class="docutils literal"><span class="pre">'F'</span></code>, or before and after the decimal point for a floating-point
value formatted with <code class="docutils literal"><span class="pre">'g'</span></code> or <code class="docutils literal"><span class="pre">'G'</span></code>. For non-number types the field
indicates the maximum field size - in other words, how many characters will be
used from the field content. The <em>precision</em> is not allowed for integer,
character, Boolean, and pointer values.</p>
@ -293,12 +290,12 @@ character, Boolean, and pointer values.</p>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">'s'</span></code></td>
<tr class="row-even"><td><code class="docutils literal"><span class="pre">'s'</span></code></td>
<td>String format. This is the default type for strings and
may be omitted.</td>
</tr>
<tr class="row-odd"><td>none</td>
<td>The same as <code class="docutils literal notranslate"><span class="pre">'s'</span></code>.</td>
<td>The same as <code class="docutils literal"><span class="pre">'s'</span></code>.</td>
</tr>
</tbody>
</table>
@ -314,12 +311,12 @@ may be omitted.</td>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">'c'</span></code></td>
<tr class="row-even"><td><code class="docutils literal"><span class="pre">'c'</span></code></td>
<td>Character format. This is the default type for
characters and may be omitted.</td>
</tr>
<tr class="row-odd"><td>none</td>
<td>The same as <code class="docutils literal notranslate"><span class="pre">'c'</span></code>.</td>
<td>The same as <code class="docutils literal"><span class="pre">'c'</span></code>.</td>
</tr>
</tbody>
</table>
@ -335,47 +332,47 @@ characters and may be omitted.</td>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">'b'</span></code></td>
<tr class="row-even"><td><code class="docutils literal"><span class="pre">'b'</span></code></td>
<td>Binary format. Outputs the number in base 2. Using the
<code class="docutils literal notranslate"><span class="pre">'#'</span></code> option with this type adds the prefix <code class="docutils literal notranslate"><span class="pre">&quot;0b&quot;</span></code>
<code class="docutils literal"><span class="pre">'#'</span></code> option with this type adds the prefix <code class="docutils literal"><span class="pre">&quot;0b&quot;</span></code>
to the output value.</td>
</tr>
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">'B'</span></code></td>
<tr class="row-odd"><td><code class="docutils literal"><span class="pre">'B'</span></code></td>
<td>Binary format. Outputs the number in base 2. Using the
<code class="docutils literal notranslate"><span class="pre">'#'</span></code> option with this type adds the prefix <code class="docutils literal notranslate"><span class="pre">&quot;0B&quot;</span></code>
<code class="docutils literal"><span class="pre">'#'</span></code> option with this type adds the prefix <code class="docutils literal"><span class="pre">&quot;0B&quot;</span></code>
to the output value.</td>
</tr>
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">'d'</span></code></td>
<tr class="row-even"><td><code class="docutils literal"><span class="pre">'d'</span></code></td>
<td>Decimal integer. Outputs the number in base 10.</td>
</tr>
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">'o'</span></code></td>
<tr class="row-odd"><td><code class="docutils literal"><span class="pre">'o'</span></code></td>
<td>Octal format. Outputs the number in base 8.</td>
</tr>
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">'x'</span></code></td>
<tr class="row-even"><td><code class="docutils literal"><span class="pre">'x'</span></code></td>
<td>Hex format. Outputs the number in base 16, using
lower-case letters for the digits above 9. Using the
<code class="docutils literal notranslate"><span class="pre">'#'</span></code> option with this type adds the prefix <code class="docutils literal notranslate"><span class="pre">&quot;0x&quot;</span></code>
<code class="docutils literal"><span class="pre">'#'</span></code> option with this type adds the prefix <code class="docutils literal"><span class="pre">&quot;0x&quot;</span></code>
to the output value.</td>
</tr>
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">'X'</span></code></td>
<tr class="row-odd"><td><code class="docutils literal"><span class="pre">'X'</span></code></td>
<td>Hex format. Outputs the number in base 16, using
upper-case letters for the digits above 9. Using the
<code class="docutils literal notranslate"><span class="pre">'#'</span></code> option with this type adds the prefix <code class="docutils literal notranslate"><span class="pre">&quot;0X&quot;</span></code>
<code class="docutils literal"><span class="pre">'#'</span></code> option with this type adds the prefix <code class="docutils literal"><span class="pre">&quot;0X&quot;</span></code>
to the output value.</td>
</tr>
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">'L'</span></code></td>
<td>Locale-specific format. This is the same as <code class="docutils literal notranslate"><span class="pre">'d'</span></code>,
<tr class="row-even"><td><code class="docutils literal"><span class="pre">'L'</span></code></td>
<td>Locale-specific format. This is the same as <code class="docutils literal"><span class="pre">'d'</span></code>,
except that it uses the current locale setting to insert
the appropriate number separator characters.</td>
</tr>
<tr class="row-odd"><td>none</td>
<td>The same as <code class="docutils literal notranslate"><span class="pre">'d'</span></code>.</td>
<td>The same as <code class="docutils literal"><span class="pre">'d'</span></code>.</td>
</tr>
</tbody>
</table>
<p>Integer presentation types can also be used with character and Boolean values.
Boolean values are formatted using textual representation, either <code class="docutils literal notranslate"><span class="pre">true</span></code> or
<code class="docutils literal notranslate"><span class="pre">false</span></code>, if the presentation type is not specified.</p>
Boolean values are formatted using textual representation, either <code class="docutils literal"><span class="pre">true</span></code> or
<code class="docutils literal"><span class="pre">false</span></code>, if the presentation type is not specified.</p>
<p>The available presentation types for floating-point values are:</p>
<table border="1" class="docutils">
<colgroup>
@ -388,52 +385,52 @@ Boolean values are formatted using textual representation, either <code class="d
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">'a'</span></code></td>
<tr class="row-even"><td><code class="docutils literal"><span class="pre">'a'</span></code></td>
<td>Hexadecimal floating point format. Prints the number in
base 16 with prefix <code class="docutils literal notranslate"><span class="pre">&quot;0x&quot;</span></code> and lower-case letters for
digits above 9. Uses <code class="docutils literal notranslate"><span class="pre">'p'</span></code> to indicate the exponent.</td>
base 16 with prefix <code class="docutils literal"><span class="pre">&quot;0x&quot;</span></code> and lower-case letters for
digits above 9. Uses <code class="docutils literal"><span class="pre">'p'</span></code> to indicate the exponent.</td>
</tr>
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">'A'</span></code></td>
<td>Same as <code class="docutils literal notranslate"><span class="pre">'a'</span></code> except it uses upper-case letters for
<tr class="row-odd"><td><code class="docutils literal"><span class="pre">'A'</span></code></td>
<td>Same as <code class="docutils literal"><span class="pre">'a'</span></code> except it uses upper-case letters for
the prefix, digits above 9 and to indicate the exponent.</td>
</tr>
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">'e'</span></code></td>
<tr class="row-even"><td><code class="docutils literal"><span class="pre">'e'</span></code></td>
<td>Exponent notation. Prints the number in scientific
notation using the letter e to indicate the exponent.</td>
notation using the letter &#8216;e&#8217; to indicate the exponent.</td>
</tr>
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">'E'</span></code></td>
<td>Exponent notation. Same as <code class="docutils literal notranslate"><span class="pre">'e'</span></code> except it uses an
upper-case <code class="docutils literal notranslate"><span class="pre">'E'</span></code> as the separator character.</td>
<tr class="row-odd"><td><code class="docutils literal"><span class="pre">'E'</span></code></td>
<td>Exponent notation. Same as <code class="docutils literal"><span class="pre">'e'</span></code> except it uses an
upper-case <code class="docutils literal"><span class="pre">'E'</span></code> as the separator character.</td>
</tr>
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">'f'</span></code></td>
<tr class="row-even"><td><code class="docutils literal"><span class="pre">'f'</span></code></td>
<td>Fixed point. Displays the number as a fixed-point
number.</td>
</tr>
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">'F'</span></code></td>
<td>Fixed point. Same as <code class="docutils literal notranslate"><span class="pre">'f'</span></code>, but converts <code class="docutils literal notranslate"><span class="pre">nan</span></code> to
<code class="docutils literal notranslate"><span class="pre">NAN</span></code> and <code class="docutils literal notranslate"><span class="pre">inf</span></code> to <code class="docutils literal notranslate"><span class="pre">INF</span></code>.</td>
<tr class="row-odd"><td><code class="docutils literal"><span class="pre">'F'</span></code></td>
<td>Fixed point. Same as <code class="docutils literal"><span class="pre">'f'</span></code>, but converts <code class="docutils literal"><span class="pre">nan</span></code> to
<code class="docutils literal"><span class="pre">NAN</span></code> and <code class="docutils literal"><span class="pre">inf</span></code> to <code class="docutils literal"><span class="pre">INF</span></code>.</td>
</tr>
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">'g'</span></code></td>
<td><p class="first">General format. For a given precision <code class="docutils literal notranslate"><span class="pre">p</span> <span class="pre">&gt;=</span> <span class="pre">1</span></code>,
this rounds the number to <code class="docutils literal notranslate"><span class="pre">p</span></code> significant digits and
<tr class="row-even"><td><code class="docutils literal"><span class="pre">'g'</span></code></td>
<td><p class="first">General format. For a given precision <code class="docutils literal"><span class="pre">p</span> <span class="pre">&gt;=</span> <span class="pre">1</span></code>,
this rounds the number to <code class="docutils literal"><span class="pre">p</span></code> significant digits and
then formats the result in either fixed-point format
or in scientific notation, depending on its magnitude.</p>
<p class="last">A precision of <code class="docutils literal notranslate"><span class="pre">0</span></code> is treated as equivalent to a
precision of <code class="docutils literal notranslate"><span class="pre">1</span></code>.</p>
<p class="last">A precision of <code class="docutils literal"><span class="pre">0</span></code> is treated as equivalent to a
precision of <code class="docutils literal"><span class="pre">1</span></code>.</p>
</td>
</tr>
<tr class="row-odd"><td><code class="docutils literal notranslate"><span class="pre">'G'</span></code></td>
<td>General format. Same as <code class="docutils literal notranslate"><span class="pre">'g'</span></code> except switches to
<code class="docutils literal notranslate"><span class="pre">'E'</span></code> if the number gets too large. The
<tr class="row-odd"><td><code class="docutils literal"><span class="pre">'G'</span></code></td>
<td>General format. Same as <code class="docutils literal"><span class="pre">'g'</span></code> except switches to
<code class="docutils literal"><span class="pre">'E'</span></code> if the number gets too large. The
representations of infinity and NaN are uppercased, too.</td>
</tr>
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">'L'</span></code></td>
<td>Locale-specific format. This is the same as <code class="docutils literal notranslate"><span class="pre">'g'</span></code>,
<tr class="row-even"><td><code class="docutils literal"><span class="pre">'L'</span></code></td>
<td>Locale-specific format. This is the same as <code class="docutils literal"><span class="pre">'g'</span></code>,
except that it uses the current locale setting to insert
the appropriate number separator characters.</td>
</tr>
<tr class="row-odd"><td>none</td>
<td>Similar to <code class="docutils literal notranslate"><span class="pre">'g'</span></code>, except that fixed-point notation,
<td>Similar to <code class="docutils literal"><span class="pre">'g'</span></code>, except that fixed-point notation,
when used, has at least one digit past the decimal
point. The default precision is as high as needed to
represent the particular value.</td>
@ -452,12 +449,12 @@ represent the particular value.</td>
</tr>
</thead>
<tbody valign="top">
<tr class="row-even"><td><code class="docutils literal notranslate"><span class="pre">'p'</span></code></td>
<tr class="row-even"><td><code class="docutils literal"><span class="pre">'p'</span></code></td>
<td>Pointer format. This is the default type for
pointers and may be omitted.</td>
</tr>
<tr class="row-odd"><td>none</td>
<td>The same as <code class="docutils literal notranslate"><span class="pre">'p'</span></code>.</td>
<td>The same as <code class="docutils literal"><span class="pre">'p'</span></code>.</td>
</tr>
</tbody>
</table>
@ -467,12 +464,12 @@ pointers and may be omitted.</td>
<p>This section contains examples of the format syntax and comparison with
the printf formatting.</p>
<p>In most of the cases the syntax is similar to the printf formatting, with the
addition of the <code class="docutils literal notranslate"><span class="pre">{}</span></code> and with <code class="docutils literal notranslate"><span class="pre">:</span></code> used instead of <code class="docutils literal notranslate"><span class="pre">%</span></code>.
For example, <code class="docutils literal notranslate"><span class="pre">&quot;%03.2f&quot;</span></code> can be translated to <code class="docutils literal notranslate"><span class="pre">&quot;{:03.2f}&quot;</span></code>.</p>
addition of the <code class="docutils literal"><span class="pre">{}</span></code> and with <code class="docutils literal"><span class="pre">:</span></code> used instead of <code class="docutils literal"><span class="pre">%</span></code>.
For example, <code class="docutils literal"><span class="pre">&quot;%03.2f&quot;</span></code> can be translated to <code class="docutils literal"><span class="pre">&quot;{:03.2f}&quot;</span></code>.</p>
<p>The new format syntax also supports new and different options, shown in the
following examples.</p>
<p>Accessing arguments by position:</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">&quot;{0}, {1}, {2}&quot;</span><span class="p">,</span> <span class="sc">&#39;a&#39;</span><span class="p">,</span> <span class="sc">&#39;b&#39;</span><span class="p">,</span> <span class="sc">&#39;c&#39;</span><span class="p">);</span>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">&quot;{0}, {1}, {2}&quot;</span><span class="p">,</span> <span class="sc">&#39;a&#39;</span><span class="p">,</span> <span class="sc">&#39;b&#39;</span><span class="p">,</span> <span class="sc">&#39;c&#39;</span><span class="p">);</span>
<span class="c1">// Result: &quot;a, b, c&quot;</span>
<span class="n">fmt</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">&quot;{}, {}, {}&quot;</span><span class="p">,</span> <span class="sc">&#39;a&#39;</span><span class="p">,</span> <span class="sc">&#39;b&#39;</span><span class="p">,</span> <span class="sc">&#39;c&#39;</span><span class="p">);</span>
<span class="c1">// Result: &quot;a, b, c&quot;</span>
@ -483,7 +480,7 @@ following examples.</p>
</pre></div>
</div>
<p>Aligning the text and specifying a width:</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">&quot;{:&lt;30}&quot;</span><span class="p">,</span> <span class="s">&quot;left aligned&quot;</span><span class="p">);</span>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">&quot;{:&lt;30}&quot;</span><span class="p">,</span> <span class="s">&quot;left aligned&quot;</span><span class="p">);</span>
<span class="c1">// Result: &quot;left aligned &quot;</span>
<span class="n">fmt</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">&quot;{:&gt;30}&quot;</span><span class="p">,</span> <span class="s">&quot;right aligned&quot;</span><span class="p">);</span>
<span class="c1">// Result: &quot; right aligned&quot;</span>
@ -494,17 +491,17 @@ following examples.</p>
</pre></div>
</div>
<p>Dynamic width:</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">&quot;{:&lt;{}}&quot;</span><span class="p">,</span> <span class="s">&quot;left aligned&quot;</span><span class="p">,</span> <span class="mi">30</span><span class="p">);</span>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">&quot;{:&lt;{}}&quot;</span><span class="p">,</span> <span class="s">&quot;left aligned&quot;</span><span class="p">,</span> <span class="mi">30</span><span class="p">);</span>
<span class="c1">// Result: &quot;left aligned &quot;</span>
</pre></div>
</div>
<p>Dynamic precision:</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">&quot;{:.{}f}&quot;</span><span class="p">,</span> <span class="mf">3.14</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">&quot;{:.{}f}&quot;</span><span class="p">,</span> <span class="mf">3.14</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
<span class="c1">// Result: &quot;3.1&quot;</span>
</pre></div>
</div>
<p>Replacing <code class="docutils literal notranslate"><span class="pre">%+f</span></code>, <code class="docutils literal notranslate"><span class="pre">%-f</span></code>, and <code class="docutils literal notranslate"><span class="pre">%</span> <span class="pre">f</span></code> and specifying a sign:</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">&quot;{:+f}; {:+f}&quot;</span><span class="p">,</span> <span class="mf">3.14</span><span class="p">,</span> <span class="o">-</span><span class="mf">3.14</span><span class="p">);</span> <span class="c1">// show it always</span>
<p>Replacing <code class="docutils literal"><span class="pre">%+f</span></code>, <code class="docutils literal"><span class="pre">%-f</span></code>, and <code class="docutils literal"><span class="pre">%</span> <span class="pre">f</span></code> and specifying a sign:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">&quot;{:+f}; {:+f}&quot;</span><span class="p">,</span> <span class="mf">3.14</span><span class="p">,</span> <span class="o">-</span><span class="mf">3.14</span><span class="p">);</span> <span class="c1">// show it always</span>
<span class="c1">// Result: &quot;+3.140000; -3.140000&quot;</span>
<span class="n">fmt</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">&quot;{: f}; {: f}&quot;</span><span class="p">,</span> <span class="mf">3.14</span><span class="p">,</span> <span class="o">-</span><span class="mf">3.14</span><span class="p">);</span> <span class="c1">// show a space for positive numbers</span>
<span class="c1">// Result: &quot; 3.140000; -3.140000&quot;</span>
@ -512,8 +509,8 @@ following examples.</p>
<span class="c1">// Result: &quot;3.140000; -3.140000&quot;</span>
</pre></div>
</div>
<p>Replacing <code class="docutils literal notranslate"><span class="pre">%x</span></code> and <code class="docutils literal notranslate"><span class="pre">%o</span></code> and converting the value to different bases:</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">&quot;int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}&quot;</span><span class="p">,</span> <span class="mi">42</span><span class="p">);</span>
<p>Replacing <code class="docutils literal"><span class="pre">%x</span></code> and <code class="docutils literal"><span class="pre">%o</span></code> and converting the value to different bases:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">&quot;int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}&quot;</span><span class="p">,</span> <span class="mi">42</span><span class="p">);</span>
<span class="c1">// Result: &quot;int: 42; hex: 2a; oct: 52; bin: 101010&quot;</span>
<span class="c1">// with 0x or 0 or 0b as prefix:</span>
<span class="n">fmt</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">&quot;int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}&quot;</span><span class="p">,</span> <span class="mi">42</span><span class="p">);</span>
@ -521,25 +518,25 @@ following examples.</p>
</pre></div>
</div>
<p>Padded hex byte with prefix and always prints both hex characters:</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">&quot;{:#04x}&quot;</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="s">&quot;{:#04x}&quot;</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
<span class="c1">// Result: &quot;0x00&quot;</span>
</pre></div>
</div>
<p>Box drawing using Unicode fill:</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">print</span><span class="p">(</span>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">fmt</span><span class="o">::</span><span class="n">print</span><span class="p">(</span>
<span class="s">&quot;┌{0:─^{2}}┐</span><span class="se">\n</span><span class="s">&quot;</span>
<span class="s">&quot;│{1: ^{2}}│</span><span class="se">\n</span><span class="s">&quot;</span>
<span class="s">&quot;└{0:─^{2}}┘</span><span class="se">\n</span><span class="s">&quot;</span><span class="p">,</span> <span class="s">&quot;&quot;</span><span class="p">,</span> <span class="s">&quot;Hello, world!&quot;</span><span class="p">,</span> <span class="mi">20</span><span class="p">);</span>
</pre></div>
</div>
<p>prints:</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span>┌────────────────────┐
<div class="highlight-c++"><div class="highlight"><pre><span></span>┌────────────────────┐
│ Hello, world! │
└────────────────────┘
</pre></div>
</div>
<p>Using type-specific formatting:</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf">&lt;fmt/chrono.h&gt;</span><span class="cp"></span>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf">&lt;fmt/chrono.h&gt;</span><span class="cp"></span>
<span class="k">auto</span> <span class="n">t</span> <span class="o">=</span> <span class="n">tm</span><span class="p">();</span>
<span class="n">t</span><span class="p">.</span><span class="n">tm_year</span> <span class="o">=</span> <span class="mi">2010</span> <span class="o">-</span> <span class="mi">1900</span><span class="p">;</span>
@ -553,7 +550,7 @@ following examples.</p>
</pre></div>
</div>
<p>Using the comma as a thousands separator:</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf">&lt;fmt/locale.h&gt;</span><span class="cp"></span>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="cp">#include</span> <span class="cpf">&lt;fmt/locale.h&gt;</span><span class="cp"></span>
<span class="k">auto</span> <span class="n">s</span> <span class="o">=</span> <span class="n">fmt</span><span class="o">::</span><span class="n">format</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">locale</span><span class="p">(</span><span class="s">&quot;en_US.UTF-8&quot;</span><span class="p">),</span> <span class="s">&quot;{:L}&quot;</span><span class="p">,</span> <span class="mi">1234567890</span><span class="p">);</span>
<span class="c1">// s == &quot;1,234,567,890&quot;</span>
@ -571,7 +568,7 @@ following examples.</p>
<div class="footer" role="contentinfo">
&copy; Copyright 2012-present, Victor Zverovich.
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.5.
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.4.1+.
</div>
<script src="_static/bootstrap.min.js"></script>

View file

@ -8,7 +8,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Usage &mdash; fmt 7.0.3 documentation</title>
<title>Usage &mdash; fmt 7.1.3 documentation</title>
<link rel="stylesheet" href="_static/basic.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
@ -17,19 +17,16 @@
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: './',
VERSION: '7.0.3',
VERSION: '7.1.3',
COLLAPSE_INDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true,
SOURCELINK_SUFFIX: '.txt'
SOURCELINK_SUFFIX: ''
};
</script>
<script type="text/javascript" src="_static/jquery.js"></script>
<script type="text/javascript" src="_static/underscore.js"></script>
<script type="text/javascript" src="_static/doctools.js"></script>
<script type="text/javascript" src="_static/language_data.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="API Reference" href="api.html" />
<link rel="prev" title="Contents" href="contents.html" />
<meta name="description" content="Small, safe and fast formatting library">
@ -69,15 +66,15 @@
<ul class="nav navbar-nav">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown"
role="button" aria-expanded="false">7.0.3
role="button" aria-expanded="false">7.1.3
<span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="https://fmt.dev/7.0.3">7.0.3</a></li>
<li><a href="https://fmt.dev/7.1.3">7.1.3</a></li>
<li><a href="https://fmt.dev/7.0.2">7.0.2</a></li>
<li><a href="https://fmt.dev/7.1.2">7.1.2</a></li>
<li><a href="https://fmt.dev/7.0.1">7.0.1</a></li>
<li><a href="https://fmt.dev/7.1.1">7.1.1</a></li>
</ul>
</li>
@ -129,8 +126,8 @@
<div class="section" id="usage">
<h1>Usage<a class="headerlink" href="#usage" title="Permalink to this headline"></a></h1>
<p>To use the {fmt} library, add <code class="file docutils literal notranslate"><span class="pre">fmt/core.h</span></code>, <code class="file docutils literal notranslate"><span class="pre">fmt/format.h</span></code>,
<code class="file docutils literal notranslate"><span class="pre">fmt/format-inl.h</span></code>, <code class="file docutils literal notranslate"><span class="pre">src/format.cc</span></code> and optionally other headers
<p>To use the {fmt} library, add <code class="file docutils literal"><span class="pre">fmt/core.h</span></code>, <code class="file docutils literal"><span class="pre">fmt/format.h</span></code>,
<code class="file docutils literal"><span class="pre">fmt/format-inl.h</span></code>, <code class="file docutils literal"><span class="pre">src/format.cc</span></code> and optionally other headers
from a <a class="reference external" href="https://github.com/fmtlib/fmt/releases/latest">release archive</a> or
the <a class="reference external" href="https://github.com/fmtlib/fmt">Git repository</a> to your project.
Alternatively, you can <a class="reference internal" href="#building"><span class="std std-ref">build the library with CMake</span></a>.</p>
@ -142,26 +139,32 @@ download from <a class="reference external" href="http://www.cmake.org/download/
<p>CMake works by generating native makefiles or project files that can
be used in the compiler environment of your choice. The typical
workflow starts with:</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span>mkdir build # Create a directory to hold the build output.
<div class="highlight-c++"><div class="highlight"><pre><span></span>mkdir build # Create a directory to hold the build output.
cd build
cmake .. # Generate native build scripts.
</pre></div>
</div>
<p>where <code class="file docutils literal notranslate"><em><span class="pre">&lt;path/to/fmt&gt;</span></em></code> is a path to the <code class="docutils literal notranslate"><span class="pre">fmt</span></code> repository.</p>
<p>where <code class="file docutils literal"><em><span class="pre">&lt;path/to/fmt&gt;</span></em></code> is a path to the <code class="docutils literal"><span class="pre">fmt</span></code> repository.</p>
<p>If you are on a *nix system, you should now see a Makefile in the
current directory. Now you can build the library by running <strong class="command">make</strong>.</p>
<p>Once the library has been built you can invoke <strong class="command">make test</strong> to run
the tests.</p>
<p>You can control generation of the make <code class="docutils literal notranslate"><span class="pre">test</span></code> target with the <code class="docutils literal notranslate"><span class="pre">FMT_TEST</span></code>
<p>You can control generation of the make <code class="docutils literal"><span class="pre">test</span></code> target with the <code class="docutils literal"><span class="pre">FMT_TEST</span></code>
CMake option. This can be useful if you include fmt as a subdirectory in
your project but dont want to add fmts tests to your <code class="docutils literal notranslate"><span class="pre">test</span></code> target.</p>
<p>If you use Windows and have Visual Studio installed, a <code class="file docutils literal notranslate"><span class="pre">FMT.sln</span></code>
file and several <code class="file docutils literal notranslate"><span class="pre">.vcproj</span></code> files will be created. You can then build them
your project but don&#8217;t want to add fmt&#8217;s tests to your <code class="docutils literal"><span class="pre">test</span></code> target.</p>
<p>If you use Windows and have Visual Studio installed, a <code class="file docutils literal"><span class="pre">FMT.sln</span></code>
file and several <code class="file docutils literal"><span class="pre">.vcproj</span></code> files will be created. You can then build them
using Visual Studio or msbuild.</p>
<p>On Mac OS X with Xcode installed, an <code class="file docutils literal notranslate"><span class="pre">.xcodeproj</span></code> file will be generated.</p>
<p>To build a <a class="reference external" href="http://en.wikipedia.org/wiki/Library_%28computing%29#Shared_libraries">shared library</a> set the <code class="docutils literal notranslate"><span class="pre">BUILD_SHARED_LIBS</span></code> CMake variable to
<code class="docutils literal notranslate"><span class="pre">TRUE</span></code>:</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">cmake</span> <span class="o">-</span><span class="n">DBUILD_SHARED_LIBS</span><span class="o">=</span><span class="n">TRUE</span> <span class="p">...</span>
<p>On Mac OS X with Xcode installed, an <code class="file docutils literal"><span class="pre">.xcodeproj</span></code> file will be generated.</p>
<p>To build a <a class="reference external" href="http://en.wikipedia.org/wiki/Library_%28computing%29#Shared_libraries">shared library</a> set the <code class="docutils literal"><span class="pre">BUILD_SHARED_LIBS</span></code> CMake variable to
<code class="docutils literal"><span class="pre">TRUE</span></code>:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">cmake</span> <span class="o">-</span><span class="n">DBUILD_SHARED_LIBS</span><span class="o">=</span><span class="n">TRUE</span> <span class="p">...</span>
</pre></div>
</div>
<p>To build a <code class="xref cpp cpp-any docutils literal"><span class="pre">static</span> <span class="pre">library</span></code> with position independent code (required if the main
consumer of the fmt library is a shared library i.e. a Python extension) set the
<code class="docutils literal"><span class="pre">CMAKE_POSITION_INDEPENDENT_CODE</span></code> CMake variable to <code class="docutils literal"><span class="pre">TRUE</span></code>:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">cmake</span> <span class="o">-</span><span class="n">DCMAKE_POSITION_INDEPENDENT_CODE</span><span class="o">=</span><span class="n">TRUE</span> <span class="p">...</span>
</pre></div>
</div>
</div>
@ -172,26 +175,70 @@ using Visual Studio or msbuild.</p>
</div>
<div class="section" id="usage-with-cmake">
<h2>Usage with CMake<a class="headerlink" href="#usage-with-cmake" title="Permalink to this headline"></a></h2>
<p>You can add the <code class="docutils literal notranslate"><span class="pre">fmt</span></code> library directory into your project and include it in
your <code class="docutils literal notranslate"><span class="pre">CMakeLists.txt</span></code> file:</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">add_subdirectory</span><span class="p">(</span><span class="n">fmt</span><span class="p">)</span>
<p>You can add the <code class="docutils literal"><span class="pre">fmt</span></code> library directory into your project and include it in
your <code class="docutils literal"><span class="pre">CMakeLists.txt</span></code> file:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">add_subdirectory</span><span class="p">(</span><span class="n">fmt</span><span class="p">)</span>
</pre></div>
</div>
<p>or</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">add_subdirectory</span><span class="p">(</span><span class="n">fmt</span> <span class="n">EXCLUDE_FROM_ALL</span><span class="p">)</span>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">add_subdirectory</span><span class="p">(</span><span class="n">fmt</span> <span class="n">EXCLUDE_FROM_ALL</span><span class="p">)</span>
</pre></div>
</div>
<p>to exclude it from <code class="docutils literal notranslate"><span class="pre">make</span></code>, <code class="docutils literal notranslate"><span class="pre">make</span> <span class="pre">all</span></code>, or <code class="docutils literal notranslate"><span class="pre">cmake</span> <span class="pre">--build</span> <span class="pre">.</span></code>.</p>
<p>to exclude it from <code class="docutils literal"><span class="pre">make</span></code>, <code class="docutils literal"><span class="pre">make</span> <span class="pre">all</span></code>, or <code class="docutils literal"><span class="pre">cmake</span> <span class="pre">--build</span> <span class="pre">.</span></code>.</p>
<p>You can detect and use an installed version of {fmt} as follows:</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">find_package</span><span class="p">(</span><span class="n">fmt</span><span class="p">)</span>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">find_package</span><span class="p">(</span><span class="n">fmt</span><span class="p">)</span>
<span class="n">target_link_libraries</span><span class="p">(</span><span class="o">&lt;</span><span class="n">your</span><span class="o">-</span><span class="n">target</span><span class="o">&gt;</span> <span class="n">fmt</span><span class="o">::</span><span class="n">fmt</span><span class="p">)</span>
</pre></div>
</div>
<p>Setting up your target to use a header-only version of <code class="docutils literal notranslate"><span class="pre">fmt</span></code> is equally easy:</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">target_link_libraries</span><span class="p">(</span><span class="o">&lt;</span><span class="n">your</span><span class="o">-</span><span class="n">target</span><span class="o">&gt;</span> <span class="n">PRIVATE</span> <span class="n">fmt</span><span class="o">::</span><span class="n">fmt</span><span class="o">-</span><span class="n">header</span><span class="o">-</span><span class="n">only</span><span class="p">)</span>
<p>Setting up your target to use a header-only version of <code class="docutils literal"><span class="pre">fmt</span></code> is equally easy:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">target_link_libraries</span><span class="p">(</span><span class="o">&lt;</span><span class="n">your</span><span class="o">-</span><span class="n">target</span><span class="o">&gt;</span> <span class="n">PRIVATE</span> <span class="n">fmt</span><span class="o">::</span><span class="n">fmt</span><span class="o">-</span><span class="n">header</span><span class="o">-</span><span class="n">only</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="section" id="usage-with-build2">
<h2>Usage with build2<a class="headerlink" href="#usage-with-build2" title="Permalink to this headline"></a></h2>
<p>You can use <a class="reference external" href="https://build2.org">build2</a>, a dependency manager and a
build-system combined, to use <code class="docutils literal"><span class="pre">fmt</span></code>.</p>
<p>Currently this package is available in these package repositories:</p>
<ul class="simple">
<li><strong>https://cppget.org/fmt/</strong> for released and published versions.</li>
<li><a class="reference external" href="https://github.com/build2-packaging/fmt.git">The git repository with the sources of the build2 package of fmt</a>
for unreleased or custom revisions of <code class="docutils literal"><span class="pre">fmt</span></code>.</li>
</ul>
<p><strong>Usage:</strong></p>
<ul class="simple">
<li><code class="docutils literal"><span class="pre">build2</span></code> package name: <code class="docutils literal"><span class="pre">fmt</span></code></li>
<li>Library target name : <code class="docutils literal"><span class="pre">lib{fmt}</span></code></li>
</ul>
<p>For example, to make your <code class="docutils literal"><span class="pre">build2</span></code> project depend on <code class="docutils literal"><span class="pre">fmt</span></code>:</p>
<ul>
<li><p class="first">Add one of the repositories to your configurations, or in your
<code class="docutils literal"><span class="pre">repositories.manifest</span></code>, if not already there:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="o">:</span>
<span class="nl">role</span><span class="p">:</span> <span class="n">prerequisite</span>
<span class="nl">location</span><span class="p">:</span> <span class="nl">https</span><span class="p">:</span><span class="c1">//pkg.cppget.org/1/stable</span>
</pre></div>
</div>
</li>
<li><p class="first">Add this package as a dependency to your <code class="docutils literal"><span class="pre">./manifest</span></code> file
(example for <code class="docutils literal"><span class="pre">v7.0.x</span></code>):</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="nl">depends</span><span class="p">:</span> <span class="n">fmt</span> <span class="o">~</span><span class="mf">7.0.0</span>
</pre></div>
</div>
</li>
<li><p class="first">Import the target and use it as a prerequisite to your own target
using <code class="xref cpp cpp-any docutils literal"><span class="pre">fmt</span></code> in the appropriate <code class="docutils literal"><span class="pre">buildfile</span></code>:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span>import fmt = fmt%lib{fmt}
lib{mylib} : cxx{**} ... $fmt
</pre></div>
</div>
</li>
</ul>
<p>Then build your project as usual with <code class="xref cpp cpp-any docutils literal"><span class="pre">b</span></code> or <code class="xref cpp cpp-any docutils literal"><span class="pre">bdep</span> <span class="pre">update</span></code>.</p>
<p>For <code class="docutils literal"><span class="pre">build2</span></code> newcomers or to get more details and use cases, you can read the
<code class="docutils literal"><span class="pre">build2</span></code>
<a class="reference external" href="https://build2.org/build2-toolchain/doc/build2-toolchain-intro.xhtml">toolchain introduction</a>.</p>
</div>
<div class="section" id="building-the-documentation">
<h2>Building the Documentation<a class="headerlink" href="#building-the-documentation" title="Permalink to this headline"></a></h2>
<p>To build the documentation you need the following software installed on your
@ -201,20 +248,20 @@ system:</p>
</li>
<li><p class="first"><a class="reference external" href="http://www.stack.nl/~dimitri/doxygen/">Doxygen</a></p>
</li>
<li><p class="first"><a class="reference external" href="http://lesscss.org/">Less</a> with <code class="docutils literal notranslate"><span class="pre">less-plugin-clean-css</span></code>.
Ubuntu doesnt package the <code class="docutils literal notranslate"><span class="pre">clean-css</span></code> plugin so you should use <code class="docutils literal notranslate"><span class="pre">npm</span></code>
instead of <code class="docutils literal notranslate"><span class="pre">apt</span></code> to install both <code class="docutils literal notranslate"><span class="pre">less</span></code> and the plugin:</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">sudo</span> <span class="n">npm</span> <span class="n">install</span> <span class="o">-</span><span class="n">g</span> <span class="n">less</span> <span class="n">less</span><span class="o">-</span><span class="n">plugin</span><span class="o">-</span><span class="n">clean</span><span class="o">-</span><span class="n">css</span><span class="p">.</span>
<li><p class="first"><a class="reference external" href="http://lesscss.org/">Less</a> with <code class="docutils literal"><span class="pre">less-plugin-clean-css</span></code>.
Ubuntu doesn&#8217;t package the <code class="docutils literal"><span class="pre">clean-css</span></code> plugin so you should use <code class="docutils literal"><span class="pre">npm</span></code>
instead of <code class="docutils literal"><span class="pre">apt</span></code> to install both <code class="docutils literal"><span class="pre">less</span></code> and the plugin:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">sudo</span> <span class="n">npm</span> <span class="n">install</span> <span class="o">-</span><span class="n">g</span> <span class="n">less</span> <span class="n">less</span><span class="o">-</span><span class="n">plugin</span><span class="o">-</span><span class="n">clean</span><span class="o">-</span><span class="n">css</span><span class="p">.</span>
</pre></div>
</div>
</li>
</ul>
<p>First generate makefiles or project files using CMake as described in
the previous section. Then compile the <code class="docutils literal notranslate"><span class="pre">doc</span></code> target/project, for example:</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">make</span> <span class="n">doc</span>
the previous section. Then compile the <code class="docutils literal"><span class="pre">doc</span></code> target/project, for example:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">make</span> <span class="n">doc</span>
</pre></div>
</div>
<p>This will generate the HTML documentation in <code class="docutils literal notranslate"><span class="pre">doc/html</span></code>.</p>
<p>This will generate the HTML documentation in <code class="docutils literal"><span class="pre">doc/html</span></code>.</p>
</div>
<div class="section" id="conda">
<h2>Conda<a class="headerlink" href="#conda" title="Permalink to this headline"></a></h2>
@ -222,14 +269,14 @@ the previous section. Then compile the <code class="docutils literal notranslate
<a class="reference external" href="https://docs.conda.io/en/latest/">Conda</a>, using its
<a class="reference external" href="https://conda-forge.org">conda-forge</a>
<a class="reference external" href="https://github.com/conda-forge/fmt-feedstock">package</a>, as follows:</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fmt</span>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">conda</span> <span class="n">install</span> <span class="o">-</span><span class="n">c</span> <span class="n">conda</span><span class="o">-</span><span class="n">forge</span> <span class="n">fmt</span>
</pre></div>
</div>
</div>
<div class="section" id="vcpkg">
<h2>Vcpkg<a class="headerlink" href="#vcpkg" title="Permalink to this headline"></a></h2>
<p>You can download and install fmt using the <a class="reference external" href="https://github.com/Microsoft/vcpkg">vcpkg</a> dependency manager:</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">git</span> <span class="n">clone</span> <span class="nl">https</span><span class="p">:</span><span class="c1">//github.com/Microsoft/vcpkg.git</span>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">git</span> <span class="n">clone</span> <span class="nl">https</span><span class="p">:</span><span class="c1">//github.com/Microsoft/vcpkg.git</span>
<span class="n">cd</span> <span class="n">vcpkg</span>
<span class="p">.</span><span class="o">/</span><span class="n">bootstrap</span><span class="o">-</span><span class="n">vcpkg</span><span class="p">.</span><span class="n">sh</span>
<span class="p">.</span><span class="o">/</span><span class="n">vcpkg</span> <span class="n">integrate</span> <span class="n">install</span>
@ -240,6 +287,17 @@ the previous section. Then compile the <code class="docutils literal notranslate
contributors. If the version is out of date, please <a class="reference external" href="https://github.com/Microsoft/vcpkg">create an issue or pull
request</a> on the vcpkg repository.</p>
</div>
<div class="section" id="lhelper">
<h2>LHelper<a class="headerlink" href="#lhelper" title="Permalink to this headline"></a></h2>
<p>You can download and install fmt using
<a class="reference external" href="https://github.com/franko/lhelper">lhelper</a> dependency manager:</p>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">lhelper</span> <span class="n">activate</span> <span class="o">&lt;</span><span class="n">some</span><span class="o">-</span><span class="n">environment</span><span class="o">&gt;</span>
<span class="n">lhelper</span> <span class="n">install</span> <span class="n">fmt</span>
</pre></div>
</div>
<p>All the recipes for lhelper are kept in the
<a class="reference external" href="https://github.com/franko/lhelper-recipes">lhelper&#8217;s recipe</a> repository.</p>
</div>
<div class="section" id="android-ndk">
<h2>Android NDK<a class="headerlink" href="#android-ndk" title="Permalink to this headline"></a></h2>
<p>fmt provides <a class="reference external" href="https://github.com/fmtlib/fmt/blob/master/Android.mk">Android.mk file</a> that can be used to build the library
@ -251,7 +309,7 @@ repository.</p>
<div class="section" id="homebrew">
<h2>Homebrew<a class="headerlink" href="#homebrew" title="Permalink to this headline"></a></h2>
<p>fmt can be installed on OS X using <a class="reference external" href="http://brew.sh/">Homebrew</a>:</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">brew</span> <span class="n">install</span> <span class="n">fmt</span>
<div class="highlight-c++"><div class="highlight"><pre><span></span><span class="n">brew</span> <span class="n">install</span> <span class="n">fmt</span>
</pre></div>
</div>
</div>
@ -266,7 +324,7 @@ repository.</p>
<div class="footer" role="contentinfo">
&copy; Copyright 2012-present, Victor Zverovich.
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.8.5.
Created using <a href="http://sphinx-doc.org/">Sphinx</a> 1.4.1+.
</div>
<script src="_static/bootstrap.min.js"></script>

View file

@ -23,7 +23,7 @@ Format API
The format API is similar in spirit to the C ``printf`` family of function but
is safer, simpler and several times `faster
<http://zverovich.net/2013/09/07/integer-to-string-conversion-in-cplusplus.html>`_
<https://www.zverovich.net/2020/06/13/fast-int-to-string-revisited.html>`_
than common standard library implementations.
The `format string syntax <syntax.html>`_ is similar to the one used by
`str.format <http://docs.python.org/3/library/stdtypes.html#str.format>`_ in
@ -48,21 +48,19 @@ The ``fmt::print`` function performs formatting and writes the result to a strea
fmt::print(stderr, "System error code = {}\n", errno);
The file argument can be omitted in which case the function prints to
``stdout``:
If you omit the file argument the function will print to ``stdout``:
.. code:: c++
fmt::print("Don't {}\n", "panic");
The Format API also supports positional arguments useful for localization:
The format API also supports positional arguments useful for localization:
.. code:: c++
fmt::print("I'd rather be {1} than {0}.", "right", "happy");
Named arguments can be created with ``fmt::arg``. This makes it easier to track
what goes where when multiple arguments are being formatted:
You can pass named arguments with ``fmt::arg``:
.. code:: c++
@ -91,16 +89,17 @@ time. For example, the code
fmt::format("The answer is {:d}", "forty-two");
throws a ``format_error`` exception with description "unknown format code 'd' for
string", because the argument ``"forty-two"`` is a string while the format code
``d`` only applies to integers, while
throws the ``format_error`` exception because the argument ``"forty-two"`` is a
string while the format code ``d`` only applies to integers.
The code
.. code:: c++
format(FMT_STRING("The answer is {:d}"), "forty-two");
reports a compile-time error for the same reason on compilers that support
relaxed ``constexpr``. See `here <api.html#c.fmt>`_ for details.
reports a compile-time error on compilers that support relaxed ``constexpr``.
See `here <api.html#c.fmt>`_ for details.
The following code
@ -117,13 +116,13 @@ formatted into a narrow string. You can use a wide format string instead:
For comparison, writing a wide character to ``std::ostream`` results in
its numeric value being written to the stream (i.e. 1070 instead of letter 'ю'
which is represented by ``L'\x42e'`` if we use Unicode) which is rarely what is
needed.
which is represented by ``L'\x42e'`` if we use Unicode) which is rarely
desirable.
Compact Binary Code
-------------------
The library is designed to produce compact per-call compiled code. For example
The library produces compact per-call compiled code. For example
(`godbolt <https://godbolt.org/g/TZU4KF>`_),
.. code:: c++
@ -144,8 +143,8 @@ compiles to just
mov rcx, rsp
mov edi, offset .L.str
mov esi, 17
mov edx, 2
call fmt::v5::vprint(fmt::v5::basic_string_view<char>, fmt::v5::format_args)
mov edx, 1
call fmt::v7::vprint(fmt::v7::basic_string_view<char>, fmt::v7::format_args)
xor eax, eax
add rsp, 24
ret
@ -167,20 +166,19 @@ The library is highly portable and relies only on a small set of C++11 features:
* deleted functions
* alias templates
These are available since GCC 4.8, Clang 3.0 and MSVC 19.0 (2015). For older
compilers use {fmt} `version 4.x
<https://github.com/fmtlib/fmt/releases/tag/4.1.0>`_ which continues to be
maintained and only requires C++98.
These are available in GCC 4.8, Clang 3.0, MSVC 19.0 (2015) and more recent
compiler version. For older compilers use {fmt} `version 4.x
<https://github.com/fmtlib/fmt/releases/tag/4.1.0>`_ which is maintained and
only requires C++98.
The output of all formatting functions is consistent across platforms. In
particular, formatting a floating-point infinity always gives ``inf`` while the
output of ``printf`` is platform-dependent. For example,
The output of all formatting functions is consistent across platforms.
For example,
.. code::
fmt::print("{}", std::numeric_limits<double>::infinity());
always prints ``inf``.
always prints ``inf`` while the output of ``printf`` is platform-dependent.
.. _ease-of-use:

View file

@ -52,6 +52,14 @@ To build a `shared library`__ set the ``BUILD_SHARED_LIBS`` CMake variable to
__ http://en.wikipedia.org/wiki/Library_%28computing%29#Shared_libraries
To build a `static library` with position independent code (required if the main
consumer of the fmt library is a shared library i.e. a Python extension) set the
``CMAKE_POSITION_INDEPENDENT_CODE`` CMake variable to ``TRUE``::
cmake -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE ...
Installing the Library
======================
@ -83,6 +91,49 @@ Setting up your target to use a header-only version of ``fmt`` is equally easy::
target_link_libraries(<your-target> PRIVATE fmt::fmt-header-only)
Usage with build2
=================
You can use `build2 <https://build2.org>`_, a dependency manager and a
build-system combined, to use ``fmt``.
Currently this package is available in these package repositories:
- **https://cppget.org/fmt/** for released and published versions.
- `The git repository with the sources of the build2 package of fmt <https://github.com/build2-packaging/fmt.git>`_
for unreleased or custom revisions of ``fmt``.
**Usage:**
- ``build2`` package name: ``fmt``
- Library target name : ``lib{fmt}``
For example, to make your ``build2`` project depend on ``fmt``:
- Add one of the repositories to your configurations, or in your
``repositories.manifest``, if not already there::
:
role: prerequisite
location: https://pkg.cppget.org/1/stable
- Add this package as a dependency to your ``./manifest`` file
(example for ``v7.0.x``)::
depends: fmt ~7.0.0
- Import the target and use it as a prerequisite to your own target
using `fmt` in the appropriate ``buildfile``::
import fmt = fmt%lib{fmt}
lib{mylib} : cxx{**} ... $fmt
Then build your project as usual with `b` or `bdep update`.
For ``build2`` newcomers or to get more details and use cases, you can read the
``build2``
`toolchain introduction <https://build2.org/build2-toolchain/doc/build2-toolchain-intro.xhtml>`_.
Building the Documentation
==========================
@ -130,6 +181,18 @@ The fmt port in vcpkg is kept up to date by Microsoft team members and community
contributors. If the version is out of date, please `create an issue or pull
request <https://github.com/Microsoft/vcpkg>`__ on the vcpkg repository.
LHelper
=======
You can download and install fmt using
`lhelper <https://github.com/franko/lhelper>`__ dependency manager::
lhelper activate <some-environment>
lhelper install fmt
All the recipes for lhelper are kept in the
`lhelper's recipe <https://github.com/franko/lhelper-recipes>`__ repository.
Android NDK
===========

View file

@ -72,43 +72,27 @@ FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
static_assert(F::is_integer, "From must be integral");
static_assert(T::is_integer, "To must be integral");
if (F::is_signed && !T::is_signed) {
if (detail::const_check(F::is_signed && !T::is_signed)) {
// From may be negative, not allowed!
if (fmt::detail::is_negative(from)) {
ec = 1;
return {};
}
// From is positive. Can it always fit in To?
if (F::digits <= T::digits) {
// yes, From always fits in To.
} else {
// from may not fit in To, we have to do a dynamic check
if (from > static_cast<From>((T::max)())) {
ec = 1;
return {};
}
if (F::digits > T::digits &&
from > static_cast<From>(detail::max_value<To>())) {
ec = 1;
return {};
}
}
if (!F::is_signed && T::is_signed) {
// can from be held in To?
if (F::digits < T::digits) {
// yes, From always fits in To.
} else {
// from may not fit in To, we have to do a dynamic check
if (from > static_cast<From>((T::max)())) {
// outside range.
ec = 1;
return {};
}
}
if (!F::is_signed && T::is_signed && F::digits >= T::digits &&
from > static_cast<From>(detail::max_value<To>())) {
ec = 1;
return {};
}
// reaching here means all is ok for lossless conversion.
return static_cast<To>(from);
} // function
return static_cast<To>(from); // Lossless conversion.
}
template <typename To, typename From,
FMT_ENABLE_IF(std::is_same<From, To>::value)>
@ -190,11 +174,9 @@ To safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
// safe conversion to IntermediateRep
IntermediateRep count =
lossless_integral_conversion<IntermediateRep>(from.count(), ec);
if (ec) {
return {};
}
if (ec) return {};
// multiply with Factor::num without overflow or underflow
if (Factor::num != 1) {
if (detail::const_check(Factor::num != 1)) {
const auto max1 = detail::max_value<IntermediateRep>() / Factor::num;
if (count > max1) {
ec = 1;
@ -209,17 +191,9 @@ To safe_duration_cast(std::chrono::duration<FromRep, FromPeriod> from,
count *= Factor::num;
}
// this can't go wrong, right? den>0 is checked earlier.
if (Factor::den != 1) {
count /= Factor::den;
}
// convert to the to type, safely
using ToRep = typename To::rep;
const ToRep tocount = lossless_integral_conversion<ToRep>(count, ec);
if (ec) {
return {};
}
return To{tocount};
if (detail::const_check(Factor::den != 1)) count /= Factor::den;
auto tocount = lossless_integral_conversion<typename To::rep>(count, ec);
return ec ? To() : To(tocount);
}
/**
@ -351,6 +325,11 @@ inline std::tm localtime(std::time_t time) {
return lt.tm_;
}
inline std::tm localtime(
std::chrono::time_point<std::chrono::system_clock> time_point) {
return localtime(std::chrono::system_clock::to_time_t(time_point));
}
// Thread-safe replacement for std::gmtime
inline std::tm gmtime(std::time_t time) {
struct dispatcher {
@ -387,6 +366,11 @@ inline std::tm gmtime(std::time_t time) {
return gt.tm_;
}
inline std::tm gmtime(
std::chrono::time_point<std::chrono::system_clock> time_point) {
return gmtime(std::chrono::system_clock::to_time_t(time_point));
}
namespace detail {
inline size_t strftime(char* str, size_t count, const char* format,
const std::tm* time) {
@ -399,6 +383,17 @@ inline size_t strftime(wchar_t* str, size_t count, const wchar_t* format,
}
} // namespace detail
template <typename Char>
struct formatter<std::chrono::time_point<std::chrono::system_clock>, Char>
: formatter<std::tm, Char> {
template <typename FormatContext>
auto format(std::chrono::time_point<std::chrono::system_clock> val,
FormatContext& ctx) -> decltype(ctx.out()) {
std::tm time = localtime(val);
return formatter<std::tm, Char>::format(time, ctx);
}
};
template <typename Char> struct formatter<std::tm, Char> {
template <typename ParseContext>
auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {

View file

@ -463,16 +463,16 @@ template <> inline void reset_color<wchar_t>(FILE* stream) FMT_NOEXCEPT {
}
template <typename Char>
inline void reset_color(basic_memory_buffer<Char>& buffer) FMT_NOEXCEPT {
inline void reset_color(buffer<Char>& buffer) FMT_NOEXCEPT {
const char* begin = data::reset_color;
const char* end = begin + sizeof(data::reset_color) - 1;
buffer.append(begin, end);
}
template <typename Char>
void vformat_to(basic_memory_buffer<Char>& buf, const text_style& ts,
void vformat_to(buffer<Char>& buf, const text_style& ts,
basic_string_view<Char> format_str,
basic_format_args<buffer_context<Char>> args) {
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
bool has_style = false;
if (ts.has_emphasis()) {
has_style = true;
@ -496,7 +496,7 @@ void vformat_to(basic_memory_buffer<Char>& buf, const text_style& ts,
template <typename S, typename Char = char_t<S>>
void vprint(std::FILE* f, const text_style& ts, const S& format,
basic_format_args<buffer_context<Char>> args) {
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
basic_memory_buffer<Char> buf;
detail::vformat_to(buf, ts, to_string_view(format), args);
buf.push_back(Char(0));
@ -504,20 +504,22 @@ void vprint(std::FILE* f, const text_style& ts, const S& format,
}
/**
\rst
Formats a string and prints it to the specified file stream using ANSI
escape sequences to specify text formatting.
Example:
**Example**::
fmt::print(fmt::emphasis::bold | fg(fmt::color::red),
"Elapsed time: {0:.2f} seconds", 1.23);
\endrst
*/
template <typename S, typename... Args,
FMT_ENABLE_IF(detail::is_string<S>::value)>
void print(std::FILE* f, const text_style& ts, const S& format_str,
const Args&... args) {
detail::check_format_string<Args...>(format_str);
using context = buffer_context<char_t<S>>;
format_arg_store<context, Args...> as{args...};
vprint(f, ts, format_str, basic_format_args<context>(as));
vprint(f, ts, format_str,
fmt::make_args_checked<Args...>(format_str, args...));
}
/**
@ -558,7 +560,42 @@ template <typename S, typename... Args, typename Char = char_t<S>>
inline std::basic_string<Char> format(const text_style& ts, const S& format_str,
const Args&... args) {
return vformat(ts, to_string_view(format_str),
detail::make_args_checked<Args...>(format_str, args...));
fmt::make_args_checked<Args...>(format_str, args...));
}
/**
Formats a string with the given text_style and writes the output to ``out``.
*/
template <typename OutputIt, typename Char,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value)>
OutputIt vformat_to(
OutputIt out, const text_style& ts, basic_string_view<Char> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
decltype(detail::get_buffer<Char>(out)) buf(detail::get_buffer_init(out));
detail::vformat_to(buf, ts, format_str, args);
return detail::get_iterator(buf);
}
/**
\rst
Formats arguments with the given text_style, writes the result to the output
iterator ``out`` and returns the iterator past the end of the output range.
**Example**::
std::vector<char> out;
fmt::format_to(std::back_inserter(out),
fmt::emphasis::bold | fg(fmt::color::red), "{}", 42);
\endrst
*/
template <typename OutputIt, typename S, typename... Args,
bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value&&
detail::is_string<S>::value>
inline auto format_to(OutputIt out, const text_style& ts, const S& format_str,
Args&&... args) ->
typename std::enable_if<enable, OutputIt>::type {
return vformat_to(out, ts, to_string_view(format_str),
fmt::make_args_checked<Args...>(format_str, args...));
}
FMT_END_NAMESPACE

View file

@ -368,7 +368,8 @@ template <typename... Args> struct type_list {};
// Returns a reference to the argument at index N from [first, rest...].
template <int N, typename T, typename... Args>
constexpr const auto& get(const T& first, const Args&... rest) {
constexpr const auto& get([[maybe_unused]] const T& first,
[[maybe_unused]] const Args&... rest) {
static_assert(N < 1 + sizeof...(Args), "index is out of bounds");
if constexpr (N == 0)
return first;
@ -406,6 +407,19 @@ constexpr text<Char> make_text(basic_string_view<Char> s, size_t pos,
return {{&s[pos], size}};
}
template <typename Char> struct code_unit {
Char value;
using char_type = Char;
template <typename OutputIt, typename... Args>
OutputIt format(OutputIt out, const Args&...) const {
return write<Char>(out, value);
}
};
template <typename Char>
struct is_compiled_format<code_unit<Char>> : std::true_type {};
// A replacement field that refers to argument N.
template <typename Char, typename T, int N> struct field {
using char_type = Char;
@ -430,7 +444,9 @@ template <typename Char, typename T, int N> struct spec_field {
OutputIt format(OutputIt out, const Args&... args) const {
// This ensures that the argument type is convertile to `const T&`.
const T& arg = get<N>(args...);
basic_format_context<OutputIt, Char> ctx(out, {});
const auto& vargs =
make_format_args<basic_format_context<OutputIt, Char>>(args...);
basic_format_context<OutputIt, Char> ctx(out, vargs);
return fmt.format(arg, ctx);
}
};
@ -489,16 +505,17 @@ constexpr auto parse_tail(T head, S format_str) {
template <typename T, typename Char> struct parse_specs_result {
formatter<T, Char> fmt;
size_t end;
int next_arg_id;
};
template <typename T, typename Char>
constexpr parse_specs_result<T, Char> parse_specs(basic_string_view<Char> str,
size_t pos) {
size_t pos, int arg_id) {
str.remove_prefix(pos);
auto ctx = basic_format_parse_context<Char>(str);
auto ctx = basic_format_parse_context<Char>(str, {}, arg_id + 1);
auto f = formatter<T, Char>();
auto end = f.parse(ctx);
return {f, pos + (end - str.data()) + 1};
return {f, pos + (end - str.data()) + 1, ctx.next_arg_id()};
}
// Compiles a non-empty format string and returns the compiled representation
@ -518,8 +535,8 @@ constexpr auto compile_format_string(S format_str) {
format_str);
} else if constexpr (str[POS + 1] == ':') {
using type = get_type<ID, Args>;
constexpr auto result = parse_specs<type>(str, POS + 2);
return parse_tail<Args, result.end, ID + 1>(
constexpr auto result = parse_specs<type>(str, POS + 2, ID);
return parse_tail<Args, result.end, result.next_arg_id>(
spec_field<char_type, type, ID>{result.fmt}, format_str);
} else {
return unknown_format();
@ -530,8 +547,13 @@ constexpr auto compile_format_string(S format_str) {
return parse_tail<Args, POS + 2, ID>(make_text(str, POS, 1), format_str);
} else {
constexpr auto end = parse_text(str, POS + 1);
return parse_tail<Args, end, ID>(make_text(str, POS, end - POS),
format_str);
if constexpr (end - POS > 1) {
return parse_tail<Args, end, ID>(make_text(str, POS, end - POS),
format_str);
} else {
return parse_tail<Args, end, ID>(code_unit<char_type>{str[POS]},
format_str);
}
}
}
@ -587,8 +609,7 @@ template <typename CompiledFormat, typename... Args,
FMT_INLINE std::basic_string<Char> format(const CompiledFormat& cf,
const Args&... args) {
basic_memory_buffer<Char> buffer;
detail::buffer<Char>& base = buffer;
cf.format(std::back_inserter(base), args...);
cf.format(detail::buffer_appender<Char>(buffer), args...);
return to_string(buffer);
}
@ -608,8 +629,7 @@ template <typename CompiledFormat, typename... Args,
std::basic_string<Char> format(const CompiledFormat& cf, const Args&... args) {
basic_memory_buffer<Char> buffer;
using context = buffer_context<Char>;
detail::buffer<Char>& base = buffer;
detail::cf::vformat_to<context>(std::back_inserter(base), cf,
detail::cf::vformat_to<context>(detail::buffer_appender<Char>(buffer), cf,
make_format_args<context>(args...));
return to_string(buffer);
}
@ -618,9 +638,13 @@ template <typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
FMT_INLINE std::basic_string<typename S::char_type> format(const S&,
Args&&... args) {
constexpr basic_string_view<typename S::char_type> str = S();
if (str.size() == 2 && str[0] == '{' && str[1] == '}')
return fmt::to_string(detail::first(args...));
#ifdef __cpp_if_constexpr
if constexpr (std::is_same<typename S::char_type, char>::value) {
constexpr basic_string_view<typename S::char_type> str = S();
if (str.size() == 2 && str[0] == '{' && str[1] == '}')
return fmt::to_string(detail::first(args...));
}
#endif
constexpr auto compiled = detail::compile<Args...>(S());
return format(compiled, std::forward<Args>(args)...);
}
@ -643,18 +667,30 @@ OutputIt format_to(OutputIt out, const S&, const Args&... args) {
return format_to(out, compiled, args...);
}
template <
typename OutputIt, typename CompiledFormat, typename... Args,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt>::value&& std::is_base_of<
detail::basic_compiled_format, CompiledFormat>::value)>
format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n,
const CompiledFormat& cf,
const Args&... args) {
template <typename OutputIt, typename CompiledFormat, typename... Args>
auto format_to_n(OutputIt out, size_t n, const CompiledFormat& cf,
const Args&... args) ->
typename std::enable_if<
detail::is_output_iterator<OutputIt,
typename CompiledFormat::char_type>::value &&
std::is_base_of<detail::basic_compiled_format,
CompiledFormat>::value,
format_to_n_result<OutputIt>>::type {
auto it =
format_to(detail::truncating_iterator<OutputIt>(out, n), cf, args...);
return {it.base(), it.count()};
}
template <typename OutputIt, typename S, typename... Args,
FMT_ENABLE_IF(detail::is_compiled_string<S>::value)>
format_to_n_result<OutputIt> format_to_n(OutputIt out, size_t n, const S&,
const Args&... args) {
constexpr auto compiled = detail::compile<Args...>(S());
auto it = format_to(detail::truncating_iterator<OutputIt>(out, n), compiled,
args...);
return {it.base(), it.count()};
}
template <typename CompiledFormat, typename... Args>
size_t formatted_size(const CompiledFormat& cf, const Args&... args) {
return format_to(detail::counting_iterator(), cf, args...).count();

View file

@ -18,7 +18,7 @@
#include <vector>
// The fmt library version in the form major * 10000 + minor * 100 + patch.
#define FMT_VERSION 70003
#define FMT_VERSION 70103
#ifdef __clang__
# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
@ -57,6 +57,7 @@
# define FMT_MSC_VER 0
# define FMT_SUPPRESS_MSC_WARNING(n)
#endif
#ifdef __has_feature
# define FMT_HAS_FEATURE(x) __has_feature(x)
#else
@ -64,7 +65,7 @@
#endif
#if defined(__has_include) && !defined(__INTELLISENSE__) && \
!(FMT_ICC_VERSION && FMT_ICC_VERSION < 1600)
(!FMT_ICC_VERSION || FMT_ICC_VERSION >= 1600)
# define FMT_HAS_INCLUDE(x) __has_include(x)
#else
# define FMT_HAS_INCLUDE(x) 0
@ -99,7 +100,7 @@
#endif
#ifndef FMT_OVERRIDE
# if FMT_HAS_FEATURE(cxx_override) || \
# if FMT_HAS_FEATURE(cxx_override_control) || \
(FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900
# define FMT_OVERRIDE override
# else
@ -152,7 +153,7 @@
# if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VER >= 1900
# define FMT_DEPRECATED [[deprecated]]
# else
# if defined(__GNUC__) || defined(__clang__)
# if (defined(__GNUC__) && !defined(__LCC__)) || defined(__clang__)
# define FMT_DEPRECATED __attribute__((deprecated))
# elif FMT_MSC_VER
# define FMT_DEPRECATED __declspec(deprecated)
@ -177,9 +178,17 @@
# endif
#endif
#ifndef FMT_BEGIN_NAMESPACE
#ifndef FMT_USE_INLINE_NAMESPACES
# if FMT_HAS_FEATURE(cxx_inline_namespaces) || FMT_GCC_VERSION >= 404 || \
FMT_MSC_VER >= 1900
(FMT_MSC_VER >= 1900 && !_MANAGED)
# define FMT_USE_INLINE_NAMESPACES 1
# else
# define FMT_USE_INLINE_NAMESPACES 0
# endif
#endif
#ifndef FMT_BEGIN_NAMESPACE
# if FMT_USE_INLINE_NAMESPACES
# define FMT_INLINE_NAMESPACE inline namespace
# define FMT_END_NAMESPACE \
} \
@ -269,8 +278,7 @@ struct monostate {};
namespace detail {
// A helper function to suppress bogus "conditional expression is constant"
// warnings.
// A helper function to suppress "conditional expression is constant" warnings.
template <typename T> constexpr T const_check(T value) { return value; }
FMT_NORETURN FMT_API void assert_fail(const char* file, int line,
@ -299,7 +307,8 @@ template <typename T> struct std_string_view {};
#ifdef FMT_USE_INT128
// Do nothing.
#elif defined(__SIZEOF_INT128__) && !FMT_NVCC && !(FMT_CLANG_VERSION && FMT_MSC_VER)
#elif defined(__SIZEOF_INT128__) && !FMT_NVCC && \
!(FMT_CLANG_VERSION && FMT_MSC_VER)
# define FMT_USE_INT128 1
using int128_t = __int128_t;
using uint128_t = __uint128_t;
@ -506,6 +515,18 @@ template <typename S> struct char_t_impl<S, enable_if_t<is_string<S>::value>> {
using type = typename result::value_type;
};
// Reports a compile-time error if S is not a valid format string.
template <typename..., typename S, FMT_ENABLE_IF(!is_compile_string<S>::value)>
FMT_INLINE void check_format_string(const S&) {
#ifdef FMT_ENFORCE_COMPILE_STRING
static_assert(is_compile_string<S>::value,
"FMT_ENFORCE_COMPILE_STRING requires all format strings to use "
"FMT_STRING.");
#endif
}
template <typename..., typename S, FMT_ENABLE_IF(is_compile_string<S>::value)>
void check_format_string(S);
struct error_handler {
constexpr error_handler() = default;
constexpr error_handler(const error_handler&) = default;
@ -545,8 +566,9 @@ class basic_format_parse_context : private ErrorHandler {
using iterator = typename basic_string_view<Char>::iterator;
explicit constexpr basic_format_parse_context(
basic_string_view<Char> format_str, ErrorHandler eh = {})
: ErrorHandler(eh), format_str_(format_str), next_arg_id_(0) {}
basic_string_view<Char> format_str, ErrorHandler eh = {},
int next_arg_id = 0)
: ErrorHandler(eh), format_str_(format_str), next_arg_id_(next_arg_id) {}
/**
Returns an iterator to the beginning of the format string range being
@ -616,8 +638,24 @@ template <typename T, typename Context>
using has_formatter =
std::is_constructible<typename Context::template formatter_type<T>>;
// Checks whether T is a container with contiguous storage.
template <typename T> struct is_contiguous : std::false_type {};
template <typename Char>
struct is_contiguous<std::basic_string<Char>> : std::true_type {};
namespace detail {
// Extracts a reference to the container from back_insert_iterator.
template <typename Container>
inline Container& get_container(std::back_insert_iterator<Container> it) {
using bi_iterator = std::back_insert_iterator<Container>;
struct accessor : bi_iterator {
accessor(bi_iterator iter) : bi_iterator(iter) {}
using bi_iterator::container;
};
return *accessor(it).container;
}
/**
\rst
A contiguous memory buffer with an optional growing ability. It is an internal
@ -640,6 +678,8 @@ template <typename T> class buffer {
size_(sz),
capacity_(cap) {}
~buffer() = default;
/** Sets the buffer data and capacity. */
void set(T* buf_data, size_t buf_capacity) FMT_NOEXCEPT {
ptr_ = buf_data;
@ -655,7 +695,6 @@ template <typename T> class buffer {
buffer(const buffer&) = delete;
void operator=(const buffer&) = delete;
virtual ~buffer() = default;
T* begin() FMT_NOEXCEPT { return ptr_; }
T* end() FMT_NOEXCEPT { return ptr_ + size_; }
@ -675,24 +714,26 @@ template <typename T> class buffer {
/** Returns a pointer to the buffer data. */
const T* data() const FMT_NOEXCEPT { return ptr_; }
/**
Resizes the buffer. If T is a POD type new elements may not be initialized.
*/
void resize(size_t new_size) {
reserve(new_size);
size_ = new_size;
}
/** Clears this buffer. */
void clear() { size_ = 0; }
/** Reserves space to store at least *capacity* elements. */
void reserve(size_t new_capacity) {
// Tries resizing the buffer to contain *count* elements. If T is a POD type
// the new elements may not be initialized.
void try_resize(size_t count) {
try_reserve(count);
size_ = count <= capacity_ ? count : capacity_;
}
// Tries increasing the buffer capacity to *new_capacity*. It can increase the
// capacity by a smaller amount than requested but guarantees there is space
// for at least one additional element either by increasing the capacity or by
// flushing the buffer if it is full.
void try_reserve(size_t new_capacity) {
if (new_capacity > capacity_) grow(new_capacity);
}
void push_back(const T& value) {
reserve(size_ + 1);
try_reserve(size_ + 1);
ptr_[size_++] = value;
}
@ -705,32 +746,150 @@ template <typename T> class buffer {
}
};
// A container-backed buffer.
struct buffer_traits {
explicit buffer_traits(size_t) {}
size_t count() const { return 0; }
size_t limit(size_t size) { return size; }
};
class fixed_buffer_traits {
private:
size_t count_ = 0;
size_t limit_;
public:
explicit fixed_buffer_traits(size_t limit) : limit_(limit) {}
size_t count() const { return count_; }
size_t limit(size_t size) {
size_t n = limit_ > count_ ? limit_ - count_ : 0;
count_ += size;
return size < n ? size : n;
}
};
// A buffer that writes to an output iterator when flushed.
template <typename OutputIt, typename T, typename Traits = buffer_traits>
class iterator_buffer final : public Traits, public buffer<T> {
private:
OutputIt out_;
enum { buffer_size = 256 };
T data_[buffer_size];
protected:
void grow(size_t) final FMT_OVERRIDE {
if (this->size() == buffer_size) flush();
}
void flush();
public:
explicit iterator_buffer(OutputIt out, size_t n = buffer_size)
: Traits(n),
buffer<T>(data_, 0, buffer_size),
out_(out) {}
~iterator_buffer() { flush(); }
OutputIt out() {
flush();
return out_;
}
size_t count() const { return Traits::count() + this->size(); }
};
template <typename T> class iterator_buffer<T*, T> final : public buffer<T> {
protected:
void grow(size_t) final FMT_OVERRIDE {}
public:
explicit iterator_buffer(T* out, size_t = 0) : buffer<T>(out, 0, ~size_t()) {}
T* out() { return &*this->end(); }
};
// A buffer that writes to a container with the contiguous storage.
template <typename Container>
class container_buffer : public buffer<typename Container::value_type> {
class iterator_buffer<std::back_insert_iterator<Container>,
enable_if_t<is_contiguous<Container>::value,
typename Container::value_type>>
final : public buffer<typename Container::value_type> {
private:
Container& container_;
protected:
void grow(size_t capacity) FMT_OVERRIDE {
void grow(size_t capacity) final FMT_OVERRIDE {
container_.resize(capacity);
this->set(&container_[0], capacity);
}
public:
explicit container_buffer(Container& c)
explicit iterator_buffer(Container& c)
: buffer<typename Container::value_type>(c.size()), container_(c) {}
explicit iterator_buffer(std::back_insert_iterator<Container> out, size_t = 0)
: iterator_buffer(get_container(out)) {}
std::back_insert_iterator<Container> out() {
return std::back_inserter(container_);
}
};
// Extracts a reference to the container from back_insert_iterator.
template <typename Container>
inline Container& get_container(std::back_insert_iterator<Container> it) {
using bi_iterator = std::back_insert_iterator<Container>;
struct accessor : bi_iterator {
accessor(bi_iterator iter) : bi_iterator(iter) {}
using bi_iterator::container;
};
return *accessor(it).container;
// A buffer that counts the number of code units written discarding the output.
template <typename T = char> class counting_buffer final : public buffer<T> {
private:
enum { buffer_size = 256 };
T data_[buffer_size];
size_t count_ = 0;
protected:
void grow(size_t) final FMT_OVERRIDE {
if (this->size() != buffer_size) return;
count_ += this->size();
this->clear();
}
public:
counting_buffer() : buffer<T>(data_, 0, buffer_size) {}
size_t count() { return count_ + this->size(); }
};
// An output iterator that appends to the buffer.
// It is used to reduce symbol sizes for the common case.
template <typename T>
class buffer_appender : public std::back_insert_iterator<buffer<T>> {
using base = std::back_insert_iterator<buffer<T>>;
public:
explicit buffer_appender(buffer<T>& buf) : base(buf) {}
buffer_appender(base it) : base(it) {}
buffer_appender& operator++() {
base::operator++();
return *this;
}
buffer_appender operator++(int) {
buffer_appender tmp = *this;
++*this;
return tmp;
}
};
// Maps an output iterator into a buffer.
template <typename T, typename OutputIt>
iterator_buffer<OutputIt, T> get_buffer(OutputIt);
template <typename T> buffer<T>& get_buffer(buffer_appender<T>);
template <typename OutputIt> OutputIt get_buffer_init(OutputIt out) {
return out;
}
template <typename T> buffer<T>& get_buffer_init(buffer_appender<T> out) {
return get_container(out);
}
template <typename Buffer>
auto get_iterator(Buffer& buf) -> decltype(buf.out()) {
return buf.out();
}
template <typename T> buffer_appender<T> get_iterator(buffer<T>& buf) {
return buffer_appender<T>(buf);
}
template <typename T, typename Char = char, typename Enable = void>
@ -759,7 +918,8 @@ template <typename Char> struct named_arg_info {
template <typename T, typename Char, size_t NUM_ARGS, size_t NUM_NAMED_ARGS>
struct arg_data {
// args_[0].named_args points to named_args_ to avoid bloating format_args.
T args_[1 + (NUM_ARGS != 0 ? NUM_ARGS : 1)];
// +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning.
T args_[1 + (NUM_ARGS != 0 ? NUM_ARGS : +1)];
named_arg_info<Char> named_args_[NUM_NAMED_ARGS];
template <typename... U>
@ -771,7 +931,8 @@ struct arg_data {
template <typename T, typename Char, size_t NUM_ARGS>
struct arg_data<T, Char, NUM_ARGS, 0> {
T args_[NUM_ARGS != 0 ? NUM_ARGS : 1];
// +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning.
T args_[NUM_ARGS != 0 ? NUM_ARGS : +1];
template <typename... U>
FMT_INLINE arg_data(const U&... init) : args_{init...} {}
@ -959,6 +1120,8 @@ enum { long_short = sizeof(long) == sizeof(int) };
using long_type = conditional_t<long_short, int, long long>;
using ulong_type = conditional_t<long_short, unsigned, unsigned long long>;
struct unformattable {};
// Maps formatting arguments to core types.
template <typename Context> struct arg_mapper {
using char_type = typename Context::char_type;
@ -1067,15 +1230,7 @@ template <typename Context> struct arg_mapper {
return map(val.value);
}
int map(...) {
constexpr bool formattable = sizeof(Context) == 0;
static_assert(
formattable,
"Cannot format argument. To make type T formattable provide a "
"formatter<T> specialization: "
"https://fmt.dev/latest/api.html#formatting-user-defined-types");
return 0;
}
unformattable map(...) { return {}; }
};
// A type constant after applying arg_mapper<Context>.
@ -1199,15 +1354,25 @@ FMT_CONSTEXPR_DECL FMT_INLINE auto visit_format_arg(
return vis(monostate());
}
// Checks whether T is a container with contiguous storage.
template <typename T> struct is_contiguous : std::false_type {};
template <typename Char>
struct is_contiguous<std::basic_string<Char>> : std::true_type {};
template <typename Char>
struct is_contiguous<detail::buffer<Char>> : std::true_type {};
template <typename T> struct formattable : std::false_type {};
namespace detail {
// A workaround for gcc 4.8 to make void_t work in a SFINAE context.
template <typename... Ts> struct void_t_impl { using type = void; };
template <typename... Ts>
using void_t = typename detail::void_t_impl<Ts...>::type;
template <typename It, typename T, typename Enable = void>
struct is_output_iterator : std::false_type {};
template <typename It, typename T>
struct is_output_iterator<
It, T,
void_t<typename std::iterator_traits<It>::iterator_category,
decltype(*std::declval<It>() = std::declval<T>())>>
: std::true_type {};
template <typename OutputIt>
struct is_back_insert_iterator : std::false_type {};
template <typename Container>
@ -1219,6 +1384,9 @@ struct is_contiguous_back_insert_iterator : std::false_type {};
template <typename Container>
struct is_contiguous_back_insert_iterator<std::back_insert_iterator<Container>>
: is_contiguous<Container> {};
template <typename Char>
struct is_contiguous_back_insert_iterator<buffer_appender<Char>>
: std::true_type {};
// A type-erased reference to an std::locale to avoid heavy <locale> include.
class locale_ref {
@ -1250,13 +1418,24 @@ FMT_CONSTEXPR basic_format_arg<Context> make_arg(const T& value) {
return arg;
}
template <typename T> int check(unformattable) {
static_assert(
formattable<T>(),
"Cannot format an argument. To make type T formattable provide a "
"formatter<T> specialization: https://fmt.dev/latest/api.html#udt");
return 0;
}
template <typename T, typename U> inline const U& check(const U& val) {
return val;
}
// The type template parameter is there to avoid an ODR violation when using
// a fallback formatter in one translation unit and an implicit conversion in
// another (not recommended).
template <bool IS_PACKED, typename Context, type, typename T,
FMT_ENABLE_IF(IS_PACKED)>
inline value<Context> make_arg(const T& val) {
return arg_mapper<Context>().map(val);
return check<T>(arg_mapper<Context>().map(val));
}
template <bool IS_PACKED, typename Context, type, typename T,
@ -1356,13 +1535,13 @@ template <typename OutputIt, typename Char> class basic_format_context {
template <typename Char>
using buffer_context =
basic_format_context<std::back_insert_iterator<detail::buffer<Char>>, Char>;
basic_format_context<detail::buffer_appender<Char>, Char>;
using format_context = buffer_context<char>;
using wformat_context = buffer_context<wchar_t>;
// Workaround a bug in gcc: https://stackoverflow.com/q/62767544/471164.
// Workaround an alias issue: https://stackoverflow.com/q/62767544/471164.
#define FMT_BUFFER_CONTEXT(Char) \
basic_format_context<std::back_insert_iterator<detail::buffer<Char>>, Char>
basic_format_context<detail::buffer_appender<Char>, Char>
/**
\rst
@ -1414,7 +1593,7 @@ class format_arg_store
/**
\rst
Constructs an `~fmt::format_arg_store` object that contains references to
Constructs a `~fmt::format_arg_store` object that contains references to
arguments and can be implicitly converted to `~fmt::format_args`. `Context`
can be omitted in which case it defaults to `~fmt::context`.
See `~fmt::arg` for lifetime considerations.
@ -1426,6 +1605,27 @@ inline format_arg_store<Context, Args...> make_format_args(
return {args...};
}
/**
\rst
Constructs a `~fmt::format_arg_store` object that contains references
to arguments and can be implicitly converted to `~fmt::format_args`.
If ``format_str`` is a compile-time string then `make_args_checked` checks
its validity at compile time.
\endrst
*/
template <typename... Args, typename S, typename Char = char_t<S>>
inline auto make_args_checked(const S& format_str,
const remove_reference_t<Args>&... args)
-> format_arg_store<buffer_context<Char>, remove_reference_t<Args>...> {
static_assert(
detail::count<(
std::is_base_of<detail::view, remove_reference_t<Args>>::value &&
std::is_reference<Args>::value)...>() == 0,
"passing views as lvalues is disallowed");
detail::check_format_string<Args...>(format_str);
return {args...};
}
/**
\rst
Returns a named argument to be used in a formatting function. It should only
@ -1729,7 +1929,14 @@ template <typename Context> class basic_format_args {
}
};
/** An alias to ``basic_format_args<context>``. */
#ifdef FMT_ARM_ABI_COMPATIBILITY
/** An alias to ``basic_format_args<format_context>``. */
// Separate types would result in shorter symbols but break ABI compatibility
// between clang and gcc on ARM (#1919).
using format_args = basic_format_args<format_context>;
using wformat_args = basic_format_args<wformat_context>;
#else
// DEPRECATED! These are kept for ABI compatibility.
// It is a separate type rather than an alias to make symbols readable.
struct format_args : basic_format_args<format_context> {
template <typename... Args>
@ -1738,32 +1945,10 @@ struct format_args : basic_format_args<format_context> {
struct wformat_args : basic_format_args<wformat_context> {
using basic_format_args::basic_format_args;
};
#endif
namespace detail {
// Reports a compile-time error if S is not a valid format string.
template <typename..., typename S, FMT_ENABLE_IF(!is_compile_string<S>::value)>
FMT_INLINE void check_format_string(const S&) {
#ifdef FMT_ENFORCE_COMPILE_STRING
static_assert(is_compile_string<S>::value,
"FMT_ENFORCE_COMPILE_STRING requires all format strings to use "
"FMT_STRING.");
#endif
}
template <typename..., typename S, FMT_ENABLE_IF(is_compile_string<S>::value)>
void check_format_string(S);
template <typename... Args, typename S, typename Char = char_t<S>>
inline format_arg_store<buffer_context<Char>, remove_reference_t<Args>...>
make_args_checked(const S& format_str,
const remove_reference_t<Args>&... args) {
static_assert(count<(std::is_base_of<view, remove_reference_t<Args>>::value &&
std::is_reference<Args>::value)...>() == 0,
"passing views as lvalues is disallowed");
check_format_string<Args...>(format_str);
return {args...};
}
template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
std::basic_string<Char> vformat(
basic_string_view<Char> format_str,
@ -1772,9 +1957,10 @@ std::basic_string<Char> vformat(
FMT_API std::string vformat(string_view format_str, format_args args);
template <typename Char>
typename FMT_BUFFER_CONTEXT(Char)::iterator vformat_to(
void vformat_to(
buffer<Char>& buf, basic_string_view<Char> format_str,
basic_format_args<FMT_BUFFER_CONTEXT(type_identity_t<Char>)> args);
basic_format_args<FMT_BUFFER_CONTEXT(type_identity_t<Char>)> args,
detail::locale_ref loc = {});
template <typename Char, typename Args,
FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
@ -1789,26 +1975,80 @@ inline void vprint_mojibake(std::FILE*, string_view, format_args) {}
/** Formats a string and writes the output to ``out``. */
// GCC 8 and earlier cannot handle std::back_insert_iterator<Container> with
// vformat_to<ArgFormatter>(...) overload, so SFINAE on iterator type instead.
template <
typename OutputIt, typename S, typename Char = char_t<S>,
FMT_ENABLE_IF(detail::is_contiguous_back_insert_iterator<OutputIt>::value)>
OutputIt vformat_to(
OutputIt out, const S& format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
auto& c = detail::get_container(out);
detail::container_buffer<remove_reference_t<decltype(c)>> buf(c);
template <typename OutputIt, typename S, typename Char = char_t<S>,
bool enable = detail::is_output_iterator<OutputIt, Char>::value>
auto vformat_to(OutputIt out, const S& format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args)
-> typename std::enable_if<enable, OutputIt>::type {
decltype(detail::get_buffer<Char>(out)) buf(detail::get_buffer_init(out));
detail::vformat_to(buf, to_string_view(format_str), args);
return out;
return detail::get_iterator(buf);
}
template <typename Container, typename S, typename... Args,
FMT_ENABLE_IF(
is_contiguous<Container>::value&& detail::is_string<S>::value)>
inline std::back_insert_iterator<Container> format_to(
std::back_insert_iterator<Container> out, const S& format_str,
Args&&... args) {
return vformat_to(out, to_string_view(format_str),
detail::make_args_checked<Args...>(format_str, args...));
/**
\rst
Formats arguments, writes the result to the output iterator ``out`` and returns
the iterator past the end of the output range.
**Example**::
std::vector<char> out;
fmt::format_to(std::back_inserter(out), "{}", 42);
\endrst
*/
// We cannot use FMT_ENABLE_IF because of a bug in gcc 8.3.
template <typename OutputIt, typename S, typename... Args,
bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value>
inline auto format_to(OutputIt out, const S& format_str, Args&&... args) ->
typename std::enable_if<enable, OutputIt>::type {
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
return vformat_to(out, to_string_view(format_str), vargs);
}
template <typename OutputIt> struct format_to_n_result {
/** Iterator past the end of the output range. */
OutputIt out;
/** Total (not truncated) output size. */
size_t size;
};
template <typename OutputIt, typename Char, typename... Args,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value)>
inline format_to_n_result<OutputIt> vformat_to_n(
OutputIt out, size_t n, basic_string_view<Char> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
detail::iterator_buffer<OutputIt, Char, detail::fixed_buffer_traits> buf(out,
n);
detail::vformat_to(buf, format_str, args);
return {buf.out(), buf.count()};
}
/**
\rst
Formats arguments, writes up to ``n`` characters of the result to the output
iterator ``out`` and returns the total output size and the iterator past the
end of the output range.
\endrst
*/
template <typename OutputIt, typename S, typename... Args,
bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value>
inline auto format_to_n(OutputIt out, size_t n, const S& format_str,
const Args&... args) ->
typename std::enable_if<enable, format_to_n_result<OutputIt>>::type {
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
return vformat_to_n(out, n, to_string_view(format_str), vargs);
}
/**
Returns the number of characters in the output of
``format(format_str, args...)``.
*/
template <typename... Args>
inline size_t formatted_size(string_view format_str, Args&&... args) {
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
detail::counting_buffer<> buf;
detail::vformat_to(buf, format_str, vargs);
return buf.count();
}
template <typename S, typename Char = char_t<S>>
@ -1832,7 +2072,7 @@ FMT_INLINE std::basic_string<Char> vformat(
// std::basic_string<char_t<S>> to reduce the symbol size.
template <typename S, typename... Args, typename Char = char_t<S>>
FMT_INLINE std::basic_string<Char> format(const S& format_str, Args&&... args) {
const auto& vargs = detail::make_args_checked<Args...>(format_str, args...);
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
return detail::vformat(to_string_view(format_str), vargs);
}
@ -1852,7 +2092,7 @@ FMT_API void vprint(std::FILE*, string_view, format_args);
*/
template <typename S, typename... Args, typename Char = char_t<S>>
inline void print(std::FILE* f, const S& format_str, Args&&... args) {
const auto& vargs = detail::make_args_checked<Args...>(format_str, args...);
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
return detail::is_unicode<Char>()
? vprint(f, to_string_view(format_str), vargs)
: detail::vprint_mojibake(f, to_string_view(format_str), vargs);
@ -1871,7 +2111,7 @@ inline void print(std::FILE* f, const S& format_str, Args&&... args) {
*/
template <typename S, typename... Args, typename Char = char_t<S>>
inline void print(const S& format_str, Args&&... args) {
const auto& vargs = detail::make_args_checked<Args...>(format_str, args...);
const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
return detail::is_unicode<Char>()
? vprint(to_string_view(format_str), vargs)
: detail::vprint_mojibake(stdout, to_string_view(format_str),

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -15,22 +15,12 @@
FMT_BEGIN_NAMESPACE
namespace detail {
template <typename Char>
typename buffer_context<Char>::iterator vformat_to(
const std::locale& loc, buffer<Char>& buf,
basic_string_view<Char> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
using af = arg_formatter<typename buffer_context<Char>::iterator, Char>;
return vformat_to<af>(std::back_inserter(buf), to_string_view(format_str),
args, detail::locale_ref(loc));
}
template <typename Char>
std::basic_string<Char> vformat(
const std::locale& loc, basic_string_view<Char> format_str,
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
basic_memory_buffer<Char> buffer;
detail::vformat_to(loc, buffer, format_str, args);
detail::vformat_to(buffer, format_str, args, detail::locale_ref(loc));
return fmt::to_string(buffer);
}
} // namespace detail
@ -45,32 +35,28 @@ inline std::basic_string<Char> vformat(
template <typename S, typename... Args, typename Char = char_t<S>>
inline std::basic_string<Char> format(const std::locale& loc,
const S& format_str, Args&&... args) {
return detail::vformat(
loc, to_string_view(format_str),
detail::make_args_checked<Args...>(format_str, args...));
return detail::vformat(loc, to_string_view(format_str),
fmt::make_args_checked<Args...>(format_str, args...));
}
template <typename S, typename OutputIt, typename... Args,
typename Char = enable_if_t<
detail::is_output_iterator<OutputIt>::value, char_t<S>>>
typename Char = char_t<S>,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt, Char>::value)>
inline OutputIt vformat_to(
OutputIt out, const std::locale& loc, const S& format_str,
format_args_t<type_identity_t<OutputIt>, Char> args) {
using af = detail::arg_formatter<OutputIt, Char>;
return vformat_to<af>(out, to_string_view(format_str), args,
detail::locale_ref(loc));
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
decltype(detail::get_buffer<Char>(out)) buf(detail::get_buffer_init(out));
vformat_to(buf, to_string_view(format_str), args, detail::locale_ref(loc));
return detail::get_iterator(buf);
}
template <typename OutputIt, typename S, typename... Args,
FMT_ENABLE_IF(detail::is_output_iterator<OutputIt>::value&&
detail::is_string<S>::value)>
inline OutputIt format_to(OutputIt out, const std::locale& loc,
const S& format_str, Args&&... args) {
detail::check_format_string<Args...>(format_str);
using context = format_context_t<OutputIt, char_t<S>>;
format_arg_store<context, Args...> as{args...};
return vformat_to(out, loc, to_string_view(format_str),
basic_format_args<context>(as));
bool enable = detail::is_output_iterator<OutputIt, char_t<S>>::value>
inline auto format_to(OutputIt out, const std::locale& loc,
const S& format_str, Args&&... args) ->
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), vargs);
}
FMT_END_NAMESPACE

View file

@ -29,7 +29,8 @@
#if FMT_HAS_INCLUDE("winapifamily.h")
# include <winapifamily.h>
#endif
#if FMT_HAS_INCLUDE("fcntl.h") && \
#if (FMT_HAS_INCLUDE(<fcntl.h>) || defined(__APPLE__) || \
defined(__linux__)) && \
(!defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
# include <fcntl.h> // for O_RDONLY
# define FMT_USE_FCNTL 1
@ -278,7 +279,8 @@ class file {
RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
RDWR = FMT_POSIX(O_RDWR), // Open for reading and writing.
CREATE = FMT_POSIX(O_CREAT) // Create if the file doesn't exist.
CREATE = FMT_POSIX(O_CREAT), // Create if the file doesn't exist.
APPEND = FMT_POSIX(O_APPEND) // Open in append mode.
};
// Constructs a file object which doesn't represent any file.
@ -343,36 +345,69 @@ class file {
// Returns the memory page size.
long getpagesize();
class direct_buffered_file;
namespace detail {
template <typename S, typename... Args>
void print(direct_buffered_file& f, const S& format_str,
const Args&... args);
struct buffer_size {
size_t value = 0;
buffer_size operator=(size_t val) const {
auto bs = buffer_size();
bs.value = val;
return bs;
}
};
// A buffered file with a direct buffer access and no synchronization.
class direct_buffered_file {
struct ostream_params {
int oflag = file::WRONLY | file::CREATE;
size_t buffer_size = BUFSIZ > 32768 ? BUFSIZ : 32768;
ostream_params() {}
template <typename... T>
ostream_params(T... params, int oflag) : ostream_params(params...) {
this->oflag = oflag;
}
template <typename... T>
ostream_params(T... params, detail::buffer_size bs)
: ostream_params(params...) {
this->buffer_size = bs.value;
}
};
} // namespace detail
static constexpr detail::buffer_size buffer_size;
// A fast output stream which is not thread-safe.
class ostream final : private detail::buffer<char> {
private:
file file_;
enum { buffer_size = 4096 };
char buffer_[buffer_size];
int pos_;
void flush() {
if (pos_ == 0) return;
file_.write(buffer_, pos_);
pos_ = 0;
if (size() == 0) return;
file_.write(data(), size());
clear();
}
int free_capacity() const { return buffer_size - pos_; }
FMT_API void grow(size_t) override final;
ostream(cstring_view path, const detail::ostream_params& params)
: file_(path, params.oflag) {
set(new char[params.buffer_size], params.buffer_size);
}
public:
direct_buffered_file(cstring_view path, int oflag)
: file_(path, oflag), pos_(0) {}
~direct_buffered_file() {
flush();
ostream(ostream&& other)
: detail::buffer<char>(other.data(), other.size(), other.capacity()),
file_(std::move(other.file_)) {
other.set(nullptr, 0);
}
~ostream() {
flush();
delete[] data();
}
template <typename... T>
friend ostream output_file(cstring_view path, T... params);
void close() {
flush();
@ -380,25 +415,20 @@ class direct_buffered_file {
}
template <typename S, typename... Args>
friend void print(direct_buffered_file& f, const S& format_str,
const Args&... args) {
// We could avoid double buffering.
auto buf = fmt::memory_buffer();
fmt::format_to(std::back_inserter(buf), format_str, args...);
auto remaining_pos = 0;
auto remaining_size = buf.size();
while (remaining_size > detail::to_unsigned(f.free_capacity())) {
auto size = f.free_capacity();
memcpy(f.buffer_ + f.pos_, buf.data() + remaining_pos, size);
f.pos_ += size;
f.flush();
remaining_pos += size;
remaining_size -= size;
}
memcpy(f.buffer_ + f.pos_, buf.data() + remaining_pos, remaining_size);
f.pos_ += static_cast<int>(remaining_size);
void print(const S& format_str, const Args&... args) {
format_to(detail::buffer_appender<char>(*this), format_str, args...);
}
};
/**
Opens a file for writing. Supported parameters passed in `params`:
* ``<integer>``: Output flags (``file::WRONLY | file::CREATE`` by default)
* ``buffer_size=<integer>``: Output buffer size
*/
template <typename... T>
inline ostream output_file(cstring_view path, T... params) {
return {path, detail::ostream_params(params...)};
}
#endif // FMT_USE_FCNTL
#ifdef FMT_LOCALE

View file

@ -49,17 +49,27 @@ template <class Char> class formatbuf : public std::basic_streambuf<Char> {
}
};
struct converter {
template <typename T, FMT_ENABLE_IF(is_integral<T>::value)> converter(T);
};
template <typename Char> struct test_stream : std::basic_ostream<Char> {
private:
// Hide all operator<< from std::basic_ostream<Char>.
void_t<> operator<<(null<>);
void_t<> operator<<(const Char*);
template <typename T, FMT_ENABLE_IF(std::is_convertible<T, int>::value &&
!std::is_enum<T>::value)>
void_t<> operator<<(T);
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 {
@ -103,7 +113,7 @@ void format_value(buffer<Char>& buf, const T& value,
#endif
output << value;
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
buf.resize(buf.size());
buf.try_resize(buf.size());
}
// Formats an object of type T that has an overloaded ostream operator<<.
@ -160,7 +170,7 @@ template <typename S, typename... Args,
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) {
vprint(os, to_string_view(format_str),
detail::make_args_checked<Args...>(format_str, args...));
fmt::make_args_checked<Args...>(format_str, args...));
}
FMT_END_NAMESPACE

View file

@ -181,7 +181,7 @@ template <typename Char> class printf_width_handler {
template <typename Char, typename Context>
void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
basic_format_args<Context> args) {
Context(std::back_inserter(buf), format, args).format();
Context(buffer_appender<Char>(buf), format, args).format();
}
} // namespace detail
@ -598,7 +598,7 @@ OutputIt basic_printf_context<OutputIt, Char>::format() {
template <typename Char>
using basic_printf_context_t =
basic_printf_context<std::back_insert_iterator<detail::buffer<Char>>, Char>;
basic_printf_context<detail::buffer_appender<Char>, Char>;
using printf_context = basic_printf_context_t<char>;
using wprintf_context = basic_printf_context_t<wchar_t>;

View file

@ -157,6 +157,9 @@ template <class Tuple, class F> void for_each(Tuple&& tup, F&& f) {
for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f));
}
template <typename Range>
using value_type = remove_cvref_t<decltype(*std::declval<Range>().begin())>;
template <typename Arg, FMT_ENABLE_IF(!is_like_std_string<
typename std::decay<Arg>::type>::value)>
FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&) {
@ -182,7 +185,6 @@ FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char) {
FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t) {
return add_space ? L" '{}'" : L"'{}'";
}
} // namespace detail
template <typename T> struct is_tuple_like {
@ -246,9 +248,18 @@ template <typename T, typename Char> struct is_range {
!std::is_constructible<detail::std_string_view<Char>, T>::value;
};
template <typename RangeT, typename Char>
struct formatter<RangeT, Char,
enable_if_t<fmt::is_range<RangeT, Char>::value>> {
template <typename T, typename Char>
struct formatter<
T, Char,
enable_if_t<fmt::is_range<T, Char>::value
// Workaround a bug in MSVC 2017 and earlier.
#if !FMT_MSC_VER || FMT_MSC_VER >= 1927
&&
(has_formatter<detail::value_type<T>, format_context>::value ||
detail::has_fallback_formatter<detail::value_type<T>,
format_context>::value)
#endif
>> {
formatting_range<Char> formatting;
template <typename ParseContext>
@ -257,8 +268,7 @@ struct formatter<RangeT, Char,
}
template <typename FormatContext>
typename FormatContext::iterator format(const RangeT& values,
FormatContext& ctx) {
typename FormatContext::iterator format(const T& values, FormatContext& ctx) {
auto out = detail::copy(formatting.prefix, ctx.out());
size_t i = 0;
auto it = values.begin();

View file

@ -0,0 +1,6 @@
<!-- Please read the contribution guidelines before submitting a pull request. -->
<!-- By submitting this pull request, you agree that your contributions are licensed under the {fmt} license,
and agree to future changes to the licensing. -->
<!-- If you're a first-time contributor, please acknowledge it by leaving the statement below. -->
I agree that my contributions are licensed under the {fmt} license, and agree to future changes to the licensing.

View file

@ -23,6 +23,36 @@ int format_float(char* buf, std::size_t size, const char* format, int precision,
return precision < 0 ? snprintf_ptr(buf, size, format, value)
: snprintf_ptr(buf, size, format, precision, value);
}
template FMT_API dragonbox::decimal_fp<float> dragonbox::to_decimal(float x)
FMT_NOEXCEPT;
template FMT_API dragonbox::decimal_fp<double> dragonbox::to_decimal(double x)
FMT_NOEXCEPT;
// DEPRECATED! This function exists for ABI compatibility.
template <typename Char>
typename basic_format_context<std::back_insert_iterator<buffer<Char>>,
Char>::iterator
vformat_to(buffer<Char>& buf, basic_string_view<Char> format_str,
basic_format_args<basic_format_context<
std::back_insert_iterator<buffer<type_identity_t<Char>>>,
type_identity_t<Char>>>
args) {
using iterator = std::back_insert_iterator<buffer<char>>;
using context = basic_format_context<
std::back_insert_iterator<buffer<type_identity_t<Char>>>,
type_identity_t<Char>>;
auto out = iterator(buf);
format_handler<iterator, Char, context> h(out, format_str, args, {});
parse_format_string<false>(format_str, h);
return out;
}
template basic_format_context<std::back_insert_iterator<buffer<char>>,
char>::iterator
vformat_to(buffer<char>&, string_view,
basic_format_args<basic_format_context<
std::back_insert_iterator<buffer<type_identity_t<char>>>,
type_identity_t<char>>>);
} // namespace detail
template struct FMT_INSTANTIATION_DEF_API detail::basic_data<void>;
@ -44,9 +74,9 @@ template FMT_API char detail::decimal_point_impl(locale_ref);
template FMT_API void detail::buffer<char>::append(const char*, const char*);
template FMT_API FMT_BUFFER_CONTEXT(char)::iterator detail::vformat_to(
template FMT_API void detail::vformat_to(
detail::buffer<char>&, string_view,
basic_format_args<FMT_BUFFER_CONTEXT(char)>);
basic_format_args<FMT_BUFFER_CONTEXT(char)>, detail::locale_ref);
template FMT_API int detail::snprintf_float(double, int, detail::float_specs,
detail::buffer<char>&);

View file

@ -62,7 +62,7 @@ using RWResult = int;
inline unsigned convert_rwcount(std::size_t count) {
return count <= UINT_MAX ? static_cast<unsigned>(count) : UINT_MAX;
}
#else
#elif FMT_USE_FCNTL
// Return type of read and write functions.
using RWResult = ssize_t;
@ -124,7 +124,8 @@ void detail::format_windows_error(detail::buffer<char>& out, int error_code,
if (result != 0) {
utf16_to_utf8 utf8_message;
if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
format_to(std::back_inserter(out), "{}: {}", message, utf8_message);
format_to(buffer_appender<char>(out), "{}: {}", message,
utf8_message);
return;
}
break;
@ -288,12 +289,12 @@ void file::pipe(file& read_end, file& write_end) {
}
buffered_file file::fdopen(const char* mode) {
// Don't retry as fdopen doesn't return EINTR.
#if defined(__MINGW32__) && defined(_POSIX_)
// Don't retry as fdopen doesn't return EINTR.
# if defined(__MINGW32__) && defined(_POSIX_)
FILE* f = ::fdopen(fd_, mode);
#else
# else
FILE* f = FMT_POSIX_CALL(fdopen(fd_, mode));
#endif
# endif
if (!f)
FMT_THROW(
system_error(errno, "cannot associate stream with file descriptor"));
@ -313,5 +314,9 @@ long getpagesize() {
return size;
# endif
}
FMT_API void ostream::grow(size_t) {
if (this->size() == this->capacity()) flush();
}
#endif // FMT_USE_FCNTL
FMT_END_NAMESPACE

View file

@ -2,5 +2,3 @@ This directory contains build support files such as
* CMake modules
* Build scripts
* qmake (static build with dynamic libc only)

View file

@ -1,27 +0,0 @@
# Staticlib configuration for qmake builds
# For some reason qmake 3.1 fails to identify source dependencies and excludes format.cc and printf.cc
# from compilation so it _MUST_ be called as qmake -nodepend
# A workaround is implemented below: a custom compiler is defined which does not track dependencies
TEMPLATE = lib
TARGET = fmt
QMAKE_EXT_CPP = .cc
CONFIG = staticlib warn_on c++11
FMT_SOURCES = \
../src/format.cc \
../src/posix.cc
fmt.name = libfmt
fmt.input = FMT_SOURCES
fmt.output = ${QMAKE_FILE_BASE}$$QMAKE_EXT_OBJ
fmt.clean = ${QMAKE_FILE_BASE}$$QMAKE_EXT_OBJ
fmt.depends = ${QMAKE_FILE_IN}
# QMAKE_RUN_CXX will not be expanded
fmt.commands = $$QMAKE_CXX -c $$QMAKE_CXXFLAGS $$QMAKE_CXXFLAGS_WARN_ON $$QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO $$QMAKE_CXXFLAGS_CXX11 ${QMAKE_FILE_IN}
fmt.variable_out = OBJECTS
fmt.CONFIG = no_dependencies no_link
QMAKE_EXTRA_COMPILERS += fmt

View file

@ -1,30 +0,0 @@
#!/usr/bin/env python
# Update the coverity branch from the master branch.
# It is not done automatically because Coverity Scan limits
# the number of submissions per day.
from __future__ import print_function
import shutil, tempfile
from subprocess import check_output, STDOUT
class Git:
def __init__(self, dir):
self.dir = dir
def __call__(self, *args):
output = check_output(['git'] + list(args), cwd=self.dir, stderr=STDOUT)
print(output)
return output
dir = tempfile.mkdtemp()
try:
git = Git(dir)
git('clone', '-b', 'coverity', 'git@github.com:fmtlib/fmt.git', dir)
output = git('merge', '-X', 'theirs', '--no-commit', 'origin/master')
if 'Fast-forward' not in output:
git('reset', 'HEAD', '.travis.yml')
git('checkout', '--', '.travis.yml')
git('commit', '-m', 'Update coverity branch')
git('push')
finally:
shutil.rmtree(dir)

View file

@ -91,8 +91,6 @@ add_fmt_test(assert-test)
add_fmt_test(chrono-test)
add_fmt_test(color-test)
add_fmt_test(core-test)
add_fmt_test(grisu-test)
target_compile_definitions(grisu-test PRIVATE FMT_USE_GRISU=1)
add_fmt_test(gtest-extra-test)
add_fmt_test(format-test mock-allocator.h)
if (MSVC)
@ -105,11 +103,21 @@ add_fmt_test(locale-test)
add_fmt_test(ostream-test)
add_fmt_test(compile-test)
add_fmt_test(printf-test)
add_fmt_test(custom-formatter-test)
add_fmt_test(ranges-test)
add_fmt_test(scan-test)
if (NOT MSVC_BUILD_STATIC)
if (NOT DEFINED MSVC_STATIC_RUNTIME AND MSVC)
foreach (flag_var
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
if (${flag_var} MATCHES "^(/|-)(MT|MTd)")
set(MSVC_STATIC_RUNTIME ON)
break()
endif()
endforeach()
endif()
if (NOT MSVC_STATIC_RUNTIME)
add_fmt_executable(posix-mock-test
posix-mock-test.cc ../src/format.cc ${TEST_MAIN_SRC})
target_include_directories(

View file

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.1.0)
cmake_minimum_required(VERSION 3.1...3.18)
project(fmt-test)

View file

@ -1,4 +1,8 @@
// Formatting library for C++ - assertion tests
// Formatting library for C++ - FMT_ASSERT test
//
// It is a separate test to minimize the number of EXPECT_DEBUG_DEATH checks
// which are slow on some platforms. In other tests FMT_ASSERT is made to throw
// an exception which is much faster and easier to check.
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.

View file

@ -95,6 +95,17 @@ TEST(TimeTest, GMTime) {
EXPECT_TRUE(EqualTime(tm, fmt::gmtime(t)));
}
TEST(TimeTest, TimePoint) {
std::chrono::system_clock::time_point point = std::chrono::system_clock::now();
std::time_t t = std::chrono::system_clock::to_time_t(point);
std::tm tm = *std::localtime(&t);
char strftime_output[256];
std::strftime(strftime_output, sizeof(strftime_output), "It is %Y-%m-%d %H:%M:%S", &tm);
EXPECT_EQ(strftime_output, fmt::format("It is {:%Y-%m-%d %H:%M:%S}", point));
}
#define EXPECT_TIME(spec, time, duration) \
{ \
std::locale loc("ja_JP.utf8"); \

View file

@ -7,6 +7,10 @@
#include "fmt/color.h"
#include <iterator>
#include <string>
#include <utility>
#include "gtest-extra.h"
TEST(ColorsTest, ColorsPrint) {
@ -84,3 +88,12 @@ TEST(ColorsTest, Format) {
EXPECT_EQ(fmt::format(fg(fmt::terminal_color::red), "{}", "foo"),
"\x1b[31mfoo\x1b[0m");
}
TEST(ColorsTest, FormatToOutAcceptsTextStyle) {
fmt::text_style ts = fg(fmt::rgb(255, 20, 30));
std::string out;
fmt::format_to(std::back_inserter(out), ts, "rgb(255,20,30){}{}{}", 1, 2, 3);
EXPECT_EQ(fmt::to_string(out),
"\x1b[38;2;255;020;030mrgb(255,20,30)123\x1b[0m");
}

View file

@ -1,6 +1,6 @@
# Test if compile errors are produced where necessary.
cmake_minimum_required(VERSION 3.1.0)
cmake_minimum_required(VERSION 3.1...3.18)
include(CheckCXXSourceCompiles)
include(CheckCXXCompilerFlag)

View file

@ -5,19 +5,10 @@
//
// For the license information refer to format.h.
#include <stdint.h>
#include <cctype>
#include <cfloat>
#include <climits>
#include <cmath>
#include <cstring>
#include <deque>
#include <list>
#include <memory>
#include <string>
#include <type_traits>
// Check if fmt/compile.h compiles with windows.h included before it.
// Check that fmt/compile.h compiles with windows.h included before it.
#ifdef _WIN32
# include <windows.h>
#endif
@ -25,16 +16,8 @@
#include "fmt/compile.h"
#include "gmock.h"
#include "gtest-extra.h"
#include "mock-allocator.h"
#include "util.h"
#undef ERROR
#undef min
#undef max
using testing::Return;
using testing::StrictMock;
// compiletime_prepared_parts_type_provider is useful only with relaxed
// constexpr.
#if FMT_USE_CONSTEXPR
@ -114,20 +97,20 @@ TEST(CompileTest, MultipleTypes) {
EXPECT_EQ(fmt::format(f, 42, 42), "42 42");
}
struct formattable {};
struct test_formattable {};
FMT_BEGIN_NAMESPACE
template <> struct formatter<formattable> : formatter<const char*> {
template <> struct formatter<test_formattable> : formatter<const char*> {
template <typename FormatContext>
auto format(formattable, FormatContext& ctx) -> decltype(ctx.out()) {
auto format(test_formattable, FormatContext& ctx) -> decltype(ctx.out()) {
return formatter<const char*>::format("foo", ctx);
}
};
FMT_END_NAMESPACE
TEST(CompileTest, FormatUserDefinedType) {
auto f = fmt::detail::compile<formattable>("{}");
EXPECT_EQ(fmt::format(f, formattable()), "foo");
auto f = fmt::detail::compile<test_formattable>("{}");
EXPECT_EQ(fmt::format(f, test_formattable()), "foo");
}
TEST(CompileTest, EmptyFormatString) {
@ -146,21 +129,45 @@ TEST(CompileTest, FormatDefault) {
EXPECT_EQ("4.2", fmt::format(FMT_COMPILE("{}"), 4.2));
EXPECT_EQ("foo", fmt::format(FMT_COMPILE("{}"), "foo"));
EXPECT_EQ("foo", fmt::format(FMT_COMPILE("{}"), std::string("foo")));
EXPECT_EQ("foo", fmt::format(FMT_COMPILE("{}"), formattable()));
EXPECT_EQ("foo", fmt::format(FMT_COMPILE("{}"), test_formattable()));
}
TEST(CompileTest, FormatWideString) {
EXPECT_EQ(L"42", fmt::format(FMT_COMPILE(L"{}"), 42));
}
TEST(CompileTest, FormatSpecs) {
EXPECT_EQ("42", fmt::format(FMT_COMPILE("{:x}"), 0x42));
}
TEST(CompileTest, DynamicWidth) {
EXPECT_EQ(" 42foo ",
fmt::format(FMT_COMPILE("{:{}}{:{}}"), 42, 4, "foo", 5));
}
TEST(CompileTest, FormatTo) {
char buf[8];
auto end = fmt::format_to(buf, FMT_COMPILE("{}"), 42);
*end = '\0';
EXPECT_STREQ("42", buf);
end = fmt::format_to(buf, FMT_COMPILE("{:x}"), 42);
*end = '\0';
EXPECT_STREQ("2a", buf);
}
TEST(CompileTest, FormatToNWithCompileMacro) {
constexpr auto buffer_size = 8;
char buffer[buffer_size];
auto res = fmt::format_to_n(buffer, buffer_size, FMT_COMPILE("{}"), 42);
*res.out = '\0';
EXPECT_STREQ("42", buffer);
res = fmt::format_to_n(buffer, buffer_size, FMT_COMPILE("{:x}"), 42);
*res.out = '\0';
EXPECT_STREQ("2a", buffer);
}
TEST(CompileTest, TextAndArg) {
EXPECT_EQ(">>>42<<<", fmt::format(FMT_COMPILE(">>>{}<<<"), 42));
EXPECT_EQ("42!", fmt::format(FMT_COMPILE("{}!"), 42));
}
#endif

View file

@ -31,21 +31,16 @@
using fmt::basic_format_arg;
using fmt::string_view;
using fmt::detail::buffer;
using fmt::detail::make_arg;
using fmt::detail::value;
using testing::_;
using testing::Invoke;
using testing::Return;
using testing::StrictMock;
namespace {
struct test_struct {};
template <typename Context, typename T>
basic_format_arg<Context> make_arg(const T& value) {
return fmt::detail::make_arg<Context>(value);
}
} // namespace
FMT_BEGIN_NAMESPACE
template <typename Char> struct formatter<test_struct, Char> {
template <typename ParseContext>
@ -53,10 +48,7 @@ template <typename Char> struct formatter<test_struct, Char> {
return ctx.begin();
}
typedef std::back_insert_iterator<buffer<Char>> iterator;
auto format(test_struct, basic_format_context<iterator, char>& ctx)
-> decltype(ctx.out()) {
auto format(test_struct, format_context& ctx) -> decltype(ctx.out()) {
const Char* test = "test";
return std::copy_n(test, std::strlen(test), ctx.out());
}
@ -81,22 +73,22 @@ TEST(BufferTest, Nonmoveable) {
}
#endif
// A test buffer with a dummy grow method.
template <typename T> struct test_buffer : buffer<T> {
void grow(size_t capacity) { this->set(nullptr, capacity); }
};
TEST(BufferTest, Indestructible) {
static_assert(!std::is_destructible<fmt::detail::buffer<int>>(),
"buffer's destructor is protected");
}
template <typename T> struct mock_buffer : buffer<T> {
MOCK_METHOD1(do_grow, void(size_t capacity));
template <typename T> struct mock_buffer final : buffer<T> {
MOCK_METHOD1(do_grow, size_t(size_t capacity));
void grow(size_t capacity) {
this->set(this->data(), capacity);
do_grow(capacity);
void grow(size_t capacity) { this->set(this->data(), do_grow(capacity)); }
mock_buffer(T* data = nullptr, size_t capacity = 0) {
this->set(data, capacity);
ON_CALL(*this, do_grow(_)).WillByDefault(Invoke([](size_t capacity) {
return capacity;
}));
}
mock_buffer() {}
mock_buffer(T* data) { this->set(data, 0); }
mock_buffer(T* data, size_t capacity) { this->set(data, capacity); }
};
TEST(BufferTest, Ctor) {
@ -123,24 +115,6 @@ TEST(BufferTest, Ctor) {
}
}
struct dying_buffer : test_buffer<int> {
MOCK_METHOD0(die, void());
~dying_buffer() { die(); }
private:
virtual void avoid_weak_vtable();
};
void dying_buffer::avoid_weak_vtable() {}
TEST(BufferTest, VirtualDtor) {
typedef StrictMock<dying_buffer> stict_mock_buffer;
stict_mock_buffer* mock_buffer = new stict_mock_buffer();
EXPECT_CALL(*mock_buffer, die());
buffer<int>* buffer = mock_buffer;
delete buffer;
}
TEST(BufferTest, Access) {
char data[10];
mock_buffer<char> buffer(data, sizeof(data));
@ -152,30 +126,40 @@ TEST(BufferTest, Access) {
EXPECT_EQ(42, const_buffer[3]);
}
TEST(BufferTest, Resize) {
TEST(BufferTest, TryResize) {
char data[123];
mock_buffer<char> buffer(data, sizeof(data));
buffer[10] = 42;
EXPECT_EQ(42, buffer[10]);
buffer.resize(20);
buffer.try_resize(20);
EXPECT_EQ(20u, buffer.size());
EXPECT_EQ(123u, buffer.capacity());
EXPECT_EQ(42, buffer[10]);
buffer.resize(5);
buffer.try_resize(5);
EXPECT_EQ(5u, buffer.size());
EXPECT_EQ(123u, buffer.capacity());
EXPECT_EQ(42, buffer[10]);
// Check if resize calls grow.
// Check if try_resize calls grow.
EXPECT_CALL(buffer, do_grow(124));
buffer.resize(124);
buffer.try_resize(124);
EXPECT_CALL(buffer, do_grow(200));
buffer.resize(200);
buffer.try_resize(200);
}
TEST(BufferTest, TryResizePartial) {
char data[10];
mock_buffer<char> buffer(data, sizeof(data));
EXPECT_CALL(buffer, do_grow(20)).WillOnce(Return(15));
buffer.try_resize(20);
EXPECT_EQ(buffer.capacity(), 15);
EXPECT_EQ(buffer.size(), 15);
}
TEST(BufferTest, Clear) {
test_buffer<char> buffer;
buffer.resize(20);
buffer.resize(0);
mock_buffer<char> buffer;
EXPECT_CALL(buffer, do_grow(20));
buffer.try_resize(20);
buffer.try_resize(0);
EXPECT_EQ(static_cast<size_t>(0), buffer.size());
EXPECT_EQ(20u, buffer.capacity());
}
@ -183,11 +167,11 @@ TEST(BufferTest, Clear) {
TEST(BufferTest, Append) {
char data[15];
mock_buffer<char> buffer(data, 10);
const char* test = "test";
auto test = "test";
buffer.append(test, test + 5);
EXPECT_STREQ(test, &buffer[0]);
EXPECT_EQ(5u, buffer.size());
buffer.resize(10);
buffer.try_resize(10);
EXPECT_CALL(buffer, do_grow(12));
buffer.append(test, test + 2);
EXPECT_EQ('t', buffer[10]);
@ -195,17 +179,31 @@ TEST(BufferTest, Append) {
EXPECT_EQ(12u, buffer.size());
}
TEST(BufferTest, AppendPartial) {
char data[10];
mock_buffer<char> buffer(data, sizeof(data));
testing::InSequence seq;
EXPECT_CALL(buffer, do_grow(15)).WillOnce(Return(10));
EXPECT_CALL(buffer, do_grow(15)).WillOnce(Invoke([&buffer](size_t) {
EXPECT_EQ(fmt::string_view(buffer.data(), buffer.size()), "0123456789");
buffer.clear();
return 10;
}));
auto test = "0123456789abcde";
buffer.append(test, test + 15);
}
TEST(BufferTest, AppendAllocatesEnoughStorage) {
char data[19];
mock_buffer<char> buffer(data, 10);
const char* test = "abcdefgh";
buffer.resize(10);
auto test = "abcdefgh";
buffer.try_resize(10);
EXPECT_CALL(buffer, do_grow(19));
buffer.append(test, test + 9);
}
TEST(ArgTest, FormatArgs) {
fmt::format_args args;
auto args = fmt::format_args();
EXPECT_FALSE(args.get(1));
}
@ -233,7 +231,7 @@ struct custom_context {
};
TEST(ArgTest, MakeValueWithCustomContext) {
test_struct t;
auto t = test_struct();
fmt::detail::value<custom_context> arg(
fmt::detail::arg_mapper<custom_context>().map(t));
custom_context ctx = {false, fmt::format_parse_context("")};
@ -255,10 +253,10 @@ FMT_END_NAMESPACE
struct test_result {};
template <typename T> struct mock_visitor {
template <typename U> struct result { typedef test_result type; };
template <typename U> struct result { using type = test_result; };
mock_visitor() {
ON_CALL(*this, visit(_)).WillByDefault(testing::Return(test_result()));
ON_CALL(*this, visit(_)).WillByDefault(Return(test_result()));
}
MOCK_METHOD1_T(visit, test_result(T value));
@ -272,10 +270,10 @@ template <typename T> struct mock_visitor {
}
};
template <typename T> struct visit_type { typedef T Type; };
template <typename T> struct visit_type { using type = T; };
#define VISIT_TYPE(Type_, visit_type_) \
template <> struct visit_type<Type_> { typedef visit_type_ Type; }
#define VISIT_TYPE(type_, visit_type_) \
template <> struct visit_type<type_> { using type = visit_type_; }
VISIT_TYPE(signed char, int);
VISIT_TYPE(unsigned char, unsigned);
@ -294,36 +292,34 @@ VISIT_TYPE(unsigned long, unsigned long long);
{ \
testing::StrictMock<mock_visitor<decltype(expected)>> visitor; \
EXPECT_CALL(visitor, visit(expected)); \
typedef std::back_insert_iterator<buffer<Char>> iterator; \
using iterator = std::back_insert_iterator<buffer<Char>>; \
fmt::visit_format_arg( \
visitor, make_arg<fmt::basic_format_context<iterator, Char>>(value)); \
}
#define CHECK_ARG(value, typename_) \
{ \
typedef decltype(value) value_type; \
typename_ visit_type<value_type>::Type expected = value; \
using value_type = decltype(value); \
typename_ visit_type<value_type>::type expected = value; \
CHECK_ARG_(char, expected, value) \
CHECK_ARG_(wchar_t, expected, value) \
}
template <typename T> class NumericArgTest : public testing::Test {};
typedef ::testing::Types<bool, signed char, unsigned char, signed,
unsigned short, int, unsigned, long, unsigned long,
long long, unsigned long long, float, double,
long double>
Types;
TYPED_TEST_CASE(NumericArgTest, Types);
using types =
::testing::Types<bool, signed char, unsigned char, signed, unsigned short,
int, unsigned, long, unsigned long, long long,
unsigned long long, float, double, long double>;
TYPED_TEST_CASE(NumericArgTest, types);
template <typename T>
typename std::enable_if<std::is_integral<T>::value, T>::type test_value() {
fmt::enable_if_t<std::is_integral<T>::value, T> test_value() {
return static_cast<T>(42);
}
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, T>::type
test_value() {
fmt::enable_if_t<std::is_floating_point<T>::value, T> test_value() {
return static_cast<T>(4.2);
}
@ -345,7 +341,7 @@ TEST(ArgTest, StringArg) {
const char* cstr = str;
CHECK_ARG_(char, cstr, str);
string_view sref(str);
auto sref = string_view(str);
CHECK_ARG_(char, sref, std::string(str));
}
@ -372,14 +368,14 @@ TEST(ArgTest, PointerArg) {
struct check_custom {
test_result operator()(
fmt::basic_format_arg<fmt::format_context>::handle h) const {
struct test_buffer : fmt::detail::buffer<char> {
struct test_buffer final : fmt::detail::buffer<char> {
char data[10];
test_buffer() : fmt::detail::buffer<char>(data, 0, 10) {}
void grow(size_t) {}
} buffer;
fmt::detail::buffer<char>& base = buffer;
fmt::format_parse_context parse_ctx("");
fmt::format_context ctx(std::back_inserter(base), fmt::format_args());
fmt::format_context ctx{fmt::detail::buffer_appender<char>(buffer),
fmt::format_args()};
h.format(parse_ctx, ctx);
EXPECT_EQ("test", std::string(buffer.data, buffer.size()));
return test_result();
@ -388,10 +384,10 @@ struct check_custom {
TEST(ArgTest, CustomArg) {
test_struct test;
typedef mock_visitor<fmt::basic_format_arg<fmt::format_context>::handle>
visitor;
using visitor =
mock_visitor<fmt::basic_format_arg<fmt::format_context>::handle>;
testing::StrictMock<visitor> v;
EXPECT_CALL(v, visit(_)).WillOnce(testing::Invoke(check_custom()));
EXPECT_CALL(v, visit(_)).WillOnce(Invoke(check_custom()));
fmt::visit_format_arg(v, make_arg<fmt::format_context>(test));
}
@ -407,9 +403,7 @@ TEST(FormatDynArgsTest, Basic) {
store.push_back(42);
store.push_back("abc1");
store.push_back(1.5f);
std::string result = fmt::vformat("{} and {} and {}", store);
EXPECT_EQ("42 and abc1 and 1.5", result);
EXPECT_EQ("42 and abc1 and 1.5", fmt::vformat("{} and {} and {}", store));
}
TEST(FormatDynArgsTest, StringsAndRefs) {
@ -451,7 +445,6 @@ TEST(FormatDynArgsTest, CustomFormat) {
++c.i;
store.push_back(std::cref(c));
++c.i;
std::string result = fmt::vformat("{} and {} and {}", store);
EXPECT_EQ("cust=0 and cust=1 and cust=3", result);
}
@ -459,8 +452,7 @@ TEST(FormatDynArgsTest, CustomFormat) {
TEST(FormatDynArgsTest, NamedInt) {
fmt::dynamic_format_arg_store<fmt::format_context> store;
store.push_back(fmt::arg("a1", 42));
std::string result = fmt::vformat("{a1}", store);
EXPECT_EQ("42", result);
EXPECT_EQ("42", fmt::vformat("{a1}", store));
}
TEST(FormatDynArgsTest, NamedStrings) {
@ -469,10 +461,7 @@ TEST(FormatDynArgsTest, NamedStrings) {
store.push_back(fmt::arg("a1", str));
store.push_back(fmt::arg("a2", std::cref(str)));
str[0] = 'X';
std::string result = fmt::vformat("{a1} and {a2}", store);
EXPECT_EQ("1234567890 and X234567890", result);
EXPECT_EQ("1234567890 and X234567890", fmt::vformat("{a1} and {a2}", store));
}
TEST(FormatDynArgsTest, NamedArgByRef) {
@ -494,7 +483,6 @@ TEST(FormatDynArgsTest, NamedArgByRef) {
store.push_back(std::cref(a1));
std::string result = fmt::vformat("{a1_} and {} and {} and {}", store);
EXPECT_EQ("42 and abc and 1.5 and 42", result);
}
@ -507,7 +495,6 @@ TEST(FormatDynArgsTest, NamedCustomFormat) {
++c.i;
store.push_back(fmt::arg("c_ref", std::cref(c)));
++c.i;
std::string result = fmt::vformat("{c1} and {c2} and {c_ref}", store);
EXPECT_EQ("cust=0 and cust=1 and cust=3", result);
}
@ -663,14 +650,14 @@ TEST(CoreTest, FormatterOverridesImplicitConversion) {
namespace my_ns {
template <typename Char> class my_string {
private:
std::basic_string<Char> s_;
public:
my_string(const Char* s) : s_(s) {}
const Char* data() const FMT_NOEXCEPT { return s_.data(); }
size_t length() const FMT_NOEXCEPT { return s_.size(); }
operator const Char*() const { return s_.c_str(); }
private:
std::basic_string<Char> s_;
};
template <typename Char>
@ -748,7 +735,7 @@ struct implicitly_convertible_to_string_view {
operator fmt::string_view() const { return "foo"; }
};
TEST(FormatterTest, FormatImplicitlyConvertibleToStringView) {
TEST(CoreTest, FormatImplicitlyConvertibleToStringView) {
EXPECT_EQ("foo", fmt::format("{}", implicitly_convertible_to_string_view()));
}
@ -758,7 +745,7 @@ struct explicitly_convertible_to_string_view {
explicit operator fmt::string_view() const { return "foo"; }
};
TEST(FormatterTest, FormatExplicitlyConvertibleToStringView) {
TEST(CoreTest, FormatExplicitlyConvertibleToStringView) {
EXPECT_EQ("foo", fmt::format("{}", explicitly_convertible_to_string_view()));
}
@ -767,7 +754,7 @@ struct explicitly_convertible_to_std_string_view {
explicit operator std::string_view() const { return "foo"; }
};
TEST(FormatterTest, FormatExplicitlyConvertibleToStdStringView) {
TEST(CoreTest, FormatExplicitlyConvertibleToStdStringView) {
EXPECT_EQ("foo",
fmt::format("{}", explicitly_convertible_to_std_string_view()));
}
@ -781,6 +768,6 @@ struct disabled_rvalue_conversion {
operator const char*() && = delete;
};
TEST(FormatterTest, DisabledRValueConversion) {
TEST(CoreTest, DisabledRValueConversion) {
EXPECT_EQ("foo", fmt::format("{}", disabled_rvalue_conversion()));
}

View file

@ -1,58 +0,0 @@
// Formatting library for C++ - custom argument formatter tests
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "fmt/format.h"
#include "gtest-extra.h"
// MSVC 2013 is known to be broken.
#if !FMT_MSC_VER || FMT_MSC_VER > 1800
// A custom argument formatter that doesn't print `-` for floating-point values
// rounded to 0.
class custom_arg_formatter
: public fmt::detail::arg_formatter<fmt::format_context::iterator, char> {
public:
using base = fmt::detail::arg_formatter<fmt::format_context::iterator, char>;
custom_arg_formatter(fmt::format_context& ctx,
fmt::format_parse_context* parse_ctx,
fmt::format_specs* s = nullptr,
const char* = nullptr)
: base(ctx, parse_ctx, s) {}
using base::operator();
iterator operator()(double value) {
// Comparing a float to 0.0 is safe.
if (round(value * pow(10, specs()->precision)) == 0.0) value = 0;
return base::operator()(value);
}
};
std::string custom_vformat(fmt::string_view format_str, fmt::format_args args) {
fmt::memory_buffer buffer;
fmt::detail::buffer<char>& base = buffer;
// Pass custom argument formatter as a template arg to vwrite.
fmt::vformat_to<custom_arg_formatter>(std::back_inserter(base), format_str,
args);
return std::string(buffer.data(), buffer.size());
}
template <typename... Args>
std::string custom_format(const char* format_str, const Args&... args) {
auto va = fmt::make_format_args(args...);
return custom_vformat(format_str, va);
}
TEST(CustomFormatterTest, Format) {
EXPECT_EQ("0.00", custom_format("{:.2f}", -.00001));
}
#endif

View file

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.1.0)
cmake_minimum_required(VERSION 3.1...3.18)
project(fmt-test)

View file

@ -38,9 +38,9 @@ namespace std {
template<class Out, class charT> class basic_format_context;
using format_context = basic_format_context<
/* unspecified */ std::back_insert_iterator<fmt::detail::buffer<char>>, char>;
/* unspecified */ fmt::detail::buffer_appender<char>, char>;
using wformat_context = basic_format_context<
/* unspecified */ std::back_insert_iterator<fmt::detail::buffer<wchar_t>>, wchar_t>;
/* unspecified */ fmt::detail::buffer_appender<wchar_t>, wchar_t>;
template<class T, class charT = char> struct formatter {
formatter() = delete;
@ -714,7 +714,7 @@ string vformat(string_view fmt, format_args args) {
fmt::detail::buffer<char>& buf = mbuf;
using af = detail::arg_formatter<fmt::format_context::iterator, char>;
detail::format_handler<af, char, format_context>
h(std::back_inserter(buf), fmt, args, {});
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);
}

View file

@ -1,6 +0,0 @@
// Copyright (c) 2020 Vladimir Solontsov
// SPDX-License-Identifier: MIT Licence
#include <fmt/core.h>
#include "gtest-extra.h"

View file

@ -19,7 +19,10 @@
#include "gtest-extra.h"
#include "util.h"
#undef max
#ifdef _WIN32
# include <windows.h>
# undef max
#endif
using fmt::detail::bigint;
using fmt::detail::fp;
@ -186,29 +189,6 @@ template <bool is_iec559> void run_double_tests() {
template <> void run_double_tests<true>() {
// Construct from double.
EXPECT_EQ(fp(1.23), fp(0x13ae147ae147aeu, -52));
// Compute boundaries:
fp value;
// Normalized & not power of 2 - equidistant boundaries:
auto b = value.assign_with_boundaries(1.23);
EXPECT_EQ(value, fp(0x0013ae147ae147ae, -52));
EXPECT_EQ(b.lower, 0x9d70a3d70a3d6c00);
EXPECT_EQ(b.upper, 0x9d70a3d70a3d7400);
// Normalized power of 2 - lower boundary is closer:
b = value.assign_with_boundaries(1.9807040628566084e+28); // 2**94
EXPECT_EQ(value, fp(0x0010000000000000, 42));
EXPECT_EQ(b.lower, 0x7ffffffffffffe00);
EXPECT_EQ(b.upper, 0x8000000000000400);
// Smallest normalized double - equidistant boundaries:
b = value.assign_with_boundaries(2.2250738585072014e-308);
EXPECT_EQ(value, fp(0x0010000000000000, -1074));
EXPECT_EQ(b.lower, 0x7ffffffffffffc00);
EXPECT_EQ(b.upper, 0x8000000000000400);
// Subnormal - equidistant boundaries:
b = value.assign_with_boundaries(4.9406564584124654e-324);
EXPECT_EQ(value, fp(0x0000000000000001, -1074));
EXPECT_EQ(b.lower, 0x4000000000000000);
EXPECT_EQ(b.upper, 0xc000000000000000);
}
TEST(FPTest, DoubleTests) {
@ -222,33 +202,6 @@ TEST(FPTest, Normalize) {
EXPECT_EQ(-6, normalized.e);
}
TEST(FPTest, ComputeFloatBoundaries) {
struct {
double x, lower, upper;
} tests[] = {
// regular
{1.5f, 1.4999999403953552, 1.5000000596046448},
// boundary
{1.0f, 0.9999999701976776, 1.0000000596046448},
// min normal
{1.1754944e-38f, 1.1754942807573643e-38, 1.1754944208872107e-38},
// max subnormal
{1.1754942e-38f, 1.1754941406275179e-38, 1.1754942807573643e-38},
// min subnormal
{1e-45f, 7.006492321624085e-46, 2.1019476964872256e-45},
};
for (auto test : tests) {
fp vlower = normalize(fp(test.lower));
fp vupper = normalize(fp(test.upper));
vlower.f >>= vupper.e - vlower.e;
vlower.e = vupper.e;
fp value;
auto b = value.assign_float_with_boundaries(test.x);
EXPECT_EQ(vlower.f, b.lower);
EXPECT_EQ(vupper.f, b.upper);
}
}
TEST(FPTest, Multiply) {
auto v = fp(123ULL << 32, 4) * fp(56ULL << 32, 7);
EXPECT_EQ(v.f, 123u * 56u);
@ -259,17 +212,55 @@ TEST(FPTest, Multiply) {
}
TEST(FPTest, GetCachedPower) {
typedef std::numeric_limits<double> limits;
using limits = std::numeric_limits<double>;
for (auto exp = limits::min_exponent; exp <= limits::max_exponent; ++exp) {
int dec_exp = 0;
auto fp = fmt::detail::get_cached_power(exp, dec_exp);
EXPECT_LE(exp, fp.e);
int dec_exp_step = 8;
EXPECT_LE(fp.e, exp + dec_exp_step * log2(10));
EXPECT_DOUBLE_EQ(pow(10, dec_exp), ldexp(static_cast<double>(fp.f), fp.e));
bigint exact, cache(fp.f);
if (dec_exp >= 0) {
exact.assign_pow10(dec_exp);
if (fp.e <= 0)
exact <<= -fp.e;
else
cache <<= fp.e;
exact.align(cache);
cache.align(exact);
auto exact_str = fmt::format("{}", exact);
auto cache_str = fmt::format("{}", cache);
EXPECT_EQ(exact_str.size(), cache_str.size());
EXPECT_EQ(exact_str.substr(0, 15), cache_str.substr(0, 15));
int diff = cache_str[15] - exact_str[15];
if (diff == 1)
EXPECT_GT(exact_str[16], '8');
else
EXPECT_EQ(diff, 0);
} else {
cache.assign_pow10(-dec_exp);
cache *= fp.f + 1; // Inexact check.
exact.assign(1);
exact <<= -fp.e;
exact.align(cache);
auto exact_str = fmt::format("{}", exact);
auto cache_str = fmt::format("{}", cache);
EXPECT_EQ(exact_str.size(), cache_str.size());
EXPECT_EQ(exact_str.substr(0, 16), cache_str.substr(0, 16));
}
}
}
TEST(FPTest, DragonboxMaxK) {
using fmt::detail::dragonbox::floor_log10_pow2;
using float_info = fmt::detail::dragonbox::float_info<float>;
EXPECT_EQ(fmt::detail::const_check(float_info::max_k),
float_info::kappa - floor_log10_pow2(float_info::min_exponent -
float_info::significand_bits));
using double_info = fmt::detail::dragonbox::float_info<double>;
EXPECT_EQ(
fmt::detail::const_check(double_info::max_k),
double_info::kappa - floor_log10_pow2(double_info::min_exponent -
double_info::significand_bits));
}
TEST(FPTest, GetRoundDirection) {
using fmt::detail::get_round_direction;
using fmt::detail::round_direction;
@ -307,7 +298,7 @@ TEST(FPTest, FixedHandler) {
EXPECT_THROW(handler().on_digit('0', 100, 100, 0, exp, false),
assertion_failure);
namespace digits = fmt::detail::digits;
EXPECT_EQ(handler(1).on_digit('0', 100, 10, 10, exp, false), digits::done);
EXPECT_EQ(handler(1).on_digit('0', 100, 10, 10, exp, false), digits::error);
// Check that divisor - error doesn't overflow.
EXPECT_EQ(handler(1).on_digit('0', 100, 10, 101, exp, false), digits::error);
// Check that 2 * error doesn't overflow.
@ -349,14 +340,6 @@ TEST(FormatTest, ArgConverter) {
EXPECT_EQ(value, fmt::visit_format_arg(value_extractor<long long>(), arg));
}
TEST(FormatTest, FormatNegativeNaN) {
double nan = std::numeric_limits<double>::quiet_NaN();
if (std::signbit(-nan))
EXPECT_EQ("-nan", fmt::format("{}", -nan));
else
fmt::print("Warning: compiler doesn't handle negative NaN correctly");
}
TEST(FormatTest, StrError) {
char* message = nullptr;
char buffer[BUFFER_SIZE];
@ -454,3 +437,10 @@ TEST(UtilTest, WriteFallbackUIntPtr) {
fmt::detail::fallback_uintptr(reinterpret_cast<void*>(0xface)), nullptr);
EXPECT_EQ(s, "0xface");
}
#ifdef _WIN32
TEST(UtilTest, WriteConsoleSignature) {
decltype(WriteConsoleW)* p = fmt::detail::WriteConsoleW;
(void)p;
}
#endif

View file

@ -24,7 +24,6 @@
// Check if fmt/format.h compiles with the X11 index macro defined.
#define index(x, y) no nice things
#include "fmt/color.h"
#include "fmt/format.h"
#undef index
@ -147,6 +146,7 @@ TEST(IteratorTest, CountingIterator) {
auto prev = it++;
EXPECT_EQ(prev.count(), 0);
EXPECT_EQ(it.count(), 1);
EXPECT_EQ((it + 41).count(), 42);
}
TEST(IteratorTest, TruncatingIterator) {
@ -169,20 +169,22 @@ TEST(IteratorTest, TruncatingBackInserter) {
}
TEST(IteratorTest, IsOutputIterator) {
EXPECT_TRUE(fmt::detail::is_output_iterator<char*>::value);
EXPECT_FALSE(fmt::detail::is_output_iterator<const char*>::value);
EXPECT_FALSE(fmt::detail::is_output_iterator<std::string>::value);
EXPECT_TRUE(fmt::detail::is_output_iterator<
std::back_insert_iterator<std::string>>::value);
EXPECT_TRUE(fmt::detail::is_output_iterator<std::string::iterator>::value);
EXPECT_FALSE(
fmt::detail::is_output_iterator<std::string::const_iterator>::value);
EXPECT_FALSE(fmt::detail::is_output_iterator<std::list<char>>::value);
EXPECT_TRUE((fmt::detail::is_output_iterator<char*, char>::value));
EXPECT_FALSE((fmt::detail::is_output_iterator<const char*, char>::value));
EXPECT_FALSE((fmt::detail::is_output_iterator<std::string, char>::value));
EXPECT_TRUE(
fmt::detail::is_output_iterator<std::list<char>::iterator>::value);
EXPECT_FALSE(
fmt::detail::is_output_iterator<std::list<char>::const_iterator>::value);
EXPECT_FALSE(fmt::detail::is_output_iterator<uint32_pair>::value);
(fmt::detail::is_output_iterator<std::back_insert_iterator<std::string>,
char>::value));
EXPECT_TRUE(
(fmt::detail::is_output_iterator<std::string::iterator, char>::value));
EXPECT_FALSE((fmt::detail::is_output_iterator<std::string::const_iterator,
char>::value));
EXPECT_FALSE((fmt::detail::is_output_iterator<std::list<char>, char>::value));
EXPECT_TRUE((
fmt::detail::is_output_iterator<std::list<char>::iterator, char>::value));
EXPECT_FALSE((fmt::detail::is_output_iterator<std::list<char>::const_iterator,
char>::value));
EXPECT_FALSE((fmt::detail::is_output_iterator<uint32_pair, char>::value));
}
TEST(MemoryBufferTest, Ctor) {
@ -236,7 +238,7 @@ TEST(MemoryBufferTest, MoveCtorInlineBuffer) {
std::allocator<char> alloc;
basic_memory_buffer<char, 5, TestAllocator> buffer((TestAllocator(&alloc)));
const char test[] = "test";
buffer.append(test, test + 4);
buffer.append(string_view(test, 4));
check_move_buffer("test", buffer);
// Adding one more character fills the inline buffer, but doesn't cause
// dynamic allocation.
@ -293,12 +295,8 @@ TEST(MemoryBufferTest, MoveAssignment) {
TEST(MemoryBufferTest, Grow) {
typedef allocator_ref<mock_allocator<int>> Allocator;
typedef basic_memory_buffer<int, 10, Allocator> Base;
mock_allocator<int> alloc;
struct TestMemoryBuffer : Base {
TestMemoryBuffer(Allocator alloc) : Base(alloc) {}
void grow(size_t size) { Base::grow(size); }
} buffer((Allocator(&alloc)));
basic_memory_buffer<int, 10, Allocator> buffer((Allocator(&alloc)));
buffer.resize(7);
using fmt::detail::to_unsigned;
for (int i = 0; i < 7; ++i) buffer[to_unsigned(i)] = i * i;
@ -306,7 +304,7 @@ TEST(MemoryBufferTest, Grow) {
int mem[20];
mem[7] = 0xdead;
EXPECT_CALL(alloc, allocate(20)).WillOnce(Return(mem));
buffer.grow(20);
buffer.try_reserve(20);
EXPECT_EQ(20u, buffer.capacity());
// Check if size elements have been copied
for (int i = 0; i < 7; ++i) EXPECT_EQ(i * i, buffer[to_unsigned(i)]);
@ -582,8 +580,8 @@ TEST(FormatterTest, LeftAlign) {
EXPECT_EQ("42 ", format("{0:<5}", 42ul));
EXPECT_EQ("-42 ", format("{0:<5}", -42ll));
EXPECT_EQ("42 ", format("{0:<5}", 42ull));
EXPECT_EQ("-42.0 ", format("{0:<7}", -42.0));
EXPECT_EQ("-42.0 ", format("{0:<7}", -42.0l));
EXPECT_EQ("-42 ", format("{0:<5}", -42.0));
EXPECT_EQ("-42 ", format("{0:<5}", -42.0l));
EXPECT_EQ("c ", format("{0:<5}", 'c'));
EXPECT_EQ("abc ", format("{0:<5}", "abc"));
EXPECT_EQ("0xface ", format("{0:<8}", reinterpret_cast<void*>(0xface)));
@ -599,8 +597,8 @@ TEST(FormatterTest, RightAlign) {
EXPECT_EQ(" 42", format("{0:>5}", 42ul));
EXPECT_EQ(" -42", format("{0:>5}", -42ll));
EXPECT_EQ(" 42", format("{0:>5}", 42ull));
EXPECT_EQ(" -42.0", format("{0:>7}", -42.0));
EXPECT_EQ(" -42.0", format("{0:>7}", -42.0l));
EXPECT_EQ(" -42", format("{0:>5}", -42.0));
EXPECT_EQ(" -42", format("{0:>5}", -42.0l));
EXPECT_EQ(" c", format("{0:>5}", 'c'));
EXPECT_EQ(" abc", format("{0:>5}", "abc"));
EXPECT_EQ(" 0xface", format("{0:>8}", reinterpret_cast<void*>(0xface)));
@ -620,8 +618,8 @@ TEST(FormatterTest, CenterAlign) {
EXPECT_EQ(" 42 ", format("{0:^5}", 42ul));
EXPECT_EQ(" -42 ", format("{0:^5}", -42ll));
EXPECT_EQ(" 42 ", format("{0:^5}", 42ull));
EXPECT_EQ(" -42.0 ", format("{0:^7}", -42.0));
EXPECT_EQ(" -42.0 ", format("{0:^7}", -42.0l));
EXPECT_EQ(" -42 ", format("{0:^5}", -42.0));
EXPECT_EQ(" -42 ", format("{0:^5}", -42.0l));
EXPECT_EQ(" c ", format("{0:^5}", 'c'));
EXPECT_EQ(" abc ", format("{0:^6}", "abc"));
EXPECT_EQ(" 0xface ", format("{0:^8}", reinterpret_cast<void*>(0xface)));
@ -639,8 +637,8 @@ TEST(FormatterTest, Fill) {
EXPECT_EQ("***42", format("{0:*>5}", 42ul));
EXPECT_EQ("**-42", format("{0:*>5}", -42ll));
EXPECT_EQ("***42", format("{0:*>5}", 42ull));
EXPECT_EQ("**-42.0", format("{0:*>7}", -42.0));
EXPECT_EQ("**-42.0", format("{0:*>7}", -42.0l));
EXPECT_EQ("**-42", format("{0:*>5}", -42.0));
EXPECT_EQ("**-42", format("{0:*>5}", -42.0l));
EXPECT_EQ("c****", format("{0:*<5}", 'c'));
EXPECT_EQ("abc**", format("{0:*<5}", "abc"));
EXPECT_EQ("**0xface", format("{0:*>8}", reinterpret_cast<void*>(0xface)));
@ -648,7 +646,7 @@ TEST(FormatterTest, Fill) {
EXPECT_EQ(std::string("\0\0\0*", 4), format(string_view("{:\0>4}", 6), '*'));
EXPECT_EQ("жж42", format("{0:ж>4}", 42));
EXPECT_THROW_MSG(format("{:\x80\x80\x80\x80\x80>}", 0), format_error,
"invalid fill");
"missing '}' in format string");
}
TEST(FormatterTest, PlusSign) {
@ -663,8 +661,8 @@ TEST(FormatterTest, PlusSign) {
EXPECT_EQ("+42", format("{0:+}", 42ll));
EXPECT_THROW_MSG(format("{0:+}", 42ull), format_error,
"format specifier requires signed argument");
EXPECT_EQ("+42.0", format("{0:+}", 42.0));
EXPECT_EQ("+42.0", format("{0:+}", 42.0l));
EXPECT_EQ("+42", format("{0:+}", 42.0));
EXPECT_EQ("+42", format("{0:+}", 42.0l));
EXPECT_THROW_MSG(format("{0:+", 'c'), format_error,
"missing '}' in format string");
EXPECT_THROW_MSG(format("{0:+}", 'c'), format_error,
@ -687,8 +685,8 @@ TEST(FormatterTest, MinusSign) {
EXPECT_EQ("42", format("{0:-}", 42ll));
EXPECT_THROW_MSG(format("{0:-}", 42ull), format_error,
"format specifier requires signed argument");
EXPECT_EQ("42.0", format("{0:-}", 42.0));
EXPECT_EQ("42.0", format("{0:-}", 42.0l));
EXPECT_EQ("42", format("{0:-}", 42.0));
EXPECT_EQ("42", format("{0:-}", 42.0l));
EXPECT_THROW_MSG(format("{0:-", 'c'), format_error,
"missing '}' in format string");
EXPECT_THROW_MSG(format("{0:-}", 'c'), format_error,
@ -711,8 +709,8 @@ TEST(FormatterTest, SpaceSign) {
EXPECT_EQ(" 42", format("{0: }", 42ll));
EXPECT_THROW_MSG(format("{0: }", 42ull), format_error,
"format specifier requires signed argument");
EXPECT_EQ(" 42.0", format("{0: }", 42.0));
EXPECT_EQ(" 42.0", format("{0: }", 42.0l));
EXPECT_EQ(" 42", format("{0: }", 42.0));
EXPECT_EQ(" 42", format("{0: }", 42.0l));
EXPECT_THROW_MSG(format("{0: ", 'c'), format_error,
"missing '}' in format string");
EXPECT_THROW_MSG(format("{0: }", 'c'), format_error,
@ -723,6 +721,12 @@ TEST(FormatterTest, SpaceSign) {
"format specifier requires numeric argument");
}
TEST(FormatterTest, SignNotTruncated) {
wchar_t format_str[] = {L'{', L':',
'+' | (1 << fmt::detail::num_bits<char>()), L'}', 0};
EXPECT_THROW(format(format_str, 42), format_error);
}
TEST(FormatterTest, HashFlag) {
EXPECT_EQ("42", format("{0:#}", 42));
EXPECT_EQ("-42", format("{0:#}", -42));
@ -761,8 +765,8 @@ TEST(FormatterTest, HashFlag) {
EXPECT_EQ("-42.0", format("{0:#}", -42.0l));
EXPECT_EQ("4.e+01", format("{:#.0e}", 42.0));
EXPECT_EQ("0.", format("{:#.0f}", 0.01));
auto s = format("{:#.0f}", 0.5); // MSVC's printf uses wrong rounding mode.
EXPECT_TRUE(s == "0." || s == "1.");
EXPECT_EQ("0.50", format("{:#.2g}", 0.5));
EXPECT_EQ("0.", format("{:#.0f}", 0.5));
EXPECT_THROW_MSG(format("{0:#", 'c'), format_error,
"missing '}' in format string");
EXPECT_THROW_MSG(format("{0:#}", 'c'), format_error,
@ -781,8 +785,8 @@ TEST(FormatterTest, ZeroFlag) {
EXPECT_EQ("00042", format("{0:05}", 42ul));
EXPECT_EQ("-0042", format("{0:05}", -42ll));
EXPECT_EQ("00042", format("{0:05}", 42ull));
EXPECT_EQ("-0042.0", format("{0:07}", -42.0));
EXPECT_EQ("-0042.0", format("{0:07}", -42.0l));
EXPECT_EQ("-000042", format("{0:07}", -42.0));
EXPECT_EQ("-000042", format("{0:07}", -42.0l));
EXPECT_THROW_MSG(format("{0:0", 'c'), format_error,
"missing '}' in format string");
EXPECT_THROW_MSG(format("{0:05}", 'c'), format_error,
@ -955,6 +959,9 @@ TEST(FormatterTest, Precision) {
EXPECT_EQ("123.", format("{:#.0f}", 123.0));
EXPECT_EQ("1.23", format("{:.02f}", 1.234));
EXPECT_EQ("0.001", format("{:.1g}", 0.001));
EXPECT_EQ("1019666400", format("{}", 1019666432.0f));
EXPECT_EQ("1e+01", format("{:.0e}", 9.5));
EXPECT_EQ("1.0e-34", fmt::format("{:.1e}", 1e-34));
EXPECT_THROW_MSG(format("{0:.2}", reinterpret_cast<void*>(0xcafe)),
format_error,
@ -1236,17 +1243,20 @@ TEST(FormatterTest, FormatConvertibleToLongLong) {
}
TEST(FormatterTest, FormatFloat) {
EXPECT_EQ("0", format("{}", 0.0f));
EXPECT_EQ("392.500000", format("{0:f}", 392.5f));
}
TEST(FormatterTest, FormatDouble) {
EXPECT_EQ("0", format("{}", 0.0));
check_unknown_types(1.2, "eEfFgGaAnL%", "double");
EXPECT_EQ("0.0", format("{:}", 0.0));
EXPECT_EQ("0", format("{:}", 0.0));
EXPECT_EQ("0.000000", format("{:f}", 0.0));
EXPECT_EQ("0", format("{:g}", 0.0));
EXPECT_EQ("392.65", format("{:}", 392.65));
EXPECT_EQ("392.65", format("{:g}", 392.65));
EXPECT_EQ("392.65", format("{:G}", 392.65));
EXPECT_EQ("4.9014e+06", format("{:g}", 4.9014e6));
EXPECT_EQ("392.650000", format("{:f}", 392.65));
EXPECT_EQ("392.650000", format("{:F}", 392.65));
EXPECT_EQ("42", format("{:L}", 42.0));
@ -1260,6 +1270,8 @@ TEST(FormatterTest, FormatDouble) {
EXPECT_EQ(buffer, format("{:a}", -42.0));
safe_sprintf(buffer, "%A", -42.0);
EXPECT_EQ(buffer, format("{:A}", -42.0));
EXPECT_EQ("9223372036854775808.000000",
format("{:f}", 9223372036854775807.0));
}
TEST(FormatterTest, PrecisionRounding) {
@ -1273,17 +1285,42 @@ TEST(FormatterTest, PrecisionRounding) {
EXPECT_EQ("1.000", format("{:.3f}", 0.9999));
EXPECT_EQ("0.00123", format("{:.3}", 0.00123));
EXPECT_EQ("0.1", format("{:.16g}", 0.1));
// Trigger rounding error in Grisu by a carefully chosen number.
auto n = 3788512123356.985352;
char buffer[64];
safe_sprintf(buffer, "%f", n);
EXPECT_EQ(buffer, format("{:f}", n));
EXPECT_EQ("1", fmt::format("{:.0}", 1.0));
EXPECT_EQ("225.51575035152063720",
fmt::format("{:.17f}", 225.51575035152064));
EXPECT_EQ("-761519619559038.2", fmt::format("{:.1f}", -761519619559038.2));
EXPECT_EQ("1.9156918820264798e-56",
fmt::format("{}", 1.9156918820264798e-56));
EXPECT_EQ("0.0000", fmt::format("{:.4f}", 7.2809479766055470e-15));
// Trigger a rounding error in Grisu by a specially chosen number.
EXPECT_EQ("3788512123356.985352", format("{:f}", 3788512123356.985352));
}
TEST(FormatterTest, PrettifyFloat) {
EXPECT_EQ("0.0001", fmt::format("{}", 1e-4));
EXPECT_EQ("1e-05", fmt::format("{}", 1e-5));
EXPECT_EQ("1000000000000000", fmt::format("{}", 1e15));
EXPECT_EQ("1e+16", fmt::format("{}", 1e16));
EXPECT_EQ("9.999e-05", fmt::format("{}", 9.999e-5));
EXPECT_EQ("10000000000", fmt::format("{}", 1e10));
EXPECT_EQ("100000000000", fmt::format("{}", 1e11));
EXPECT_EQ("12340000000", fmt::format("{}", 1234e7));
EXPECT_EQ("12.34", fmt::format("{}", 1234e-2));
EXPECT_EQ("0.001234", fmt::format("{}", 1234e-6));
EXPECT_EQ("0.1", fmt::format("{}", 0.1f));
EXPECT_EQ("0.10000000149011612", fmt::format("{}", double(0.1f)));
EXPECT_EQ("1.3563156e-19", fmt::format("{}", 1.35631564e-19f));
}
TEST(FormatterTest, FormatNaN) {
double nan = std::numeric_limits<double>::quiet_NaN();
EXPECT_EQ("nan", format("{}", nan));
EXPECT_EQ("+nan", format("{:+}", nan));
if (std::signbit(-nan))
EXPECT_EQ("-nan", format("{}", -nan));
else
fmt::print("Warning: compiler doesn't handle negative NaN correctly");
EXPECT_EQ(" nan", format("{: }", nan));
EXPECT_EQ("NAN", format("{:F}", nan));
EXPECT_EQ("nan ", format("{:<7}", nan));
@ -1304,7 +1341,7 @@ TEST(FormatterTest, FormatInfinity) {
}
TEST(FormatterTest, FormatLongDouble) {
EXPECT_EQ("0.0", format("{0:}", 0.0l));
EXPECT_EQ("0", format("{0:}", 0.0l));
EXPECT_EQ("0.000000", format("{0:f}", 0.0l));
EXPECT_EQ("392.65", format("{0:}", 392.65l));
EXPECT_EQ("392.65", format("{0:g}", 392.65l));
@ -1521,6 +1558,7 @@ TEST(FormatterTest, WideFormatString) {
EXPECT_EQ(L"4.2", format(L"{}", 4.2));
EXPECT_EQ(L"abc", format(L"{}", L"abc"));
EXPECT_EQ(L"z", format(L"{}", L'z'));
EXPECT_THROW(fmt::format(L"{:*\x343E}", 42), fmt::format_error);
}
TEST(FormatterTest, FormatStringFromSpeedTest) {
@ -1806,59 +1844,6 @@ TEST(FormatTest, StrongEnum) {
}
#endif
using buffer_iterator = fmt::format_context::iterator;
class mock_arg_formatter
: public fmt::detail::arg_formatter_base<buffer_iterator, char> {
private:
#if FMT_USE_INT128
MOCK_METHOD1(call, void(__int128_t value));
#else
MOCK_METHOD1(call, void(long long value));
#endif
public:
using base = fmt::detail::arg_formatter_base<buffer_iterator, char>;
mock_arg_formatter(fmt::format_context& ctx, fmt::format_parse_context*,
fmt::format_specs* s = nullptr, const char* = nullptr)
: base(ctx.out(), s, ctx.locale()) {
EXPECT_CALL(*this, call(42));
}
template <typename T>
typename std::enable_if<fmt::detail::is_integral<T>::value, iterator>::type
operator()(T value) {
call(value);
return base::operator()(value);
}
template <typename T>
typename std::enable_if<!fmt::detail::is_integral<T>::value, iterator>::type
operator()(T value) {
return base::operator()(value);
}
iterator operator()(fmt::basic_format_arg<fmt::format_context>::handle) {
return base::operator()(fmt::monostate());
}
};
static void custom_vformat(fmt::string_view format_str, fmt::format_args args) {
fmt::memory_buffer buffer;
fmt::detail::buffer<char>& base = buffer;
fmt::vformat_to<mock_arg_formatter>(std::back_inserter(base), format_str,
args);
}
template <typename... Args>
void custom_format(const char* format_str, const Args&... args) {
auto va = fmt::make_format_args(args...);
return custom_vformat(format_str, va);
}
TEST(FormatTest, CustomArgFormatter) { custom_format("{}", 42); }
TEST(FormatTest, NonNullTerminatedFormatString) {
EXPECT_EQ("42", format(string_view("{}foo", 2), 42));
}
@ -1947,6 +1932,12 @@ TEST(FormatTest, FormattedSize) {
EXPECT_EQ(2u, fmt::formatted_size("{}", 42));
}
TEST(FormatTest, FormatTo) {
std::vector<char> v;
fmt::format_to(std::back_inserter(v), "{}", "foo");
EXPECT_EQ(string_view(v.data(), v.size()), "foo");
}
TEST(FormatTest, FormatToN) {
char buffer[4];
buffer[3] = 'x';
@ -1954,10 +1945,12 @@ TEST(FormatTest, FormatToN) {
EXPECT_EQ(5u, result.size);
EXPECT_EQ(buffer + 3, result.out);
EXPECT_EQ("123x", fmt::string_view(buffer, 4));
result = fmt::format_to_n(buffer, 3, "{:s}", "foobar");
EXPECT_EQ(6u, result.size);
EXPECT_EQ(buffer + 3, result.out);
EXPECT_EQ("foox", fmt::string_view(buffer, 4));
buffer[0] = 'x';
buffer[1] = 'x';
buffer[2] = 'x';
@ -1965,10 +1958,20 @@ TEST(FormatTest, FormatToN) {
EXPECT_EQ(1u, result.size);
EXPECT_EQ(buffer + 1, result.out);
EXPECT_EQ("Axxx", fmt::string_view(buffer, 4));
result = fmt::format_to_n(buffer, 3, "{}{} ", 'B', 'C');
EXPECT_EQ(3u, result.size);
EXPECT_EQ(buffer + 3, result.out);
EXPECT_EQ("BC x", fmt::string_view(buffer, 4));
result = fmt::format_to_n(buffer, 4, "{}", "ABCDE");
EXPECT_EQ(5u, result.size);
EXPECT_EQ("ABCD", fmt::string_view(buffer, 4));
buffer[3] = 'x';
result = fmt::format_to_n(buffer, 3, "{}", std::string(1000, '*'));
EXPECT_EQ(1000u, result.size);
EXPECT_EQ("***x", fmt::string_view(buffer, 4));
}
TEST(FormatTest, WideFormatToN) {
@ -2413,12 +2416,6 @@ TEST(FormatTest, FmtStringInTemplate) {
#endif // FMT_USE_CONSTEXPR
TEST(FormatTest, EmphasisNonHeaderOnly) {
// Ensure this compiles even if FMT_HEADER_ONLY is not defined.
EXPECT_EQ(fmt::format(fmt::emphasis::bold, "bold error"),
"\x1b[1mbold error\x1b[0m");
}
TEST(FormatTest, CharTraitsIsNotAmbiguous) {
// Test that we don't inject detail names into the std namespace.
using namespace std;
@ -2431,25 +2428,30 @@ TEST(FormatTest, CharTraitsIsNotAmbiguous) {
#endif
}
struct mychar {
#if __cplusplus > 201103L
struct custom_char {
int value;
mychar() = default;
custom_char() = default;
template <typename T> mychar(T val) : value(static_cast<int>(val)) {}
template <typename T>
constexpr custom_char(T val) : value(static_cast<int>(val)) {}
operator int() const { return value; }
};
int to_ascii(custom_char c) { return c; }
FMT_BEGIN_NAMESPACE
template <> struct is_char<mychar> : std::true_type {};
template <> struct is_char<custom_char> : std::true_type {};
FMT_END_NAMESPACE
TEST(FormatTest, FormatCustomChar) {
const mychar format[] = {'{', '}', 0};
auto result = fmt::format(format, mychar('x'));
const custom_char format[] = {'{', '}', 0};
auto result = fmt::format(format, custom_char('x'));
EXPECT_EQ(result.size(), 1);
EXPECT_EQ(result[0], mychar('x'));
EXPECT_EQ(result[0], custom_char('x'));
}
#endif
// Convert a char8_t string to std::string. Otherwise GTest will insist on
// inserting `char8_t` NTBS into a `char` stream which is disabled by P1423.
@ -2467,3 +2469,27 @@ TEST(FormatTest, FormatUTF8Precision) {
EXPECT_EQ(result.size(), 5);
EXPECT_EQ(from_u8str(result), from_u8str(str.substr(0, 5)));
}
struct check_back_appender {};
FMT_BEGIN_NAMESPACE
template <> struct formatter<check_back_appender> {
template <typename ParseContext>
auto parse(ParseContext& ctx) -> decltype(ctx.begin()) {
return ctx.begin();
}
template <typename Context>
auto format(check_back_appender, Context& ctx) -> decltype(ctx.out()) {
auto out = ctx.out();
static_assert(std::is_same<decltype(++out), decltype(out)&>::value,
"needs to satisfy weakly_incrementable");
*out = 'y';
return ++out;
}
};
FMT_END_NAMESPACE
TEST(FormatTest, BackInsertSlicing) {
EXPECT_EQ(fmt::format("{}", check_back_appender{}), "y");
}

View file

@ -1,38 +1,30 @@
# Copyright (c) 2019, Paul Dreik
# License: see LICENSE.rst in the fmt root directory
# settings this links in a main. useful for reproducing,
# kcov, gdb, afl, valgrind.
# (note that libFuzzer can also reproduce, just pass it the files)
option(FMT_FUZZ_LINKMAIN "enables the reproduce mode, instead of libFuzzer" On)
# Link in the main function. Useful for reproducing, kcov, gdb, afl, valgrind.
# (Note that libFuzzer can also reproduce, just pass it the files.)
option(FMT_FUZZ_LINKMAIN "Enables the reproduce mode, instead of libFuzzer" On)
# For oss-fuzz - insert $LIB_FUZZING_ENGINE into the link flags, but only for
# the fuzz targets, otherwise the cmake configuration step fails.
# the fuzz targets, otherwise the CMake configuration step fails.
set(FMT_FUZZ_LDFLAGS "" CACHE STRING "LDFLAGS for the fuzz targets")
# Find all fuzzers.
set(SOURCES
chrono_duration.cpp
named_arg.cpp
one_arg.cpp
sprintf.cpp
two_args.cpp
)
macro(implement_fuzzer sourcefile)
get_filename_component(basename ${sourcefile} NAME_WE)
set(name fuzzer_${basename})
add_executable(${name} ${sourcefile} fuzzer_common.h)
# Adds a binary for reproducing, i.e. no fuzzing, just enables replaying data
# through the fuzzers.
function(add_fuzzer source)
get_filename_component(basename ${source} NAME_WE)
set(name ${basename}-fuzzer)
add_executable(${name} ${source} fuzzer-common.h)
if (FMT_FUZZ_LINKMAIN)
target_sources(${name} PRIVATE main.cpp)
target_sources(${name} PRIVATE main.cc)
endif ()
target_link_libraries(${name} PRIVATE fmt)
if (FMT_FUZZ_LDFLAGS)
target_link_libraries(${name} PRIVATE ${FMT_FUZZ_LDFLAGS})
endif ()
if (FMT_FUZZ_LDFLAGS)
target_link_libraries(${name} PRIVATE ${FMT_FUZZ_LDFLAGS})
endif ()
target_compile_features(${name} PRIVATE cxx_generic_lambdas)
endmacro ()
endfunction()
foreach (X IN ITEMS ${SOURCES})
implement_fuzzer(${X})
foreach (source chrono-duration.cc float.cc named-arg.cc one-arg.cc two-args.cc)
add_fuzzer(${source})
endforeach ()

View file

@ -1,27 +1,4 @@
# FMT Fuzzer
Fuzzing has revealed [several bugs](https://github.com/fmtlib/fmt/issues?&q=is%3Aissue+fuzz)
in fmt. It is a part of the continous fuzzing at
[oss-fuzz](https://github.com/google/oss-fuzz).
The source code is modified to make the fuzzing possible without locking up on
resource exhaustion:
```cpp
#ifdef FMT_FUZZ
if(spec.precision>100000) {
throw std::runtime_error("fuzz mode - avoiding large precision");
}
#endif
```
This macro `FMT_FUZZ` is enabled on OSS-Fuzz builds and makes fuzzing
practically possible. It is used in fmt code to prevent resource exhaustion in
fuzzing mode.
The macro `FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION` is the
defacto standard for making fuzzing practically possible to disable certain
fuzzing-unfriendly features (for example, randomness), see [the libFuzzer
documentation](https://llvm.org/docs/LibFuzzer.html#fuzzer-friendly-build-mode).
## Running the fuzzers locally
# Running the fuzzers locally
There is a [helper script](build.sh) to build the fuzzers, which has only been
tested on Debian and Ubuntu linux so far. There should be no problems fuzzing on
@ -34,7 +11,7 @@ mkdir build
cd build
export CXX=clang++
export CXXFLAGS="-fsanitize=fuzzer-no-link -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION= -g"
cmake .. -DFMT_SAFE_DURATION_CAST=On -DFMT_FUZZ=On -DFMT_FUZZ_LINKMAIN=Off -DFMT_FUZZ_LDFLAGS="-fsanitize=fuzzer"
cmake .. -DFMT_SAFE_DURATION_CAST=On -DFMT_FUZZ=On -DFMT_FUZZ_LINKMAIN=Off -DFMT_FUZZ_LDFLAGS="-fsanitize=fuzzer"
cmake --build .
```
should work to build the fuzzers for all platforms which clang supports.
@ -44,5 +21,5 @@ Execute a fuzzer with for instance
cd build
export UBSAN_OPTIONS=halt_on_error=1
mkdir out_chrono
bin/fuzzer_chrono_duration out_chrono
bin/fuzzer_chrono_duration out_chrono
```

View file

@ -1,7 +1,6 @@
#!/bin/sh
#
# Creates fuzzer builds of various kinds
# - reproduce mode (no fuzzing, just enables replaying data through the fuzzers)
# - oss-fuzz emulated mode (makes sure a simulated invocation by oss-fuzz works)
# - libFuzzer build (you will need clang)
# - afl build (you will need afl)
@ -9,7 +8,7 @@
#
# Copyright (c) 2019 Paul Dreik
#
# License: see LICENSE.rst in the fmt root directory
# For the license information refer to format.h.
set -e
me=$(basename $0)
@ -23,16 +22,7 @@ here=$(pwd)
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"
#builds the fuzzers as one would do if using afl or just making
#binaries for reproducing.
builddir=$here/build-fuzzers-reproduce
mkdir -p $builddir
cd $builddir
CXX="ccache g++" CXXFLAGS="$CXXFLAGSALL" cmake \
$CMAKEFLAGSALL
cmake --build $builddir
#for performance analysis of the fuzzers
# For performance analysis of the fuzzers.
builddir=$here/build-fuzzers-perfanalysis
mkdir -p $builddir
cd $builddir
@ -43,7 +33,7 @@ $CMAKEFLAGSALL \
cmake --build $builddir
#builds the fuzzers as oss-fuzz does
# Builds the fuzzers as oss-fuzz does.
builddir=$here/build-fuzzers-ossfuzz
mkdir -p $builddir
cd $builddir
@ -56,7 +46,7 @@ cmake $CMAKEFLAGSALL \
cmake --build $builddir
#builds fuzzers for local fuzzing with libfuzzer with asan+usan
# Builds fuzzers for local fuzzing with libfuzzer with asan+usan.
builddir=$here/build-fuzzers-libfuzzer
mkdir -p $builddir
cd $builddir
@ -68,19 +58,7 @@ cmake $CMAKEFLAGSALL \
cmake --build $builddir
#builds fuzzers for local fuzzing with libfuzzer with asan only
builddir=$here/build-fuzzers-libfuzzer-addr
mkdir -p $builddir
cd $builddir
CXX="clang++" \
CXXFLAGS="$CXXFLAGSALL -fsanitize=fuzzer-no-link,undefined" cmake \
cmake $CMAKEFLAGSALL \
-DFMT_FUZZ_LINKMAIN=Off \
-DFMT_FUZZ_LDFLAGS="-fsanitize=fuzzer"
cmake --build $builddir
#builds a fast fuzzer for making coverage fast
# Builds a fast fuzzer for making coverage fast.
builddir=$here/build-fuzzers-fast
mkdir -p $builddir
cd $builddir
@ -94,7 +72,7 @@ cmake $CMAKEFLAGSALL \
cmake --build $builddir
#builds fuzzers for local fuzzing with afl
# Builds fuzzers for local fuzzing with afl.
builddir=$here/build-fuzzers-afl
mkdir -p $builddir
cd $builddir

View file

@ -0,0 +1,135 @@
// Copyright (c) 2019, Paul Dreik
// For the license information refer to format.h.
#include <cstdint>
#include <fmt/chrono.h>
#include "fuzzer-common.h"
template <typename Period, typename Rep>
void invoke_inner(fmt::string_view format_str, Rep rep) {
auto value = std::chrono::duration<Rep, Period>(rep);
try {
#if FMT_FUZZ_FORMAT_TO_STRING
std::string message = fmt::format(format_str, value);
#else
fmt::memory_buffer buf;
fmt::format_to(buf, format_str, value);
#endif
} catch (std::exception&) {
}
}
// Rep is a duration's representation type.
template <typename Rep>
void invoke_outer(const uint8_t* data, size_t size, int period) {
// Always use a fixed location of the data.
static_assert(sizeof(Rep) <= fixed_size, "fixed size is too small");
if (size <= fixed_size + 1) return;
const Rep rep = assign_from_buf<Rep>(data);
data += fixed_size;
size -= fixed_size;
// data is already allocated separately in libFuzzer so reading past the end
// will most likely be detected anyway.
const auto format_str = fmt::string_view(as_chars(data), size);
// yocto, zepto, zetta and yotta are not handled.
switch (period) {
case 1:
invoke_inner<std::atto>(format_str, rep);
break;
case 2:
invoke_inner<std::femto>(format_str, rep);
break;
case 3:
invoke_inner<std::pico>(format_str, rep);
break;
case 4:
invoke_inner<std::nano>(format_str, rep);
break;
case 5:
invoke_inner<std::micro>(format_str, rep);
break;
case 6:
invoke_inner<std::milli>(format_str, rep);
break;
case 7:
invoke_inner<std::centi>(format_str, rep);
break;
case 8:
invoke_inner<std::deci>(format_str, rep);
break;
case 9:
invoke_inner<std::deca>(format_str, rep);
break;
case 10:
invoke_inner<std::kilo>(format_str, rep);
break;
case 11:
invoke_inner<std::mega>(format_str, rep);
break;
case 12:
invoke_inner<std::giga>(format_str, rep);
break;
case 13:
invoke_inner<std::tera>(format_str, rep);
break;
case 14:
invoke_inner<std::peta>(format_str, rep);
break;
case 15:
invoke_inner<std::exa>(format_str, rep);
break;
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
if (size <= 4) return 0;
const auto representation = data[0];
const auto period = data[1];
data += 2;
size -= 2;
switch (representation) {
case 1:
invoke_outer<char>(data, size, period);
break;
case 2:
invoke_outer<signed char>(data, size, period);
break;
case 3:
invoke_outer<unsigned char>(data, size, period);
break;
case 4:
invoke_outer<short>(data, size, period);
break;
case 5:
invoke_outer<unsigned short>(data, size, period);
break;
case 6:
invoke_outer<int>(data, size, period);
break;
case 7:
invoke_outer<unsigned int>(data, size, period);
break;
case 8:
invoke_outer<long>(data, size, period);
break;
case 9:
invoke_outer<unsigned long>(data, size, period);
break;
case 10:
invoke_outer<float>(data, size, period);
break;
case 11:
invoke_outer<double>(data, size, period);
break;
case 12:
invoke_outer<long double>(data, size, period);
break;
}
return 0;
}

View file

@ -1,152 +0,0 @@
// Copyright (c) 2019, Paul Dreik
// License: see LICENSE.rst in the fmt root directory
#include <fmt/chrono.h>
#include <cstdint>
#include <limits>
#include <stdexcept>
#include <type_traits>
#include <vector>
#include "fuzzer_common.h"
template <typename Item, typename Ratio>
void invoke_inner(fmt::string_view formatstring, const Item item) {
const std::chrono::duration<Item, Ratio> value(item);
try {
#if FMT_FUZZ_FORMAT_TO_STRING
std::string message = fmt::format(formatstring, value);
#else
fmt::memory_buffer buf;
fmt::format_to(buf, formatstring, value);
#endif
} catch (std::exception& /*e*/) {
}
}
// Item is the underlying type for duration (int, long etc)
template <typename Item>
void invoke_outer(const uint8_t* Data, size_t Size, const int scaling) {
// always use a fixed location of the data
using fmt_fuzzer::Nfixed;
constexpr auto N = sizeof(Item);
static_assert(N <= Nfixed, "fixed size is too small");
if (Size <= Nfixed + 1) {
return;
}
const Item item = fmt_fuzzer::assignFromBuf<Item>(Data);
// fast forward
Data += Nfixed;
Size -= Nfixed;
// Data is already allocated separately in libFuzzer so reading past
// the end will most likely be detected anyway
const auto formatstring = fmt::string_view(fmt_fuzzer::as_chars(Data), Size);
// doit_impl<Item,std::yocto>(buf.data(),item);
// doit_impl<Item,std::zepto>(buf.data(),item);
switch (scaling) {
case 1:
invoke_inner<Item, std::atto>(formatstring, item);
break;
case 2:
invoke_inner<Item, std::femto>(formatstring, item);
break;
case 3:
invoke_inner<Item, std::pico>(formatstring, item);
break;
case 4:
invoke_inner<Item, std::nano>(formatstring, item);
break;
case 5:
invoke_inner<Item, std::micro>(formatstring, item);
break;
case 6:
invoke_inner<Item, std::milli>(formatstring, item);
break;
case 7:
invoke_inner<Item, std::centi>(formatstring, item);
break;
case 8:
invoke_inner<Item, std::deci>(formatstring, item);
break;
case 9:
invoke_inner<Item, std::deca>(formatstring, item);
break;
case 10:
invoke_inner<Item, std::kilo>(formatstring, item);
break;
case 11:
invoke_inner<Item, std::mega>(formatstring, item);
break;
case 12:
invoke_inner<Item, std::giga>(formatstring, item);
break;
case 13:
invoke_inner<Item, std::tera>(formatstring, item);
break;
case 14:
invoke_inner<Item, std::peta>(formatstring, item);
break;
case 15:
invoke_inner<Item, std::exa>(formatstring, item);
}
// doit_impl<Item,std::zeta>(buf.data(),item);
// doit_impl<Item,std::yotta>(buf.data(),item);
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
if (Size <= 4) {
return 0;
}
const auto representation = Data[0];
const auto scaling = Data[1];
Data += 2;
Size -= 2;
switch (representation) {
case 1:
invoke_outer<char>(Data, Size, scaling);
break;
case 2:
invoke_outer<unsigned char>(Data, Size, scaling);
break;
case 3:
invoke_outer<signed char>(Data, Size, scaling);
break;
case 4:
invoke_outer<short>(Data, Size, scaling);
break;
case 5:
invoke_outer<unsigned short>(Data, Size, scaling);
break;
case 6:
invoke_outer<int>(Data, Size, scaling);
break;
case 7:
invoke_outer<unsigned int>(Data, Size, scaling);
break;
case 8:
invoke_outer<long>(Data, Size, scaling);
break;
case 9:
invoke_outer<unsigned long>(Data, Size, scaling);
break;
case 10:
invoke_outer<float>(Data, Size, scaling);
break;
case 11:
invoke_outer<double>(Data, Size, scaling);
break;
case 12:
invoke_outer<long double>(Data, Size, scaling);
break;
default:
break;
}
return 0;
}

34
fmt/test/fuzzing/float.cc Normal file
View file

@ -0,0 +1,34 @@
// A fuzzer for floating-point formatter.
// For the license information refer to format.h.
#include <cstdint>
#include <cstdlib>
#include <stdexcept>
#include <limits>
#include <fmt/format.h>
#include "fuzzer-common.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
if (size <= sizeof(double) || !std::numeric_limits<double>::is_iec559)
return 0;
auto value = assign_from_buf<double>(data);
auto buffer = fmt::memory_buffer();
fmt::format_to(buffer, "{}", value);
// Check a round trip.
if (std::isnan(value)) {
auto nan = std::signbit(value) ? "-nan" : "nan";
if (fmt::string_view(buffer.data(), buffer.size()) != nan)
throw std::runtime_error("round trip failure");
return 0;
}
buffer.push_back('\0');
char* ptr = nullptr;
if (std::strtod(buffer.data(), &ptr) != value)
throw std::runtime_error("round trip failure");
if (ptr + 1 != buffer.end())
throw std::runtime_error("unparsed output");
return 0;
}

View file

@ -0,0 +1,75 @@
// Copyright (c) 2019, Paul Dreik
// For the license information refer to format.h.
#ifndef FUZZER_COMMON_H
#define FUZZER_COMMON_H
#include <cstdint> // std::uint8_t
#include <cstring> // memcpy
#include <vector>
#include <fmt/core.h>
// 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
// as intended. To avoid a combinatoric explosion, select this at compile time
// instead of dynamically from the fuzz data.
#define FMT_FUZZ_FORMAT_TO_STRING 0
// If {fmt} is given a buffer that is separately allocated, chances that address
// sanitizer detects out of bound reads is much higher. However, it slows down
// the fuzzing.
#define FMT_FUZZ_SEPARATE_ALLOCATION 1
// The size of the largest possible type in use.
// To let the the fuzzer mutation be efficient at cross pollinating between
// different types, use a fixed size format. The same bit pattern, interpreted
// as another type, is likely interesting.
constexpr auto fixed_size = 16;
// Casts data to a char pointer.
template <typename T> inline const char* as_chars(const T* data) {
return reinterpret_cast<const char*>(data);
}
// Casts data to a byte pointer.
template <typename T> inline const std::uint8_t* as_bytes(const T* data) {
return reinterpret_cast<const std::uint8_t*>(data);
}
// Blits bytes from data to form an (assumed trivially constructible) object
// of type Item.
template <class Item> inline Item assign_from_buf(const std::uint8_t* data) {
auto item = Item();
std::memcpy(&item, data, sizeof(Item));
return item;
}
// Reads a boolean value by looking at the first byte from data.
template <> inline bool assign_from_buf<bool>(const std::uint8_t* data) {
return *data != 0;
}
struct data_to_string {
#if FMT_FUZZ_SEPARATE_ALLOCATION
std::vector<char> buffer;
data_to_string(const uint8_t* data, size_t size, bool add_terminator = false)
: buffer(size + (add_terminator ? 1 : 0)) {
std::memcpy(buffer.data(), data, size);
}
fmt::string_view get() const { return {buffer.data(), buffer.size()}; }
#else
fmt::string_view sv;
data_to_string(const uint8_t* data, size_t size, bool = false)
: str(as_chars(data), size) {}
fmt::string_view get() const { return sv; }
#endif
const char* data() const { return get().data(); }
};
#endif // FUZZER_COMMON_H

View file

@ -1,67 +0,0 @@
#ifndef FUZZER_COMMON_H
#define FUZZER_COMMON_H
// Copyright (c) 2019, Paul Dreik
// License: see LICENSE.rst in the fmt root directory
#include <cstdint> // std::uint8_t
#include <cstring> // memcpy
#include <type_traits> // trivially copyable
// one can format to either a string, or a buf. buf is faster,
// but 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 instead of dynamically from the fuzz data
#define FMT_FUZZ_FORMAT_TO_STRING 0
// if fmt is given a buffer that is separately allocated,
// chances that address sanitizer detects out of bound reads is
// much higher. However, it slows down the fuzzing.
#define FMT_FUZZ_SEPARATE_ALLOCATION 1
// To let the the fuzzer mutation be efficient at cross pollinating
// between different types, use a fixed size format.
// The same bit pattern, interpreted as another type,
// is likely interesting.
// For this, we must know the size of the largest possible type in use.
// There are some problems on travis, claiming Nfixed is not a constant
// expression which seems to be an issue with older versions of libstdc++
#if _GLIBCXX_RELEASE >= 7
# include <algorithm>
namespace fmt_fuzzer {
constexpr auto Nfixed = std::max(sizeof(long double), sizeof(std::intmax_t));
}
#else
namespace fmt_fuzzer {
constexpr auto Nfixed = 16;
}
#endif
namespace fmt_fuzzer {
// view data as a c char pointer.
template <typename T> inline const char* as_chars(const T* data) {
return static_cast<const char*>(static_cast<const void*>(data));
}
// view data as a byte pointer
template <typename T> inline const std::uint8_t* as_bytes(const T* data) {
return static_cast<const std::uint8_t*>(static_cast<const void*>(data));
}
// blits bytes from Data to form an (assumed trivially constructible) object
// of type Item
template <class Item> inline Item assignFromBuf(const std::uint8_t* Data) {
Item item{};
std::memcpy(&item, Data, sizeof(Item));
return item;
}
// reads a boolean value by looking at the first byte from Data
template <> inline bool assignFromBuf<bool>(const std::uint8_t* Data) {
return !!Data[0];
}
} // namespace fmt_fuzzer
#endif // FUZZER_COMMON_H

22
fmt/test/fuzzing/main.cc Normal file
View file

@ -0,0 +1,22 @@
#include <cassert>
#include <fstream>
#include <vector>
#include "fuzzer-common.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);
int main(int argc, char** argv) {
for (int i = 1; i < argc; ++i) {
std::ifstream in(argv[i]);
assert(in);
in.seekg(0, std::ios_base::end);
const auto size = in.tellg();
assert(size >= 0);
in.seekg(0, std::ios_base::beg);
std::vector<char> buf(static_cast<size_t>(size));
in.read(buf.data(), size);
assert(in.gcount() == size);
LLVMFuzzerTestOneInput(as_bytes(buf.data()), buf.size());
}
}

View file

@ -1,21 +0,0 @@
#include <cassert>
#include <fstream>
#include <sstream>
#include <vector>
#include "fuzzer_common.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size);
int main(int argc, char* argv[]) {
for (int i = 1; i < argc; ++i) {
std::ifstream in(argv[i]);
assert(in);
in.seekg(0, std::ios_base::end);
const auto pos = in.tellg();
assert(pos >= 0);
in.seekg(0, std::ios_base::beg);
std::vector<char> buf(static_cast<size_t>(pos));
in.read(buf.data(), static_cast<long>(buf.size()));
assert(in.gcount() == pos);
LLVMFuzzerTestOneInput(fmt_fuzzer::as_bytes(buf.data()), buf.size());
}
}

View file

@ -0,0 +1,100 @@
// Copyright (c) 2019, Paul Dreik
// For the license information refer to format.h.
#include <cstdint>
#include <type_traits>
#include <vector>
#include <fmt/chrono.h>
#include "fuzzer-common.h"
template <typename T>
void invoke_fmt(const uint8_t* data, size_t size, unsigned arg_name_size) {
static_assert(sizeof(T) <= fixed_size, "fixed_size too small");
if (size <= fixed_size) return;
const T value = assign_from_buf<T>(data);
data += fixed_size;
size -= fixed_size;
if (arg_name_size <= 0 || arg_name_size >= size) return;
data_to_string arg_name(data, arg_name_size, true);
data += arg_name_size;
size -= arg_name_size;
data_to_string format_str(data, size);
try {
#if FMT_FUZZ_FORMAT_TO_STRING
std::string message =
fmt::format(format_str.get(), fmt::arg(arg_name.data(), value));
#else
fmt::memory_buffer out;
fmt::format_to(out, format_str.get(), fmt::arg(arg_name.data(), value));
#endif
} catch (std::exception&) {
}
}
// For dynamic dispatching to an explicit instantiation.
template <typename Callback> void invoke(int type, Callback callback) {
switch (type) {
case 0:
callback(bool());
break;
case 1:
callback(char());
break;
case 2:
using sc = signed char;
callback(sc());
break;
case 3:
using uc = unsigned char;
callback(uc());
break;
case 4:
callback(short());
break;
case 5:
using us = unsigned short;
callback(us());
break;
case 6:
callback(int());
break;
case 7:
callback(unsigned());
break;
case 8:
callback(long());
break;
case 9:
using ul = unsigned long;
callback(ul());
break;
case 10:
callback(float());
break;
case 11:
callback(double());
break;
case 12:
using LD = long double;
callback(LD());
break;
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
if (size <= 3) return 0;
// Switch types depending on the first byte of the input.
const auto type = data[0] & 0x0F;
const unsigned arg_name_size = (data[0] & 0xF0) >> 4;
data++;
size--;
invoke(type, [=](auto arg) {
invoke_fmt<decltype(arg)>(data, size, arg_name_size);
});
return 0;
}

View file

@ -1,128 +0,0 @@
// Copyright (c) 2019, Paul Dreik
// License: see LICENSE.rst in the fmt root directory
#include <fmt/chrono.h>
#include <fmt/core.h>
#include <cstdint>
#include <stdexcept>
#include <type_traits>
#include <vector>
#include "fuzzer_common.h"
template <typename Item1>
void invoke_fmt(const uint8_t* Data, size_t Size, unsigned int argsize) {
constexpr auto N1 = sizeof(Item1);
static_assert(N1 <= fmt_fuzzer::Nfixed, "Nfixed too small");
if (Size <= fmt_fuzzer::Nfixed) {
return;
}
const Item1 item1 = fmt_fuzzer::assignFromBuf<Item1>(Data);
Data += fmt_fuzzer::Nfixed;
Size -= fmt_fuzzer::Nfixed;
// how many chars should be used for the argument name?
if (argsize <= 0 || argsize >= Size) {
return;
}
// allocating buffers separately is slower, but increases chances
// of detecting memory errors
#if FMT_FUZZ_SEPARATE_ALLOCATION
std::vector<char> argnamebuffer(argsize + 1);
std::memcpy(argnamebuffer.data(), Data, argsize);
auto argname = argnamebuffer.data();
#else
auto argname = fmt_fuzzer::as_chars(Data);
#endif
Data += argsize;
Size -= argsize;
#if FMT_FUZZ_SEPARATE_ALLOCATION
// allocates as tight as possible, making it easier to catch buffer overruns.
std::vector<char> fmtstringbuffer(Size);
std::memcpy(fmtstringbuffer.data(), Data, Size);
auto fmtstring = fmt::string_view(fmtstringbuffer.data(), Size);
#else
auto fmtstring = fmt::string_view(fmt_fuzzer::as_chars(Data), Size);
#endif
#if FMT_FUZZ_FORMAT_TO_STRING
std::string message = fmt::format(fmtstring, fmt::arg(argname, item1));
#else
fmt::memory_buffer outbuf;
fmt::format_to(outbuf, fmtstring, fmt::arg(argname, item1));
#endif
}
// for dynamic dispatching to an explicit instantiation
template <typename Callback> void invoke(int index, Callback callback) {
switch (index) {
case 0:
callback(bool{});
break;
case 1:
callback(char{});
break;
case 2:
using sc = signed char;
callback(sc{});
break;
case 3:
using uc = unsigned char;
callback(uc{});
break;
case 4:
callback(short{});
break;
case 5:
using us = unsigned short;
callback(us{});
break;
case 6:
callback(int{});
break;
case 7:
callback(unsigned{});
break;
case 8:
callback(long{});
break;
case 9:
using ul = unsigned long;
callback(ul{});
break;
case 10:
callback(float{});
break;
case 11:
callback(double{});
break;
case 12:
using LD = long double;
callback(LD{});
break;
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
if (Size <= 3) {
return 0;
}
// switch types depending on the first byte of the input
const auto first = Data[0] & 0x0F;
const unsigned int second = (Data[0] & 0xF0) >> 4;
Data++;
Size--;
auto outerfcn = [=](auto param1) {
invoke_fmt<decltype(param1)>(Data, Size, second);
};
try {
invoke(first, outerfcn);
} catch (std::exception& /*e*/) {
}
return 0;
}

View file

@ -0,0 +1,91 @@
// Copyright (c) 2019, Paul Dreik
// For the license information refer to format.h.
#include <cstdint>
#include <exception>
#include <fmt/chrono.h>
#include "fuzzer-common.h"
template <typename T, typename Repr>
const T* from_repr(const Repr& r) { return &r; }
template <>
const std::tm* from_repr<std::tm>(const std::time_t& t) {
return std::localtime(&t);
}
template <typename T, typename Repr = T>
void invoke_fmt(const uint8_t* data, size_t size) {
static_assert(sizeof(Repr) <= fixed_size, "Nfixed is too small");
if (size <= fixed_size) return;
auto repr = assign_from_buf<Repr>(data);
const T* value = from_repr<T>(repr);
if (!value) return;
data += fixed_size;
size -= fixed_size;
data_to_string format_str(data, size);
try {
#if FMT_FUZZ_FORMAT_TO_STRING
std::string message = fmt::format(format_str.get(), *value);
#else
fmt::memory_buffer message;
fmt::format_to(message, format_str.get(), *value);
#endif
} catch (std::exception&) {
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
if (size <= 3) return 0;
const auto first = data[0];
data++;
size--;
switch (first) {
case 0:
invoke_fmt<bool>(data, size);
break;
case 1:
invoke_fmt<char>(data, size);
break;
case 2:
invoke_fmt<unsigned char>(data, size);
break;
case 3:
invoke_fmt<signed char>(data, size);
break;
case 4:
invoke_fmt<short>(data, size);
break;
case 5:
invoke_fmt<unsigned short>(data, size);
break;
case 6:
invoke_fmt<int>(data, size);
break;
case 7:
invoke_fmt<unsigned int>(data, size);
break;
case 8:
invoke_fmt<long>(data, size);
break;
case 9:
invoke_fmt<unsigned long>(data, size);
break;
case 10:
invoke_fmt<float>(data, size);
break;
case 11:
invoke_fmt<double>(data, size);
break;
case 12:
invoke_fmt<long double>(data, size);
break;
case 13:
invoke_fmt<std::tm, std::time_t>(data, size);
break;
}
return 0;
}

View file

@ -1,131 +0,0 @@
// Copyright (c) 2019, Paul Dreik
// License: see LICENSE.rst in the fmt root directory
#include <fmt/core.h>
#include <cstdint>
#include <stdexcept>
#include <type_traits>
#include <vector>
#include <fmt/chrono.h>
#include "fuzzer_common.h"
using fmt_fuzzer::Nfixed;
template <typename Item>
void invoke_fmt(const uint8_t* Data, size_t Size) {
constexpr auto N = sizeof(Item);
static_assert(N <= Nfixed, "Nfixed is too small");
if (Size <= Nfixed) {
return;
}
const Item item = fmt_fuzzer::assignFromBuf<Item>(Data);
Data += Nfixed;
Size -= Nfixed;
#if FMT_FUZZ_SEPARATE_ALLOCATION
// allocates as tight as possible, making it easier to catch buffer overruns.
std::vector<char> fmtstringbuffer(Size);
std::memcpy(fmtstringbuffer.data(), Data, Size);
auto fmtstring = fmt::string_view(fmtstringbuffer.data(), Size);
#else
auto fmtstring = fmt::string_view(fmt_fuzzer::as_chars(Data), Size);
#endif
#if FMT_FUZZ_FORMAT_TO_STRING
std::string message = fmt::format(fmtstring, item);
#else
fmt::memory_buffer message;
fmt::format_to(message, fmtstring, item);
#endif
}
void invoke_fmt_time(const uint8_t* Data, size_t Size) {
using Item = std::time_t;
constexpr auto N = sizeof(Item);
static_assert(N <= Nfixed, "Nfixed too small");
if (Size <= Nfixed) {
return;
}
const Item item = fmt_fuzzer::assignFromBuf<Item>(Data);
Data += Nfixed;
Size -= Nfixed;
#if FMT_FUZZ_SEPARATE_ALLOCATION
// allocates as tight as possible, making it easier to catch buffer overruns.
std::vector<char> fmtstringbuffer(Size);
std::memcpy(fmtstringbuffer.data(), Data, Size);
auto fmtstring = fmt::string_view(fmtstringbuffer.data(), Size);
#else
auto fmtstring = fmt::string_view(fmt_fuzzer::as_chars(Data), Size);
#endif
auto* b = std::localtime(&item);
if (b) {
#if FMT_FUZZ_FORMAT_TO_STRING
std::string message = fmt::format(fmtstring, *b);
#else
fmt::memory_buffer message;
fmt::format_to(message, fmtstring, *b);
#endif
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
if (Size <= 3) {
return 0;
}
const auto first = Data[0];
Data++;
Size--;
try {
switch (first) {
case 0:
invoke_fmt<bool>(Data, Size);
break;
case 1:
invoke_fmt<char>(Data, Size);
break;
case 2:
invoke_fmt<unsigned char>(Data, Size);
break;
case 3:
invoke_fmt<signed char>(Data, Size);
break;
case 4:
invoke_fmt<short>(Data, Size);
break;
case 5:
invoke_fmt<unsigned short>(Data, Size);
break;
case 6:
invoke_fmt<int>(Data, Size);
break;
case 7:
invoke_fmt<unsigned int>(Data, Size);
break;
case 8:
invoke_fmt<long>(Data, Size);
break;
case 9:
invoke_fmt<unsigned long>(Data, Size);
break;
case 10:
invoke_fmt<float>(Data, Size);
break;
case 11:
invoke_fmt<double>(Data, Size);
break;
case 12:
invoke_fmt<long double>(Data, Size);
break;
case 13:
invoke_fmt_time(Data, Size);
break;
default:
break;
}
} catch (std::exception& /*e*/) {
}
return 0;
}

View file

@ -1,116 +0,0 @@
// Copyright (c) 2019, Paul Dreik
// License: see LICENSE.rst in the fmt root directory
#include <fmt/format.h>
#include <fmt/printf.h>
#include <cstdint>
#include <stdexcept>
#include "fuzzer_common.h"
using fmt_fuzzer::Nfixed;
template <typename Item1, typename Item2>
void invoke_fmt(const uint8_t* Data, size_t Size) {
constexpr auto N1 = sizeof(Item1);
constexpr auto N2 = sizeof(Item2);
static_assert(N1 <= Nfixed, "size1 exceeded");
static_assert(N2 <= Nfixed, "size2 exceeded");
if (Size <= Nfixed + Nfixed) {
return;
}
Item1 item1 = fmt_fuzzer::assignFromBuf<Item1>(Data);
Data += Nfixed;
Size -= Nfixed;
Item2 item2 = fmt_fuzzer::assignFromBuf<Item2>(Data);
Data += Nfixed;
Size -= Nfixed;
auto fmtstring = fmt::string_view(fmt_fuzzer::as_chars(Data), Size);
#if FMT_FUZZ_FORMAT_TO_STRING
std::string message = fmt::format(fmtstring, item1, item2);
#else
fmt::memory_buffer message;
fmt::format_to(message, fmtstring, item1, item2);
#endif
}
// for dynamic dispatching to an explicit instantiation
template <typename Callback> void invoke(int index, Callback callback) {
switch (index) {
case 0:
callback(bool{});
break;
case 1:
callback(char{});
break;
case 2:
using sc = signed char;
callback(sc{});
break;
case 3:
using uc = unsigned char;
callback(uc{});
break;
case 4:
callback(short{});
break;
case 5:
using us = unsigned short;
callback(us{});
break;
case 6:
callback(int{});
break;
case 7:
callback(unsigned{});
break;
case 8:
callback(long{});
break;
case 9:
using ul = unsigned long;
callback(ul{});
break;
case 10:
callback(float{});
break;
case 11:
callback(double{});
break;
case 12:
using LD = long double;
callback(LD{});
break;
case 13:
using ptr = void*;
callback(ptr{});
break;
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
if (Size <= 3) {
return 0;
}
// switch types depending on the first byte of the input
const auto first = Data[0] & 0x0F;
const auto second = (Data[0] & 0xF0) >> 4;
Data++;
Size--;
auto outer = [=](auto param1) {
auto inner = [=](auto param2) {
invoke_fmt<decltype(param1), decltype(param2)>(Data, Size);
};
invoke(second, inner);
};
try {
invoke(first, outer);
} catch (std::exception& /*e*/) {
}
return 0;
}

View file

@ -0,0 +1,105 @@
// Copyright (c) 2019, Paul Dreik
// For the license information refer to format.h.
#include <cstdint>
#include <exception>
#include <string>
#include <fmt/format.h>
#include "fuzzer-common.h"
template <typename Item1, typename Item2>
void invoke_fmt(const uint8_t* data, size_t size) {
static_assert(sizeof(Item1) <= fixed_size, "size1 exceeded");
static_assert(sizeof(Item2) <= fixed_size, "size2 exceeded");
if (size <= fixed_size + fixed_size) return;
const Item1 item1 = assign_from_buf<Item1>(data);
data += fixed_size;
size -= fixed_size;
const Item2 item2 = assign_from_buf<Item2>(data);
data += fixed_size;
size -= fixed_size;
auto format_str = fmt::string_view(as_chars(data), size);
#if FMT_FUZZ_FORMAT_TO_STRING
std::string message = fmt::format(format_str, item1, item2);
#else
fmt::memory_buffer message;
fmt::format_to(message, format_str, item1, item2);
#endif
}
// For dynamic dispatching to an explicit instantiation.
template <typename Callback> void invoke(int index, Callback callback) {
switch (index) {
case 0:
callback(bool());
break;
case 1:
callback(char());
break;
case 2:
using sc = signed char;
callback(sc());
break;
case 3:
using uc = unsigned char;
callback(uc());
break;
case 4:
callback(short());
break;
case 5:
using us = unsigned short;
callback(us());
break;
case 6:
callback(int());
break;
case 7:
callback(unsigned());
break;
case 8:
callback(long());
break;
case 9:
using ul = unsigned long;
callback(ul());
break;
case 10:
callback(float());
break;
case 11:
callback(double());
break;
case 12:
using LD = long double;
callback(LD());
break;
case 13:
using ptr = void*;
callback(ptr());
break;
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
if (size <= 3) return 0;
// Switch types depending on the first byte of the input.
const auto type1 = data[0] & 0x0F;
const auto type2 = (data[0] & 0xF0) >> 4;
data++;
size--;
try {
invoke(type1, [=](auto param1) {
invoke(type2, [=](auto param2) {
invoke_fmt<decltype(param1), decltype(param2)>(data, size);
});
});
} catch (std::exception&) {
}
return 0;
}

View file

@ -1,112 +0,0 @@
// Copyright (c) 2019, Paul Dreik
// License: see LICENSE.rst in the fmt root directory
#include <fmt/format.h>
#include <cstdint>
#include <stdexcept>
#include <type_traits>
#include "fuzzer_common.h"
constexpr auto Nfixed = fmt_fuzzer::Nfixed;
template <typename Item1, typename Item2>
void invoke_fmt(const uint8_t* Data, size_t Size) {
constexpr auto N1 = sizeof(Item1);
constexpr auto N2 = sizeof(Item2);
static_assert(N1 <= Nfixed, "size1 exceeded");
static_assert(N2 <= Nfixed, "size2 exceeded");
if (Size <= Nfixed + Nfixed) {
return;
}
const Item1 item1 = fmt_fuzzer::assignFromBuf<Item1>(Data);
Data += Nfixed;
Size -= Nfixed;
const Item2 item2 = fmt_fuzzer::assignFromBuf<Item2>(Data);
Data += Nfixed;
Size -= Nfixed;
auto fmtstring = fmt::string_view(fmt_fuzzer::as_chars(Data), Size);
#if FMT_FUZZ_FORMAT_TO_STRING
std::string message = fmt::format(fmtstring, item1, item2);
#else
fmt::memory_buffer message;
fmt::format_to(message, fmtstring, item1, item2);
#endif
}
// for dynamic dispatching to an explicit instantiation
template <typename Callback> void invoke(int index, Callback callback) {
switch (index) {
case 0:
callback(bool{});
break;
case 1:
callback(char{});
break;
case 2:
using sc = signed char;
callback(sc{});
break;
case 3:
using uc = unsigned char;
callback(uc{});
break;
case 4:
callback(short{});
break;
case 5:
using us = unsigned short;
callback(us{});
break;
case 6:
callback(int{});
break;
case 7:
callback(unsigned{});
break;
case 8:
callback(long{});
break;
case 9:
using ul = unsigned long;
callback(ul{});
break;
case 10:
callback(float{});
break;
case 11:
callback(double{});
break;
case 12:
using LD = long double;
callback(LD{});
break;
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
if (Size <= 3) {
return 0;
}
// switch types depending on the first byte of the input
const auto first = Data[0] & 0x0F;
const auto second = (Data[0] & 0xF0) >> 4;
Data++;
Size--;
auto outer = [=](auto param1) {
auto inner = [=](auto param2) {
invoke_fmt<decltype(param1), decltype(param2)>(Data, Size);
};
invoke(second, inner);
};
try {
invoke(first, outer);
} catch (std::exception& /*e*/) {
}
return 0;
}

View file

@ -1,75 +0,0 @@
// Formatting library for C++ - Grisu tests
//
// Copyright (c) 2012 - present, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#include "fmt/format.h"
#include "gtest.h"
static bool reported_skipped;
#undef TEST
#define TEST(test_fixture, test_name) \
void test_fixture##test_name(); \
GTEST_TEST(test_fixture, test_name) { \
if (FMT_USE_GRISU) { \
test_fixture##test_name(); \
} else if (!reported_skipped) { \
reported_skipped = true; \
fmt::print("Skipping Grisu tests.\n"); \
} \
} \
void test_fixture##test_name()
TEST(GrisuTest, NaN) {
auto nan = std::numeric_limits<double>::quiet_NaN();
EXPECT_EQ("nan", fmt::format("{}", nan));
EXPECT_EQ("-nan", fmt::format("{}", -nan));
}
TEST(GrisuTest, Inf) {
auto inf = std::numeric_limits<double>::infinity();
EXPECT_EQ("inf", fmt::format("{}", inf));
EXPECT_EQ("-inf", fmt::format("{}", -inf));
}
TEST(GrisuTest, Zero) { EXPECT_EQ("0.0", fmt::format("{}", 0.0)); }
TEST(GrisuTest, Round) {
EXPECT_EQ("1.9156918820264798e-56",
fmt::format("{}", 1.9156918820264798e-56));
EXPECT_EQ("0.0000", fmt::format("{:.4f}", 7.2809479766055470e-15));
}
TEST(GrisuTest, Prettify) {
EXPECT_EQ("0.0001", fmt::format("{}", 1e-4));
EXPECT_EQ("1e-05", fmt::format("{}", 1e-5));
EXPECT_EQ("9.999e-05", fmt::format("{}", 9.999e-5));
EXPECT_EQ("10000000000.0", fmt::format("{}", 1e10));
EXPECT_EQ("100000000000.0", fmt::format("{}", 1e11));
EXPECT_EQ("12340000000.0", fmt::format("{}", 1234e7));
EXPECT_EQ("12.34", fmt::format("{}", 1234e-2));
EXPECT_EQ("0.001234", fmt::format("{}", 1234e-6));
EXPECT_EQ("0.1", fmt::format("{}", 0.1f));
EXPECT_EQ("0.10000000149011612", fmt::format("{}", double(0.1f)));
}
TEST(GrisuTest, ZeroPrecision) { EXPECT_EQ("1", fmt::format("{:.0}", 1.0)); }
TEST(GrisuTest, Fallback) {
EXPECT_EQ("1e+23", fmt::format("{}", 1e23));
EXPECT_EQ("9e-265", fmt::format("{}", 9e-265));
EXPECT_EQ("5.423717798060526e+125",
fmt::format("{}", 5.423717798060526e+125));
EXPECT_EQ("1.372371880954233e-288",
fmt::format("{}", 1.372371880954233e-288));
EXPECT_EQ("55388492.622190244", fmt::format("{}", 55388492.622190244));
EXPECT_EQ("2.2506787569811123e-253",
fmt::format("{}", 2.2506787569811123e-253));
EXPECT_EQ("1103618912042992.8", fmt::format("{}", 1103618912042992.8));
// pow(2, -25) - assymetric boundaries:
EXPECT_EQ("2.9802322387695312e-08",
fmt::format("{}", 2.9802322387695312e-08));
}

View file

@ -145,7 +145,13 @@ std::string read(fmt::file& f, size_t count);
read(file, fmt::string_view(expected_content).size()))
#else
# define EXPECT_WRITE(file, statement, expected_output) SUCCEED()
# define EXPECT_WRITE(file, statement, expected_output) \
do { \
(void)(file); \
(void)(statement); \
(void)(expected_output); \
SUCCEED(); \
} while (false)
#endif // FMT_USE_FCNTL
template <typename Mock> struct ScopedMock : testing::StrictMock<Mock> {

View file

@ -7,6 +7,8 @@
#include "fmt/locale.h"
#include <complex>
#include "gmock.h"
using fmt::detail::max_value;
@ -50,6 +52,7 @@ TEST(LocaleTest, Format) {
EXPECT_EQ("1234567", fmt::format(std::locale(), "{:L}", 1234567));
EXPECT_EQ("1~234~567", fmt::format(loc, "{:L}", 1234567));
EXPECT_EQ("-1~234~567", fmt::format(loc, "{:L}", -1234567));
EXPECT_EQ("-256", fmt::format(loc, "{:L}", -256));
fmt::format_arg_store<fmt::format_context, int> as{1234567};
EXPECT_EQ("1~234~567", fmt::vformat(loc, "{:L}", fmt::format_args(as)));
std::string s;
@ -106,4 +109,52 @@ TEST(LocaleTest, DoubleFormatter) {
EXPECT_STREQ("12,345", buf);
}
FMT_BEGIN_NAMESPACE
template <class charT> struct formatter<std::complex<double>, charT> {
private:
detail::dynamic_format_specs<char> specs_;
public:
typename basic_format_parse_context<charT>::iterator parse(
basic_format_parse_context<charT>& ctx) {
using handler_type =
detail::dynamic_specs_handler<basic_format_parse_context<charT>>;
detail::specs_checker<handler_type> handler(handler_type(specs_, ctx),
detail::type::string_type);
auto it = parse_format_specs(ctx.begin(), ctx.end(), handler);
detail::parse_float_type_spec(specs_, ctx.error_handler());
return it;
}
template <class FormatContext>
typename FormatContext::iterator format(const std::complex<double>& c,
FormatContext& ctx) {
detail::handle_dynamic_spec<detail::precision_checker>(
specs_.precision, specs_.precision_ref, ctx);
auto format_specs = std::string();
if (specs_.precision > 0)
format_specs = fmt::format(".{}", specs_.precision);
if (specs_.type)
format_specs += specs_.type;
auto real = fmt::format(ctx.locale().template get<std::locale>(),
"{:" + format_specs + "}", c.real());
auto imag = fmt::format(ctx.locale().template get<std::locale>(),
"{:" + format_specs + "}", c.imag());
auto fill_align_width = std::string();
if (specs_.width > 0)
fill_align_width = fmt::format(">{}", specs_.width);
return format_to(
ctx.out(), "{:" + fill_align_width + "}",
fmt::format(c.real() != 0 ? "({0}+{1}i)" : "{1}i", real, imag));
}
};
FMT_END_NAMESPACE
TEST(FormatTest, Complex) {
std::string s = fmt::format("{}", std::complex<double>(1, 2));
EXPECT_EQ(s, "(1+2i)");
EXPECT_EQ(fmt::format("{:.2f}", std::complex<double>(1, 2)), "(1.00+2.00i)");
EXPECT_EQ(fmt::format("{:8}", std::complex<double>(1, 2)), " (1+2i)");
}
#endif // FMT_STATIC_THOUSANDS_SEPARATOR

View file

@ -81,9 +81,9 @@ TEST(UtilTest, FormatWindowsError) {
EXPECT_EQ(fmt::format("test: {}", utf8_message.str()),
fmt::to_string(actual_message));
actual_message.resize(0);
auto max_size = fmt::detail::max_value<size_t>();
auto max_size = fmt::detail::max_value<size_t>() / 2;
fmt::detail::format_windows_error(actual_message, ERROR_FILE_EXISTS,
fmt::string_view(0, max_size));
fmt::string_view(nullptr, max_size));
EXPECT_EQ(fmt::format("error {}", ERROR_FILE_EXISTS),
fmt::to_string(actual_message));
}
@ -287,26 +287,38 @@ TEST(BufferedFileTest, Fileno) {
EXPECT_READ(copy, FILE_CONTENT);
}
TEST(DirectBufferedFileTest, Print) {
fmt::direct_buffered_file out(
"test-file", fmt::file::WRONLY | fmt::file::CREATE);
fmt::print(out, "The answer is {}.\n", 42);
TEST(OStreamTest, Move) {
fmt::ostream out = fmt::output_file("test-file");
fmt::ostream moved(std::move(out));
moved.print("hello");
}
TEST(OStreamTest, Print) {
fmt::ostream out = fmt::output_file("test-file");
out.print("The answer is {}.\n", 42);
out.close();
file in("test-file", file::RDONLY);
EXPECT_READ(in, "The answer is 42.\n");
}
TEST(DirectBufferedFileTest, BufferBoundary) {
TEST(OStreamTest, BufferBoundary) {
auto str = std::string(4096, 'x');
fmt::direct_buffered_file out(
"test-file", fmt::file::WRONLY | fmt::file::CREATE);
fmt::print(out, "{}", str);
fmt::print(out, "{}", str);
fmt::ostream out = fmt::output_file("test-file");
out.print("{}", str);
out.print("{}", str);
out.close();
file in("test-file", file::RDONLY);
EXPECT_READ(in, str + str);
}
TEST(OStreamTest, BufferSize) {
fmt::ostream out = fmt::output_file("test-file", fmt::buffer_size=1);
out.print("{}", "foo");
out.close();
file in("test-file", file::RDONLY);
EXPECT_READ(in, "foo");
}
TEST(FileTest, DefaultCtor) {
file f;
EXPECT_EQ(-1, f.descriptor());

View file

@ -5,7 +5,6 @@
//
// For the license information refer to format.h.
#define FMT_STRING_ALIAS 1
#include "fmt/format.h"
struct test {};
@ -24,6 +23,7 @@ template <> struct formatter<test> : formatter<int> {
#include <sstream>
#include "fmt/ostream.h"
#include "fmt/ranges.h"
#include "gmock.h"
#include "gtest-extra.h"
#include "util.h"
@ -75,8 +75,8 @@ struct test_arg_formatter
TEST(OStreamTest, CustomArg) {
fmt::memory_buffer buffer;
fmt::detail::buffer<char>& base = buffer;
fmt::format_context ctx(std::back_inserter(base), fmt::format_args());
fmt::format_context ctx(fmt::detail::buffer_appender<char>{buffer},
fmt::format_args());
fmt::format_specs spec;
test_arg_formatter af(ctx, spec);
fmt::visit_format_arg(
@ -150,8 +150,9 @@ TEST(OStreamTest, WriteToOStreamMaxSize) {
std::streamsize max_streamsize = fmt::detail::max_value<std::streamsize>();
if (max_size <= fmt::detail::to_unsigned(max_streamsize)) return;
struct test_buffer : fmt::detail::buffer<char> {
explicit test_buffer(size_t size) { resize(size); }
struct test_buffer final : fmt::detail::buffer<char> {
explicit test_buffer(size_t size)
: fmt::detail::buffer<char>(nullptr, size, size) {}
void grow(size_t) {}
} buffer(max_size);
@ -289,9 +290,20 @@ std::ostream& operator<<(std::ostream& os,
TEST(OStreamTest, FormatExplicitlyConvertibleToStdStringView) {
EXPECT_EQ("bar", fmt::format("{}", explicitly_convertible_to_string_like()));
}
#endif // FMT_USE_STRING_VIEW
struct streamable_and_convertible_to_bool {
operator bool() const { return true; }
};
std::ostream& operator<<(std::ostream& os, streamable_and_convertible_to_bool) {
return os << "foo";
}
TEST(OStreamTest, FormatConvertibleToBool) {
EXPECT_EQ("foo", fmt::format("{}", streamable_and_convertible_to_bool()));
}
struct copyfmt_test {};
std::ostream& operator<<(std::ostream& os, copyfmt_test) {
@ -307,3 +319,12 @@ TEST(OStreamTest, CopyFmt) {
TEST(OStreamTest, CompileTimeString) {
EXPECT_EQ("42", fmt::format(FMT_STRING("{}"), 42));
}
TEST(OStreamTest, ToString) {
EXPECT_EQ("ABC", fmt::to_string(fmt_test::ABC()));
}
TEST(OStreamTest, Range) {
auto strs = std::vector<TestString>{TestString("foo"), TestString("bar")};
EXPECT_EQ("{foo, bar}", format("{}", strs));
}

View file

@ -54,7 +54,7 @@ TEST(RangesTest, FormatTuple) {
TEST(RangesTest, JoinTuple) {
// Value tuple args
std::tuple<char, int, float> t1 = std::make_tuple('a', 1, 2.0f);
EXPECT_EQ("(a, 1, 2.0)", fmt::format("({})", fmt::join(t1, ", ")));
EXPECT_EQ("(a, 1, 2)", fmt::format("({})", fmt::join(t1, ", ")));
// Testing lvalue tuple args
int x = 4;
@ -67,7 +67,7 @@ TEST(RangesTest, JoinTuple) {
// Single element tuple
std::tuple<float> t4{4.0f};
EXPECT_EQ("4.0", fmt::format("{}", fmt::join(t4, "/")));
EXPECT_EQ("4", fmt::format("{}", fmt::join(t4, "/")));
}
TEST(RangesTest, JoinInitializerList) {
@ -141,15 +141,63 @@ TEST(RangesTest, FormatStringLike) {
#endif // FMT_USE_STRING_VIEW
struct zstring_sentinel {};
bool operator==(const char* p, zstring_sentinel) { return *p == '\0'; }
bool operator!=(const char* p, zstring_sentinel) { return *p != '\0'; }
struct zstring {
const char* p;
const char* begin() const { return p; }
zstring_sentinel end() const { return {}; }
};
TEST(RangesTest, JoinSentinel) {
zstring hello{"hello"};
EXPECT_EQ("{'h', 'e', 'l', 'l', 'o'}", fmt::format("{}", hello));
EXPECT_EQ("h_e_l_l_o", fmt::format("{}", fmt::join(hello, "_")));
}
// A range that provides non-const only begin()/end() to test fmt::join handles
// that
//
// Some ranges (eg those produced by range-v3's views::filter()) can cache
// information during iteration so they only provide non-const begin()/end().
template <typename T> class non_const_only_range {
private:
std::vector<T> vec;
public:
using const_iterator = typename ::std::vector<T>::const_iterator;
template <typename... Args>
explicit non_const_only_range(Args&&... args)
: vec(::std::forward<Args>(args)...) {}
const_iterator begin() { return vec.begin(); }
const_iterator end() { return vec.end(); }
};
TEST(RangesTest, JoinRange) {
non_const_only_range<int> x(3u, 0);
EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(x, ",")));
EXPECT_EQ(
"0,0,0",
fmt::format("{}", fmt::join(non_const_only_range<int>(3u, 0), ",")));
std::vector<int> y(3u, 0);
EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(y, ",")));
EXPECT_EQ("0,0,0",
fmt::format("{}", fmt::join(std::vector<int>(3u, 0), ",")));
const std::vector<int> z(3u, 0);
EXPECT_EQ("0,0,0", fmt::format("{}", fmt::join(z, ",")));
}
#if !FMT_MSC_VER || FMT_MSC_VER >= 1927
struct unformattable {};
TEST(RangesTest, UnformattableRange) {
EXPECT_FALSE((fmt::has_formatter<std::vector<unformattable>,
fmt::format_context>::value));
}
#endif