diff --git a/.github/pull_request_template b/.github/pull_request_template deleted file mode 100644 index dcfc0fdb..00000000 --- a/.github/pull_request_template +++ /dev/null @@ -1,3 +0,0 @@ - diff --git a/.gitignore b/.gitignore index c57070c5..1e6172fe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,17 @@ +.vscode/ + +*.iml +.idea/ +.externalNativeBuild/ +.gradle/ +gradle/ +gradlew* +local.properties +build/ + bin/ /_CPack_Packages +/CMakeScripts /doc/doxyxml /doc/html virtualenv @@ -8,6 +20,7 @@ virtualenv *~ *.a *.so* +*.xcodeproj *.zip cmake_install.cmake CPack*.cmake @@ -15,5 +28,6 @@ fmt-*.cmake CTestTestfile.cmake CMakeCache.txt CMakeFiles +FMT.build Makefile run-msbuild.bat diff --git a/.travis.yml b/.travis.yml index c359852e..cbc024d7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,27 +1,129 @@ language: cpp dist: trusty -sudo: required # the doc target uses sudo to install dependencies +sudo: false + +os: linux + +git: + depth: 1 -os: - - linux - - osx env: global: - secure: |- - Gsnp9ERFnXt+diCfc7Vb72g+7HDn1MCHvw4zfUDdoBh9bxxFlLQRlzZZfwWhzni57lflrt - 0QHXafu+oBVOJuNv6WauV3+ZyuWIQRmNGjZFNLvZsXHK/dyad2vGQBPvEkb+8l/aCyTpbr - 6pxmyzLHSn1ZR7OX5rfPvwM3tOyZ3H0= - matrix: - - BUILD=Doc - - BUILD=Debug STANDARD=0x - - BUILD=Release STANDARD=98 - - BUILD=Release STANDARD=0x + a1eovNn4uol9won7ghr67eD3/59oeESN+G9bWE+ecI1V6yRseG9whniGhIpC/YfMW/Qz5I + 5sxSmFjaw9bxCISNwUIrL1O5x2AmRYTnFcXk4dFsUvlZg+WeF/aKyBYCNRM8C2ndbBmtAO + o1F2EwFbiso0EmtzhAPs19ujiVxkLn4= matrix: - exclude: - - os: osx - env: BUILD=Doc + include: + # Documentation + - env: BUILD=Doc + sudo: required + # g++ 6 on Linux with C++14 + - env: COMPILER=g++-6 BUILD=Debug STANDARD=14 + compiler: gcc + addons: + apt: + update: true + sources: + - ubuntu-toolchain-r-test + packages: + - g++-6 + - env: COMPILER=g++-6 BUILD=Release STANDARD=14 + compiler: gcc + addons: + apt: + update: true + sources: + - ubuntu-toolchain-r-test + packages: + - g++-6 + # Apple clang on OS X with C++14 + - env: BUILD=Debug STANDARD=14 + compiler: clang + os: osx + - env: BUILD=Release STANDARD=14 + compiler: clang + os: osx + # clang 6.0 on Linux with C++14 + - env: COMPILER=clang++-6.0 BUILD=Debug STANDARD=14 + compiler: clang + addons: + apt: + update: true + packages: + - clang-6.0 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-trusty + - llvm-toolchain-trusty-6.0 + # clang 4.0 on Linux with C++14 + - env: COMPILER=clang++-4.0 BUILD=Debug STANDARD=11 + compiler: clang + addons: + apt: + update: true + packages: + - clang-4.0 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-trusty + - llvm-toolchain-trusty-4.0 + # g++ 4.8 on Linux with C++11 + - env: COMPILER=g++-4.8 BUILD=Debug STANDARD=11 + compiler: gcc + # g++ 4.4 on Linux with C++11 + - env: COMPILER=g++-4.4 BUILD=Debug STANDARD=11 + compiler: gcc + addons: + apt: + update: true + packages: + - g++-4.4 + sources: + - ubuntu-toolchain-r-test + # Android +# - language: android +# android: +# addons: +# apt: +# update: true +# components: +# - tools +# - platform-tools +# - android-21 +# - sys-img-armeabi-v7a-android-21 +# env: +# - ANDROID=true +# before_install: +# - git submodule update --init --recursive +# - sudo apt-get install wget unzip tree +# install: +# # Accept SDK Licenses + Install NDK +# - yes | sdkmanager --update > /dev/null 2>&1 +# - sdkmanager ndk-bundle > /dev/null 2>&1 +# # Download Gradle 4.3.1 +# - wget https://services.gradle.org/distributions/gradle-4.3.1-bin.zip +# - mkdir -p gradle +# - unzip -q -d ./gradle gradle-4.3.1-bin.zip +# - export GRADLE=${TRAVIS_BUILD_DIR}/gradle/gradle-4.3.1/bin/gradle +# before_script: +# - bash $GRADLE --version +# - cd ./support +# script: +# - bash $GRADLE clean assemble +# after_success: +# - cd ${TRAVIS_BUILD_DIR} +# - tree ./libs + allow_failures: + # Errors + - env: COMPILER=g++-4.4 BUILD=Debug STANDARD=11 + compiler: gcc + +before_script: + - if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then export CXX=${COMPILER}; fi + - if [[ "${BUILD}" != "Doc" ]]; then ${CXX} --version; fi script: - support/travis-build.py diff --git a/CMakeLists.txt b/CMakeLists.txt index d99babdb..f872e3c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,20 +1,18 @@ -message(STATUS "CMake version: ${CMAKE_VERSION}") +cmake_minimum_required(VERSION 3.1.0) -cmake_minimum_required(VERSION 2.8.12) - -if (POLICY CMP0048) # Version variables - cmake_policy(SET CMP0048 OLD) -endif () - -if (POLICY CMP0063) # Visibility - cmake_policy(SET CMP0063 OLD) -endif (POLICY CMP0063) +# Use newer policies if available, up to most recent tested version of CMake. +if(${CMAKE_VERSION} VERSION_LESS 3.11) + 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) # or if it is the master project. set(MASTER_PROJECT OFF) if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) set(MASTER_PROJECT ON) + message(STATUS "CMake version: ${CMAKE_VERSION}") endif () # Joins arguments and places the results in ${result_var}. @@ -36,19 +34,19 @@ if (NOT CMAKE_BUILD_TYPE) endif () option(FMT_PEDANTIC "Enable extra warnings and expensive tests." OFF) +option(FMT_WERROR "Halt the compilation with an error on compiler warnings." OFF) # Options that control generation of various targets. option(FMT_DOC "Generate the doc target." ${MASTER_PROJECT}) option(FMT_INSTALL "Generate the install target." ${MASTER_PROJECT}) option(FMT_TEST "Generate the test target." ${MASTER_PROJECT}) -option(FMT_USE_CPP11 "Enable the addition of C++11 compiler flags." ON) project(FMT) -# Starting with cmake 3.0 VERSION is part of the project command. -file(READ fmt/format.h format_h) -if (NOT format_h MATCHES "FMT_VERSION ([0-9]+)([0-9][0-9])([0-9][0-9])") - message(FATAL_ERROR "Cannot get FMT_VERSION from format.h.") +# Get version from core.h +file(READ include/fmt/core.h core_h) +if (NOT core_h MATCHES "FMT_VERSION ([0-9]+)([0-9][0-9])([0-9][0-9])") + message(FATAL_ERROR "Cannot get FMT_VERSION from core.h.") endif () # Use math to skip leading zeros if any. math(EXPR CPACK_PACKAGE_VERSION_MAJOR ${CMAKE_MATCH_1}) @@ -65,10 +63,59 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/support/cmake") -include(cxx11) +include(cxx14) +include(CheckCXXCompilerFlag) -if (CMAKE_COMPILER_IS_GNUCXX OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) - set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -Wshadow -pedantic) +if (CMAKE_CXX_COMPILER_ID MATCHES "GNU") + set(PEDANTIC_COMPILE_FLAGS -pedantic-errors -Wall -Wextra -pedantic + -Wold-style-cast -Wfloat-equal -Wlogical-op -Wundef + -Wredundant-decls -Wshadow -Wwrite-strings -Wpointer-arith + -Wcast-qual -Wformat=2 -Wmissing-include-dirs + -Wcast-align -Wnon-virtual-dtor + -Wctor-dtor-privacy -Wdisabled-optimization + -Winvalid-pch -Woverloaded-virtual + -Wno-ctor-dtor-privacy -Wno-dangling-else -Wno-float-equal + -Wno-format-nonliteral -Wno-sign-conversion -Wno-shadow) + if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6) + set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wnoexcept) + endif () + if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0) + set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wdouble-promotion + -Wtrampolines -Wzero-as-null-pointer-constant -Wuseless-cast + -Wvector-operation-performance -Wsized-deallocation) + endif () + if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0) + set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wshift-overflow=2 + -Wnull-dereference -Wduplicated-cond) + endif () + + set(WERROR_FLAG -Werror) +endif () + +if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(PEDANTIC_COMPILE_FLAGS -Weverything -Wpedantic + -Wno-weak-vtables -Wno-padded -Wno-gnu-statement-expression + -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-reserved-id-macro + -Wno-global-constructors -Wno-disabled-macro-expansion + -Wno-switch-enum -Wno-documentation-unknown-command + -Wno-unused-member-function + -Wno-format-nonliteral -Wno-missing-noreturn -Wno-undefined-func-template + -Wno-shadow -Wno-sign-conversion -Wno-used-but-marked-unused + -Wno-covered-switch-default -Wno-missing-prototypes + -Wno-missing-variable-declarations -Wno-double-promotion) + + set(WERROR_FLAG -Werror) + + check_cxx_compiler_flag(-Wno-zero-as-null-pointer-constant HAS_NULLPTR_WARNING) + if (HAS_NULLPTR_WARNING) + set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} + -Wno-zero-as-null-pointer-constant) + endif () +endif () + +if (MSVC) + set(PEDANTIC_COMPILE_FLAGS /W3) + set(WERROR_FLAG /WX) endif () if (MASTER_PROJECT AND CMAKE_GENERATOR MATCHES "Visual Studio") @@ -94,7 +141,106 @@ else () check_symbol_exists(open fcntl.h HAVE_OPEN) endif () -add_subdirectory(fmt) +function(add_headers VAR) + set(headers ${${VAR}}) + foreach (header ${ARGN}) + set(headers ${headers} include/fmt/${header}) + endforeach() + set(${VAR} ${headers} PARENT_SCOPE) +endfunction() + +# Define the fmt library, its includes and the needed defines. +add_headers(FMT_HEADERS color.h core.h format.h format-inl.h ostream.h printf.h + time.h ranges.h) +set(FMT_SOURCES src/format.cc) +if (HAVE_OPEN) + add_headers(FMT_HEADERS posix.h) + set(FMT_SOURCES ${FMT_SOURCES} src/posix.cc) +endif () + +add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} README.rst ChangeLog.rst) +add_library(fmt::fmt ALIAS fmt) + +if (FMT_WERROR) + target_compile_options(fmt PRIVATE ${WERROR_FLAG}) +endif () +if (FMT_PEDANTIC) + target_compile_options(fmt PRIVATE ${PEDANTIC_COMPILE_FLAGS}) +endif () + +target_include_directories(fmt PUBLIC + $ + $) + +set_target_properties(fmt PROPERTIES + VERSION ${FMT_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR} + DEBUG_POSTFIX d) + +if (BUILD_SHARED_LIBS) + if (UNIX AND NOT APPLE) + # 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) + endif () + target_compile_definitions(fmt PRIVATE FMT_EXPORT INTERFACE FMT_SHARED) +endif () + +add_library(fmt-header-only INTERFACE) +add_library(fmt::fmt-header-only ALIAS fmt-header-only) + +target_compile_definitions(fmt-header-only INTERFACE FMT_HEADER_ONLY=1) + +target_include_directories(fmt-header-only INTERFACE + $ + $) + +# Install targets. +if (FMT_INSTALL) + include(GNUInstallDirs) + include(CMakePackageConfigHelpers) + set(FMT_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/fmt CACHE STRING + "Installation directory for cmake files, relative to ${CMAKE_INSTALL_PREFIX}.") + set(version_config ${PROJECT_BINARY_DIR}/fmt-config-version.cmake) + set(project_config ${PROJECT_BINARY_DIR}/fmt-config.cmake) + set(targets_export_name fmt-targets) + + set (INSTALL_TARGETS fmt) + if (TARGET fmt-header-only) + set(INSTALL_TARGETS ${INSTALL_TARGETS} fmt-header-only) + endif () + + set(FMT_LIB_DIR ${CMAKE_INSTALL_LIBDIR} CACHE STRING + "Installation directory for libraries, relative to ${CMAKE_INSTALL_PREFIX}.") + + set(FMT_INC_DIR ${CMAKE_INSTALL_INCLUDEDIR}/fmt CACHE STRING + "Installation directory for include files, relative to ${CMAKE_INSTALL_PREFIX}.") + + # Generate the version, config and target files into the build directory. + write_basic_package_version_file( + ${version_config} + VERSION ${FMT_VERSION} + COMPATIBILITY AnyNewerVersion) + configure_package_config_file( + ${PROJECT_SOURCE_DIR}/support/cmake/fmt-config.cmake.in + ${project_config} + INSTALL_DESTINATION ${FMT_CMAKE_DIR}) + # Use a namespace because CMake provides better diagnostics for namespaced + # imported targets. + export(TARGETS ${INSTALL_TARGETS} NAMESPACE fmt:: + FILE ${PROJECT_BINARY_DIR}/${targets_export_name}.cmake) + + # Install version, config and target files. + install( + FILES ${project_config} ${version_config} + DESTINATION ${FMT_CMAKE_DIR}) + install(EXPORT ${targets_export_name} DESTINATION ${FMT_CMAKE_DIR} + NAMESPACE fmt::) + + # Install the library and headers. + install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name} + DESTINATION ${FMT_LIB_DIR}) + install(FILES ${FMT_HEADERS} DESTINATION ${FMT_INC_DIR}) +endif () if (FMT_DOC) add_subdirectory(doc) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 506811d4..899b6460 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -6,6 +6,7 @@ All C++ code must adhere to `Google C++ Style Guide exceptions: * Exceptions are permitted -* snake_case should be used instead of UpperCamelCase for function names +* snake_case should be used instead of UpperCamelCase for function and type + names Thanks for contributing! diff --git a/ChangeLog.rst b/ChangeLog.rst index ce0406a9..e158e458 100644 --- a/ChangeLog.rst +++ b/ChangeLog.rst @@ -1,34 +1,648 @@ +5.2.1 - 2018-09-21 +------------------ + +* Fixed ``visit`` lookup issues on gcc 7 & 8 + (`#870 `_). + Thanks `@medithe `_. + +* Fixed linkage errors on older gcc. + +* Prevented ``fmt/range.h`` from specializing ``fmt::basic_string_view`` + (`#865 `_, + `#868 `_). + Thanks `@hhggit (dual) `_. + +* Improved error message when formatting unknown types + (`#872 `_). + Thanks `@foonathan (Jonathan Müller) `_, + +* Disabled templated user-defined literals when compiled under nvcc + (`#875 `_). + Thanks `@CandyGumdrop (Candy Gumdrop) `_, + +* Fixed ``format_to`` formatting to ``wmemory_buffer`` + (`#874 `_). + +5.2.0 - 2018-09-13 +------------------ + +* Optimized format string parsing and argument processing which resulted in up + to 5x speed up on long format strings and significant performance boost on + various benchmarks. For example, version 5.2 is 2.22x faster than 5.1 on + decimal integer formatting with ``format_to`` (macOS, clang-902.0.39.2): + + ================== ======= ======= + Method Time, s Speedup + ================== ======= ======= + fmt::format 5.1 0.58 + fmt::format 5.2 0.35 1.66x + fmt::format_to 5.1 0.51 + fmt::format_to 5.2 0.23 2.22x + sprintf 0.71 + std::to_string 1.01 + std::stringstream 1.73 + ================== ======= ======= + +* Changed the ``fmt`` macro from opt-out to opt-in to prevent name collisions. + To enable it define the ``FMT_STRING_ALIAS`` macro to 1 before including + ``fmt/format.h``: + + .. code:: c++ + + #define FMT_STRING_ALIAS 1 + #include + std::string answer = format(fmt("{}"), 42); + +* Added compile-time format string checks to ``format_to`` overload that takes + ``fmt::memory_buffer`` (`#783 `_): + + .. code:: c++ + + fmt::memory_buffer buf; + // Compile-time error: invalid type specifier. + fmt::format_to(buf, fmt("{:d}"), "foo"); + +* Moved experimental color support to ``fmt/color.h`` and enabled the + new API by default. The old API can be enabled by defining the + ``FMT_DEPRECATED_COLORS`` macro. + +* Added formatting support for types explicitly convertible to + ``fmt::string_view``: + + .. code:: c++ + + struct foo { + explicit operator fmt::string_view() const { return "foo"; } + }; + auto s = format("{}", foo()); + + In particular, this makes formatting function work with + ``folly::StringPiece``. + +* Implemented preliminary support for ``char*_t`` by replacing the ``format`` + function overloads with a single function template parameterized on the string + type. + +* Added support for dynamic argument lists + (`#814 `_, + `#819 `_). + Thanks `@MikePopoloski (Michael Popoloski) + `_. + +* Reduced executable size overhead for embedded targets using newlib nano by + making locale dependency optional + (`#839 `_). + Thanks `@teajay-fr (Thomas Benard) `_. + +* Keep ``noexcept`` specifier when exceptions are disabled + (`#801 `_, + `#810 `_). + Thanks `@qis (Alexej Harm) `_. + +* Fixed formatting of user-defined types providing ``operator<<`` with + ``format_to_n`` + (`#806 `_). + Thanks `@mkurdej (Marek Kurdej) `_. + +* Fixed dynamic linkage of new symbols + (`#808 `_). + +* Fixed global initialization issue + (`#807 `_): + + .. code:: c++ + + // This works on compilers with constexpr support. + static const std::string answer = fmt::format("{}", 42); + +* Fixed various compiler warnings and errors + (`#804 `_, + `#809 `_, + `#811 `_, + `#822 `_, + `#827 `_, + `#830 `_, + `#838 `_, + `#843 `_, + `#844 `_, + `#851 `_, + `#852 `_, + `#854 `_). + Thanks `@henryiii (Henry Schreiner) `_, + `@medithe `_, and + `@eliasdaler (Elias Daler) `_. + +5.1.0 - 2018-07-05 +------------------ + +* Added experimental support for RGB color output enabled with + the ``FMT_EXTENDED_COLORS`` macro: + + .. code:: c++ + + #define FMT_EXTENDED_COLORS + #define FMT_HEADER_ONLY // or compile fmt with FMT_EXTENDED_COLORS defined + #include + + fmt::print(fmt::color::steel_blue, "Some beautiful text"); + + The old API (the ``print_colored`` and ``vprint_colored`` functions and the + ``color`` enum) is now deprecated. + (`#762 `_ + `#767 `_). + thanks `@remotion (remo) `_. + +* Added quotes to strings in ranges and tuples + (`#766 `_). + Thanks `@Remotion (Remo) `_. + +* Made ``format_to`` work with ``basic_memory_buffer`` + (`#776 `_). + +* Added ``vformat_to_n`` and ``wchar_t`` overload of ``format_to_n`` + (`#764 `_, + `#769 `_). + +* Made ``is_range`` and ``is_tuple_like`` part of public (experimental) API + to allow specialization for user-defined types + (`#751 `_, + `#759 `_). + Thanks `@drrlvn (Dror Levin) `_. + +* Added more compilers to continuous integration and increased ``FMT_PEDANTIC`` + warning levels + (`#736 `_). + Thanks `@eliaskosunen (Elias Kosunen) `_. + +* Fixed compilation with MSVC 2013. + +* Fixed handling of user-defined types in ``format_to`` + (`#793 `_). + +* Forced linking of inline ``vformat`` functions into the library + (`#795 `_). + +* Fixed incorrect call to on_align in ``'{:}='`` + (`#750 `_). + +* Fixed floating-point formatting to a non-back_insert_iterator with sign & + numeric alignment specified + (`#756 `_). + +* Fixed formatting to an array with ``format_to_n`` + (`#778 `_). + +* Fixed formatting of more than 15 named arguments + (`#754 `_). + +* Fixed handling of compile-time strings when including ``fmt/ostream.h``. + (`#768 `_). + +* Fixed various compiler warnings and errors + (`#742 `_, + `#748 `_, + `#752 `_, + `#770 `_, + `#775 `_, + `#779 `_, + `#780 `_, + `#790 `_, + `#792 `_, + `#800 `_). + Thanks `@Remotion (Remo) `_, + `@gabime (Gabi Melman) `_, + `@foonathan (Jonathan Müller) `_, + `@Dark-Passenger (Dhruv Paranjape) `_, and + `@0x8000-0000 (Sign Bit) `_. + +5.0.0 - 2018-05-21 +------------------ + +* Added a requirement for partial C++11 support, most importantly variadic + templates and type traits, and dropped ``FMT_VARIADIC_*`` emulation macros. + Variadic templates are available since GCC 4.4, Clang 2.9 and MSVC 18.0 (2013). + For older compilers use {fmt} `version 4.x + `_ which continues to be + maintained and works with C++98 compilers. + +* Renamed symbols to follow standard C++ naming conventions and proposed a subset + of the library for standardization in `P0645R2 Text Formatting + `_. + +* Implemented ``constexpr`` parsing of format strings and `compile-time format + string checks + `_. For + example + + .. code:: c++ + + #include + + std::string s = format(fmt("{:d}"), "foo"); + + gives a compile-time error because ``d`` is an invalid specifier for strings + (`godbolt `__):: + + ... + :4:19: note: in instantiation of function template specialization 'fmt::v5::format' requested here + std::string s = format(fmt("{:d}"), "foo"); + ^ + format.h:1337:13: note: non-constexpr function 'on_error' cannot be used in a constant expression + handler.on_error("invalid type specifier"); + + Compile-time checks require relaxed ``constexpr`` (C++14 feature) support. If + the latter is not available, checks will be performed at runtime. + +* Separated format string parsing and formatting in the extension API to enable + compile-time format string processing. For example + + .. code:: c++ + + struct Answer {}; + + namespace fmt { + template <> + struct formatter { + constexpr auto parse(parse_context& ctx) { + auto it = ctx.begin(); + spec = *it; + if (spec != 'd' && spec != 's') + throw format_error("invalid specifier"); + return ++it; + } + + template + auto format(Answer, FormatContext& ctx) { + return spec == 's' ? + format_to(ctx.begin(), "{}", "fourty-two") : + format_to(ctx.begin(), "{}", 42); + } + + char spec = 0; + }; + } + + std::string s = format(fmt("{:x}"), Answer()); + + gives a compile-time error due to invalid format specifier (`godbolt + `__):: + + ... + :12:45: error: expression '' is not a constant expression + throw format_error("invalid specifier"); + +* Added `iterator support + `_: + + .. code:: c++ + + #include + #include + + std::vector out; + fmt::format_to(std::back_inserter(out), "{}", 42); + +* Added the `format_to_n + `_ + function that restricts the output to the specified number of characters + (`#298 `_): + + .. code:: c++ + + char out[4]; + fmt::format_to_n(out, sizeof(out), "{}", 12345); + // out == "1234" (without terminating '\0') + +* Added the `formatted_size + `_ + function for computing the output size: + + .. code:: c++ + + #include + + auto size = fmt::formatted_size("{}", 12345); // size == 5 + +* Improved compile times by reducing dependencies on standard headers and + providing a lightweight `core API `_: + + .. code:: c++ + + #include + + fmt::print("The answer is {}.", 42); + + See `Compile time and code bloat + `_. + +* Added the `make_format_args + `_ + function for capturing formatting arguments: + + .. code:: c++ + + // Prints formatted error message. + void vreport_error(const char *format, fmt::format_args args) { + fmt::print("Error: "); + fmt::vprint(format, args); + } + template + void report_error(const char *format, const Args & ... args) { + vreport_error(format, fmt::make_format_args(args...)); + } + +* Added the ``make_printf_args`` function for capturing ``printf`` arguments + (`#687 `_, + `#694 `_). + Thanks `@Kronuz (Germán Méndez Bravo) `_. + +* Added prefix ``v`` to non-variadic functions taking ``format_args`` to + distinguish them from variadic ones: + + .. code:: c++ + + std::string vformat(string_view format_str, format_args args); + + template + std::string format(string_view format_str, const Args & ... args); + +* Added experimental support for formatting ranges, containers and tuple-like + types in ``fmt/ranges.h`` (`#735 `_): + + .. code:: c++ + + #include + + std::vector v = {1, 2, 3}; + fmt::print("{}", v); // prints {1, 2, 3} + + Thanks `@Remotion (Remo) `_. + +* Implemented ``wchar_t`` date and time formatting + (`#712 `_): + + .. code:: c++ + + #include + + std::time_t t = std::time(nullptr); + auto s = fmt::format(L"The date is {:%Y-%m-%d}.", *std::localtime(&t)); + + Thanks `@DanielaE (Daniela Engert) `_. + +* Provided more wide string overloads + (`#724 `_). + Thanks `@DanielaE (Daniela Engert) `_. + +* Switched from a custom null-terminated string view class to ``string_view`` + in the format API and provided ``fmt::string_view`` which implements a subset + of ``std::string_view`` API for pre-C++17 systems. + +* Added support for ``std::experimental::string_view`` + (`#607 `_): + + .. code:: c++ + + #include + #include + + fmt::print("{}", std::experimental::string_view("foo")); + + Thanks `@virgiliofornazin (Virgilio Alexandre Fornazin) + `__. + +* Allowed mixing named and automatic arguments: + + .. code:: c++ + + fmt::format("{} {two}", 1, fmt::arg("two", 2)); + +* Removed the write API in favor of the `format API + `_ with compile-time handling of + format strings. + +* Disallowed formatting of multibyte strings into a wide character target + (`#606 `_). + +* Improved documentation + (`#515 `_, + `#614 `_, + `#617 `_, + `#661 `_, + `#680 `_). + Thanks `@ibell (Ian Bell) `_, + `@mihaitodor (Mihai Todor) `_, and + `@johnthagen `_. + +* Implemented more efficient handling of large number of format arguments. + +* Introduced an inline namespace for symbol versioning. + +* Added debug postfix ``d`` to the ``fmt`` library name + (`#636 `_). + +* Removed unnecessary ``fmt/`` prefix in includes + (`#397 `_). + Thanks `@chronoxor (Ivan Shynkarenka) `_. + +* Moved ``fmt/*.h`` to ``include/fmt/*.h`` to prevent irrelevant files and + directories appearing on the include search paths when fmt is used as a + subproject and moved source files to the ``src`` directory. + +* Added qmake project file ``support/fmt.pro`` + (`#641 `_). + Thanks `@cowo78 (Giuseppe Corbelli) `_. + +* Added Gradle build file ``support/build.gradle`` + (`#649 `_). + Thanks `@luncliff (Park DongHa) `_. + +* Removed ``FMT_CPPFORMAT`` CMake option. + +* Fixed a name conflict with the macro ``CHAR_WIDTH`` in glibc + (`#616 `_). + Thanks `@aroig (Abdó Roig-Maranges) `_. + +* Fixed handling of nested braces in ``fmt::join`` + (`#638 `_). + +* Added ``SOURCELINK_SUFFIX`` for compatibility with Sphinx 1.5 + (`#497 `_). + Thanks `@ginggs (Graham Inggs) `_. + +* Added a missing ``inline`` in the header-only mode + (`#626 `_). + Thanks `@aroig (Abdó Roig-Maranges) `_. + +* Fixed various compiler warnings + (`#640 `_, + `#656 `_, + `#679 `_, + `#681 `_, + `#705 `__, + `#715 `_, + `#717 `_, + `#720 `_, + `#723 `_, + `#726 `_, + `#730 `_, + `#739 `_). + Thanks `@peterbell10 `_, + `@LarsGullik `_, + `@foonathan (Jonathan Müller) `_, + `@eliaskosunen (Elias Kosunen) `_, + `@christianparpart (Christian Parpart) `_, + `@DanielaE (Daniela Engert) `_, + and `@mwinterb `_. + +* Worked around an MSVC bug and fixed several warnings + (`#653 `_). + Thanks `@alabuzhev (Alex Alabuzhev) `_. + +* Worked around GCC bug 67371 + (`#682 `_). + +* Fixed compilation with ``-fno-exceptions`` + (`#655 `_). + Thanks `@chenxiaolong (Andrew Gunnerson) `_. + +* Made ``constexpr remove_prefix`` gcc version check tighter + (`#648 `_). + +* Renamed internal type enum constants to prevent collision with poorly written + C libraries (`#644 `_). + +* Added detection of ``wostream operator<<`` + (`#650 `_). + +* Fixed compilation on OpenBSD + (`#660 `_). + Thanks `@hubslave `_. + +* Fixed compilation on FreeBSD 12 + (`#732 `_). + Thanks `@dankm `_. + +* Fixed compilation when there is a mismatch between ``-std`` options between + the library and user code + (`#664 `_). + +* Fixed compilation with GCC 7 and ``-std=c++11`` + (`#734 `_). + +* Improved generated binary code on GCC 7 and older + (`#668 `_). + +* Fixed handling of numeric alignment with no width + (`#675 `_). + +* Fixed handling of empty strings in UTF8/16 converters + (`#676 `_). + Thanks `@vgalka-sl (Vasili Galka) `_. + +* Fixed formatting of an empty ``string_view`` + (`#689 `_). + +* Fixed detection of ``string_view`` on libc++ + (`#686 `_). + +* Fixed DLL issues (`#696 `_). + Thanks `@sebkoenig `_. + +* Fixed compile checks for mixing narrow and wide strings + (`#690 `_). + +* Disabled unsafe implicit conversion to ``std::string`` + (`#729 `_). + +* Fixed handling of reused format specs (as in ``fmt::join``) for pointers + (`#725 `_). + Thanks `@mwinterb `_. + +* Fixed installation of ``fmt/ranges.h`` + (`#738 `_). + Thanks `@sv1990 `_. + 4.1.0 - 2017-12-20 ------------------ -* Added ``fmt::to_wstring()`` in addition to ``fmt::to_string()`` (`#559 `_). Thanks `@alabuzhev (Alex Alabuzhev) `_. +* Added ``fmt::to_wstring()`` in addition to ``fmt::to_string()`` + (`#559 `_). + Thanks `@alabuzhev (Alex Alabuzhev) `_. -* Added support for C++17 ``std::string_view`` (`#571 `_ and `#578 `_). Thanks `@thelostt (Mário Feroldi) `_ and `@mwinterb `_. +* Added support for C++17 ``std::string_view`` + (`#571 `_ and + `#578 `_). + Thanks `@thelostt (Mário Feroldi) `_ and + `@mwinterb `_. -* Enabled stream exceptions to catch errors (`#581 `_). Thanks `@crusader-mike `_. +* Enabled stream exceptions to catch errors + (`#581 `_). + Thanks `@crusader-mike `_. -* Allowed formatting of class hierarchies with ``fmt::format_arg()`` (`#547 `_). Thanks `@rollbear (Björn Fahller) `_. +* Allowed formatting of class hierarchies with ``fmt::format_arg()`` + (`#547 `_). + Thanks `@rollbear (Björn Fahller) `_. * Removed limitations on character types (`#563 `_). Thanks `@Yelnats321 (Elnar Dakeshov) `_. -* Conditionally enabled use of ``std::allocator_traits`` (`#583 `_). Thanks `@mwinterb `_. +* Conditionally enabled use of ``std::allocator_traits`` + (`#583 `_). + Thanks `@mwinterb `_. -* Added support for ``const`` variadic member function emulation with ``FMT_VARIADIC_CONST`` (`#591 `_). Thanks `@ludekvodicka (Ludek Vodicka) `_. +* Added support for ``const`` variadic member function emulation with + ``FMT_VARIADIC_CONST`` (`#591 `_). + Thanks `@ludekvodicka (Ludek Vodicka) `_. -* Various bugfixes: bad overflow check, unsupported implicit type conversion when determining formatting function, test segfaults (`#551 `_), ill-formed macros (`#542 `_) and ambiguous overloads (`#580 `_). Thanks `@xylosper (Byoung-young Lee) `_. +* Various bugfixes: bad overflow check, unsupported implicit type conversion + when determining formatting function, test segfaults + (`#551 `_), ill-formed macros + (`#542 `_) and ambiguous overloads + (`#580 `_). + Thanks `@xylosper (Byoung-young Lee) `_. -* Prevented warnings on MSVC (`#605 `_, `#602 `_, and `#545 `_), clang (`#582 `_), GCC (`#573 `_), various conversion warnings (`#609 `_, `#567 `_, `#553 `_ and `#553 `_), and added ``override`` and ``[[noreturn]]`` (`#549 `_ and `#555 `_). Thanks `@alabuzhev (Alex Alabuzhev) `_, `@virgiliofornazin (Virgilio Alexandre Fornazin) `_, `@alexanderbock (Alexander Bock) `_, `@yumetodo `_, `@VaderY (Császár Mátyás) `_, `@jpcima (JP Cimalando) `_, `@thelostt (Mário Feroldi) `_, and `@Manu343726 (Manu Sánchez) `_. +* Prevented warnings on MSVC (`#605 `_, + `#602 `_, and + `#545 `_), + clang (`#582 `_), + GCC (`#573 `_), + various conversion warnings (`#609 `_, + `#567 `_, + `#553 `_ and + `#553 `_), and added ``override`` and + ``[[noreturn]]`` (`#549 `_ and + `#555 `_). + Thanks `@alabuzhev (Alex Alabuzhev) `_, + `@virgiliofornazin (Virgilio Alexandre Fornazin) + `_, + `@alexanderbock (Alexander Bock) `_, + `@yumetodo `_, + `@VaderY (Császár Mátyás) `_, + `@jpcima (JP Cimalando) `_, + `@thelostt (Mário Feroldi) `_, and + `@Manu343726 (Manu Sánchez) `_. -* Improved CMake: Used GNUInstallDirs to set installation location (`#610 `_) and fixed warnings (`#536 `_ and `#556 `_). Thanks `@mikecrowe (Mike Crowe) `_, `@evgen231 `_ and `@henryiii (Henry Schreiner) `_. +* Improved CMake: Used ``GNUInstallDirs`` to set installation location + (`#610 `_) and fixed warnings + (`#536 `_ and + `#556 `_). + Thanks `@mikecrowe (Mike Crowe) `_, + `@evgen231 `_ and + `@henryiii (Henry Schreiner) `_. 4.0.0 - 2017-06-27 ------------------ -* Removed old compatibility headers ``cppformat/*.h`` and CMake options (`#527 `_). Thanks `@maddinat0r (Alex Martin) `_. +* Removed old compatibility headers ``cppformat/*.h`` and CMake options + (`#527 `_). + Thanks `@maddinat0r (Alex Martin) `_. -* Added ``string.h`` containing ``fmt::to_string()`` as alternative to ``std::to_string()`` as well as other string writer functionality (`#326 `_ and `#441 `_): +* Added ``string.h`` containing ``fmt::to_string()`` as alternative to + ``std::to_string()`` as well as other string writer functionality + (`#326 `_ and + `#441 `_): .. code:: c++ @@ -36,9 +650,17 @@ std::string answer = fmt::to_string(42); - Thanks to `@glebov-andrey (Andrey Glebov) `_. + Thanks to `@glebov-andrey (Andrey Glebov) + `_. -* Moved ``fmt::printf()`` to new ``printf.h`` header and allowed ``%s`` as generic specifier (`#453 `_), made ``%.f`` more conformant to regular ``printf()`` (`#490 `_), added custom writer support (`#476 `_) and implemented missing custom argument formatting (`#339 `_ and `#340 `_): +* Moved ``fmt::printf()`` to new ``printf.h`` header and allowed ``%s`` as + generic specifier (`#453 `_), + made ``%.f`` more conformant to regular ``printf()`` + (`#490 `_), added custom writer + support (`#476 `_) and implemented + missing custom argument formatting + (`#339 `_ and + `#340 `_): .. code:: c++ @@ -47,11 +669,21 @@ // %s format specifier can be used with any argument type. fmt::printf("%s", 42); - Thanks `@mojoBrendan `_, `@manylegged (Arthur Danskin) `_ and `@spacemoose (Glen Stark) `_. See also `#360 `_, `#335 `_ and `#331 `_. + Thanks `@mojoBrendan `_, + `@manylegged (Arthur Danskin) `_ and + `@spacemoose (Glen Stark) `_. + See also `#360 `_, + `#335 `_ and + `#331 `_. -* Added ``container.h`` containing a ``BasicContainerWriter`` to write to containers like ``std::vector`` (`#450 `_). Thanks `@polyvertex (Jean-Charles Lefebvre) `_. +* Added ``container.h`` containing a ``BasicContainerWriter`` + to write to containers like ``std::vector`` + (`#450 `_). + Thanks `@polyvertex (Jean-Charles Lefebvre) `_. -* Added ``fmt::join()`` function that takes a range and formats its elements separated by a given string (`#466 `_): +* Added ``fmt::join()`` function that takes a range and formats + its elements separated by a given string + (`#466 `_): .. code:: c++ @@ -63,75 +695,174 @@ Thanks `@olivier80 `_. -* Added support for custom formatting specifications to simplify customization of built-in formatting (`#444 `_). Thanks `@polyvertex (Jean-Charles Lefebvre) `_. See also `#439 `_. +* Added support for custom formatting specifications to simplify customization + of built-in formatting (`#444 `_). + Thanks `@polyvertex (Jean-Charles Lefebvre) `_. + See also `#439 `_. -* Added ``fmt::format_system_error()`` for error code formatting (`#323 `_ and `#526 `_). Thanks `@maddinat0r (Alex Martin) `_. +* Added ``fmt::format_system_error()`` for error code formatting + (`#323 `_ and + `#526 `_). + Thanks `@maddinat0r (Alex Martin) `_. -* Added thread-safe ``fmt::localtime()`` and ``fmt::gmtime()`` as replacement for the standard version to ``time.h`` (`#396 `_). Thanks `@codicodi `_. +* Added thread-safe ``fmt::localtime()`` and ``fmt::gmtime()`` + as replacement for the standard version to ``time.h`` + (`#396 `_). + Thanks `@codicodi `_. -* Internal improvements to ``NamedArg`` and ``ArgLists`` (`#389 `_ and `#390 `_). Thanks `@chronoxor `_. +* Internal improvements to ``NamedArg`` and ``ArgLists`` + (`#389 `_ and + `#390 `_). + Thanks `@chronoxor `_. -* Fixed crash due to bug in ``FormatBuf`` (`#493 `_). Thanks `@effzeh `_. See also `#480 `_ and `#491 `_. +* Fixed crash due to bug in ``FormatBuf`` + (`#493 `_). + Thanks `@effzeh `_. See also + `#480 `_ and + `#491 `_. * Fixed handling of wide strings in ``fmt::StringWriter``. -* Improved compiler error messages (`#357 `_). +* Improved compiler error messages + (`#357 `_). -* Fixed various warnings and issues with various compilers (`#494 `_, `#499 `_, `#483 `_, `#519 `_, `#485 `_, `#482 `_, `#475 `_, `#473 `_ and `#414 `_). Thanks `@chronoxor `_, `@zhaohuaxishi `_, `@pkestene (Pierre Kestener) `_, `@dschmidt (Dominik Schmidt) `_ and `@0x414c (Alexey Gorishny) `_ . +* Fixed various warnings and issues with various compilers + (`#494 `_, + `#499 `_, + `#483 `_, + `#485 `_, + `#482 `_, + `#475 `_, + `#473 `_ and + `#414 `_). + Thanks `@chronoxor `_, + `@zhaohuaxishi `_, + `@pkestene (Pierre Kestener) `_, + `@dschmidt (Dominik Schmidt) `_ and + `@0x414c (Alexey Gorishny) `_ . -* Improved CMake: targets are now namespaced (`#511 `_ and `#513 `_), supported header-only ``printf.h`` (`#354 `_), fixed issue with minimal supported library subset (`#418 `_, `#419 `_ and `#420 `_). Thanks `@bjoernthiel (Bjoern Thiel) `_, - `@niosHD (Mario Werner) `_, `@LogicalKnight (Sean LK) `_ and `@alabuzhev (Alex Alabuzhev) `_. +* Improved CMake: targets are now namespaced + (`#511 `_ and + `#513 `_), supported header-only + ``printf.h`` (`#354 `_), fixed issue + with minimal supported library subset + (`#418 `_, + `#419 `_ and + `#420 `_). + Thanks `@bjoernthiel (Bjoern Thiel) `_, + `@niosHD (Mario Werner) `_, + `@LogicalKnight (Sean LK) `_ and + `@alabuzhev (Alex Alabuzhev) `_. -* Improved documentation. Thanks to `@pwm1234 (Phil) `_ for `#393 `_. +* Improved documentation. Thanks to + `@pwm1234 (Phil) `_ for + `#393 `_. 3.0.2 - 2017-06-14 ------------------ -* Added ``FMT_VERSION`` macro (`#411 `_). +* Added ``FMT_VERSION`` macro + (`#411 `_). -* Used ``FMT_NULL`` instead of literal ``0`` (`#409 `_). Thanks `@alabuzhev (Alex Alabuzhev) `_. +* Used ``FMT_NULL`` instead of literal ``0`` + (`#409 `_). + Thanks `@alabuzhev (Alex Alabuzhev) `_. -* Added extern templates for ``format_float`` (`#413 `_). +* Added extern templates for ``format_float`` + (`#413 `_). -* Fixed implicit conversion issue (`#507 `_). +* Fixed implicit conversion issue + (`#507 `_). * Fixed signbit detection (`#423 `_). * Fixed naming collision (`#425 `_). -* Fixed missing intrinsic for C++/CLI (`#457 `_). Thanks `@calumr (Calum Robinson) `_ +* Fixed missing intrinsic for C++/CLI + (`#457 `_). + Thanks `@calumr (Calum Robinson) `_ -* Fixed Android detection (`#458 `_). Thanks `@Gachapen (Magnus Bjerke Vik) `_. +* Fixed Android detection (`#458 `_). + Thanks `@Gachapen (Magnus Bjerke Vik) `_. -* Use lean ``windows.h`` if not in header-only mode (`#503 `_). Thanks `@Quentin01 (Quentin Buathier) `_. +* Use lean ``windows.h`` if not in header-only mode + (`#503 `_). + Thanks `@Quentin01 (Quentin Buathier) `_. -* Fixed issue with CMake exporting C++11 flag (`#445 `_). Thanks `@EricWF (Eric) `_. +* Fixed issue with CMake exporting C++11 flag + (`#445 `_). + Thanks `@EricWF (Eric) `_. -* Fixed issue with nvcc and MSVC compiler bug and MinGW (`#505 `_). +* Fixed issue with nvcc and MSVC compiler bug and MinGW + (`#505 `_). -* Fixed DLL issues (`#469 `_ and `#502 `_). Thanks `@richardeakin (Richard Eakin) `_ and `@AndreasSchoenle (Andreas Schönle) `_. +* Fixed DLL issues (`#469 `_ and + `#502 `_). + Thanks `@richardeakin (Richard Eakin) `_ and + `@AndreasSchoenle (Andreas Schönle) `_. -* Fixed test compilation under FreeBSD (`#433 `_). +* Fixed test compilation under FreeBSD + (`#433 `_). -* Fixed various warnings (`#403 `_, `#410 `_ and `#510 `_). Thanks `@Lecetem `_, `@chenhayat (Chen Hayat) `_ and `@trozen `_. +* Fixed various warnings (`#403 `_, + `#410 `_ and + `#510 `_). + Thanks `@Lecetem `_, + `@chenhayat (Chen Hayat) `_ and + `@trozen `_. -* Removed redundant include (`#479 `_). +* Worked around a broken ``__builtin_clz`` in clang with MS codegen + (`#519 `_). + +* Removed redundant include + (`#479 `_). * Fixed documentation issues. 3.0.1 - 2016-11-01 ------------------ -* Fixed handling of thousands seperator (`#353 `_) +* Fixed handling of thousands seperator + (`#353 `_). -* Fixed handling of ``unsigned char`` strings (`#373 `_) +* Fixed handling of ``unsigned char`` strings + (`#373 `_). -* Corrected buffer growth when formatting time (`#367 `_) +* Corrected buffer growth when formatting time + (`#367 `_). -* Removed warnings under MSVC and clang (`#318 `_, `#250 `_, also merged `#385 `_ and `#361 `_). Thanks `@jcelerier (Jean-Michaël Celerier) `_ and `@nmoehrle (Nils Moehrle) `_. +* Removed warnings under MSVC and clang + (`#318 `_, + `#250 `_, also merged + `#385 `_ and + `#361 `_). + Thanks `@jcelerier (Jean-Michaël Celerier) `_ + and `@nmoehrle (Nils Moehrle) `_. -* Fixed compilation issues under Android (`#327 `_, `#345 `_ and `#381 `_), FreeBSD (`#358 `_), Cygwin (`#388 `_), MinGW (`#355 `_) as well as other issues (`#350 `_, `#366 `_, `#348 `_, `#402 `_, `#405 `_). Thanks to `@dpantele (Dmitry) `_, `@hghwng (Hugh Wang) `_, `@arvedarved (Tilman Keskinöz) `_, `@LogicalKnight (Sean) `_ and `@JanHellwig (Jan Hellwig) `_. - -* Fixed some documentation issues and extended specification (`#320 `_, `#333 `_, `#347 `_, `#362 `_). Thanks to `@smellman (Taro Matsuzawa aka. btm) `_. +* Fixed compilation issues under Android + (`#327 `_, + `#345 `_ and + `#381 `_), + FreeBSD (`#358 `_), + Cygwin (`#388 `_), + MinGW (`#355 `_) as well as other + issues (`#350 `_, + `#366 `_, + `#348 `_, + `#402 `_, + `#405 `_). + Thanks to `@dpantele (Dmitry) `_, + `@hghwng (Hugh Wang) `_, + `@arvedarved (Tilman Keskinöz) `_, + `@LogicalKnight (Sean) `_ and + `@JanHellwig (Jan Hellwig) `_. + +* Fixed some documentation issues and extended specification + (`#320 `_, + `#333 `_, + `#347 `_, + `#362 `_). + Thanks to `@smellman (Taro Matsuzawa aka. btm) + `_. 3.0.0 - 2016-05-07 ------------------ @@ -249,8 +980,8 @@ `@Gachapen (Magnus Bjerke Vik) `_ and `@jwilk (Jakub Wilk) `_. -* Fixed compiler and sanitizer warnings ( - `#244 `_, +* Fixed compiler and sanitizer warnings + (`#244 `_, `#256 `_, `#259 `_, `#263 `_, @@ -670,8 +1401,8 @@ Fixes `@Jopie64 (Johan) `_. * Fixed portability issues (mostly causing test failures) on ARM, ppc64, ppc64le, - s390x and SunOS 5.11 i386 ( - `#138 `_, + s390x and SunOS 5.11 i386 + (`#138 `_, `#179 `_, `#180 `_, `#202 `_, diff --git a/README.rst b/README.rst index 32f50257..bd634a4a 100644 --- a/README.rst +++ b/README.rst @@ -11,50 +11,48 @@ :alt: Join the chat at https://gitter.im/fmtlib/fmt :target: https://gitter.im/fmtlib/fmt -**fmt** is an open-source formatting library for C++. -It can be used as a safe alternative to printf or as a fast -alternative to IOStreams. +**{fmt}** is an open-source formatting library for C++. +It can be used as a safe and fast alternative to (s)printf and IOStreams. -`Documentation `_ +`Documentation `__ + +This is a development branch that implements the C++ standards proposal `P0645 +Text Formatting `__. +Released versions are available from the `Releases page +`__. Features -------- -* Two APIs: faster concatenation-based `write API - `_ and slower, - but still very fast, replacement-based `format API - `_ with positional arguments - for localization. -* Write API similar to the one used by IOStreams but stateless allowing - faster implementation. -* Format API with `format string syntax - `_ - similar to the one used by `str.format - `_ in Python. +* Replacement-based `format API `_ with + positional arguments for localization. +* `Format string syntax `_ similar to the one + of `str.format `_ + in Python. * Safe `printf implementation - `_ - including the POSIX extension for positional arguments. + `_ including + the POSIX extension for positional arguments. * Support for user-defined types. -* High speed: performance of the format API is close to that of - glibc's `printf `_ - and better than the performance of IOStreams. See `Speed tests`_ and +* High speed: performance of the format API is close to that of glibc's `printf + `_ and better than the + performance of IOStreams. See `Speed tests`_ and `Fast integer to string conversion in C++ `_. -* Small code size both in terms of source code (the core library consists of a single - header file and a single source file) and compiled code. - See `Compile time and code bloat`_. +* 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 `_. -* Safety: the library is fully type safe, errors in format strings are - reported using exceptions, automatic memory management prevents buffer - overflow errors. +* Safety: the library is fully type safe, errors in format strings can be + reported at compile time, automatic memory management prevents buffer overflow + errors. * Ease of use: small self-contained code base, no external dependencies, permissive BSD `license `_ -* `Portability `_ with consistent output - across platforms and support for older compilers. +* `Portability `_ with + consistent output across platforms and support for older compilers. * Clean warning-free codebase even on high warning levels - (-Wall -Wextra -pedantic). + (``-Wall -Wextra -pedantic``). * Support for wide strings. * Optional header-only configuration enabled with the ``FMT_HEADER_ONLY`` macro. @@ -77,56 +75,85 @@ Arguments can be accessed by position and arguments' indices can be repeated: std::string s = fmt::format("{0}{1}{0}", "abra", "cad"); // s == "abracadabra" -fmt can be used as a safe portable replacement for ``itoa``: +Format strings can be checked at compile time: .. code:: c++ - fmt::MemoryWriter w; - w << 42; // replaces itoa(42, buffer, 10) - w << fmt::hex(42); // replaces itoa(42, buffer, 16) - // access the string using w.str() or w.c_str() + // test.cc + #define FMT_STRING_ALIAS 1 + #include + std::string s = format(fmt("{2}"), 42); -An object of any user-defined type for which there is an overloaded -:code:`std::ostream` insertion operator (``operator<<``) can be formatted: +.. code:: + + $ c++ -Iinclude -std=c++14 test.cc + ... + test.cc:4:17: note: in instantiation of function template specialization 'fmt::v5::format' requested here + std::string s = format(fmt("{2}"), 42); + ^ + include/fmt/core.h:778:19: note: non-constexpr function 'on_error' cannot be used in a constant expression + ErrorHandler::on_error(message); + ^ + include/fmt/format.h:2226:16: note: in call to '&checker.context_->on_error(&"argument index out of range"[0])' + context_.on_error("argument index out of range"); + ^ + +{fmt} can be used as a safe portable replacement for ``itoa`` +(`godbolt `_): .. code:: c++ - #include "fmt/ostream.h" + 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 using to_string(buf) or buf.data() - class Date { - int year_, month_, day_; - public: - Date(int year, int month, int day) : year_(year), month_(month), day_(day) {} +Formatting of user-defined types is supported via a simple +`extension API `_: - friend std::ostream &operator<<(std::ostream &os, const Date &d) { - return os << d.year_ << '-' << d.month_ << '-' << d.day_; +.. code:: c++ + + #include "fmt/format.h" + + struct date { + int year, month, day; + }; + + template <> + struct fmt::formatter { + template + constexpr auto parse(ParseContext &ctx) { return ctx.begin(); } + + template + auto format(const date &d, FormatContext &ctx) { + return format_to(ctx.begin(), "{}-{}-{}", d.year, d.month, d.day); } }; - std::string s = fmt::format("The date is {}", Date(2012, 12, 9)); + std::string s = fmt::format("The date is {}", date{2012, 12, 9}); // s == "The date is 2012-12-9" -You can use the `FMT_VARIADIC -`_ -macro to create your own functions similar to `format +You can create your own functions similar to `format `_ and `print `_ -which take arbitrary arguments: +which take arbitrary arguments (`godbolt `_): .. code:: c++ // Prints formatted error message. - void report_error(const char *format, fmt::ArgList args) { + void vreport_error(const char *format, fmt::format_args args) { fmt::print("Error: "); - fmt::print(format, args); + fmt::vprint(format, args); + } + template + void report_error(const char *format, const Args & ... args) { + vreport_error(format, fmt::make_format_args(args...)); } - FMT_VARIADIC(void, report_error, const char *) report_error("file not found: {}", path); -Note that you only need to define one function that takes ``fmt::ArgList`` -argument. ``FMT_VARIADIC`` automatically defines necessary wrappers that -accept variable number of arguments. +Note that ``vreport_error`` is not parameterized on argument types which can +improve compile times and reduce code size compared to fully parameterized version. Projects using this library --------------------------- @@ -135,15 +162,11 @@ Projects using this library * `AMPL/MP `_: An open-source library for mathematical programming + +* `AvioBook `_: A comprehensive aircraft operations suite * `CUAUV `_: Cornell University's autonomous underwater vehicle -* `Drake `_: A planning, control, and analysis toolbox for nonlinear dynamical systems (MIT) - -* `Envoy `_: C++ L7 proxy and communication bus (Lyft) - -* `FiveM `_: a modification framework for GTA V - * `HarpyWar/pvpgn `_: Player vs Player Gaming Network with tweaks @@ -155,14 +178,25 @@ Projects using this library * `Lifeline `_: A 2D game -* `MongoDB Smasher `_: A small tool to generate randomized datasets +* `Drake `_: A planning, control, and analysis toolbox + for nonlinear dynamical systems (MIT) -* `OpenSpace `_: An open-source astrovisualization framework +* `Envoy `_: C++ L7 proxy and communication bus + (Lyft) + +* `FiveM `_: a modification framework for GTA V + +* `MongoDB Smasher `_: A small tool to + generate randomized datasets + +* `OpenSpace `_: An open-source astrovisualization + framework * `PenUltima Online (POL) `_: An MMO server, compatible with most Ultima Online clients -* `quasardb `_: A distributed, high-performance, associative database +* `quasardb `_: A distributed, high-performance, + associative database * `readpe `_: Read Portable Executable @@ -244,7 +278,7 @@ Boost Format library ~~~~~~~~~~~~~~~~~~~~ This is a very powerful library which supports both printf-like format -strings and positional arguments. The main its drawback is performance. +strings and positional arguments. Its main drawback is performance. According to 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`_). @@ -308,11 +342,12 @@ further details see the `source ================= ============= =========== Library Method Run Time, s ================= ============= =========== -EGLIBC 2.19 printf 1.30 -libstdc++ 4.8.2 std::ostream 1.85 -fmt 1.0 fmt::print 1.42 -tinyformat 2.0.1 tfm::printf 2.25 -Boost Format 1.54 boost::format 9.94 +libc printf 1.35 +libc++ std::ostream 3.42 +fmt 534bff7 fmt::print 1.56 +tinyformat 2.0.1 tfm::printf 3.73 +Boost Format 1.54 boost::format 8.44 +Folly Format folly::format 2.54 ================= ============= =========== As you can see ``boost::format`` is much slower than the alternative methods; this @@ -332,38 +367,45 @@ from `format-benchmark `_ tests compile time and code bloat for nontrivial projects. It generates 100 translation units and uses ``printf()`` or its alternative five times in each to simulate a medium sized project. The resulting -executable size and compile time (g++-4.8.1, Ubuntu GNU/Linux 13.10, -best of three) is shown in the following tables. +executable size and compile time (Apple LLVM version 8.1.0 (clang-802.0.42), +macOS Sierra, best of three) is shown in the following tables. **Optimized build (-O3)** -============ =============== ==================== ================== -Method Compile Time, s Executable size, KiB Stripped size, KiB -============ =============== ==================== ================== -printf 2.6 41 30 -IOStreams 19.4 92 70 -fmt 46.8 46 34 -tinyformat 64.6 418 386 -Boost Format 222.8 990 923 -============ =============== ==================== ================== +============= =============== ==================== ================== +Method Compile Time, s Executable size, KiB Stripped size, KiB +============= =============== ==================== ================== +printf 2.6 29 26 +printf+string 16.4 29 26 +IOStreams 31.1 59 55 +fmt 19.0 37 34 +tinyformat 44.0 103 97 +Boost Format 91.9 226 203 +Folly Format 115.7 101 88 +============= =============== ==================== ================== -As you can see, fmt has two times less overhead in terms of resulting -code size compared to IOStreams and comes pretty close to ``printf``. -Boost Format has by far the largest overheads. +As you can see, fmt has 60% less overhead in terms of resulting binary code +size compared to IOStreams and comes pretty close to ``printf``. Boost Format +and Folly Format have the largest overheads. + +``printf+string`` is the same as ``printf`` but with extra ```` +include to measure the overhead of the latter. **Non-optimized build** -============ =============== ==================== ================== -Method Compile Time, s Executable size, KiB Stripped size, KiB -============ =============== ==================== ================== -printf 2.1 41 30 -IOStreams 19.7 86 62 -fmt 47.9 108 86 -tinyformat 27.7 234 190 -Boost Format 122.6 884 763 -============ =============== ==================== ================== +============= =============== ==================== ================== +Method Compile Time, s Executable size, KiB Stripped size, KiB +============= =============== ==================== ================== +printf 2.2 33 30 +printf+string 16.0 33 30 +IOStreams 28.3 56 52 +fmt 18.2 59 50 +tinyformat 32.6 88 82 +Boost Format 54.1 365 303 +Folly Format 79.9 445 430 +============= =============== ==================== ================== -``libc``, ``libstdc++`` and ``libfmt`` are all linked as shared +``libc``, ``lib(std)c++`` and ``libfmt`` are all linked as shared libraries to compare formatting function overhead only. Boost Format and tinyformat are header-only libraries so they don't provide any linkage options. @@ -393,6 +435,29 @@ or the bloat test:: $ make bloat-test +FAQ +--- + +Q: how can I capture formatting arguments and format them later? + +A: use ``std::tuple``: + +.. code:: c++ + + template + auto capture(const Args&... args) { + return std::make_tuple(args...); + } + + auto print_message = [](const auto&... args) { + fmt::print(args...); + }; + + // Capture and store arguments: + auto args = capture("{} {}", 42, "foo"); + // Do formatting: + std::apply(print_message, args); + License ------- @@ -412,10 +477,13 @@ It only applies if you distribute the documentation of fmt. Acknowledgments --------------- -The fmt library is maintained by Victor Zverovich (`vitaut `_) -and Jonathan Müller (`foonathan `_) with contributions from many -other people. See `Contributors `_ and `Releases `_ for some of the names. Let us know if your contribution -is not listed or mentioned incorrectly and we'll make it right. +The fmt library is maintained by Victor Zverovich (`vitaut +`_) and Jonathan Müller (`foonathan +`_) with contributions from many other people. +See `Contributors `_ and +`Releases `_ for some of the names. +Let us know if your contribution is not listed or mentioned incorrectly and +we'll make it right. The benchmark section of this readme file and the performance tests are taken from the excellent `tinyformat `_ library diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt index df3e9b1e..c16427a9 100644 --- a/doc/CMakeLists.txt +++ b/doc/CMakeLists.txt @@ -6,7 +6,7 @@ endif () add_custom_target(doc COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/build.py ${FMT_VERSION} - SOURCES build.py conf.py _templates/layout.html) + SOURCES api.rst syntax.rst build.py conf.py _templates/layout.html) install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html/ DESTINATION share/doc/fmt OPTIONAL) diff --git a/doc/api.rst b/doc/api.rst index 9647c90b..5ecaaa46 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -4,52 +4,290 @@ API Reference ************* -All functions and classes provided by the fmt library reside -in namespace ``fmt`` and macros have prefix ``FMT_``. For brevity the -namespace is usually omitted in examples. +The {fmt} library API consists of the following parts: -Format API -========== +* :ref:`fmt/core.h `: the core API providing argument handling + facilities and a lightweight subset of formatting functions +* :ref:`fmt/format.h `: the full format API providing compile-time + format string checks, output iterator and user-defined type support +* :ref:`fmt/time.h `: date and time formatting +* :ref:`fmt/ostream.h `: ``std::ostream`` support +* :ref:`fmt/printf.h `: ``printf`` formatting -The following functions defined in ``fmt/format.h`` use :ref:`format string -syntax ` similar to the one used by Python's `str.format -`_ function. +All functions and types provided by the library reside in namespace ``fmt`` and +macros have prefix ``FMT_`` or ``fmt``. + +.. _core-api: + +Core API +======== + +``fmt/core.h`` defines the core API which provides argument handling facilities +and a lightweight subset of formatting functions. + +The following functions use :ref:`format string syntax ` +imilar to that of Python's `str.format +`_. They take *format_str* and *args* as arguments. *format_str* is a format string that contains literal text and replacement fields surrounded by braces ``{}``. The fields are replaced with formatted arguments in the resulting string. -*args* is an argument list representing arbitrary arguments. - -The `performance of the format API -`_ is close -to that of glibc's ``printf`` and better than the performance of IOStreams. -For even better speed use the `write API`_. +*args* is an argument list representing objects to be formatted. .. _format: -.. doxygenfunction:: format(CStringRef, ArgList) - -.. doxygenfunction:: operator""_format(const char *, std::size_t) +.. doxygenfunction:: format(const String&, const Args&...) +.. doxygenfunction:: vformat(const String&, basic_format_args::type>) .. _print: -.. doxygenfunction:: print(CStringRef, ArgList) +.. doxygenfunction:: print(string_view, const Args&...) +.. doxygenfunction:: vprint(string_view, format_args) -.. doxygenfunction:: print(std::FILE *, CStringRef, ArgList) +.. doxygenfunction:: print(std::FILE *, string_view, const Args&...) +.. doxygenfunction:: vprint(std::FILE *, string_view, format_args) -.. doxygenclass:: fmt::BasicFormatter +.. doxygenfunction:: print(std::FILE *, wstring_view, const Args&...) +.. doxygenfunction:: vprint(std::FILE *, wstring_view, wformat_args) + +Named arguments +--------------- + +.. doxygenfunction:: fmt::arg(string_view, const T&) + +Argument lists +-------------- + +.. doxygenfunction:: fmt::make_format_args(const Args&...) + +.. doxygenclass:: fmt::format_arg_store :members: +.. doxygenclass:: fmt::basic_format_args + :members: + +.. doxygenstruct:: fmt::format_args + +.. doxygenclass:: fmt::basic_format_arg + :members: + +Compatibility +------------- + +.. doxygenclass:: fmt::basic_string_view + :members: + +.. doxygentypedef:: fmt::string_view +.. doxygentypedef:: fmt::wstring_view + +.. _format-api: + +Format API +========== + +``fmt/format.h`` defines the full format API providing compile-time format +string checks, output iterator and user-defined type support. + +Compile-time format string checks +--------------------------------- + +.. doxygendefine:: fmt + +Formatting user-defined types +----------------------------- + +To make a user-defined type formattable, specialize the ``formatter`` struct +template and implement ``parse`` and ``format`` methods:: + + #include + + struct point { double x, y; }; + + namespace fmt { + template <> + struct formatter { + template + constexpr auto parse(ParseContext &ctx) { return ctx.begin(); } + + template + auto format(const point &p, FormatContext &ctx) { + return format_to(ctx.begin(), "({:.1f}, {:.1f})", p.x, p.y); + } + }; + } + +Then you can pass objects of type ``point`` to any formatting function:: + + point p = {1, 2}; + std::string s = fmt::format("{}", p); + // s == "(1.0, 2.0)" + +In the example above the ``formatter::parse`` function ignores the +contents of the format string referred to by ``ctx.begin()`` so the object will +always be formatted in the same way. See ``formatter::parse`` in +:file:`fmt/time.h` for an advanced example of how to parse the format string and +customize the formatted output. + +You can also reuse existing formatters, for example:: + + enum class color {red, green, blue}; + + template <> + struct fmt::formatter: formatter { + // parse is inherited from formatter. + template + auto format(color c, FormatContext &ctx) { + string_view name = "unknown"; + switch (c) { + case color::red: name = "red"; break; + case color::green: name = "green"; break; + case color::blue: name = "blue"; break; + } + return formatter::format(name, ctx); + } + }; + +This section shows how to define a custom format function for a user-defined +type. The next section describes how to get ``fmt`` to use a conventional stream +output ``operator<<`` when one is defined for a user-defined type. + +Output iterator support +----------------------- + +.. doxygenfunction:: fmt::format_to(OutputIt, string_view, const Args&...) +.. doxygenfunction:: fmt::format_to_n(OutputIt, std::size_t, string_view, const Args&...) +.. doxygenstruct:: fmt::format_to_n_result + :members: + +Literal-based API +----------------- + +The following user-defined literals are defined in ``fmt/format.h``. + +.. doxygenfunction:: operator""_format(const char *, std::size_t) + +.. doxygenfunction:: operator""_a(const char *, std::size_t) + +Utilities +--------- + +.. doxygenfunction:: fmt::formatted_size(string_view, const Args&...) + +.. doxygenfunction:: fmt::to_string(const T&) + +.. doxygenfunction:: fmt::to_wstring(const T&) + +.. doxygenclass:: fmt::basic_memory_buffer + :protected-members: + :members: + +System errors +------------- + +fmt does not use ``errno`` to communicate errors to the user, but it may call +system functions which set ``errno``. Users should not make any assumptions about +the value of ``errno`` being preserved by library functions. + +.. doxygenclass:: fmt::system_error + :members: + +.. doxygenfunction:: fmt::format_system_error + +.. doxygenclass:: fmt::windows_error + :members: + +.. _formatstrings: + +Custom allocators +----------------- + +The {fmt} library supports custom dynamic memory allocators. +A custom allocator class can be specified as a template argument to +:class:`fmt::basic_memory_buffer`:: + + using custom_memory_buffer = + fmt::basic_memory_buffer; + +It is also possible to write a formatting function that uses a custom +allocator:: + + using custom_string = + std::basic_string, custom_allocator>; + + custom_string vformat(custom_allocator alloc, fmt::string_view format_str, + fmt::format_args args) { + custom_memory_buffer buf(alloc); + fmt::vformat_to(buf, format_str, args); + return custom_string(buf.data(), buf.size(), alloc); + } + + template + inline custom_string format(custom_allocator alloc, + fmt::string_view format_str, + const Args & ... args) { + 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. + +Custom formatting of built-in types +----------------------------------- + +It is possible to change the way arguments are formatted by providing a +custom argument formatter class:: + + using arg_formatter = + fmt::arg_formatter>; + + // A custom argument formatter that formats negative integers as unsigned + // with the ``x`` format specifier. + class custom_arg_formatter : public arg_formatter { + public: + custom_arg_formatter(fmt::format_context &ctx, fmt::format_specs &spec) + : arg_formatter(ctx, spec) {} + + using arg_formatter::operator(); + + auto operator()(int value) { + if (spec().type() == 'x') + return (*this)(static_cast(value)); // convert to unsigned and format + return arg_formatter::operator()(value); + } + }; + + std::string custom_vformat(fmt::string_view format_str, fmt::format_args args) { + fmt::memory_buffer buffer; + // Pass custom argument formatter as a template arg to vformat_to. + fmt::vformat_to(buffer, format_str, args); + return fmt::to_string(buffer); + } + + template + inline std::string custom_format( + fmt::string_view format_str, const Args &... args) { + return custom_vformat(format_str, fmt::make_format_args(args...)); + } + + std::string s = custom_format("{:x}", -42); // s == "ffffffd6" + +.. doxygenclass:: fmt::arg_formatter + :members: + +.. _time-api: + Date and time formatting ------------------------- +======================== The library supports `strftime `_-like date and time formatting:: - #include "fmt/time.h" + #include std::time_t t = std::time(nullptr); // Prints "The date is 2016-04-29." (with the current date) @@ -58,134 +296,35 @@ formatting:: The format string syntax is described in the documentation of `strftime `_. -Formatting user-defined types ------------------------------ - -A custom ``format_arg`` function may be implemented and used to format any -user-defined type. That is how date and time formatting described in the -previous section is implemented in :file:`fmt/time.h`. The following example -shows how to implement custom formatting for a user-defined structure. - -:: - - struct MyStruct { double a, b; }; - - void format_arg(fmt::BasicFormatter &f, - const char *&format_str, const MyStruct &s) { - f.writer().write("[MyStruct: a={:.1f}, b={:.2f}]", s.a, s.b); - } - - MyStruct m = { 1, 2 }; - std::string s = fmt::format("m={}", n); - // s == "m=[MyStruct: a=1.0, b=2.00]" - -Note in the example above the ``format_arg`` function ignores the contents of -``format_str`` so the type will always be formatted as specified. See -``format_arg`` in :file:`fmt/time.h` for an advanced example of how to use -the ``format_str`` argument to customize the formatted output. - -This technique can also be used for formatting class hierarchies:: - - namespace local { - struct Parent { - Parent(int p) : p(p) {} - virtual void write(fmt::Writer &w) const { - w.write("Parent : p={}", p); - } - int p; - }; - - struct Child : Parent { - Child(int c, int p) : Parent(p), c(c) {} - virtual void write(fmt::Writer &w) const { - w.write("Child c={} : ", c); - Parent::write(w); - } - int c; - }; - - void format_arg(fmt::BasicFormatter &f, - const char *&format_str, const Parent &p) { - p.write(f.writer()); - } - } - Local::Child c(1,2); - Local::Parent &p = c; - fmt::print("via ref to base: {}\n", p); - fmt::print("direct to child: {}\n", c); - -This section shows how to define a custom format function for a user-defined -type. The next section describes how to get ``fmt`` to use a conventional stream -output ``operator<<`` when one is defined for a user-defined type. +.. _ostream-api: ``std::ostream`` support ------------------------- +======================== -The header ``fmt/ostream.h`` provides ``std::ostream`` support including -formatting of user-defined types that have overloaded ``operator<<``:: +``fmt/ostream.h`` provides ``std::ostream`` support including formatting of +user-defined types that have overloaded ``operator<<``:: - #include "fmt/ostream.h" + #include - class Date { + class date { int year_, month_, day_; public: - Date(int year, int month, int day): year_(year), month_(month), day_(day) {} + date(int year, int month, int day): year_(year), month_(month), day_(day) {} - friend std::ostream &operator<<(std::ostream &os, const Date &d) { + friend std::ostream &operator<<(std::ostream &os, const date &d) { return os << d.year_ << '-' << d.month_ << '-' << d.day_; } }; - std::string s = fmt::format("The date is {}", Date(2012, 12, 9)); + std::string s = fmt::format("The date is {}", date(2012, 12, 9)); // s == "The date is 2012-12-9" -.. doxygenfunction:: print(std::ostream&, CStringRef, ArgList) +.. doxygenfunction:: print(std::ostream&, string_view, const Args&...) -Argument formatters -------------------- +.. _printf-api: -It is possible to change the way arguments are formatted by providing a -custom argument formatter class:: - - // A custom argument formatter that formats negative integers as unsigned - // with the ``x`` format specifier. - class CustomArgFormatter : - public fmt::BasicArgFormatter { - public: - CustomArgFormatter(fmt::BasicFormatter &f, - fmt::FormatSpec &s, const char *fmt) - : fmt::BasicArgFormatter(f, s, fmt) {} - - void visit_int(int value) { - if (spec().type() == 'x') - visit_uint(value); // convert to unsigned and format - else - fmt::BasicArgFormatter::visit_int(value); - } - }; - - std::string custom_format(const char *format_str, fmt::ArgList args) { - fmt::MemoryWriter writer; - // Pass custom argument formatter as a template arg to BasicFormatter. - fmt::BasicFormatter formatter(args, writer); - formatter.format(format_str); - return writer.str(); - } - FMT_VARIADIC(std::string, custom_format, const char *) - - std::string s = custom_format("{:x}", -42); // s == "ffffffd6" - -.. doxygenclass:: fmt::ArgVisitor - :members: - -.. doxygenclass:: fmt::BasicArgFormatter - :members: - -.. doxygenclass:: fmt::ArgFormatter - :members: - -Printf formatting ------------------ +``printf`` formatting +===================== The header ``fmt/printf.h`` provides ``printf``-like formatting functionality. The following functions use `printf format string syntax @@ -194,118 +333,10 @@ the POSIX extension for positional arguments. Unlike their standard counterparts, the ``fmt`` functions are type-safe and throw an exception if an argument type doesn't match its format specification. -.. doxygenfunction:: printf(CStringRef, ArgList) +.. doxygenfunction:: printf(string_view, const Args&...) -.. doxygenfunction:: fprintf(std::FILE *, CStringRef, ArgList) +.. doxygenfunction:: fprintf(std::FILE *, string_view, const Args&...) -.. doxygenfunction:: fprintf(std::ostream&, CStringRef, ArgList) +.. doxygenfunction:: fprintf(std::ostream&, string_view, const Args&...) -.. doxygenfunction:: sprintf(CStringRef, ArgList) - -.. doxygenclass:: fmt::PrintfFormatter - :members: - -.. doxygenclass:: fmt::BasicPrintfArgFormatter - :members: - -.. doxygenclass:: fmt::PrintfArgFormatter - :members: - -Write API -========= - -The write API provides classes for writing formatted data into character -streams. It is usually faster than the `format API`_ but, as IOStreams, -may result in larger compiled code size. The main writer class is -`~fmt::BasicMemoryWriter` which stores its output in a memory buffer and -provides direct access to it. It is possible to create custom writers that -store output elsewhere by subclassing `~fmt::BasicWriter`. - -.. doxygenclass:: fmt::BasicWriter - :members: - -.. doxygenclass:: fmt::BasicMemoryWriter - :members: - -.. doxygenclass:: fmt::BasicArrayWriter - :members: - -.. doxygenclass:: fmt::BasicStringWriter - :members: - -.. doxygenclass:: fmt::BasicContainerWriter - :members: - -.. doxygenfunction:: bin(int) - -.. doxygenfunction:: oct(int) - -.. doxygenfunction:: hex(int) - -.. doxygenfunction:: hexu(int) - -.. doxygenfunction:: pad(int, unsigned, Char) - -Utilities -========= - -.. doxygenfunction:: fmt::arg(StringRef, const T&) - -.. doxygenfunction:: operator""_a(const char *, std::size_t) - -.. doxygendefine:: FMT_CAPTURE - -.. doxygendefine:: FMT_VARIADIC - -.. doxygenclass:: fmt::ArgList - :members: - -.. doxygenfunction:: fmt::to_string(const T&) - -.. doxygenfunction:: fmt::to_wstring(const T&) - -.. doxygenclass:: fmt::BasicStringRef - :members: - -.. doxygenclass:: fmt::BasicCStringRef - :members: - -.. doxygenclass:: fmt::Buffer - :protected-members: - :members: - -System errors -============= - -.. doxygenclass:: fmt::SystemError - :members: - -.. doxygenfunction:: fmt::format_system_error - -.. doxygenclass:: fmt::WindowsError - :members: - -.. _formatstrings: - -Custom allocators -================= - -The fmt library supports custom dynamic memory allocators. -A custom allocator class can be specified as a template argument to -:class:`fmt::BasicMemoryWriter`:: - - typedef fmt::BasicMemoryWriter CustomMemoryWriter; - -It is also possible to write a formatting function that uses a custom -allocator:: - - typedef std::basic_string, CustomAllocator> - CustomString; - - CustomString format(CustomAllocator alloc, fmt::CStringRef format_str, - fmt::ArgList args) { - CustomMemoryWriter writer(alloc); - writer.write(format_str, args); - return CustomString(writer.data(), writer.size(), alloc); - } - FMT_VARIADIC(CustomString, format, CustomAllocator, fmt::CStringRef) +.. doxygenfunction:: sprintf(string_view, const Args&...) diff --git a/doc/build.py b/doc/build.py index cb8d0c3c..5947e465 100755 --- a/doc/build.py +++ b/doc/build.py @@ -6,7 +6,7 @@ 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'] +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'] def pip_install(package, commit=None, **kwargs): "Install package using pip." @@ -56,14 +56,14 @@ def create_build_env(dirname='virtualenv'): pip_install('sphinx-doc/sphinx', '12b83372ac9316e8cbe86e7fed889296a4cc29ee', min_version='1.4.1.dev20160531') pip_install('michaeljones/breathe', - '6b1c5bb7a1866f15fc328b8716258354b10c1daa', + '129222318f7c8f865d2631e7da7b033567e7f56a', min_version='4.2.0') def build_docs(version='dev', **kwargs): doc_dir = kwargs.get('doc_dir', os.path.dirname(os.path.realpath(__file__))) work_dir = kwargs.get('work_dir', '.') - include_dir = kwargs.get('include_dir', - os.path.join(os.path.dirname(doc_dir), 'fmt')) + include_dir = kwargs.get( + 'include_dir', os.path.join(os.path.dirname(doc_dir), 'include', 'fmt')) # Build docs. cmd = ['doxygen', '-'] p = Popen(cmd, stdin=PIPE) @@ -74,8 +74,8 @@ def build_docs(version='dev', **kwargs): GENERATE_MAN = NO GENERATE_RTF = NO CASE_SENSE_NAMES = NO - INPUT = {0}/container.h {0}/format.h {0}/ostream.h \ - {0}/printf.h {0}/string.h + INPUT = {0}/core.h {0}/format.h {0}/ostream.h \ + {0}/printf.h {0}/time.h QUIET = YES JAVADOC_AUTOBRIEF = YES AUTOLINK_SUPPORT = NO @@ -89,7 +89,10 @@ def build_docs(version='dev', **kwargs): FMT_USE_VARIADIC_TEMPLATES=1 \ FMT_USE_RVALUE_REFERENCES=1 \ FMT_USE_USER_DEFINED_LITERALS=1 \ - FMT_API= + FMT_API= \ + "FMT_BEGIN_NAMESPACE=namespace fmt {{" \ + "FMT_END_NAMESPACE=}}" \ + "FMT_STRING_ALIAS=1" EXCLUDE_SYMBOLS = fmt::internal::* StringValue write_str '''.format(include_dir, doxyxml_dir).encode('UTF-8')) if p.returncode != 0: diff --git a/doc/conf.py b/doc/conf.py index 1e9010e7..0756192b 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -47,7 +47,7 @@ source_suffix = '.rst' # General information about the project. project = u'fmt' -copyright = u'2012-2015, Victor Zverovich' +copyright = u'2012-present, Victor Zverovich' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff --git a/doc/index.rst b/doc/index.rst index a00828b0..17d6b4bb 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -2,8 +2,7 @@ Overview ======== **fmt** (formerly cppformat) is an open-source formatting library. -It can be used as a safe alternative to printf or as a fast -alternative to C++ IOStreams. +It can be used as a fast and safe alternative to printf and IOStreams. .. raw:: html @@ -16,7 +15,7 @@ alternative to C++ IOStreams. -.. _format-api: +.. _format-api-intro: Format API ---------- @@ -25,21 +24,21 @@ The replacement-based Format API provides a safe alternative to ``printf``, ``sprintf`` and friends with comparable or `better performance `_. The `format string syntax `_ is similar to the one used by -`str.format `_ +`str.format `_ in Python: .. code:: c++ - fmt::format("The answer is {}", 42); + fmt::format("The answer is {}.", 42); -The ``fmt::format`` function returns a string "The answer is 42". You can use -``fmt::MemoryWriter`` to avoid constructing ``std::string``: +The ``fmt::format`` function returns a string "The answer is 42.". You can use +``fmt::memory_buffer`` to avoid constructing ``std::string``: .. code:: c++ - fmt::MemoryWriter w; - w.write("Look, a {} string", 'C'); - w.c_str(); // returns a C string (const char*) + fmt::memory_buffer out; + format_to(out, "For a moment, {} happened.", "nothing"); + out.data(); // returns a pointer to the formatted data The ``fmt::print`` function performs formatting and writes the result to a file: @@ -54,11 +53,6 @@ The file argument can be omitted in which case the function prints to fmt::print("Don't {}\n", "panic"); -If your compiler supports C++11, then the formatting functions are implemented -with variadic templates. Otherwise variadic functions are emulated by generating -a set of lightweight wrappers. This ensures compatibility with older compilers -while providing a natural API. - The Format API also supports positional arguments useful for localization: .. code:: c++ @@ -93,39 +87,31 @@ literal operators, they must be made visible with the directive ``using namespace fmt::literals;``. Note that this brings in only ``_a`` and ``_format`` but nothing else from the ``fmt`` namespace. -.. _write-api: - -Write API ---------- - -The concatenation-based Write API (experimental) provides a `fast -`_ -stateless alternative to IOStreams: - -.. code:: c++ - - fmt::MemoryWriter out; - out << "The answer in hexadecimal is " << hex(42); - .. _safety: Safety ------ The library is fully type safe, automatic memory management prevents buffer -overflow, errors in format strings are reported using exceptions. For example, -the code +overflow, errors in format strings are reported using exceptions or at compile +tim. For example, the code .. code:: c++ fmt::format("The answer is {:d}", "forty-two"); -throws a ``FormatError`` 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. +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 -Where possible, errors are caught at compile time. For example, the code +.. code:: c++ + + format(fmt("The answer is {:d}"), "forty-two"); + +reports a compile-time error for the same reason on compilers that support +relaxed ``constexpr``. + +The following code .. code:: c++ @@ -143,44 +129,56 @@ 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. -Note that fmt does not use the value of the ``errno`` global to communicate -errors to the user, but it may call system functions which set ``errno``. Since -fmt does not attempt to preserve the value of ``errno``, users should not make -any assumptions about it and always set it to ``0`` before making any system -calls that convey error information via ``errno``. +Compact binary code +------------------- + +The library is designed to produce compact per-call compiled code. For example +(`godbolt `_), + +.. code:: c++ + + #include + + int main() { + fmt::print("The answer is {}.", 42); + } + +compiles to just + +.. code:: asm + + 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, fmt::v5::format_args) + xor eax, eax + add rsp, 24 + ret + .L.str: + .asciz "The answer is {}." .. _portability: Portability ----------- -The library is highly portable. Here is an incomplete list of operating systems -and compilers where it has been tested and known to work: +The library is highly portable and relies only on a small set of C++11 features: -* 64-bit (amd64) GNU/Linux with GCC 4.4.3, - `4.6.3 `_, 4.7.2, 4.8.1, and Intel C++ - Compiler (ICC) 14.0.2 +* variadic templates +* type traits +* rvalue references +* decltype +* trailing return types +* deleted functions -* 32-bit (i386) GNU/Linux with GCC 4.4.3, 4.6.3 - -* Mac OS X with GCC 4.2.1 and Clang 4.2, 5.1.0 - -* 64-bit Windows with Visual C++ 2010, 2013 and - `2015 `_ - -* 32-bit Windows with Visual C++ 2010 - -Although the library uses C++11 features when available, it also works with -older compilers and standard library implementations. The only thing to keep in -mind for C++98 portability: - -* Variadic templates: minimum GCC 4.4, Clang 2.9 or VS2013. This feature allows - the Format API to accept an unlimited number of arguments. With older - compilers the maximum is 15. - -* User-defined literals: minimum GCC 4.7, Clang 3.1 or VS2015. The suffixes - ``_format`` and ``_a`` are functionally equivalent to the functions - ``fmt::format`` and ``fmt::arg``. +These are available since GCC 4.4, Clang 2.9 and MSVC 18.0 (2013). For older +compilers use fmt `version 4.x +`_ which continues to be +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 @@ -198,7 +196,7 @@ Ease of Use ----------- fmt has a small self-contained code base with the core library consisting of -a single header file and a single source file and no external dependencies. +just three header files and no external dependencies. A permissive BSD `license `_ allows using the library both in open-source and commercial projects. diff --git a/doc/syntax.rst b/doc/syntax.rst index e6d2efeb..fc27c5e2 100644 --- a/doc/syntax.rst +++ b/doc/syntax.rst @@ -4,8 +4,9 @@ Format String Syntax ******************** -Formatting functions such as :ref:`fmt::format() ` and :ref:`fmt::print() ` -use the same format string syntax described in this section. +Formatting functions such as :ref:`fmt::format() ` and +:ref:`fmt::print() ` use the same format string syntax described in this +section. Format strings contain "replacement fields" surrounded by curly braces ``{}``. Anything that is not contained in braces is considered literal text, which is @@ -35,6 +36,8 @@ 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. +Named arguments can be referred to by their names or indices. + Some simple format string examples:: "First, thou shalt count to {0}" // References the first argument @@ -51,8 +54,8 @@ described in the next section. A *format_spec* field can also include nested replacement fields in certain positions within it. These nested replacement fields can contain only an -argument id; format specifications are not allowed. This allows the -formatting of a value to be dynamically specified. +argument id; format specifications are not allowed. This allows the formatting +of a value to be dynamically specified. See the :ref:`formatexamples` section for some examples. @@ -73,7 +76,7 @@ The general form of a *standard format specifier* is: .. productionlist:: sf format_spec: [[`fill`]`align`][`sign`]["#"]["0"][`width`]["." `precision`][`type`] - fill: + fill: align: "<" | ">" | "=" | "^" sign: "+" | "-" | " " width: `integer` | "{" `arg_id` "}" @@ -81,11 +84,11 @@ The general form of a *standard format specifier* is: type: `int_type` | "a" | "A" | "c" | "e" | "E" | "f" | "F" | "g" | "G" | "p" | "s" int_type: "b" | "B" | "d" | "n" | "o" | "x" | "X" -The *fill* character can be any character other than '{' or '}'. 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 *format_spec* is not -a valid alignment option, then it is assumed that both the fill character and -the alignment option are absent. +The *fill* character can be any character other than '{', '}' or '\\0'. 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 *format_spec* +is not a valid alignment option, then it is assumed that both the fill character +and the alignment option are absent. The meaning of the various alignment options is as follows: @@ -360,7 +363,12 @@ Replacing ``%x`` and ``%o`` and converting the value to different bases:: // Result: "int: 42; hex: 2a; oct: 52; bin: 101010" // with 0x or 0 or 0b as prefix: format("int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}", 42); - // Result: "int: 42; hex: 0x2a; oct: 052; bin: 0b101010" + // Result: "int: 42; hex: 0x2a; oct: 052; bin: 0b101010" + +Padded hex byte with prefix and always prints both hex characters:: + + format("{:#04x}", 0); + // Result: "0x00" .. ifconfig:: False diff --git a/doc/usage.rst b/doc/usage.rst index 4c65f8ab..4d39882c 100644 --- a/doc/usage.rst +++ b/doc/usage.rst @@ -61,19 +61,22 @@ __ http://en.wikipedia.org/wiki/Library_%28computing%29#Shared_libraries Header-only usage with CMake ============================ -In order to add ``fmtlib`` into an existing ``CMakeLists.txt`` file, you can add the ``fmt`` library directory into your main project, which will enable the ``fmt`` library:: +You can add the ``fmt`` library directory into your project and include it in +your ``CMakeLists.txt`` file:: add_subdirectory(fmt) - -If you have a project called ``foo`` that you would like to link against the fmt library in a header-only fashion, you can enable with with:: - target_link_libraries(foo PRIVATE fmt::fmt-header-only) - -And then to ensure that the ``fmt`` library does not always get built, you can modify the call to ``add_subdirectory`` to read :: +or + +:: add_subdirectory(fmt EXCLUDE_FROM_ALL) - -This will ensure that the ``fmt`` library is exluded from calls to ``make``, ``make all``, or ``cmake --build .``. + +to exclude it from ``make``, ``make all``, or ``cmake --build .``. + +Settting up your target to use a header-only version of ``fmt`` is equaly easy:: + + target_link_libraries( PRIVATE fmt-header-only) Building the documentation ========================== diff --git a/fmt/CMakeLists.txt b/fmt/CMakeLists.txt deleted file mode 100644 index 3259d788..00000000 --- a/fmt/CMakeLists.txt +++ /dev/null @@ -1,94 +0,0 @@ -# Define the fmt library, its includes and the needed defines. -# *.cc are added to FMT_HEADERS for the header-only configuration. -set(FMT_HEADERS container.h format.h format.cc ostream.h ostream.cc printf.h - printf.cc string.h time.h) -if (HAVE_OPEN) - set(FMT_HEADERS ${FMT_HEADERS} posix.h) - set(FMT_SOURCES ${FMT_SOURCES} posix.cc) -endif () - -add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} ../README.rst ../ChangeLog.rst) -add_library(fmt::fmt ALIAS fmt) - -# Starting with cmake 3.1 the CXX_STANDARD property can be used instead. -# Note: Don't make -std=c++11 public or interface, since it breaks projects -# that use C++14. -target_compile_options(fmt PRIVATE ${CPP11_FLAG}) -if (FMT_PEDANTIC) - target_compile_options(fmt PRIVATE ${PEDANTIC_COMPILE_FLAGS}) -endif () - -target_include_directories(fmt PUBLIC - $ - $) - -set_target_properties(fmt PROPERTIES - VERSION ${FMT_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR}) - -if (BUILD_SHARED_LIBS) - if (UNIX AND NOT APPLE) - # 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) - endif () - target_compile_definitions(fmt PRIVATE FMT_EXPORT INTERFACE FMT_SHARED) -endif () - -#------------------------------------------------------------------------------ -# additionally define a header only library when cmake is new enough -if (CMAKE_VERSION VERSION_GREATER 3.1.0 OR CMAKE_VERSION VERSION_EQUAL 3.1.0) - add_library(fmt-header-only INTERFACE) - add_library(fmt::fmt-header-only ALIAS fmt-header-only) - - target_compile_definitions(fmt-header-only INTERFACE FMT_HEADER_ONLY=1) - - target_include_directories(fmt-header-only INTERFACE - $ - $) -endif () - -# Install targets. -if (FMT_INSTALL) - include(GNUInstallDirs) - include(CMakePackageConfigHelpers) - set(FMT_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/fmt CACHE STRING - "Installation directory for cmake files, relative to ${CMAKE_INSTALL_PREFIX}.") - set(version_config ${PROJECT_BINARY_DIR}/fmt-config-version.cmake) - set(project_config ${PROJECT_BINARY_DIR}/fmt-config.cmake) - set(targets_export_name fmt-targets) - - set (INSTALL_TARGETS fmt) - if (TARGET fmt-header-only) - set(INSTALL_TARGETS ${INSTALL_TARGETS} fmt-header-only) - endif () - - set(FMT_LIB_DIR ${CMAKE_INSTALL_LIBDIR} CACHE STRING - "Installation directory for libraries, relative to ${CMAKE_INSTALL_PREFIX}.") - - set(FMT_INC_DIR ${CMAKE_INSTALL_INCLUDEDIR}/fmt CACHE STRING - "Installation directory for include files, relative to ${CMAKE_INSTALL_PREFIX}.") - - # Generate the version, config and target files into the build directory. - write_basic_package_version_file( - ${version_config} - VERSION ${FMT_VERSION} - COMPATIBILITY AnyNewerVersion) - configure_package_config_file( - ${PROJECT_SOURCE_DIR}/support/cmake/fmt-config.cmake.in - ${project_config} - INSTALL_DESTINATION ${FMT_CMAKE_DIR}) - export(TARGETS ${INSTALL_TARGETS} NAMESPACE fmt:: - FILE ${PROJECT_BINARY_DIR}/${targets_export_name}.cmake) - - # Install version, config and target files. - install( - FILES ${project_config} ${version_config} - DESTINATION ${FMT_CMAKE_DIR}) - install(EXPORT ${targets_export_name} DESTINATION ${FMT_CMAKE_DIR} - NAMESPACE fmt::) - - # Install the library and headers. - install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name} - DESTINATION ${FMT_LIB_DIR}) - install(FILES ${FMT_HEADERS} DESTINATION ${FMT_INC_DIR}) -endif () diff --git a/fmt/container.h b/fmt/container.h deleted file mode 100644 index cb6303fb..00000000 --- a/fmt/container.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - Formatting library for C++ - standard container utilities - - Copyright (c) 2012 - 2016, Victor Zverovich - All rights reserved. - - For the license information refer to format.h. - */ - -#ifndef FMT_CONTAINER_H_ -#define FMT_CONTAINER_H_ - -#include "format.h" - -namespace fmt { - -namespace internal { - -/** - \rst - A "buffer" that appends data to a standard container (e.g. typically a - ``std::vector`` or ``std::basic_string``). - \endrst - */ -template -class ContainerBuffer : public Buffer { - private: - Container& container_; - - protected: - virtual void grow(std::size_t size) FMT_OVERRIDE { - container_.resize(size); - this->ptr_ = &container_[0]; - this->capacity_ = size; - } - - public: - explicit ContainerBuffer(Container& container) : container_(container) { - this->size_ = container_.size(); - if (this->size_ > 0) { - this->ptr_ = &container_[0]; - this->capacity_ = this->size_; - } - } -}; -} // namespace internal - -/** - \rst - This class template provides operations for formatting and appending data - to a standard *container* like ``std::vector`` or ``std::basic_string``. - - **Example**:: - - void vecformat(std::vector& dest, fmt::BasicCStringRef format, - fmt::ArgList args) { - fmt::BasicContainerWriter > appender(dest); - appender.write(format, args); - } - FMT_VARIADIC(void, vecformat, std::vector&, - fmt::BasicCStringRef); - \endrst - */ -template -class BasicContainerWriter - : public BasicWriter { - private: - internal::ContainerBuffer buffer_; - - public: - /** - \rst - Constructs a :class:`fmt::BasicContainerWriter` object. - \endrst - */ - explicit BasicContainerWriter(Container& dest) - : BasicWriter(buffer_), buffer_(dest) {} -}; - -} // namespace fmt - -#endif // FMT_CONTAINER_H_ diff --git a/fmt/format.cc b/fmt/format.cc deleted file mode 100644 index 2d236bc6..00000000 --- a/fmt/format.cc +++ /dev/null @@ -1,495 +0,0 @@ -/* - Formatting library for C++ - - Copyright (c) 2012 - 2016, Victor Zverovich - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "format.h" - -#include - -#include -#include -#include -#include -#include -#include // for std::ptrdiff_t - -#if defined(_WIN32) && defined(__MINGW32__) -# include -#endif - -#if FMT_USE_WINDOWS_H -# if !defined(FMT_HEADER_ONLY) && !defined(WIN32_LEAN_AND_MEAN) -# define WIN32_LEAN_AND_MEAN -# endif -# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX) -# include -# else -# define NOMINMAX -# include -# undef NOMINMAX -# endif -#endif - -#if FMT_EXCEPTIONS -# define FMT_TRY try -# define FMT_CATCH(x) catch (x) -#else -# define FMT_TRY if (true) -# define FMT_CATCH(x) if (false) -#endif - -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4127) // conditional expression is constant -# pragma warning(disable: 4702) // unreachable code -// Disable deprecation warning for strerror. The latter is not called but -// MSVC fails to detect it. -# pragma warning(disable: 4996) -#endif - -// Dummy implementations of strerror_r and strerror_s called if corresponding -// system functions are not available. -FMT_MAYBE_UNUSED -static inline fmt::internal::Null<> strerror_r(int, char *, ...) { - return fmt::internal::Null<>(); -} -FMT_MAYBE_UNUSED -static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) { - return fmt::internal::Null<>(); -} - -namespace fmt { - -FMT_FUNC internal::RuntimeError::~RuntimeError() FMT_DTOR_NOEXCEPT {} -FMT_FUNC FormatError::~FormatError() FMT_DTOR_NOEXCEPT {} -FMT_FUNC SystemError::~SystemError() FMT_DTOR_NOEXCEPT {} - -namespace { - -#ifndef _MSC_VER -# define FMT_SNPRINTF snprintf -#else // _MSC_VER -inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) { - va_list args; - va_start(args, format); - int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args); - va_end(args); - return result; -} -# define FMT_SNPRINTF fmt_snprintf -#endif // _MSC_VER - -#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) -# define FMT_SWPRINTF snwprintf -#else -# define FMT_SWPRINTF swprintf -#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) - -const char RESET_COLOR[] = "\x1b[0m"; - -typedef void (*FormatFunc)(Writer &, int, StringRef); - -// Portable thread-safe version of strerror. -// Sets buffer to point to a string describing the error code. -// This can be either a pointer to a string stored in buffer, -// or a pointer to some static immutable string. -// Returns one of the following values: -// 0 - success -// ERANGE - buffer is not large enough to store the error message -// other - failure -// Buffer should be at least of size 1. -int safe_strerror( - int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT { - FMT_ASSERT(buffer != FMT_NULL && buffer_size != 0, "invalid buffer"); - - class StrError { - private: - int error_code_; - char *&buffer_; - std::size_t buffer_size_; - - // A noop assignment operator to avoid bogus warnings. - void operator=(const StrError &) {} - - // Handle the result of XSI-compliant version of strerror_r. - int handle(int result) { - // glibc versions before 2.13 return result in errno. - return result == -1 ? errno : result; - } - - // Handle the result of GNU-specific version of strerror_r. - int handle(char *message) { - // If the buffer is full then the message is probably truncated. - if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1) - return ERANGE; - buffer_ = message; - return 0; - } - - // Handle the case when strerror_r is not available. - int handle(internal::Null<>) { - return fallback(strerror_s(buffer_, buffer_size_, error_code_)); - } - - // Fallback to strerror_s when strerror_r is not available. - int fallback(int result) { - // If the buffer is full then the message is probably truncated. - return result == 0 && strlen(buffer_) == buffer_size_ - 1 ? - ERANGE : result; - } - -#ifdef __c2__ -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated-declarations" -#endif - - // Fallback to strerror if strerror_r and strerror_s are not available. - int fallback(internal::Null<>) { - errno = 0; - buffer_ = strerror(error_code_); - return errno; - } - -#ifdef __c2__ -# pragma clang diagnostic pop -#endif - - public: - StrError(int err_code, char *&buf, std::size_t buf_size) - : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {} - - int run() { - return handle(strerror_r(error_code_, buffer_, buffer_size_)); - } - }; - return StrError(error_code, buffer, buffer_size).run(); -} - -void format_error_code(Writer &out, int error_code, - StringRef message) FMT_NOEXCEPT { - // Report error code making sure that the output fits into - // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential - // bad_alloc. - out.clear(); - static const char SEP[] = ": "; - static const char ERROR_STR[] = "error "; - // Subtract 2 to account for terminating null characters in SEP and ERROR_STR. - std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2; - typedef internal::IntTraits::MainType MainType; - MainType abs_value = static_cast(error_code); - if (internal::is_negative(error_code)) { - abs_value = 0 - abs_value; - ++error_code_size; - } - error_code_size += internal::count_digits(abs_value); - if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size) - out << message << SEP; - out << ERROR_STR << error_code; - assert(out.size() <= internal::INLINE_BUFFER_SIZE); -} - -void report_error(FormatFunc func, int error_code, - StringRef message) FMT_NOEXCEPT { - MemoryWriter full_message; - func(full_message, error_code, message); - // Use Writer::data instead of Writer::c_str to avoid potential memory - // allocation. - std::fwrite(full_message.data(), full_message.size(), 1, stderr); - std::fputc('\n', stderr); -} -} // namespace - -FMT_FUNC void SystemError::init( - int err_code, CStringRef format_str, ArgList args) { - error_code_ = err_code; - MemoryWriter w; - format_system_error(w, err_code, format(format_str, args)); - std::runtime_error &base = *this; - base = std::runtime_error(w.str()); -} - -template -int internal::CharTraits::format_float( - char *buffer, std::size_t size, const char *format, - unsigned width, int precision, T value) { - if (width == 0) { - return precision < 0 ? - FMT_SNPRINTF(buffer, size, format, value) : - FMT_SNPRINTF(buffer, size, format, precision, value); - } - return precision < 0 ? - FMT_SNPRINTF(buffer, size, format, width, value) : - FMT_SNPRINTF(buffer, size, format, width, precision, value); -} - -template -int internal::CharTraits::format_float( - wchar_t *buffer, std::size_t size, const wchar_t *format, - unsigned width, int precision, T value) { - if (width == 0) { - return precision < 0 ? - FMT_SWPRINTF(buffer, size, format, value) : - FMT_SWPRINTF(buffer, size, format, precision, value); - } - return precision < 0 ? - FMT_SWPRINTF(buffer, size, format, width, value) : - FMT_SWPRINTF(buffer, size, format, width, precision, value); -} - -template -const char internal::BasicData::DIGITS[] = - "0001020304050607080910111213141516171819" - "2021222324252627282930313233343536373839" - "4041424344454647484950515253545556575859" - "6061626364656667686970717273747576777879" - "8081828384858687888990919293949596979899"; - -#define FMT_POWERS_OF_10(factor) \ - factor * 10, \ - factor * 100, \ - factor * 1000, \ - factor * 10000, \ - factor * 100000, \ - factor * 1000000, \ - factor * 10000000, \ - factor * 100000000, \ - factor * 1000000000 - -template -const uint32_t internal::BasicData::POWERS_OF_10_32[] = { - 0, FMT_POWERS_OF_10(1) -}; - -template -const uint64_t internal::BasicData::POWERS_OF_10_64[] = { - 0, - FMT_POWERS_OF_10(1), - FMT_POWERS_OF_10(ULongLong(1000000000)), - // Multiply several constants instead of using a single long long constant - // to avoid warnings about C++98 not supporting long long. - ULongLong(1000000000) * ULongLong(1000000000) * 10 -}; - -FMT_FUNC void internal::report_unknown_type(char code, const char *type) { - (void)type; - if (std::isprint(static_cast(code))) { - FMT_THROW(FormatError( - format("unknown format code '{}' for {}", code, type))); - } - FMT_THROW(FormatError( - format("unknown format code '\\x{:02x}' for {}", - static_cast(code), type))); -} - -#if FMT_USE_WINDOWS_H - -FMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(StringRef s) { - static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16"; - if (s.size() > INT_MAX) - FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG)); - int s_size = static_cast(s.size()); - int length = MultiByteToWideChar( - CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0); - if (length == 0) - FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); - buffer_.resize(length + 1); - length = MultiByteToWideChar( - CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length); - if (length == 0) - FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); - buffer_[length] = 0; -} - -FMT_FUNC internal::UTF16ToUTF8::UTF16ToUTF8(WStringRef s) { - if (int error_code = convert(s)) { - FMT_THROW(WindowsError(error_code, - "cannot convert string from UTF-16 to UTF-8")); - } -} - -FMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s) { - if (s.size() > INT_MAX) - return ERROR_INVALID_PARAMETER; - int s_size = static_cast(s.size()); - int length = WideCharToMultiByte( - CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL); - if (length == 0) - return GetLastError(); - buffer_.resize(length + 1); - length = WideCharToMultiByte( - CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL); - if (length == 0) - return GetLastError(); - buffer_[length] = 0; - return 0; -} - -FMT_FUNC void WindowsError::init( - int err_code, CStringRef format_str, ArgList args) { - error_code_ = err_code; - MemoryWriter w; - internal::format_windows_error(w, err_code, format(format_str, args)); - std::runtime_error &base = *this; - base = std::runtime_error(w.str()); -} - -FMT_FUNC void internal::format_windows_error( - Writer &out, int error_code, StringRef message) FMT_NOEXCEPT { - FMT_TRY { - MemoryBuffer buffer; - buffer.resize(INLINE_BUFFER_SIZE); - for (;;) { - wchar_t *system_message = &buffer[0]; - int result = FormatMessageW( - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - system_message, static_cast(buffer.size()), FMT_NULL); - if (result != 0) { - UTF16ToUTF8 utf8_message; - if (utf8_message.convert(system_message) == ERROR_SUCCESS) { - out << message << ": " << utf8_message; - return; - } - break; - } - if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) - break; // Can't get error message, report error code instead. - buffer.resize(buffer.size() * 2); - } - } FMT_CATCH(...) {} - fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. -} - -#endif // FMT_USE_WINDOWS_H - -FMT_FUNC void format_system_error( - Writer &out, int error_code, StringRef message) FMT_NOEXCEPT { - FMT_TRY { - internal::MemoryBuffer buffer; - buffer.resize(internal::INLINE_BUFFER_SIZE); - for (;;) { - char *system_message = &buffer[0]; - int result = safe_strerror(error_code, system_message, buffer.size()); - if (result == 0) { - out << message << ": " << system_message; - return; - } - if (result != ERANGE) - break; // Can't get error message, report error code instead. - buffer.resize(buffer.size() * 2); - } - } FMT_CATCH(...) {} - fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. -} - -template -void internal::FixedBuffer::grow(std::size_t) { - FMT_THROW(std::runtime_error("buffer overflow")); -} - -FMT_FUNC internal::Arg internal::FormatterBase::do_get_arg( - unsigned arg_index, const char *&error) { - internal::Arg arg = args_[arg_index]; - switch (arg.type) { - case internal::Arg::NONE: - error = "argument index out of range"; - break; - case internal::Arg::NAMED_ARG: - arg = *static_cast(arg.pointer); - break; - default: - /*nothing*/; - } - return arg; -} - -FMT_FUNC void report_system_error( - int error_code, fmt::StringRef message) FMT_NOEXCEPT { - // 'fmt::' is for bcc32. - report_error(format_system_error, error_code, message); -} - -#if FMT_USE_WINDOWS_H -FMT_FUNC void report_windows_error( - int error_code, fmt::StringRef message) FMT_NOEXCEPT { - // 'fmt::' is for bcc32. - report_error(internal::format_windows_error, error_code, message); -} -#endif - -FMT_FUNC void print(std::FILE *f, CStringRef format_str, ArgList args) { - MemoryWriter w; - w.write(format_str, args); - std::fwrite(w.data(), 1, w.size(), f); -} - -FMT_FUNC void print(CStringRef format_str, ArgList args) { - print(stdout, format_str, args); -} - -FMT_FUNC void print_colored(Color c, CStringRef format, ArgList args) { - char escape[] = "\x1b[30m"; - escape[3] = static_cast('0' + c); - std::fputs(escape, stdout); - print(format, args); - std::fputs(RESET_COLOR, stdout); -} - -#ifndef FMT_HEADER_ONLY - -template struct internal::BasicData; - -// Explicit instantiations for char. - -template void internal::FixedBuffer::grow(std::size_t); - -template FMT_API int internal::CharTraits::format_float( - char *buffer, std::size_t size, const char *format, - unsigned width, int precision, double value); - -template FMT_API int internal::CharTraits::format_float( - char *buffer, std::size_t size, const char *format, - unsigned width, int precision, long double value); - -// Explicit instantiations for wchar_t. - -template void internal::FixedBuffer::grow(std::size_t); - -template FMT_API int internal::CharTraits::format_float( - wchar_t *buffer, std::size_t size, const wchar_t *format, - unsigned width, int precision, double value); - -template FMT_API int internal::CharTraits::format_float( - wchar_t *buffer, std::size_t size, const wchar_t *format, - unsigned width, int precision, long double value); - -#endif // FMT_HEADER_ONLY - -} // namespace fmt - -#ifdef _MSC_VER -# pragma warning(pop) -#endif diff --git a/fmt/format.h b/fmt/format.h deleted file mode 100644 index 561a9e07..00000000 --- a/fmt/format.h +++ /dev/null @@ -1,4173 +0,0 @@ -/* - Formatting library for C++ - - Copyright (c) 2012 - 2016, Victor Zverovich - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FMT_FORMAT_H_ -#define FMT_FORMAT_H_ - -#define FMT_INCLUDE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include // for std::pair -#undef FMT_INCLUDE - -// The fmt library version in the form major * 10000 + minor * 100 + patch. -#define FMT_VERSION 40100 - -#if defined(__has_include) -# define FMT_HAS_INCLUDE(x) __has_include(x) -#else -# define FMT_HAS_INCLUDE(x) 0 -#endif - -#if (FMT_HAS_INCLUDE() && __cplusplus > 201402L) || \ - (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910) -# include -# define FMT_HAS_STRING_VIEW 1 -#else -# define FMT_HAS_STRING_VIEW 0 -#endif - -#if defined _SECURE_SCL && _SECURE_SCL -# define FMT_SECURE_SCL _SECURE_SCL -#else -# define FMT_SECURE_SCL 0 -#endif - -#if FMT_SECURE_SCL -# include -#endif - -#ifdef _MSC_VER -# define FMT_MSC_VER _MSC_VER -#else -# define FMT_MSC_VER 0 -#endif - -#if FMT_MSC_VER && FMT_MSC_VER <= 1500 -typedef unsigned __int32 uint32_t; -typedef unsigned __int64 uint64_t; -typedef __int64 intmax_t; -#else -#include -#endif - -#if !defined(FMT_HEADER_ONLY) && defined(_WIN32) -# ifdef FMT_EXPORT -# define FMT_API __declspec(dllexport) -# elif defined(FMT_SHARED) -# define FMT_API __declspec(dllimport) -# endif -#endif -#ifndef FMT_API -# define FMT_API -#endif - -#ifdef __GNUC__ -# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -# define FMT_GCC_EXTENSION __extension__ -# if FMT_GCC_VERSION >= 406 -# pragma GCC diagnostic push -// Disable the warning about "long long" which is sometimes reported even -// when using __extension__. -# pragma GCC diagnostic ignored "-Wlong-long" -// Disable the warning about declaration shadowing because it affects too -// many valid cases. -# pragma GCC diagnostic ignored "-Wshadow" -// Disable the warning about implicit conversions that may change the sign of -// an integer; silencing it otherwise would require many explicit casts. -# pragma GCC diagnostic ignored "-Wsign-conversion" -# endif -# if __cplusplus >= 201103L || defined __GXX_EXPERIMENTAL_CXX0X__ -# define FMT_HAS_GXX_CXX11 1 -# endif -#else -# define FMT_GCC_VERSION 0 -# define FMT_GCC_EXTENSION -# define FMT_HAS_GXX_CXX11 0 -#endif - -#if defined(__INTEL_COMPILER) -# define FMT_ICC_VERSION __INTEL_COMPILER -#elif defined(__ICL) -# define FMT_ICC_VERSION __ICL -#endif - -#if defined(__clang__) && !defined(FMT_ICC_VERSION) -# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdocumentation-unknown-command" -# pragma clang diagnostic ignored "-Wpadded" -#endif - -#ifdef __GNUC_LIBSTD__ -# define FMT_GNUC_LIBSTD_VERSION (__GNUC_LIBSTD__ * 100 + __GNUC_LIBSTD_MINOR__) -#endif - -#ifdef __has_feature -# define FMT_HAS_FEATURE(x) __has_feature(x) -#else -# define FMT_HAS_FEATURE(x) 0 -#endif - -#ifdef __has_builtin -# define FMT_HAS_BUILTIN(x) __has_builtin(x) -#else -# define FMT_HAS_BUILTIN(x) 0 -#endif - -#ifdef __has_cpp_attribute -# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) -#else -# define FMT_HAS_CPP_ATTRIBUTE(x) 0 -#endif - -#if FMT_HAS_CPP_ATTRIBUTE(maybe_unused) -# define FMT_HAS_CXX17_ATTRIBUTE_MAYBE_UNUSED -// VC++ 1910 support /std: option and that will set _MSVC_LANG macro -// Clang with Microsoft CodeGen doesn't define _MSVC_LANG macro -#elif defined(_MSVC_LANG) && _MSVC_LANG > 201402 && _MSC_VER >= 1910 -# define FMT_HAS_CXX17_ATTRIBUTE_MAYBE_UNUSED -#endif - -#ifdef FMT_HAS_CXX17_ATTRIBUTE_MAYBE_UNUSED -# define FMT_MAYBE_UNUSED [[maybe_unused]] -// g++/clang++ also support [[gnu::unused]]. However, we don't use it. -#elif defined(__GNUC__) -# define FMT_MAYBE_UNUSED __attribute__((unused)) -#else -# define FMT_MAYBE_UNUSED -#endif - -// Use the compiler's attribute noreturn -#if defined(__MINGW32__) || defined(__MINGW64__) -# define FMT_NORETURN __attribute__((noreturn)) -#elif FMT_HAS_CPP_ATTRIBUTE(noreturn) && __cplusplus >= 201103L -# define FMT_NORETURN [[noreturn]] -#else -# define FMT_NORETURN -#endif - -#ifndef FMT_USE_VARIADIC_TEMPLATES -// Variadic templates are available in GCC since version 4.4 -// (http://gcc.gnu.org/projects/cxx0x.html) and in Visual C++ -// since version 2013. -# define FMT_USE_VARIADIC_TEMPLATES \ - (FMT_HAS_FEATURE(cxx_variadic_templates) || \ - (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1800) -#endif - -#ifndef FMT_USE_RVALUE_REFERENCES -// Don't use rvalue references when compiling with clang and an old libstdc++ -// as the latter doesn't provide std::move. -# if defined(FMT_GNUC_LIBSTD_VERSION) && FMT_GNUC_LIBSTD_VERSION <= 402 -# define FMT_USE_RVALUE_REFERENCES 0 -# else -# define FMT_USE_RVALUE_REFERENCES \ - (FMT_HAS_FEATURE(cxx_rvalue_references) || \ - (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1600) -# endif -#endif - -#if __cplusplus >= 201103L || FMT_MSC_VER >= 1700 -# define FMT_USE_ALLOCATOR_TRAITS 1 -#else -# define FMT_USE_ALLOCATOR_TRAITS 0 -#endif - -// Check if exceptions are disabled. -#if defined(__GNUC__) && !defined(__EXCEPTIONS) -# define FMT_EXCEPTIONS 0 -#endif -#if FMT_MSC_VER && !_HAS_EXCEPTIONS -# define FMT_EXCEPTIONS 0 -#endif -#ifndef FMT_EXCEPTIONS -# define FMT_EXCEPTIONS 1 -#endif - -#ifndef FMT_THROW -# if FMT_EXCEPTIONS -# define FMT_THROW(x) throw x -# else -# define FMT_THROW(x) assert(false) -# endif -#endif - -// Define FMT_USE_NOEXCEPT to make fmt use noexcept (C++11 feature). -#ifndef FMT_USE_NOEXCEPT -# define FMT_USE_NOEXCEPT 0 -#endif - -#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ - (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \ - FMT_MSC_VER >= 1900 -# define FMT_DETECTED_NOEXCEPT noexcept -#else -# define FMT_DETECTED_NOEXCEPT throw() -#endif - -#ifndef FMT_NOEXCEPT -# if FMT_EXCEPTIONS -# define FMT_NOEXCEPT FMT_DETECTED_NOEXCEPT -# else -# define FMT_NOEXCEPT -# endif -#endif - -// This is needed because GCC still uses throw() in its headers when exceptions -// are disabled. -#if FMT_GCC_VERSION -# define FMT_DTOR_NOEXCEPT FMT_DETECTED_NOEXCEPT -#else -# define FMT_DTOR_NOEXCEPT FMT_NOEXCEPT -#endif - -#ifndef FMT_OVERRIDE -# if (defined(FMT_USE_OVERRIDE) && FMT_USE_OVERRIDE) || FMT_HAS_FEATURE(cxx_override) || \ - (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \ - FMT_MSC_VER >= 1900 -# define FMT_OVERRIDE override -# else -# define FMT_OVERRIDE -# endif -#endif - -#ifndef FMT_NULL -# if FMT_HAS_FEATURE(cxx_nullptr) || \ - (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \ - FMT_MSC_VER >= 1600 -# define FMT_NULL nullptr -# else -# define FMT_NULL NULL -# endif -#endif - -// A macro to disallow the copy constructor and operator= functions -// This should be used in the private: declarations for a class -#ifndef FMT_USE_DELETED_FUNCTIONS -# define FMT_USE_DELETED_FUNCTIONS 0 -#endif - -#if FMT_USE_DELETED_FUNCTIONS || FMT_HAS_FEATURE(cxx_deleted_functions) || \ - (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1800 -# define FMT_DELETED_OR_UNDEFINED = delete -# define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&) = delete; \ - TypeName& operator=(const TypeName&) = delete -#else -# define FMT_DELETED_OR_UNDEFINED -# define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&); \ - TypeName& operator=(const TypeName&) -#endif - -#ifndef FMT_USE_DEFAULTED_FUNCTIONS -# define FMT_USE_DEFAULTED_FUNCTIONS 0 -#endif - -#ifndef FMT_DEFAULTED_COPY_CTOR -# if FMT_USE_DEFAULTED_FUNCTIONS || FMT_HAS_FEATURE(cxx_defaulted_functions) || \ - (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1800 -# define FMT_DEFAULTED_COPY_CTOR(TypeName) \ - TypeName(const TypeName&) = default; -# else -# define FMT_DEFAULTED_COPY_CTOR(TypeName) -# endif -#endif - -#ifndef FMT_USE_USER_DEFINED_LITERALS -// All compilers which support UDLs also support variadic templates. This -// makes the fmt::literals implementation easier. However, an explicit check -// for variadic templates is added here just in case. -// For Intel's compiler both it and the system gcc/msc must support UDLs. -# if FMT_USE_VARIADIC_TEMPLATES && FMT_USE_RVALUE_REFERENCES && \ - (FMT_HAS_FEATURE(cxx_user_literals) || \ - (FMT_GCC_VERSION >= 407 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900) && \ - (!defined(FMT_ICC_VERSION) || FMT_ICC_VERSION >= 1500) -# define FMT_USE_USER_DEFINED_LITERALS 1 -# else -# define FMT_USE_USER_DEFINED_LITERALS 0 -# endif -#endif - -#ifndef FMT_USE_EXTERN_TEMPLATES -# define FMT_USE_EXTERN_TEMPLATES \ - (FMT_CLANG_VERSION >= 209 || (FMT_GCC_VERSION >= 303 && FMT_HAS_GXX_CXX11)) -#endif - -#ifdef FMT_HEADER_ONLY -// If header only do not use extern templates. -# undef FMT_USE_EXTERN_TEMPLATES -# define FMT_USE_EXTERN_TEMPLATES 0 -#endif - -#ifndef FMT_ASSERT -# define FMT_ASSERT(condition, message) assert((condition) && message) -#endif - -// __builtin_clz is broken in clang with Microsoft CodeGen: -// https://github.com/fmtlib/fmt/issues/519 -#ifndef _MSC_VER -# if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz) -# define FMT_BUILTIN_CLZ(n) __builtin_clz(n) -# endif - -# if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll) -# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) -# endif -#endif - -// Some compilers masquerade as both MSVC and GCC-likes or -// otherwise support __builtin_clz and __builtin_clzll, so -// only define FMT_BUILTIN_CLZ using the MSVC intrinsics -// if the clz and clzll builtins are not available. -#if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL) && !defined(_MANAGED) -# include // _BitScanReverse, _BitScanReverse64 - -namespace fmt { -namespace internal { -// avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning -# ifndef __clang__ -# pragma intrinsic(_BitScanReverse) -# endif -inline uint32_t clz(uint32_t x) { - unsigned long r = 0; - _BitScanReverse(&r, x); - - assert(x != 0); - // Static analysis complains about using uninitialized data - // "r", but the only way that can happen is if "x" is 0, - // which the callers guarantee to not happen. -# pragma warning(suppress: 6102) - return 31 - r; -} -# define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n) - -// avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning -# if defined(_WIN64) && !defined(__clang__) -# pragma intrinsic(_BitScanReverse64) -# endif - -inline uint32_t clzll(uint64_t x) { - unsigned long r = 0; -# ifdef _WIN64 - _BitScanReverse64(&r, x); -# else - // Scan the high 32 bits. - if (_BitScanReverse(&r, static_cast(x >> 32))) - return 63 - (r + 32); - - // Scan the low 32 bits. - _BitScanReverse(&r, static_cast(x)); -# endif - - assert(x != 0); - // Static analysis complains about using uninitialized data - // "r", but the only way that can happen is if "x" is 0, - // which the callers guarantee to not happen. -# pragma warning(suppress: 6102) - return 63 - r; -} -# define FMT_BUILTIN_CLZLL(n) fmt::internal::clzll(n) -} -} -#endif - -namespace fmt { -namespace internal { -struct DummyInt { - int data[2]; - operator int() const { return 0; } -}; -typedef std::numeric_limits FPUtil; - -// Dummy implementations of system functions such as signbit and ecvt called -// if the latter are not available. -inline DummyInt signbit(...) { return DummyInt(); } -inline DummyInt _ecvt_s(...) { return DummyInt(); } -inline DummyInt isinf(...) { return DummyInt(); } -inline DummyInt _finite(...) { return DummyInt(); } -inline DummyInt isnan(...) { return DummyInt(); } -inline DummyInt _isnan(...) { return DummyInt(); } - -// A helper function to suppress bogus "conditional expression is constant" -// warnings. -template -inline T const_check(T value) { return value; } -} -} // namespace fmt - -namespace std { -// Standard permits specialization of std::numeric_limits. This specialization -// is used to resolve ambiguity between isinf and std::isinf in glibc: -// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=48891 -// and the same for isnan and signbit. -template <> -class numeric_limits : - public std::numeric_limits { - public: - // Portable version of isinf. - template - static bool isinfinity(T x) { - using namespace fmt::internal; - // The resolution "priority" is: - // isinf macro > std::isinf > ::isinf > fmt::internal::isinf - if (const_check(sizeof(isinf(x)) == sizeof(bool) || - sizeof(isinf(x)) == sizeof(int))) { - return isinf(x) != 0; - } - return !_finite(static_cast(x)); - } - - // Portable version of isnan. - template - static bool isnotanumber(T x) { - using namespace fmt::internal; - if (const_check(sizeof(isnan(x)) == sizeof(bool) || - sizeof(isnan(x)) == sizeof(int))) { - return isnan(x) != 0; - } - return _isnan(static_cast(x)) != 0; - } - - // Portable version of signbit. - static bool isnegative(double x) { - using namespace fmt::internal; - if (const_check(sizeof(signbit(x)) == sizeof(bool) || - sizeof(signbit(x)) == sizeof(int))) { - return signbit(x) != 0; - } - if (x < 0) return true; - if (!isnotanumber(x)) return false; - int dec = 0, sign = 0; - char buffer[2]; // The buffer size must be >= 2 or _ecvt_s will fail. - _ecvt_s(buffer, sizeof(buffer), x, 0, &dec, &sign); - return sign != 0; - } -}; -} // namespace std - -namespace fmt { - -// Fix the warning about long long on older versions of GCC -// that don't support the diagnostic pragma. -FMT_GCC_EXTENSION typedef long long LongLong; -FMT_GCC_EXTENSION typedef unsigned long long ULongLong; - -#if FMT_USE_RVALUE_REFERENCES -using std::move; -#endif - -template -class BasicWriter; - -typedef BasicWriter Writer; -typedef BasicWriter WWriter; - -template -class ArgFormatter; - -struct FormatSpec; - -template -class BasicPrintfArgFormatter; - -template > -class BasicFormatter; - -/** - \rst - A string reference. It can be constructed from a C string or - ``std::basic_string``. - - You can use one of the following typedefs for common character types: - - +------------+-------------------------+ - | Type | Definition | - +============+=========================+ - | StringRef | BasicStringRef | - +------------+-------------------------+ - | WStringRef | BasicStringRef | - +------------+-------------------------+ - - This class is most useful as a parameter type to allow passing - different types of strings to a function, for example:: - - template - std::string format(StringRef format_str, const Args & ... args); - - format("{}", 42); - format(std::string("{}"), 42); - \endrst - */ -template -class BasicStringRef { - private: - const Char *data_; - std::size_t size_; - - public: - /** Constructs a string reference object from a C string and a size. */ - BasicStringRef(const Char *s, std::size_t size) : data_(s), size_(size) {} - - /** - \rst - Constructs a string reference object from a C string computing - the size with ``std::char_traits::length``. - \endrst - */ - BasicStringRef(const Char *s) - : data_(s), size_(std::char_traits::length(s)) {} - - /** - \rst - Constructs a string reference from a ``std::basic_string`` object. - \endrst - */ - template - BasicStringRef( - const std::basic_string, Allocator> &s) - : data_(s.c_str()), size_(s.size()) {} - -#if FMT_HAS_STRING_VIEW - /** - \rst - Constructs a string reference from a ``std::basic_string_view`` object. - \endrst - */ - BasicStringRef( - const std::basic_string_view> &s) - : data_(s.data()), size_(s.size()) {} - - /** - \rst - Converts a string reference to an ``std::string_view`` object. - \endrst - */ - explicit operator std::basic_string_view() const FMT_NOEXCEPT { - return std::basic_string_view(data_, size_); - } -#endif - - /** - \rst - Converts a string reference to an ``std::string`` object. - \endrst - */ - std::basic_string to_string() const { - return std::basic_string(data_, size_); - } - - /** Returns a pointer to the string data. */ - const Char *data() const { return data_; } - - /** Returns the string size. */ - std::size_t size() const { return size_; } - - // Lexicographically compare this string reference to other. - int compare(BasicStringRef other) const { - std::size_t size = size_ < other.size_ ? size_ : other.size_; - int result = std::char_traits::compare(data_, other.data_, size); - if (result == 0) - result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1); - return result; - } - - friend bool operator==(BasicStringRef lhs, BasicStringRef rhs) { - return lhs.compare(rhs) == 0; - } - friend bool operator!=(BasicStringRef lhs, BasicStringRef rhs) { - return lhs.compare(rhs) != 0; - } - friend bool operator<(BasicStringRef lhs, BasicStringRef rhs) { - return lhs.compare(rhs) < 0; - } - friend bool operator<=(BasicStringRef lhs, BasicStringRef rhs) { - return lhs.compare(rhs) <= 0; - } - friend bool operator>(BasicStringRef lhs, BasicStringRef rhs) { - return lhs.compare(rhs) > 0; - } - friend bool operator>=(BasicStringRef lhs, BasicStringRef rhs) { - return lhs.compare(rhs) >= 0; - } -}; - -typedef BasicStringRef StringRef; -typedef BasicStringRef WStringRef; - -/** - \rst - A reference to a null terminated string. It can be constructed from a C - string or ``std::basic_string``. - - You can use one of the following typedefs for common character types: - - +-------------+--------------------------+ - | Type | Definition | - +=============+==========================+ - | CStringRef | BasicCStringRef | - +-------------+--------------------------+ - | WCStringRef | BasicCStringRef | - +-------------+--------------------------+ - - This class is most useful as a parameter type to allow passing - different types of strings to a function, for example:: - - template - std::string format(CStringRef format_str, const Args & ... args); - - format("{}", 42); - format(std::string("{}"), 42); - \endrst - */ -template -class BasicCStringRef { - private: - const Char *data_; - - public: - /** Constructs a string reference object from a C string. */ - BasicCStringRef(const Char *s) : data_(s) {} - - /** - \rst - Constructs a string reference from a ``std::basic_string`` object. - \endrst - */ - template - BasicCStringRef( - const std::basic_string, Allocator> &s) - : data_(s.c_str()) {} - - /** Returns the pointer to a C string. */ - const Char *c_str() const { return data_; } -}; - -typedef BasicCStringRef CStringRef; -typedef BasicCStringRef WCStringRef; - -/** A formatting error such as invalid format string. */ -class FormatError : public std::runtime_error { - public: - explicit FormatError(CStringRef message) - : std::runtime_error(message.c_str()) {} - FormatError(const FormatError &ferr) : std::runtime_error(ferr) {} - FMT_API ~FormatError() FMT_DTOR_NOEXCEPT FMT_OVERRIDE; -}; - -namespace internal { - -// MakeUnsigned::Type gives an unsigned type corresponding to integer type T. -template -struct MakeUnsigned { typedef T Type; }; - -#define FMT_SPECIALIZE_MAKE_UNSIGNED(T, U) \ - template <> \ - struct MakeUnsigned { typedef U Type; } - -FMT_SPECIALIZE_MAKE_UNSIGNED(char, unsigned char); -FMT_SPECIALIZE_MAKE_UNSIGNED(signed char, unsigned char); -FMT_SPECIALIZE_MAKE_UNSIGNED(short, unsigned short); -FMT_SPECIALIZE_MAKE_UNSIGNED(int, unsigned); -FMT_SPECIALIZE_MAKE_UNSIGNED(long, unsigned long); -FMT_SPECIALIZE_MAKE_UNSIGNED(LongLong, ULongLong); - -// Casts nonnegative integer to unsigned. -template -inline typename MakeUnsigned::Type to_unsigned(Int value) { - FMT_ASSERT(value >= 0, "negative value"); - return static_cast::Type>(value); -} - -// The number of characters to store in the MemoryBuffer object itself -// to avoid dynamic memory allocation. -enum { INLINE_BUFFER_SIZE = 500 }; - -#if FMT_SECURE_SCL -// Use checked iterator to avoid warnings on MSVC. -template -inline stdext::checked_array_iterator make_ptr(T *ptr, std::size_t size) { - return stdext::checked_array_iterator(ptr, size); -} -#else -template -inline T *make_ptr(T *ptr, std::size_t) { return ptr; } -#endif -} // namespace internal - -/** - \rst - A buffer supporting a subset of ``std::vector``'s operations. - \endrst - */ -template -class Buffer { - private: - FMT_DISALLOW_COPY_AND_ASSIGN(Buffer); - - protected: - T *ptr_; - std::size_t size_; - std::size_t capacity_; - - Buffer(T *ptr = FMT_NULL, std::size_t capacity = 0) - : ptr_(ptr), size_(0), capacity_(capacity) {} - - /** - \rst - Increases the buffer capacity to hold at least *size* elements updating - ``ptr_`` and ``capacity_``. - \endrst - */ - virtual void grow(std::size_t size) = 0; - - public: - virtual ~Buffer() {} - - /** Returns the size of this buffer. */ - std::size_t size() const { return size_; } - - /** Returns the capacity of this buffer. */ - std::size_t capacity() const { return capacity_; } - - /** - Resizes the buffer. If T is a POD type new elements may not be initialized. - */ - void resize(std::size_t new_size) { - if (new_size > capacity_) - grow(new_size); - size_ = new_size; - } - - /** - \rst - Reserves space to store at least *capacity* elements. - \endrst - */ - void reserve(std::size_t capacity) { - if (capacity > capacity_) - grow(capacity); - } - - void clear() FMT_NOEXCEPT { size_ = 0; } - - void push_back(const T &value) { - if (size_ == capacity_) - grow(size_ + 1); - ptr_[size_++] = value; - } - - /** Appends data to the end of the buffer. */ - template - void append(const U *begin, const U *end); - - T &operator[](std::size_t index) { return ptr_[index]; } - const T &operator[](std::size_t index) const { return ptr_[index]; } -}; - -template -template -void Buffer::append(const U *begin, const U *end) { - FMT_ASSERT(end >= begin, "negative value"); - std::size_t new_size = size_ + static_cast(end - begin); - if (new_size > capacity_) - grow(new_size); - std::uninitialized_copy(begin, end, - internal::make_ptr(ptr_, capacity_) + size_); - size_ = new_size; -} - -namespace internal { - -// A memory buffer for trivially copyable/constructible types with the first -// SIZE elements stored in the object itself. -template > -class MemoryBuffer : private Allocator, public Buffer { - private: - T data_[SIZE]; - - // Deallocate memory allocated by the buffer. - void deallocate() { - if (this->ptr_ != data_) Allocator::deallocate(this->ptr_, this->capacity_); - } - - protected: - void grow(std::size_t size) FMT_OVERRIDE; - - public: - explicit MemoryBuffer(const Allocator &alloc = Allocator()) - : Allocator(alloc), Buffer(data_, SIZE) {} - ~MemoryBuffer() FMT_OVERRIDE { deallocate(); } - -#if FMT_USE_RVALUE_REFERENCES - private: - // Move data from other to this buffer. - void move(MemoryBuffer &other) { - Allocator &this_alloc = *this, &other_alloc = other; - this_alloc = std::move(other_alloc); - this->size_ = other.size_; - this->capacity_ = other.capacity_; - if (other.ptr_ == other.data_) { - this->ptr_ = data_; - std::uninitialized_copy(other.data_, other.data_ + this->size_, - make_ptr(data_, this->capacity_)); - } else { - this->ptr_ = other.ptr_; - // Set pointer to the inline array so that delete is not called - // when deallocating. - other.ptr_ = other.data_; - } - } - - public: - MemoryBuffer(MemoryBuffer &&other) { - move(other); - } - - MemoryBuffer &operator=(MemoryBuffer &&other) { - assert(this != &other); - deallocate(); - move(other); - return *this; - } -#endif - - // Returns a copy of the allocator associated with this buffer. - Allocator get_allocator() const { return *this; } -}; - -template -void MemoryBuffer::grow(std::size_t size) { - std::size_t new_capacity = this->capacity_ + this->capacity_ / 2; - if (size > new_capacity) - new_capacity = size; -#if FMT_USE_ALLOCATOR_TRAITS - T *new_ptr = - std::allocator_traits::allocate(*this, new_capacity, FMT_NULL); -#else - T *new_ptr = this->allocate(new_capacity, FMT_NULL); -#endif - // The following code doesn't throw, so the raw pointer above doesn't leak. - std::uninitialized_copy(this->ptr_, this->ptr_ + this->size_, - make_ptr(new_ptr, new_capacity)); - std::size_t old_capacity = this->capacity_; - T *old_ptr = this->ptr_; - this->capacity_ = new_capacity; - this->ptr_ = new_ptr; - // deallocate may throw (at least in principle), but it doesn't matter since - // the buffer already uses the new storage and will deallocate it in case - // of exception. - if (old_ptr != data_) - Allocator::deallocate(old_ptr, old_capacity); -} - -// A fixed-size buffer. -template -class FixedBuffer : public fmt::Buffer { - public: - FixedBuffer(Char *array, std::size_t size) : fmt::Buffer(array, size) {} - - protected: - FMT_API void grow(std::size_t size) FMT_OVERRIDE; -}; - -template -class BasicCharTraits { - public: -#if FMT_SECURE_SCL - typedef stdext::checked_array_iterator CharPtr; -#else - typedef Char *CharPtr; -#endif - static Char cast(int value) { return static_cast(value); } -}; - -template -class CharTraits; - -template <> -class CharTraits : public BasicCharTraits { - private: - // Conversion from wchar_t to char is not allowed. - static char convert(wchar_t); - - public: - static char convert(char value) { return value; } - - // Formats a floating-point number. - template - FMT_API static int format_float(char *buffer, std::size_t size, - const char *format, unsigned width, int precision, T value); -}; - -#if FMT_USE_EXTERN_TEMPLATES -extern template int CharTraits::format_float - (char *buffer, std::size_t size, - const char* format, unsigned width, int precision, double value); -extern template int CharTraits::format_float - (char *buffer, std::size_t size, - const char* format, unsigned width, int precision, long double value); -#endif - -template <> -class CharTraits : public BasicCharTraits { - public: - static wchar_t convert(char value) { return value; } - static wchar_t convert(wchar_t value) { return value; } - - template - FMT_API static int format_float(wchar_t *buffer, std::size_t size, - const wchar_t *format, unsigned width, int precision, T value); -}; - -#if FMT_USE_EXTERN_TEMPLATES -extern template int CharTraits::format_float - (wchar_t *buffer, std::size_t size, - const wchar_t* format, unsigned width, int precision, double value); -extern template int CharTraits::format_float - (wchar_t *buffer, std::size_t size, - const wchar_t* format, unsigned width, int precision, long double value); -#endif - -// Checks if a number is negative - used to avoid warnings. -template -struct SignChecker { - template - static bool is_negative(T value) { return value < 0; } -}; - -template <> -struct SignChecker { - template - static bool is_negative(T) { return false; } -}; - -// Returns true if value is negative, false otherwise. -// Same as (value < 0) but doesn't produce warnings if T is an unsigned type. -template -inline bool is_negative(T value) { - return SignChecker::is_signed>::is_negative(value); -} - -// Selects uint32_t if FitsIn32Bits is true, uint64_t otherwise. -template -struct TypeSelector { typedef uint32_t Type; }; - -template <> -struct TypeSelector { typedef uint64_t Type; }; - -template -struct IntTraits { - // Smallest of uint32_t and uint64_t that is large enough to represent - // all values of T. - typedef typename - TypeSelector::digits <= 32>::Type MainType; -}; - -FMT_API FMT_NORETURN void report_unknown_type(char code, const char *type); - -// Static data is placed in this class template to allow header-only -// configuration. -template -struct FMT_API BasicData { - static const uint32_t POWERS_OF_10_32[]; - static const uint64_t POWERS_OF_10_64[]; - static const char DIGITS[]; -}; - -#if FMT_USE_EXTERN_TEMPLATES -extern template struct BasicData; -#endif - -typedef BasicData<> Data; - -#ifdef FMT_BUILTIN_CLZLL -// Returns the number of decimal digits in n. Leading zeros are not counted -// except for n == 0 in which case count_digits returns 1. -inline unsigned count_digits(uint64_t n) { - // Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 - // and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits. - int t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12; - return to_unsigned(t) - (n < Data::POWERS_OF_10_64[t]) + 1; -} -#else -// Fallback version of count_digits used when __builtin_clz is not available. -inline unsigned count_digits(uint64_t n) { - unsigned count = 1; - for (;;) { - // Integer division is slow so do it for a group of four digits instead - // of for every digit. The idea comes from the talk by Alexandrescu - // "Three Optimization Tips for C++". See speed-test for a comparison. - if (n < 10) return count; - if (n < 100) return count + 1; - if (n < 1000) return count + 2; - if (n < 10000) return count + 3; - n /= 10000u; - count += 4; - } -} -#endif - -#ifdef FMT_BUILTIN_CLZ -// Optional version of count_digits for better performance on 32-bit platforms. -inline unsigned count_digits(uint32_t n) { - int t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12; - return to_unsigned(t) - (n < Data::POWERS_OF_10_32[t]) + 1; -} -#endif - -// A functor that doesn't add a thousands separator. -struct NoThousandsSep { - template - void operator()(Char *) {} -}; - -// A functor that adds a thousands separator. -class ThousandsSep { - private: - fmt::StringRef sep_; - - // Index of a decimal digit with the least significant digit having index 0. - unsigned digit_index_; - - public: - explicit ThousandsSep(fmt::StringRef sep) : sep_(sep), digit_index_(0) {} - - template - void operator()(Char *&buffer) { - if (++digit_index_ % 3 != 0) - return; - buffer -= sep_.size(); - std::uninitialized_copy(sep_.data(), sep_.data() + sep_.size(), - internal::make_ptr(buffer, sep_.size())); - } -}; - -// Formats a decimal unsigned integer value writing into buffer. -// thousands_sep is a functor that is called after writing each char to -// add a thousands separator if necessary. -template -inline void format_decimal(Char *buffer, UInt value, unsigned num_digits, - ThousandsSep thousands_sep) { - buffer += num_digits; - while (value >= 100) { - // Integer division is slow so do it for a group of two digits instead - // of for every digit. The idea comes from the talk by Alexandrescu - // "Three Optimization Tips for C++". See speed-test for a comparison. - unsigned index = static_cast((value % 100) * 2); - value /= 100; - *--buffer = Data::DIGITS[index + 1]; - thousands_sep(buffer); - *--buffer = Data::DIGITS[index]; - thousands_sep(buffer); - } - if (value < 10) { - *--buffer = static_cast('0' + value); - return; - } - unsigned index = static_cast(value * 2); - *--buffer = Data::DIGITS[index + 1]; - thousands_sep(buffer); - *--buffer = Data::DIGITS[index]; -} - -template -inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) { - format_decimal(buffer, value, num_digits, NoThousandsSep()); - return; -} - -#ifndef _WIN32 -# define FMT_USE_WINDOWS_H 0 -#elif !defined(FMT_USE_WINDOWS_H) -# define FMT_USE_WINDOWS_H 1 -#endif - -// Define FMT_USE_WINDOWS_H to 0 to disable use of windows.h. -// All the functionality that relies on it will be disabled too. -#if FMT_USE_WINDOWS_H -// A converter from UTF-8 to UTF-16. -// It is only provided for Windows since other systems support UTF-8 natively. -class UTF8ToUTF16 { - private: - MemoryBuffer buffer_; - - public: - FMT_API explicit UTF8ToUTF16(StringRef s); - operator WStringRef() const { return WStringRef(&buffer_[0], size()); } - size_t size() const { return buffer_.size() - 1; } - const wchar_t *c_str() const { return &buffer_[0]; } - std::wstring str() const { return std::wstring(&buffer_[0], size()); } -}; - -// A converter from UTF-16 to UTF-8. -// It is only provided for Windows since other systems support UTF-8 natively. -class UTF16ToUTF8 { - private: - MemoryBuffer buffer_; - - public: - UTF16ToUTF8() {} - FMT_API explicit UTF16ToUTF8(WStringRef s); - operator StringRef() const { return StringRef(&buffer_[0], size()); } - size_t size() const { return buffer_.size() - 1; } - const char *c_str() const { return &buffer_[0]; } - std::string str() const { return std::string(&buffer_[0], size()); } - - // Performs conversion returning a system error code instead of - // throwing exception on conversion error. This method may still throw - // in case of memory allocation error. - FMT_API int convert(WStringRef s); -}; - -FMT_API void format_windows_error(fmt::Writer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT; -#endif - -// A formatting argument value. -struct Value { - template - struct StringValue { - const Char *value; - std::size_t size; - }; - - typedef void (*FormatFunc)( - void *formatter, const void *arg, void *format_str_ptr); - - struct CustomValue { - const void *value; - FormatFunc format; - }; - - union { - int int_value; - unsigned uint_value; - LongLong long_long_value; - ULongLong ulong_long_value; - double double_value; - long double long_double_value; - const void *pointer; - StringValue string; - StringValue sstring; - StringValue ustring; - StringValue wstring; - CustomValue custom; - }; - - enum Type { - NONE, NAMED_ARG, - // Integer types should go first, - INT, UINT, LONG_LONG, ULONG_LONG, BOOL, CHAR, LAST_INTEGER_TYPE = CHAR, - // followed by floating-point types. - DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE, - CSTRING, STRING, WSTRING, POINTER, CUSTOM - }; -}; - -// A formatting argument. It is a trivially copyable/constructible type to -// allow storage in internal::MemoryBuffer. -struct Arg : Value { - Type type; -}; - -template -struct NamedArg; -template -struct NamedArgWithType; - -template -struct Null {}; - -// A helper class template to enable or disable overloads taking wide -// characters and strings in MakeValue. -template -struct WCharHelper { - typedef Null Supported; - typedef T Unsupported; -}; - -template -struct WCharHelper { - typedef T Supported; - typedef Null Unsupported; -}; - -typedef char Yes[1]; -typedef char No[2]; - -template -T &get(); - -// These are non-members to workaround an overload resolution bug in bcc32. -Yes &convert(fmt::ULongLong); -No &convert(...); - -template -struct ConvertToIntImpl { - enum { value = ENABLE_CONVERSION }; -}; - -template -struct ConvertToIntImpl2 { - enum { value = false }; -}; - -template -struct ConvertToIntImpl2 { - enum { - // Don't convert numeric types. - value = ConvertToIntImpl::is_specialized>::value - }; -}; - -template -struct ConvertToInt { - enum { - enable_conversion = sizeof(fmt::internal::convert(get())) == sizeof(Yes) - }; - enum { value = ConvertToIntImpl2::value }; -}; - -#define FMT_DISABLE_CONVERSION_TO_INT(Type) \ - template <> \ - struct ConvertToInt { enum { value = 0 }; } - -// Silence warnings about convering float to int. -FMT_DISABLE_CONVERSION_TO_INT(float); -FMT_DISABLE_CONVERSION_TO_INT(double); -FMT_DISABLE_CONVERSION_TO_INT(long double); - -template -struct EnableIf {}; - -template -struct EnableIf { typedef T type; }; - -template -struct Conditional { typedef T type; }; - -template -struct Conditional { typedef F type; }; - -// For bcc32 which doesn't understand ! in template arguments. -template -struct Not { enum { value = 0 }; }; - -template <> -struct Not { enum { value = 1 }; }; - -template -struct FalseType { enum { value = 0 }; }; - -template struct LConvCheck { - LConvCheck(int) {} -}; - -// Returns the thousands separator for the current locale. -// We check if ``lconv`` contains ``thousands_sep`` because on Android -// ``lconv`` is stubbed as an empty struct. -template -inline StringRef thousands_sep( - LConv *lc, LConvCheck = 0) { - return lc->thousands_sep; -} - -inline fmt::StringRef thousands_sep(...) { return ""; } - -#define FMT_CONCAT(a, b) a##b - -#if FMT_GCC_VERSION >= 303 -# define FMT_UNUSED __attribute__((unused)) -#else -# define FMT_UNUSED -#endif - -#ifndef FMT_USE_STATIC_ASSERT -# define FMT_USE_STATIC_ASSERT 0 -#endif - -#if FMT_USE_STATIC_ASSERT || FMT_HAS_FEATURE(cxx_static_assert) || \ - (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600 -# define FMT_STATIC_ASSERT(cond, message) static_assert(cond, message) -#else -# define FMT_CONCAT_(a, b) FMT_CONCAT(a, b) -# define FMT_STATIC_ASSERT(cond, message) \ - typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED -#endif - -template -void format_arg(Formatter&, ...) { - FMT_STATIC_ASSERT(FalseType::value, - "Cannot format argument. To enable the use of ostream " - "operator<< include fmt/ostream.h. Otherwise provide " - "an overload of format_arg."); -} - -// Makes an Arg object from any type. -template -class MakeValue : public Arg { - public: - typedef typename Formatter::Char Char; - - private: - // The following two methods are private to disallow formatting of - // arbitrary pointers. If you want to output a pointer cast it to - // "void *" or "const void *". In particular, this forbids formatting - // of "[const] volatile char *" which is printed as bool by iostreams. - // Do not implement! - template - MakeValue(const T *value); - template - MakeValue(T *value); - - // The following methods are private to disallow formatting of wide - // characters and strings into narrow strings as in - // fmt::format("{}", L"test"); - // To fix this, use a wide format string: fmt::format(L"{}", L"test"). -#if !FMT_MSC_VER || defined(_NATIVE_WCHAR_T_DEFINED) - MakeValue(typename WCharHelper::Unsupported); -#endif - MakeValue(typename WCharHelper::Unsupported); - MakeValue(typename WCharHelper::Unsupported); - MakeValue(typename WCharHelper::Unsupported); -#if FMT_HAS_STRING_VIEW - MakeValue(typename WCharHelper::Unsupported); -#endif - MakeValue(typename WCharHelper::Unsupported); - - void set_string(StringRef str) { - string.value = str.data(); - string.size = str.size(); - } - - void set_string(WStringRef str) { - wstring.value = str.data(); - wstring.size = str.size(); - } - - // Formats an argument of a custom type, such as a user-defined class. - template - static void format_custom_arg( - void *formatter, const void *arg, void *format_str_ptr) { - format_arg(*static_cast(formatter), - *static_cast(format_str_ptr), - *static_cast(arg)); - } - - public: - MakeValue() {} - -#define FMT_MAKE_VALUE_(Type, field, TYPE, rhs) \ - MakeValue(Type value) { field = rhs; } \ - static uint64_t type(Type) { return Arg::TYPE; } - -#define FMT_MAKE_VALUE(Type, field, TYPE) \ - FMT_MAKE_VALUE_(Type, field, TYPE, value) - - FMT_MAKE_VALUE(bool, int_value, BOOL) - FMT_MAKE_VALUE(short, int_value, INT) - FMT_MAKE_VALUE(unsigned short, uint_value, UINT) - FMT_MAKE_VALUE(int, int_value, INT) - FMT_MAKE_VALUE(unsigned, uint_value, UINT) - - MakeValue(long value) { - // To minimize the number of types we need to deal with, long is - // translated either to int or to long long depending on its size. - if (const_check(sizeof(long) == sizeof(int))) - int_value = static_cast(value); - else - long_long_value = value; - } - static uint64_t type(long) { - return sizeof(long) == sizeof(int) ? Arg::INT : Arg::LONG_LONG; - } - - MakeValue(unsigned long value) { - if (const_check(sizeof(unsigned long) == sizeof(unsigned))) - uint_value = static_cast(value); - else - ulong_long_value = value; - } - static uint64_t type(unsigned long) { - return sizeof(unsigned long) == sizeof(unsigned) ? - Arg::UINT : Arg::ULONG_LONG; - } - - FMT_MAKE_VALUE(LongLong, long_long_value, LONG_LONG) - FMT_MAKE_VALUE(ULongLong, ulong_long_value, ULONG_LONG) - FMT_MAKE_VALUE(float, double_value, DOUBLE) - FMT_MAKE_VALUE(double, double_value, DOUBLE) - FMT_MAKE_VALUE(long double, long_double_value, LONG_DOUBLE) - FMT_MAKE_VALUE(signed char, int_value, INT) - FMT_MAKE_VALUE(unsigned char, uint_value, UINT) - FMT_MAKE_VALUE(char, int_value, CHAR) - -#if __cplusplus >= 201103L - template < - typename T, - typename = typename std::enable_if< - std::is_enum::value && ConvertToInt::value>::type> - MakeValue(T value) { int_value = value; } - - template < - typename T, - typename = typename std::enable_if< - std::is_enum::value && ConvertToInt::value>::type> - static uint64_t type(T) { return Arg::INT; } -#endif - -#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) - MakeValue(typename WCharHelper::Supported value) { - int_value = value; - } - static uint64_t type(wchar_t) { return Arg::CHAR; } -#endif - -#define FMT_MAKE_STR_VALUE(Type, TYPE) \ - MakeValue(Type value) { set_string(value); } \ - static uint64_t type(Type) { return Arg::TYPE; } - - FMT_MAKE_VALUE(char *, string.value, CSTRING) - FMT_MAKE_VALUE(const char *, string.value, CSTRING) - FMT_MAKE_VALUE(signed char *, sstring.value, CSTRING) - FMT_MAKE_VALUE(const signed char *, sstring.value, CSTRING) - FMT_MAKE_VALUE(unsigned char *, ustring.value, CSTRING) - FMT_MAKE_VALUE(const unsigned char *, ustring.value, CSTRING) - FMT_MAKE_STR_VALUE(const std::string &, STRING) -#if FMT_HAS_STRING_VIEW - FMT_MAKE_STR_VALUE(const std::string_view &, STRING) -#endif - FMT_MAKE_STR_VALUE(StringRef, STRING) - FMT_MAKE_VALUE_(CStringRef, string.value, CSTRING, value.c_str()) - -#define FMT_MAKE_WSTR_VALUE(Type, TYPE) \ - MakeValue(typename WCharHelper::Supported value) { \ - set_string(value); \ - } \ - static uint64_t type(Type) { return Arg::TYPE; } - - FMT_MAKE_WSTR_VALUE(wchar_t *, WSTRING) - FMT_MAKE_WSTR_VALUE(const wchar_t *, WSTRING) - FMT_MAKE_WSTR_VALUE(const std::wstring &, WSTRING) -#if FMT_HAS_STRING_VIEW - FMT_MAKE_WSTR_VALUE(const std::wstring_view &, WSTRING) -#endif - FMT_MAKE_WSTR_VALUE(WStringRef, WSTRING) - - FMT_MAKE_VALUE(void *, pointer, POINTER) - FMT_MAKE_VALUE(const void *, pointer, POINTER) - - template - MakeValue(const T &value, - typename EnableIf::value>::value, int>::type = 0) { - custom.value = &value; - custom.format = &format_custom_arg; - } - - template - static typename EnableIf::value>::value, uint64_t>::type - type(const T &) { - return Arg::CUSTOM; - } - - // Additional template param `Char_` is needed here because make_type always - // uses char. - template - MakeValue(const NamedArg &value) { pointer = &value; } - template - MakeValue(const NamedArgWithType &value) { pointer = &value; } - - template - static uint64_t type(const NamedArg &) { return Arg::NAMED_ARG; } - template - static uint64_t type(const NamedArgWithType &) { return Arg::NAMED_ARG; } -}; - -template -class MakeArg : public Arg { -public: - MakeArg() { - type = Arg::NONE; - } - - template - MakeArg(const T &value) - : Arg(MakeValue(value)) { - type = static_cast(MakeValue::type(value)); - } -}; - -template -struct NamedArg : Arg { - BasicStringRef name; - - template - NamedArg(BasicStringRef argname, const T &value) - : Arg(MakeArg< BasicFormatter >(value)), name(argname) {} -}; - -template -struct NamedArgWithType : NamedArg { - NamedArgWithType(BasicStringRef argname, const T &value) - : NamedArg(argname, value) {} -}; - -class RuntimeError : public std::runtime_error { - protected: - RuntimeError() : std::runtime_error("") {} - RuntimeError(const RuntimeError &rerr) : std::runtime_error(rerr) {} - FMT_API ~RuntimeError() FMT_DTOR_NOEXCEPT FMT_OVERRIDE; -}; - -template -class ArgMap; -} // namespace internal - -/** An argument list. */ -class ArgList { - private: - // To reduce compiled code size per formatting function call, types of first - // MAX_PACKED_ARGS arguments are passed in the types_ field. - uint64_t types_; - union { - // If the number of arguments is less than MAX_PACKED_ARGS, the argument - // values are stored in values_, otherwise they are stored in args_. - // This is done to reduce compiled code size as storing larger objects - // may require more code (at least on x86-64) even if the same amount of - // data is actually copied to stack. It saves ~10% on the bloat test. - const internal::Value *values_; - const internal::Arg *args_; - }; - - internal::Arg::Type type(unsigned index) const { - return type(types_, index); - } - - template - friend class internal::ArgMap; - - public: - // Maximum number of arguments with packed types. - enum { MAX_PACKED_ARGS = 16 }; - - ArgList() : types_(0) {} - - ArgList(ULongLong types, const internal::Value *values) - : types_(types), values_(values) {} - ArgList(ULongLong types, const internal::Arg *args) - : types_(types), args_(args) {} - - uint64_t types() const { return types_; } - - /** Returns the argument at specified index. */ - internal::Arg operator[](unsigned index) const { - using internal::Arg; - Arg arg; - bool use_values = type(MAX_PACKED_ARGS - 1) == Arg::NONE; - if (index < MAX_PACKED_ARGS) { - Arg::Type arg_type = type(index); - internal::Value &val = arg; - if (arg_type != Arg::NONE) - val = use_values ? values_[index] : args_[index]; - arg.type = arg_type; - return arg; - } - if (use_values) { - // The index is greater than the number of arguments that can be stored - // in values, so return a "none" argument. - arg.type = Arg::NONE; - return arg; - } - for (unsigned i = MAX_PACKED_ARGS; i <= index; ++i) { - if (args_[i].type == Arg::NONE) - return args_[i]; - } - return args_[index]; - } - - static internal::Arg::Type type(uint64_t types, unsigned index) { - unsigned shift = index * 4; - uint64_t mask = 0xf; - return static_cast( - (types & (mask << shift)) >> shift); - } -}; - -#define FMT_DISPATCH(call) static_cast(this)->call - -/** - \rst - An argument visitor based on the `curiously recurring template pattern - `_. - - To use `~fmt::ArgVisitor` define a subclass that implements some or all of the - visit methods with the same signatures as the methods in `~fmt::ArgVisitor`, - for example, `~fmt::ArgVisitor::visit_int()`. - Pass the subclass as the *Impl* template parameter. Then calling - `~fmt::ArgVisitor::visit` for some argument will dispatch to a visit method - specific to the argument type. For example, if the argument type is - ``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass - will be called. If the subclass doesn't contain a method with this signature, - then a corresponding method of `~fmt::ArgVisitor` will be called. - - **Example**:: - - class MyArgVisitor : public fmt::ArgVisitor { - public: - void visit_int(int value) { fmt::print("{}", value); } - void visit_double(double value) { fmt::print("{}", value ); } - }; - \endrst - */ -template -class ArgVisitor { - private: - typedef internal::Arg Arg; - - public: - void report_unhandled_arg() {} - - Result visit_unhandled_arg() { - FMT_DISPATCH(report_unhandled_arg()); - return Result(); - } - - /** Visits an ``int`` argument. **/ - Result visit_int(int value) { - return FMT_DISPATCH(visit_any_int(value)); - } - - /** Visits a ``long long`` argument. **/ - Result visit_long_long(LongLong value) { - return FMT_DISPATCH(visit_any_int(value)); - } - - /** Visits an ``unsigned`` argument. **/ - Result visit_uint(unsigned value) { - return FMT_DISPATCH(visit_any_int(value)); - } - - /** Visits an ``unsigned long long`` argument. **/ - Result visit_ulong_long(ULongLong value) { - return FMT_DISPATCH(visit_any_int(value)); - } - - /** Visits a ``bool`` argument. **/ - Result visit_bool(bool value) { - return FMT_DISPATCH(visit_any_int(value)); - } - - /** Visits a ``char`` or ``wchar_t`` argument. **/ - Result visit_char(int value) { - return FMT_DISPATCH(visit_any_int(value)); - } - - /** Visits an argument of any integral type. **/ - template - Result visit_any_int(T) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - /** Visits a ``double`` argument. **/ - Result visit_double(double value) { - return FMT_DISPATCH(visit_any_double(value)); - } - - /** Visits a ``long double`` argument. **/ - Result visit_long_double(long double value) { - return FMT_DISPATCH(visit_any_double(value)); - } - - /** Visits a ``double`` or ``long double`` argument. **/ - template - Result visit_any_double(T) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - /** Visits a null-terminated C string (``const char *``) argument. **/ - Result visit_cstring(const char *) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - /** Visits a string argument. **/ - Result visit_string(Arg::StringValue) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - /** Visits a wide string argument. **/ - Result visit_wstring(Arg::StringValue) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - /** Visits a pointer argument. **/ - Result visit_pointer(const void *) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - /** Visits an argument of a custom (user-defined) type. **/ - Result visit_custom(Arg::CustomValue) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - /** - \rst - Visits an argument dispatching to the appropriate visit method based on - the argument type. For example, if the argument type is ``double`` then - the `~fmt::ArgVisitor::visit_double()` method of the *Impl* class will be - called. - \endrst - */ - Result visit(const Arg &arg) { - switch (arg.type) { - case Arg::NONE: - case Arg::NAMED_ARG: - FMT_ASSERT(false, "invalid argument type"); - break; - case Arg::INT: - return FMT_DISPATCH(visit_int(arg.int_value)); - case Arg::UINT: - return FMT_DISPATCH(visit_uint(arg.uint_value)); - case Arg::LONG_LONG: - return FMT_DISPATCH(visit_long_long(arg.long_long_value)); - case Arg::ULONG_LONG: - return FMT_DISPATCH(visit_ulong_long(arg.ulong_long_value)); - case Arg::BOOL: - return FMT_DISPATCH(visit_bool(arg.int_value != 0)); - case Arg::CHAR: - return FMT_DISPATCH(visit_char(arg.int_value)); - case Arg::DOUBLE: - return FMT_DISPATCH(visit_double(arg.double_value)); - case Arg::LONG_DOUBLE: - return FMT_DISPATCH(visit_long_double(arg.long_double_value)); - case Arg::CSTRING: - return FMT_DISPATCH(visit_cstring(arg.string.value)); - case Arg::STRING: - return FMT_DISPATCH(visit_string(arg.string)); - case Arg::WSTRING: - return FMT_DISPATCH(visit_wstring(arg.wstring)); - case Arg::POINTER: - return FMT_DISPATCH(visit_pointer(arg.pointer)); - case Arg::CUSTOM: - return FMT_DISPATCH(visit_custom(arg.custom)); - } - return Result(); - } -}; - -enum Alignment { - ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC -}; - -// Flags. -enum { - SIGN_FLAG = 1, PLUS_FLAG = 2, MINUS_FLAG = 4, HASH_FLAG = 8, - CHAR_FLAG = 0x10 // Argument has char type - used in error reporting. -}; - -// An empty format specifier. -struct EmptySpec {}; - -// A type specifier. -template -struct TypeSpec : EmptySpec { - Alignment align() const { return ALIGN_DEFAULT; } - unsigned width() const { return 0; } - int precision() const { return -1; } - bool flag(unsigned) const { return false; } - char type() const { return TYPE; } - char type_prefix() const { return TYPE; } - char fill() const { return ' '; } -}; - -// A width specifier. -struct WidthSpec { - unsigned width_; - // Fill is always wchar_t and cast to char if necessary to avoid having - // two specialization of WidthSpec and its subclasses. - wchar_t fill_; - - WidthSpec(unsigned width, wchar_t fill) : width_(width), fill_(fill) {} - - unsigned width() const { return width_; } - wchar_t fill() const { return fill_; } -}; - -// An alignment specifier. -struct AlignSpec : WidthSpec { - Alignment align_; - - AlignSpec(unsigned width, wchar_t fill, Alignment align = ALIGN_DEFAULT) - : WidthSpec(width, fill), align_(align) {} - - Alignment align() const { return align_; } - - int precision() const { return -1; } -}; - -// An alignment and type specifier. -template -struct AlignTypeSpec : AlignSpec { - AlignTypeSpec(unsigned width, wchar_t fill) : AlignSpec(width, fill) {} - - bool flag(unsigned) const { return false; } - char type() const { return TYPE; } - char type_prefix() const { return TYPE; } -}; - -// A full format specifier. -struct FormatSpec : AlignSpec { - unsigned flags_; - int precision_; - char type_; - - FormatSpec( - unsigned width = 0, char type = 0, wchar_t fill = ' ') - : AlignSpec(width, fill), flags_(0), precision_(-1), type_(type) {} - - bool flag(unsigned f) const { return (flags_ & f) != 0; } - int precision() const { return precision_; } - char type() const { return type_; } - char type_prefix() const { return type_; } -}; - -// An integer format specifier. -template , typename Char = char> -class IntFormatSpec : public SpecT { - private: - T value_; - - public: - IntFormatSpec(T val, const SpecT &spec = SpecT()) - : SpecT(spec), value_(val) {} - - T value() const { return value_; } -}; - -// A string format specifier. -template -class StrFormatSpec : public AlignSpec { - private: - const Char *str_; - - public: - template - StrFormatSpec(const Char *str, unsigned width, FillChar fill) - : AlignSpec(width, fill), str_(str) { - internal::CharTraits::convert(FillChar()); - } - - const Char *str() const { return str_; } -}; - -/** - Returns an integer format specifier to format the value in base 2. - */ -IntFormatSpec > bin(int value); - -/** - Returns an integer format specifier to format the value in base 8. - */ -IntFormatSpec > oct(int value); - -/** - Returns an integer format specifier to format the value in base 16 using - lower-case letters for the digits above 9. - */ -IntFormatSpec > hex(int value); - -/** - Returns an integer formatter format specifier to format in base 16 using - upper-case letters for the digits above 9. - */ -IntFormatSpec > hexu(int value); - -/** - \rst - Returns an integer format specifier to pad the formatted argument with the - fill character to the specified width using the default (right) numeric - alignment. - - **Example**:: - - MemoryWriter out; - out << pad(hex(0xcafe), 8, '0'); - // out.str() == "0000cafe" - - \endrst - */ -template -IntFormatSpec, Char> pad( - int value, unsigned width, Char fill = ' '); - -#define FMT_DEFINE_INT_FORMATTERS(TYPE) \ -inline IntFormatSpec > bin(TYPE value) { \ - return IntFormatSpec >(value, TypeSpec<'b'>()); \ -} \ - \ -inline IntFormatSpec > oct(TYPE value) { \ - return IntFormatSpec >(value, TypeSpec<'o'>()); \ -} \ - \ -inline IntFormatSpec > hex(TYPE value) { \ - return IntFormatSpec >(value, TypeSpec<'x'>()); \ -} \ - \ -inline IntFormatSpec > hexu(TYPE value) { \ - return IntFormatSpec >(value, TypeSpec<'X'>()); \ -} \ - \ -template \ -inline IntFormatSpec > pad( \ - IntFormatSpec > f, unsigned width) { \ - return IntFormatSpec >( \ - f.value(), AlignTypeSpec(width, ' ')); \ -} \ - \ -/* For compatibility with older compilers we provide two overloads for pad, */ \ -/* one that takes a fill character and one that doesn't. In the future this */ \ -/* can be replaced with one overload making the template argument Char */ \ -/* default to char (C++11). */ \ -template \ -inline IntFormatSpec, Char> pad( \ - IntFormatSpec, Char> f, \ - unsigned width, Char fill) { \ - return IntFormatSpec, Char>( \ - f.value(), AlignTypeSpec(width, fill)); \ -} \ - \ -inline IntFormatSpec > pad( \ - TYPE value, unsigned width) { \ - return IntFormatSpec >( \ - value, AlignTypeSpec<0>(width, ' ')); \ -} \ - \ -template \ -inline IntFormatSpec, Char> pad( \ - TYPE value, unsigned width, Char fill) { \ - return IntFormatSpec, Char>( \ - value, AlignTypeSpec<0>(width, fill)); \ -} - -FMT_DEFINE_INT_FORMATTERS(int) -FMT_DEFINE_INT_FORMATTERS(long) -FMT_DEFINE_INT_FORMATTERS(unsigned) -FMT_DEFINE_INT_FORMATTERS(unsigned long) -FMT_DEFINE_INT_FORMATTERS(LongLong) -FMT_DEFINE_INT_FORMATTERS(ULongLong) - -/** - \rst - Returns a string formatter that pads the formatted argument with the fill - character to the specified width using the default (left) string alignment. - - **Example**:: - - std::string s = str(MemoryWriter() << pad("abc", 8)); - // s == "abc " - - \endrst - */ -template -inline StrFormatSpec pad( - const Char *str, unsigned width, Char fill = ' ') { - return StrFormatSpec(str, width, fill); -} - -inline StrFormatSpec pad( - const wchar_t *str, unsigned width, char fill = ' ') { - return StrFormatSpec(str, width, fill); -} - -namespace internal { - -template -class ArgMap { - private: - typedef std::vector< - std::pair, internal::Arg> > MapType; - typedef typename MapType::value_type Pair; - - MapType map_; - - public: - void init(const ArgList &args); - - const internal::Arg *find(const fmt::BasicStringRef &name) const { - // The list is unsorted, so just return the first matching name. - for (typename MapType::const_iterator it = map_.begin(), end = map_.end(); - it != end; ++it) { - if (it->first == name) - return &it->second; - } - return FMT_NULL; - } -}; - -template -void ArgMap::init(const ArgList &args) { - if (!map_.empty()) - return; - typedef internal::NamedArg NamedArg; - const NamedArg *named_arg = FMT_NULL; - bool use_values = - args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE; - if (use_values) { - for (unsigned i = 0;/*nothing*/; ++i) { - internal::Arg::Type arg_type = args.type(i); - switch (arg_type) { - case internal::Arg::NONE: - return; - case internal::Arg::NAMED_ARG: - named_arg = static_cast(args.values_[i].pointer); - map_.push_back(Pair(named_arg->name, *named_arg)); - break; - default: - /*nothing*/; - } - } - return; - } - for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) { - internal::Arg::Type arg_type = args.type(i); - if (arg_type == internal::Arg::NAMED_ARG) { - named_arg = static_cast(args.args_[i].pointer); - map_.push_back(Pair(named_arg->name, *named_arg)); - } - } - for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) { - switch (args.args_[i].type) { - case internal::Arg::NONE: - return; - case internal::Arg::NAMED_ARG: - named_arg = static_cast(args.args_[i].pointer); - map_.push_back(Pair(named_arg->name, *named_arg)); - break; - default: - /*nothing*/; - } - } -} - -template -class ArgFormatterBase : public ArgVisitor { - private: - BasicWriter &writer_; - Spec &spec_; - - FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatterBase); - - void write_pointer(const void *p) { - spec_.flags_ = HASH_FLAG; - spec_.type_ = 'x'; - writer_.write_int(reinterpret_cast(p), spec_); - } - - // workaround MSVC two-phase lookup issue - typedef internal::Arg Arg; - - protected: - BasicWriter &writer() { return writer_; } - Spec &spec() { return spec_; } - - void write(bool value) { - const char *str_value = value ? "true" : "false"; - Arg::StringValue str = { str_value, std::strlen(str_value) }; - writer_.write_str(str, spec_); - } - - void write(const char *value) { - Arg::StringValue str = {value, value ? std::strlen(value) : 0}; - writer_.write_str(str, spec_); - } - - public: - typedef Spec SpecType; - - ArgFormatterBase(BasicWriter &w, Spec &s) - : writer_(w), spec_(s) {} - - template - void visit_any_int(T value) { writer_.write_int(value, spec_); } - - template - void visit_any_double(T value) { writer_.write_double(value, spec_); } - - void visit_bool(bool value) { - if (spec_.type_) { - visit_any_int(value); - return; - } - write(value); - } - - void visit_char(int value) { - if (spec_.type_ && spec_.type_ != 'c') { - spec_.flags_ |= CHAR_FLAG; - writer_.write_int(value, spec_); - return; - } - if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0) - FMT_THROW(FormatError("invalid format specifier for char")); - typedef typename BasicWriter::CharPtr CharPtr; - Char fill = internal::CharTraits::cast(spec_.fill()); - CharPtr out = CharPtr(); - const unsigned CHAR_SIZE = 1; - if (spec_.width_ > CHAR_SIZE) { - out = writer_.grow_buffer(spec_.width_); - if (spec_.align_ == ALIGN_RIGHT) { - std::uninitialized_fill_n(out, spec_.width_ - CHAR_SIZE, fill); - out += spec_.width_ - CHAR_SIZE; - } else if (spec_.align_ == ALIGN_CENTER) { - out = writer_.fill_padding(out, spec_.width_, - internal::const_check(CHAR_SIZE), fill); - } else { - std::uninitialized_fill_n(out + CHAR_SIZE, - spec_.width_ - CHAR_SIZE, fill); - } - } else { - out = writer_.grow_buffer(CHAR_SIZE); - } - *out = internal::CharTraits::cast(value); - } - - void visit_cstring(const char *value) { - if (spec_.type_ == 'p') - return write_pointer(value); - write(value); - } - - // Qualification with "internal" here and below is a workaround for nvcc. - void visit_string(internal::Arg::StringValue value) { - writer_.write_str(value, spec_); - } - - using ArgVisitor::visit_wstring; - - void visit_wstring(internal::Arg::StringValue value) { - writer_.write_str(value, spec_); - } - - void visit_pointer(const void *value) { - if (spec_.type_ && spec_.type_ != 'p') - report_unknown_type(spec_.type_, "pointer"); - write_pointer(value); - } -}; - -class FormatterBase { - private: - ArgList args_; - int next_arg_index_; - - // Returns the argument with specified index. - FMT_API Arg do_get_arg(unsigned arg_index, const char *&error); - - protected: - const ArgList &args() const { return args_; } - - explicit FormatterBase(const ArgList &args) { - args_ = args; - next_arg_index_ = 0; - } - - // Returns the next argument. - Arg next_arg(const char *&error) { - if (next_arg_index_ >= 0) - return do_get_arg(internal::to_unsigned(next_arg_index_++), error); - error = "cannot switch from manual to automatic argument indexing"; - return Arg(); - } - - // Checks if manual indexing is used and returns the argument with - // specified index. - Arg get_arg(unsigned arg_index, const char *&error) { - return check_no_auto_index(error) ? do_get_arg(arg_index, error) : Arg(); - } - - bool check_no_auto_index(const char *&error) { - if (next_arg_index_ > 0) { - error = "cannot switch from automatic to manual argument indexing"; - return false; - } - next_arg_index_ = -1; - return true; - } - - template - void write(BasicWriter &w, const Char *start, const Char *end) { - if (start != end) - w << BasicStringRef(start, internal::to_unsigned(end - start)); - } -}; -} // namespace internal - -/** - \rst - An argument formatter based on the `curiously recurring template pattern - `_. - - To use `~fmt::BasicArgFormatter` define a subclass that implements some or - all of the visit methods with the same signatures as the methods in - `~fmt::ArgVisitor`, for example, `~fmt::ArgVisitor::visit_int()`. - Pass the subclass as the *Impl* template parameter. When a formatting - function processes an argument, it will dispatch to a visit method - specific to the argument type. For example, if the argument type is - ``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass - will be called. If the subclass doesn't contain a method with this signature, - then a corresponding method of `~fmt::BasicArgFormatter` or its superclass - will be called. - \endrst - */ -template -class BasicArgFormatter : public internal::ArgFormatterBase { - private: - BasicFormatter &formatter_; - const Char *format_; - - public: - /** - \rst - Constructs an argument formatter object. - *formatter* is a reference to the main formatter object, *spec* contains - format specifier information for standard argument types, and *fmt* points - to the part of the format string being parsed for custom argument types. - \endrst - */ - BasicArgFormatter(BasicFormatter &formatter, - Spec &spec, const Char *fmt) - : internal::ArgFormatterBase(formatter.writer(), spec), - formatter_(formatter), format_(fmt) {} - - /** Formats an argument of a custom (user-defined) type. */ - void visit_custom(internal::Arg::CustomValue c) { - c.format(&formatter_, c.value, &format_); - } -}; - -/** The default argument formatter. */ -template -class ArgFormatter : - public BasicArgFormatter, Char, FormatSpec> { - public: - /** Constructs an argument formatter object. */ - ArgFormatter(BasicFormatter &formatter, - FormatSpec &spec, const Char *fmt) - : BasicArgFormatter, - Char, FormatSpec>(formatter, spec, fmt) {} -}; - -/** This template formats data and writes the output to a writer. */ -template -class BasicFormatter : private internal::FormatterBase { - public: - /** The character type for the output. */ - typedef CharType Char; - - private: - BasicWriter &writer_; - internal::ArgMap map_; - - FMT_DISALLOW_COPY_AND_ASSIGN(BasicFormatter); - - using internal::FormatterBase::get_arg; - - // Checks if manual indexing is used and returns the argument with - // specified name. - internal::Arg get_arg(BasicStringRef arg_name, const char *&error); - - // Parses argument index and returns corresponding argument. - internal::Arg parse_arg_index(const Char *&s); - - // Parses argument name and returns corresponding argument. - internal::Arg parse_arg_name(const Char *&s); - - public: - /** - \rst - Constructs a ``BasicFormatter`` object. References to the arguments and - the writer are stored in the formatter object so make sure they have - appropriate lifetimes. - \endrst - */ - BasicFormatter(const ArgList &args, BasicWriter &w) - : internal::FormatterBase(args), writer_(w) {} - - /** Returns a reference to the writer associated with this formatter. */ - BasicWriter &writer() { return writer_; } - - /** Formats stored arguments and writes the output to the writer. */ - void format(BasicCStringRef format_str); - - // Formats a single argument and advances format_str, a format string pointer. - const Char *format(const Char *&format_str, const internal::Arg &arg); -}; - -// Generates a comma-separated list with results of applying f to -// numbers 0..n-1. -# define FMT_GEN(n, f) FMT_GEN##n(f) -# define FMT_GEN1(f) f(0) -# define FMT_GEN2(f) FMT_GEN1(f), f(1) -# define FMT_GEN3(f) FMT_GEN2(f), f(2) -# define FMT_GEN4(f) FMT_GEN3(f), f(3) -# define FMT_GEN5(f) FMT_GEN4(f), f(4) -# define FMT_GEN6(f) FMT_GEN5(f), f(5) -# define FMT_GEN7(f) FMT_GEN6(f), f(6) -# define FMT_GEN8(f) FMT_GEN7(f), f(7) -# define FMT_GEN9(f) FMT_GEN8(f), f(8) -# define FMT_GEN10(f) FMT_GEN9(f), f(9) -# define FMT_GEN11(f) FMT_GEN10(f), f(10) -# define FMT_GEN12(f) FMT_GEN11(f), f(11) -# define FMT_GEN13(f) FMT_GEN12(f), f(12) -# define FMT_GEN14(f) FMT_GEN13(f), f(13) -# define FMT_GEN15(f) FMT_GEN14(f), f(14) - -namespace internal { -inline uint64_t make_type() { return 0; } - -template -inline uint64_t make_type(const T &arg) { - return MakeValue< BasicFormatter >::type(arg); -} - -template -struct ArgArray; - -template -struct ArgArray { - // '+' is used to silence GCC -Wduplicated-branches warning. - typedef Value Type[N > 0 ? N : +1]; - - template - static Value make(const T &value) { -#ifdef __clang__ - Value result = MakeValue(value); - // Workaround a bug in Apple LLVM version 4.2 (clang-425.0.28) of clang: - // https://github.com/fmtlib/fmt/issues/276 - (void)result.custom.format; - return result; -#else - return MakeValue(value); -#endif - } -}; - -template -struct ArgArray { - typedef Arg Type[N + 1]; // +1 for the list end Arg::NONE - - template - static Arg make(const T &value) { return MakeArg(value); } -}; - -#if FMT_USE_VARIADIC_TEMPLATES -template -inline uint64_t make_type(const Arg &first, const Args & ... tail) { - return make_type(first) | (make_type(tail...) << 4); -} - -#else - -struct ArgType { - uint64_t type; - - ArgType() : type(0) {} - - template - ArgType(const T &arg) : type(make_type(arg)) {} -}; - -# define FMT_ARG_TYPE_DEFAULT(n) ArgType t##n = ArgType() - -inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { - return t0.type | (t1.type << 4) | (t2.type << 8) | (t3.type << 12) | - (t4.type << 16) | (t5.type << 20) | (t6.type << 24) | (t7.type << 28) | - (t8.type << 32) | (t9.type << 36) | (t10.type << 40) | (t11.type << 44) | - (t12.type << 48) | (t13.type << 52) | (t14.type << 56); -} -#endif -} // namespace internal - -# define FMT_MAKE_TEMPLATE_ARG(n) typename T##n -# define FMT_MAKE_ARG_TYPE(n) T##n -# define FMT_MAKE_ARG(n) const T##n &v##n -# define FMT_ASSIGN_char(n) \ - arr[n] = fmt::internal::MakeValue< fmt::BasicFormatter >(v##n) -# define FMT_ASSIGN_wchar_t(n) \ - arr[n] = fmt::internal::MakeValue< fmt::BasicFormatter >(v##n) - -#if FMT_USE_VARIADIC_TEMPLATES -// Defines a variadic function returning void. -# define FMT_VARIADIC_VOID(func, arg_type) \ - template \ - void func(arg_type arg0, const Args & ... args) { \ - typedef fmt::internal::ArgArray ArgArray; \ - typename ArgArray::Type array{ \ - ArgArray::template make >(args)...}; \ - func(arg0, fmt::ArgList(fmt::internal::make_type(args...), array)); \ - } - -// Defines a variadic constructor. -# define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ - template \ - ctor(arg0_type arg0, arg1_type arg1, const Args & ... args) { \ - typedef fmt::internal::ArgArray ArgArray; \ - typename ArgArray::Type array{ \ - ArgArray::template make >(args)...}; \ - func(arg0, arg1, fmt::ArgList(fmt::internal::make_type(args...), array)); \ - } - -#else - -# define FMT_MAKE_REF(n) \ - fmt::internal::MakeValue< fmt::BasicFormatter >(v##n) -# define FMT_MAKE_REF2(n) v##n - -// Defines a wrapper for a function taking one argument of type arg_type -// and n additional arguments of arbitrary types. -# define FMT_WRAP1(func, arg_type, n) \ - template \ - inline void func(arg_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ - const fmt::internal::ArgArray::Type array = {FMT_GEN(n, FMT_MAKE_REF)}; \ - func(arg1, fmt::ArgList( \ - fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array)); \ - } - -// Emulates a variadic function returning void on a pre-C++11 compiler. -# define FMT_VARIADIC_VOID(func, arg_type) \ - inline void func(arg_type arg) { func(arg, fmt::ArgList()); } \ - FMT_WRAP1(func, arg_type, 1) FMT_WRAP1(func, arg_type, 2) \ - FMT_WRAP1(func, arg_type, 3) FMT_WRAP1(func, arg_type, 4) \ - FMT_WRAP1(func, arg_type, 5) FMT_WRAP1(func, arg_type, 6) \ - FMT_WRAP1(func, arg_type, 7) FMT_WRAP1(func, arg_type, 8) \ - FMT_WRAP1(func, arg_type, 9) FMT_WRAP1(func, arg_type, 10) - -# define FMT_CTOR(ctor, func, arg0_type, arg1_type, n) \ - template \ - ctor(arg0_type arg0, arg1_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ - const fmt::internal::ArgArray::Type array = {FMT_GEN(n, FMT_MAKE_REF)}; \ - func(arg0, arg1, fmt::ArgList( \ - fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), array)); \ - } - -// Emulates a variadic constructor on a pre-C++11 compiler. -# define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 1) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 2) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 3) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 4) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 5) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 6) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 7) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 8) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 9) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 10) -#endif - -// Generates a comma-separated list with results of applying f to pairs -// (argument, index). -#define FMT_FOR_EACH1(f, x0) f(x0, 0) -#define FMT_FOR_EACH2(f, x0, x1) \ - FMT_FOR_EACH1(f, x0), f(x1, 1) -#define FMT_FOR_EACH3(f, x0, x1, x2) \ - FMT_FOR_EACH2(f, x0 ,x1), f(x2, 2) -#define FMT_FOR_EACH4(f, x0, x1, x2, x3) \ - FMT_FOR_EACH3(f, x0, x1, x2), f(x3, 3) -#define FMT_FOR_EACH5(f, x0, x1, x2, x3, x4) \ - FMT_FOR_EACH4(f, x0, x1, x2, x3), f(x4, 4) -#define FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5) \ - FMT_FOR_EACH5(f, x0, x1, x2, x3, x4), f(x5, 5) -#define FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6) \ - FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5), f(x6, 6) -#define FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7) \ - FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6), f(x7, 7) -#define FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8) \ - FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7), f(x8, 8) -#define FMT_FOR_EACH10(f, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) \ - FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8), f(x9, 9) - -/** - An error returned by an operating system or a language runtime, - for example a file opening error. -*/ -class SystemError : public internal::RuntimeError { - private: - FMT_API void init(int err_code, CStringRef format_str, ArgList args); - - protected: - int error_code_; - - typedef char Char; // For FMT_VARIADIC_CTOR. - - SystemError() {} - - public: - /** - \rst - Constructs a :class:`fmt::SystemError` object with a description - formatted with `fmt::format_system_error`. *message* and additional - arguments passed into the constructor are formatted similarly to - `fmt::format`. - - **Example**:: - - // This throws a SystemError with the description - // cannot open file 'madeup': No such file or directory - // or similar (system message may vary). - const char *filename = "madeup"; - std::FILE *file = std::fopen(filename, "r"); - if (!file) - throw fmt::SystemError(errno, "cannot open file '{}'", filename); - \endrst - */ - SystemError(int error_code, CStringRef message) { - init(error_code, message, ArgList()); - } - FMT_DEFAULTED_COPY_CTOR(SystemError) - FMT_VARIADIC_CTOR(SystemError, init, int, CStringRef) - - FMT_API ~SystemError() FMT_DTOR_NOEXCEPT FMT_OVERRIDE; - - int error_code() const { return error_code_; } -}; - -/** - \rst - Formats an error returned by an operating system or a language runtime, - for example a file opening error, and writes it to *out* in the following - form: - - .. parsed-literal:: - **: ** - - where ** is the passed message and ** is - the system message corresponding to the error code. - *error_code* is a system error code as given by ``errno``. - If *error_code* is not a valid error code such as -1, the system message - may look like "Unknown error -1" and is platform-dependent. - \endrst - */ -FMT_API void format_system_error(fmt::Writer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT; - -/** - \rst - This template provides operations for formatting and writing data into - a character stream. The output is stored in a buffer provided by a subclass - such as :class:`fmt::BasicMemoryWriter`. - - You can use one of the following typedefs for common character types: - - +---------+----------------------+ - | Type | Definition | - +=========+======================+ - | Writer | BasicWriter | - +---------+----------------------+ - | WWriter | BasicWriter | - +---------+----------------------+ - - \endrst - */ -template -class BasicWriter { - private: - // Output buffer. - Buffer &buffer_; - - FMT_DISALLOW_COPY_AND_ASSIGN(BasicWriter); - - typedef typename internal::CharTraits::CharPtr CharPtr; - -#if FMT_SECURE_SCL - // Returns pointer value. - static Char *get(CharPtr p) { return p.base(); } -#else - static Char *get(Char *p) { return p; } -#endif - - // Fills the padding around the content and returns the pointer to the - // content area. - static CharPtr fill_padding(CharPtr buffer, - unsigned total_size, std::size_t content_size, wchar_t fill); - - // Grows the buffer by n characters and returns a pointer to the newly - // allocated area. - CharPtr grow_buffer(std::size_t n) { - std::size_t size = buffer_.size(); - buffer_.resize(size + n); - return internal::make_ptr(&buffer_[size], n); - } - - // Writes an unsigned decimal integer. - template - Char *write_unsigned_decimal(UInt value, unsigned prefix_size = 0) { - unsigned num_digits = internal::count_digits(value); - Char *ptr = get(grow_buffer(prefix_size + num_digits)); - internal::format_decimal(ptr + prefix_size, value, num_digits); - return ptr; - } - - // Writes a decimal integer. - template - void write_decimal(Int value) { - typedef typename internal::IntTraits::MainType MainType; - MainType abs_value = static_cast(value); - if (internal::is_negative(value)) { - abs_value = 0 - abs_value; - *write_unsigned_decimal(abs_value, 1) = '-'; - } else { - write_unsigned_decimal(abs_value, 0); - } - } - - // Prepare a buffer for integer formatting. - CharPtr prepare_int_buffer(unsigned num_digits, - const EmptySpec &, const char *prefix, unsigned prefix_size) { - unsigned size = prefix_size + num_digits; - CharPtr p = grow_buffer(size); - std::uninitialized_copy(prefix, prefix + prefix_size, p); - return p + size - 1; - } - - template - CharPtr prepare_int_buffer(unsigned num_digits, - const Spec &spec, const char *prefix, unsigned prefix_size); - - // Formats an integer. - template - void write_int(T value, Spec spec); - - // Formats a floating-point number (double or long double). - template - void write_double(T value, const Spec &spec); - - // Writes a formatted string. - template - CharPtr write_str(const StrChar *s, std::size_t size, const AlignSpec &spec); - - template - void write_str(const internal::Arg::StringValue &str, - const Spec &spec); - - // This following methods are private to disallow writing wide characters - // and strings to a char stream. If you want to print a wide string as a - // pointer as std::ostream does, cast it to const void*. - // Do not implement! - void operator<<(typename internal::WCharHelper::Unsupported); - void operator<<( - typename internal::WCharHelper::Unsupported); - - // Appends floating-point length specifier to the format string. - // The second argument is only used for overload resolution. - void append_float_length(Char *&format_ptr, long double) { - *format_ptr++ = 'L'; - } - - template - void append_float_length(Char *&, T) {} - - template - friend class internal::ArgFormatterBase; - - template - friend class BasicPrintfArgFormatter; - - protected: - /** - Constructs a ``BasicWriter`` object. - */ - explicit BasicWriter(Buffer &b) : buffer_(b) {} - - public: - /** - \rst - Destroys a ``BasicWriter`` object. - \endrst - */ - virtual ~BasicWriter() {} - - /** - Returns the total number of characters written. - */ - std::size_t size() const { return buffer_.size(); } - - /** - Returns a pointer to the output buffer content. No terminating null - character is appended. - */ - const Char *data() const FMT_NOEXCEPT { return &buffer_[0]; } - - /** - Returns a pointer to the output buffer content with terminating null - character appended. - */ - const Char *c_str() const { - std::size_t size = buffer_.size(); - buffer_.reserve(size + 1); - buffer_[size] = '\0'; - return &buffer_[0]; - } - - /** - \rst - Returns the content of the output buffer as an `std::string`. - \endrst - */ - std::basic_string str() const { - return std::basic_string(&buffer_[0], buffer_.size()); - } - - /** - \rst - Writes formatted data. - - *args* is an argument list representing arbitrary arguments. - - **Example**:: - - MemoryWriter out; - out.write("Current point:\n"); - out.write("({:+f}, {:+f})", -3.14, 3.14); - - This will write the following output to the ``out`` object: - - .. code-block:: none - - Current point: - (-3.140000, +3.140000) - - The output can be accessed using :func:`data()`, :func:`c_str` or - :func:`str` methods. - - See also :ref:`syntax`. - \endrst - */ - void write(BasicCStringRef format, ArgList args) { - BasicFormatter(args, *this).format(format); - } - FMT_VARIADIC_VOID(write, BasicCStringRef) - - BasicWriter &operator<<(int value) { - write_decimal(value); - return *this; - } - BasicWriter &operator<<(unsigned value) { - return *this << IntFormatSpec(value); - } - BasicWriter &operator<<(long value) { - write_decimal(value); - return *this; - } - BasicWriter &operator<<(unsigned long value) { - return *this << IntFormatSpec(value); - } - BasicWriter &operator<<(LongLong value) { - write_decimal(value); - return *this; - } - - /** - \rst - Formats *value* and writes it to the stream. - \endrst - */ - BasicWriter &operator<<(ULongLong value) { - return *this << IntFormatSpec(value); - } - - BasicWriter &operator<<(double value) { - write_double(value, FormatSpec()); - return *this; - } - - /** - \rst - Formats *value* using the general format for floating-point numbers - (``'g'``) and writes it to the stream. - \endrst - */ - BasicWriter &operator<<(long double value) { - write_double(value, FormatSpec()); - return *this; - } - - /** - Writes a character to the stream. - */ - BasicWriter &operator<<(char value) { - buffer_.push_back(value); - return *this; - } - - BasicWriter &operator<<( - typename internal::WCharHelper::Supported value) { - buffer_.push_back(value); - return *this; - } - - /** - \rst - Writes *value* to the stream. - \endrst - */ - BasicWriter &operator<<(fmt::BasicStringRef value) { - const Char *str = value.data(); - buffer_.append(str, str + value.size()); - return *this; - } - - BasicWriter &operator<<( - typename internal::WCharHelper::Supported value) { - const char *str = value.data(); - buffer_.append(str, str + value.size()); - return *this; - } - - template - BasicWriter &operator<<(IntFormatSpec spec) { - internal::CharTraits::convert(FillChar()); - write_int(spec.value(), spec); - return *this; - } - - template - BasicWriter &operator<<(const StrFormatSpec &spec) { - const StrChar *s = spec.str(); - write_str(s, std::char_traits::length(s), spec); - return *this; - } - - void clear() FMT_NOEXCEPT { buffer_.clear(); } - - Buffer &buffer() FMT_NOEXCEPT { return buffer_; } -}; - -template -template -typename BasicWriter::CharPtr BasicWriter::write_str( - const StrChar *s, std::size_t size, const AlignSpec &spec) { - CharPtr out = CharPtr(); - if (spec.width() > size) { - out = grow_buffer(spec.width()); - Char fill = internal::CharTraits::cast(spec.fill()); - if (spec.align() == ALIGN_RIGHT) { - std::uninitialized_fill_n(out, spec.width() - size, fill); - out += spec.width() - size; - } else if (spec.align() == ALIGN_CENTER) { - out = fill_padding(out, spec.width(), size, fill); - } else { - std::uninitialized_fill_n(out + size, spec.width() - size, fill); - } - } else { - out = grow_buffer(size); - } - std::uninitialized_copy(s, s + size, out); - return out; -} - -template -template -void BasicWriter::write_str( - const internal::Arg::StringValue &s, const Spec &spec) { - // Check if StrChar is convertible to Char. - internal::CharTraits::convert(StrChar()); - if (spec.type_ && spec.type_ != 's') - internal::report_unknown_type(spec.type_, "string"); - const StrChar *str_value = s.value; - std::size_t str_size = s.size; - if (str_size == 0) { - if (!str_value) { - FMT_THROW(FormatError("string pointer is null")); - } - } - std::size_t precision = static_cast(spec.precision_); - if (spec.precision_ >= 0 && precision < str_size) - str_size = precision; - write_str(str_value, str_size, spec); -} - -template -typename BasicWriter::CharPtr - BasicWriter::fill_padding( - CharPtr buffer, unsigned total_size, - std::size_t content_size, wchar_t fill) { - std::size_t padding = total_size - content_size; - std::size_t left_padding = padding / 2; - Char fill_char = internal::CharTraits::cast(fill); - std::uninitialized_fill_n(buffer, left_padding, fill_char); - buffer += left_padding; - CharPtr content = buffer; - std::uninitialized_fill_n(buffer + content_size, - padding - left_padding, fill_char); - return content; -} - -template -template -typename BasicWriter::CharPtr - BasicWriter::prepare_int_buffer( - unsigned num_digits, const Spec &spec, - const char *prefix, unsigned prefix_size) { - unsigned width = spec.width(); - Alignment align = spec.align(); - Char fill = internal::CharTraits::cast(spec.fill()); - if (spec.precision() > static_cast(num_digits)) { - // Octal prefix '0' is counted as a digit, so ignore it if precision - // is specified. - if (prefix_size > 0 && prefix[prefix_size - 1] == '0') - --prefix_size; - unsigned number_size = - prefix_size + internal::to_unsigned(spec.precision()); - AlignSpec subspec(number_size, '0', ALIGN_NUMERIC); - if (number_size >= width) - return prepare_int_buffer(num_digits, subspec, prefix, prefix_size); - buffer_.reserve(width); - unsigned fill_size = width - number_size; - if (align != ALIGN_LEFT) { - CharPtr p = grow_buffer(fill_size); - std::uninitialized_fill(p, p + fill_size, fill); - } - CharPtr result = prepare_int_buffer( - num_digits, subspec, prefix, prefix_size); - if (align == ALIGN_LEFT) { - CharPtr p = grow_buffer(fill_size); - std::uninitialized_fill(p, p + fill_size, fill); - } - return result; - } - unsigned size = prefix_size + num_digits; - if (width <= size) { - CharPtr p = grow_buffer(size); - std::uninitialized_copy(prefix, prefix + prefix_size, p); - return p + size - 1; - } - CharPtr p = grow_buffer(width); - CharPtr end = p + width; - if (align == ALIGN_LEFT) { - std::uninitialized_copy(prefix, prefix + prefix_size, p); - p += size; - std::uninitialized_fill(p, end, fill); - } else if (align == ALIGN_CENTER) { - p = fill_padding(p, width, size, fill); - std::uninitialized_copy(prefix, prefix + prefix_size, p); - p += size; - } else { - if (align == ALIGN_NUMERIC) { - if (prefix_size != 0) { - p = std::uninitialized_copy(prefix, prefix + prefix_size, p); - size -= prefix_size; - } - } else { - std::uninitialized_copy(prefix, prefix + prefix_size, end - size); - } - std::uninitialized_fill(p, end - size, fill); - p = end; - } - return p - 1; -} - -template -template -void BasicWriter::write_int(T value, Spec spec) { - unsigned prefix_size = 0; - typedef typename internal::IntTraits::MainType UnsignedType; - UnsignedType abs_value = static_cast(value); - char prefix[4] = ""; - if (internal::is_negative(value)) { - prefix[0] = '-'; - ++prefix_size; - abs_value = 0 - abs_value; - } else if (spec.flag(SIGN_FLAG)) { - prefix[0] = spec.flag(PLUS_FLAG) ? '+' : ' '; - ++prefix_size; - } - switch (spec.type()) { - case 0: case 'd': { - unsigned num_digits = internal::count_digits(abs_value); - CharPtr p = prepare_int_buffer(num_digits, spec, prefix, prefix_size) + 1; - internal::format_decimal(get(p), abs_value, 0); - break; - } - case 'x': case 'X': { - UnsignedType n = abs_value; - if (spec.flag(HASH_FLAG)) { - prefix[prefix_size++] = '0'; - prefix[prefix_size++] = spec.type_prefix(); - } - unsigned num_digits = 0; - do { - ++num_digits; - } while ((n >>= 4) != 0); - Char *p = get(prepare_int_buffer( - num_digits, spec, prefix, prefix_size)); - n = abs_value; - const char *digits = spec.type() == 'x' ? - "0123456789abcdef" : "0123456789ABCDEF"; - do { - *p-- = digits[n & 0xf]; - } while ((n >>= 4) != 0); - break; - } - case 'b': case 'B': { - UnsignedType n = abs_value; - if (spec.flag(HASH_FLAG)) { - prefix[prefix_size++] = '0'; - prefix[prefix_size++] = spec.type_prefix(); - } - unsigned num_digits = 0; - do { - ++num_digits; - } while ((n >>= 1) != 0); - Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); - n = abs_value; - do { - *p-- = static_cast('0' + (n & 1)); - } while ((n >>= 1) != 0); - break; - } - case 'o': { - UnsignedType n = abs_value; - if (spec.flag(HASH_FLAG)) - prefix[prefix_size++] = '0'; - unsigned num_digits = 0; - do { - ++num_digits; - } while ((n >>= 3) != 0); - Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); - n = abs_value; - do { - *p-- = static_cast('0' + (n & 7)); - } while ((n >>= 3) != 0); - break; - } - case 'n': { - unsigned num_digits = internal::count_digits(abs_value); - fmt::StringRef sep = ""; -#if !(defined(ANDROID) || defined(__ANDROID__)) - sep = internal::thousands_sep(std::localeconv()); -#endif - unsigned size = static_cast( - num_digits + sep.size() * ((num_digits - 1) / 3)); - CharPtr p = prepare_int_buffer(size, spec, prefix, prefix_size) + 1; - internal::format_decimal(get(p), abs_value, 0, internal::ThousandsSep(sep)); - break; - } - default: - internal::report_unknown_type( - spec.type(), spec.flag(CHAR_FLAG) ? "char" : "integer"); - break; - } -} - -template -template -void BasicWriter::write_double(T value, const Spec &spec) { - // Check type. - char type = spec.type(); - bool upper = false; - switch (type) { - case 0: - type = 'g'; - break; - case 'e': case 'f': case 'g': case 'a': - break; - case 'F': -#if FMT_MSC_VER - // MSVC's printf doesn't support 'F'. - type = 'f'; -#endif - // Fall through. - case 'E': case 'G': case 'A': - upper = true; - break; - default: - internal::report_unknown_type(type, "double"); - break; - } - - char sign = 0; - // Use isnegative instead of value < 0 because the latter is always - // false for NaN. - if (internal::FPUtil::isnegative(static_cast(value))) { - sign = '-'; - value = -value; - } else if (spec.flag(SIGN_FLAG)) { - sign = spec.flag(PLUS_FLAG) ? '+' : ' '; - } - - if (internal::FPUtil::isnotanumber(value)) { - // Format NaN ourselves because sprintf's output is not consistent - // across platforms. - std::size_t nan_size = 4; - const char *nan = upper ? " NAN" : " nan"; - if (!sign) { - --nan_size; - ++nan; - } - CharPtr out = write_str(nan, nan_size, spec); - if (sign) - *out = sign; - return; - } - - if (internal::FPUtil::isinfinity(value)) { - // Format infinity ourselves because sprintf's output is not consistent - // across platforms. - std::size_t inf_size = 4; - const char *inf = upper ? " INF" : " inf"; - if (!sign) { - --inf_size; - ++inf; - } - CharPtr out = write_str(inf, inf_size, spec); - if (sign) - *out = sign; - return; - } - - std::size_t offset = buffer_.size(); - unsigned width = spec.width(); - if (sign) { - buffer_.reserve(buffer_.size() + (width > 1u ? width : 1u)); - if (width > 0) - --width; - ++offset; - } - - // Build format string. - enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg - Char format[MAX_FORMAT_SIZE]; - Char *format_ptr = format; - *format_ptr++ = '%'; - unsigned width_for_sprintf = width; - if (spec.flag(HASH_FLAG)) - *format_ptr++ = '#'; - if (spec.align() == ALIGN_CENTER) { - width_for_sprintf = 0; - } else { - if (spec.align() == ALIGN_LEFT) - *format_ptr++ = '-'; - if (width != 0) - *format_ptr++ = '*'; - } - if (spec.precision() >= 0) { - *format_ptr++ = '.'; - *format_ptr++ = '*'; - } - - append_float_length(format_ptr, value); - *format_ptr++ = type; - *format_ptr = '\0'; - - // Format using snprintf. - Char fill = internal::CharTraits::cast(spec.fill()); - unsigned n = 0; - Char *start = FMT_NULL; - for (;;) { - std::size_t buffer_size = buffer_.capacity() - offset; -#if FMT_MSC_VER - // MSVC's vsnprintf_s doesn't work with zero size, so reserve - // space for at least one extra character to make the size non-zero. - // Note that the buffer's capacity will increase by more than 1. - if (buffer_size == 0) { - buffer_.reserve(offset + 1); - buffer_size = buffer_.capacity() - offset; - } -#endif - start = &buffer_[offset]; - int result = internal::CharTraits::format_float( - start, buffer_size, format, width_for_sprintf, spec.precision(), value); - if (result >= 0) { - n = internal::to_unsigned(result); - if (offset + n < buffer_.capacity()) - break; // The buffer is large enough - continue with formatting. - buffer_.reserve(offset + n + 1); - } else { - // If result is negative we ask to increase the capacity by at least 1, - // but as std::vector, the buffer grows exponentially. - buffer_.reserve(buffer_.capacity() + 1); - } - } - if (sign) { - if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) || - *start != ' ') { - *(start - 1) = sign; - sign = 0; - } else { - *(start - 1) = fill; - } - ++n; - } - if (spec.align() == ALIGN_CENTER && spec.width() > n) { - width = spec.width(); - CharPtr p = grow_buffer(width); - std::memmove(get(p) + (width - n) / 2, get(p), n * sizeof(Char)); - fill_padding(p, spec.width(), n, fill); - return; - } - if (spec.fill() != ' ' || sign) { - while (*start == ' ') - *start++ = fill; - if (sign) - *(start - 1) = sign; - } - grow_buffer(n); -} - -/** - \rst - This class template provides operations for formatting and writing data - into a character stream. The output is stored in a memory buffer that grows - dynamically. - - You can use one of the following typedefs for common character types - and the standard allocator: - - +---------------+-----------------------------------------------------+ - | Type | Definition | - +===============+=====================================================+ - | MemoryWriter | BasicMemoryWriter> | - +---------------+-----------------------------------------------------+ - | WMemoryWriter | BasicMemoryWriter> | - +---------------+-----------------------------------------------------+ - - **Example**:: - - MemoryWriter out; - out << "The answer is " << 42 << "\n"; - out.write("({:+f}, {:+f})", -3.14, 3.14); - - This will write the following output to the ``out`` object: - - .. code-block:: none - - The answer is 42 - (-3.140000, +3.140000) - - The output can be converted to an ``std::string`` with ``out.str()`` or - accessed as a C string with ``out.c_str()``. - \endrst - */ -template > -class BasicMemoryWriter : public BasicWriter { - private: - internal::MemoryBuffer buffer_; - - public: - explicit BasicMemoryWriter(const Allocator& alloc = Allocator()) - : BasicWriter(buffer_), buffer_(alloc) {} - -#if FMT_USE_RVALUE_REFERENCES - /** - \rst - Constructs a :class:`fmt::BasicMemoryWriter` object moving the content - of the other object to it. - \endrst - */ - BasicMemoryWriter(BasicMemoryWriter &&other) - : BasicWriter(buffer_), buffer_(std::move(other.buffer_)) { - } - - /** - \rst - Moves the content of the other ``BasicMemoryWriter`` object to this one. - \endrst - */ - BasicMemoryWriter &operator=(BasicMemoryWriter &&other) { - buffer_ = std::move(other.buffer_); - return *this; - } -#endif -}; - -typedef BasicMemoryWriter MemoryWriter; -typedef BasicMemoryWriter WMemoryWriter; - -/** - \rst - This class template provides operations for formatting and writing data - into a fixed-size array. For writing into a dynamically growing buffer - use :class:`fmt::BasicMemoryWriter`. - - Any write method will throw ``std::runtime_error`` if the output doesn't fit - into the array. - - You can use one of the following typedefs for common character types: - - +--------------+---------------------------+ - | Type | Definition | - +==============+===========================+ - | ArrayWriter | BasicArrayWriter | - +--------------+---------------------------+ - | WArrayWriter | BasicArrayWriter | - +--------------+---------------------------+ - \endrst - */ -template -class BasicArrayWriter : public BasicWriter { - private: - internal::FixedBuffer buffer_; - - public: - /** - \rst - Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the - given size. - \endrst - */ - BasicArrayWriter(Char *array, std::size_t size) - : BasicWriter(buffer_), buffer_(array, size) {} - - /** - \rst - Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the - size known at compile time. - \endrst - */ - template - explicit BasicArrayWriter(Char (&array)[SIZE]) - : BasicWriter(buffer_), buffer_(array, SIZE) {} -}; - -typedef BasicArrayWriter ArrayWriter; -typedef BasicArrayWriter WArrayWriter; - -// Reports a system error without throwing an exception. -// Can be used to report errors from destructors. -FMT_API void report_system_error(int error_code, - StringRef message) FMT_NOEXCEPT; - -#if FMT_USE_WINDOWS_H - -/** A Windows error. */ -class WindowsError : public SystemError { - private: - FMT_API void init(int error_code, CStringRef format_str, ArgList args); - - public: - /** - \rst - Constructs a :class:`fmt::WindowsError` object with the description - of the form - - .. parsed-literal:: - **: ** - - where ** is the formatted message and ** is the - system message corresponding to the error code. - *error_code* is a Windows error code as given by ``GetLastError``. - If *error_code* is not a valid error code such as -1, the system message - will look like "error -1". - - **Example**:: - - // This throws a WindowsError with the description - // cannot open file 'madeup': The system cannot find the file specified. - // or similar (system message may vary). - const char *filename = "madeup"; - LPOFSTRUCT of = LPOFSTRUCT(); - HFILE file = OpenFile(filename, &of, OF_READ); - if (file == HFILE_ERROR) { - throw fmt::WindowsError(GetLastError(), - "cannot open file '{}'", filename); - } - \endrst - */ - WindowsError(int error_code, CStringRef message) { - init(error_code, message, ArgList()); - } - FMT_VARIADIC_CTOR(WindowsError, init, int, CStringRef) -}; - -// Reports a Windows error without throwing an exception. -// Can be used to report errors from destructors. -FMT_API void report_windows_error(int error_code, - StringRef message) FMT_NOEXCEPT; - -#endif - -enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE }; - -/** - Formats a string and prints it to stdout using ANSI escape sequences - to specify color (experimental). - Example: - print_colored(fmt::RED, "Elapsed time: {0:.2f} seconds", 1.23); - */ -FMT_API void print_colored(Color c, CStringRef format, ArgList args); - -/** - \rst - Formats arguments and returns the result as a string. - - **Example**:: - - std::string message = format("The answer is {}", 42); - \endrst -*/ -inline std::string format(CStringRef format_str, ArgList args) { - MemoryWriter w; - w.write(format_str, args); - return w.str(); -} - -inline std::wstring format(WCStringRef format_str, ArgList args) { - WMemoryWriter w; - w.write(format_str, args); - return w.str(); -} - -/** - \rst - Prints formatted data to the file *f*. - - **Example**:: - - print(stderr, "Don't {}!", "panic"); - \endrst - */ -FMT_API void print(std::FILE *f, CStringRef format_str, ArgList args); - -/** - \rst - Prints formatted data to ``stdout``. - - **Example**:: - - print("Elapsed time: {0:.2f} seconds", 1.23); - \endrst - */ -FMT_API void print(CStringRef format_str, ArgList args); - -/** - Fast integer formatter. - */ -class FormatInt { - private: - // Buffer should be large enough to hold all digits (digits10 + 1), - // a sign and a null character. - enum {BUFFER_SIZE = std::numeric_limits::digits10 + 3}; - mutable char buffer_[BUFFER_SIZE]; - char *str_; - - // Formats value in reverse and returns the number of digits. - char *format_decimal(ULongLong value) { - char *buffer_end = buffer_ + BUFFER_SIZE - 1; - while (value >= 100) { - // Integer division is slow so do it for a group of two digits instead - // of for every digit. The idea comes from the talk by Alexandrescu - // "Three Optimization Tips for C++". See speed-test for a comparison. - unsigned index = static_cast((value % 100) * 2); - value /= 100; - *--buffer_end = internal::Data::DIGITS[index + 1]; - *--buffer_end = internal::Data::DIGITS[index]; - } - if (value < 10) { - *--buffer_end = static_cast('0' + value); - return buffer_end; - } - unsigned index = static_cast(value * 2); - *--buffer_end = internal::Data::DIGITS[index + 1]; - *--buffer_end = internal::Data::DIGITS[index]; - return buffer_end; - } - - void FormatSigned(LongLong value) { - ULongLong abs_value = static_cast(value); - bool negative = value < 0; - if (negative) - abs_value = 0 - abs_value; - str_ = format_decimal(abs_value); - if (negative) - *--str_ = '-'; - } - - public: - explicit FormatInt(int value) { FormatSigned(value); } - explicit FormatInt(long value) { FormatSigned(value); } - explicit FormatInt(LongLong value) { FormatSigned(value); } - explicit FormatInt(unsigned value) : str_(format_decimal(value)) {} - explicit FormatInt(unsigned long value) : str_(format_decimal(value)) {} - explicit FormatInt(ULongLong value) : str_(format_decimal(value)) {} - - /** Returns the number of characters written to the output buffer. */ - std::size_t size() const { - return internal::to_unsigned(buffer_ - str_ + BUFFER_SIZE - 1); - } - - /** - Returns a pointer to the output buffer content. No terminating null - character is appended. - */ - const char *data() const { return str_; } - - /** - Returns a pointer to the output buffer content with terminating null - character appended. - */ - const char *c_str() const { - buffer_[BUFFER_SIZE - 1] = '\0'; - return str_; - } - - /** - \rst - Returns the content of the output buffer as an ``std::string``. - \endrst - */ - std::string str() const { return std::string(str_, size()); } -}; - -// Formats a decimal integer value writing into buffer and returns -// a pointer to the end of the formatted string. This function doesn't -// write a terminating null character. -template -inline void format_decimal(char *&buffer, T value) { - typedef typename internal::IntTraits::MainType MainType; - MainType abs_value = static_cast(value); - if (internal::is_negative(value)) { - *buffer++ = '-'; - abs_value = 0 - abs_value; - } - if (abs_value < 100) { - if (abs_value < 10) { - *buffer++ = static_cast('0' + abs_value); - return; - } - unsigned index = static_cast(abs_value * 2); - *buffer++ = internal::Data::DIGITS[index]; - *buffer++ = internal::Data::DIGITS[index + 1]; - return; - } - unsigned num_digits = internal::count_digits(abs_value); - internal::format_decimal(buffer, abs_value, num_digits); - buffer += num_digits; -} - -/** - \rst - Returns a named argument for formatting functions. - - **Example**:: - - print("Elapsed time: {s:.2f} seconds", arg("s", 1.23)); - - \endrst - */ -template -inline internal::NamedArgWithType arg(StringRef name, const T &arg) { - return internal::NamedArgWithType(name, arg); -} - -template -inline internal::NamedArgWithType arg(WStringRef name, const T &arg) { - return internal::NamedArgWithType(name, arg); -} - -// The following two functions are deleted intentionally to disable -// nested named arguments as in ``format("{}", arg("a", arg("b", 42)))``. -template -void arg(StringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; -template -void arg(WStringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; -} - -#if FMT_GCC_VERSION -// Use the system_header pragma to suppress warnings about variadic macros -// because suppressing -Wvariadic-macros with the diagnostic pragma doesn't -// work. It is used at the end because we want to suppress as little warnings -// as possible. -# pragma GCC system_header -#endif - -// This is used to work around VC++ bugs in handling variadic macros. -#define FMT_EXPAND(args) args - -// Returns the number of arguments. -// Based on https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s. -#define FMT_NARG(...) FMT_NARG_(__VA_ARGS__, FMT_RSEQ_N()) -#define FMT_NARG_(...) FMT_EXPAND(FMT_ARG_N(__VA_ARGS__)) -#define FMT_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N -#define FMT_RSEQ_N() 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 - -#define FMT_FOR_EACH_(N, f, ...) \ - FMT_EXPAND(FMT_CONCAT(FMT_FOR_EACH, N)(f, __VA_ARGS__)) -#define FMT_FOR_EACH(f, ...) \ - FMT_EXPAND(FMT_FOR_EACH_(FMT_NARG(__VA_ARGS__), f, __VA_ARGS__)) - -#define FMT_ADD_ARG_NAME(type, index) type arg##index -#define FMT_GET_ARG_NAME(type, index) arg##index - -#if FMT_USE_VARIADIC_TEMPLATES -# define FMT_VARIADIC_(Const, Char, ReturnType, func, call, ...) \ - template \ - ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ - const Args & ... args) Const { \ - typedef fmt::internal::ArgArray ArgArray; \ - typename ArgArray::Type array{ \ - ArgArray::template make >(args)...}; \ - call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ - fmt::ArgList(fmt::internal::make_type(args...), array)); \ - } -#else -// Defines a wrapper for a function taking __VA_ARGS__ arguments -// and n additional arguments of arbitrary types. -# define FMT_WRAP(Const, Char, ReturnType, func, call, n, ...) \ - template \ - inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ - FMT_GEN(n, FMT_MAKE_ARG)) Const { \ - fmt::internal::ArgArray::Type arr; \ - FMT_GEN(n, FMT_ASSIGN_##Char); \ - call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList( \ - fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), arr)); \ - } - -# define FMT_VARIADIC_(Const, Char, ReturnType, func, call, ...) \ - inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__)) Const { \ - call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList()); \ - } \ - FMT_WRAP(Const, Char, ReturnType, func, call, 1, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 2, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 3, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 4, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 5, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 6, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 7, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 8, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 9, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 10, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 11, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 12, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 13, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 14, __VA_ARGS__) \ - FMT_WRAP(Const, Char, ReturnType, func, call, 15, __VA_ARGS__) -#endif // FMT_USE_VARIADIC_TEMPLATES - -/** - \rst - Defines a variadic function with the specified return type, function name - and argument types passed as variable arguments to this macro. - - **Example**:: - - void print_error(const char *file, int line, const char *format, - fmt::ArgList args) { - fmt::print("{}: {}: ", file, line); - fmt::print(format, args); - } - FMT_VARIADIC(void, print_error, const char *, int, const char *) - - ``FMT_VARIADIC`` is used for compatibility with legacy C++ compilers that - don't implement variadic templates. You don't have to use this macro if - you don't need legacy compiler support and can use variadic templates - directly:: - - template - void print_error(const char *file, int line, const char *format, - const Args & ... args) { - fmt::print("{}: {}: ", file, line); - fmt::print(format, args...); - } - \endrst - */ -#define FMT_VARIADIC(ReturnType, func, ...) \ - FMT_VARIADIC_(, char, ReturnType, func, return func, __VA_ARGS__) - -#define FMT_VARIADIC_CONST(ReturnType, func, ...) \ - FMT_VARIADIC_(const, char, ReturnType, func, return func, __VA_ARGS__) - -#define FMT_VARIADIC_W(ReturnType, func, ...) \ - FMT_VARIADIC_(, wchar_t, ReturnType, func, return func, __VA_ARGS__) - -#define FMT_VARIADIC_CONST_W(ReturnType, func, ...) \ - FMT_VARIADIC_(const, wchar_t, ReturnType, func, return func, __VA_ARGS__) - -#define FMT_CAPTURE_ARG_(id, index) ::fmt::arg(#id, id) - -#define FMT_CAPTURE_ARG_W_(id, index) ::fmt::arg(L###id, id) - -/** - \rst - Convenient macro to capture the arguments' names and values into several - ``fmt::arg(name, value)``. - - **Example**:: - - int x = 1, y = 2; - print("point: ({x}, {y})", FMT_CAPTURE(x, y)); - // same as: - // print("point: ({x}, {y})", arg("x", x), arg("y", y)); - - \endrst - */ -#define FMT_CAPTURE(...) FMT_FOR_EACH(FMT_CAPTURE_ARG_, __VA_ARGS__) - -#define FMT_CAPTURE_W(...) FMT_FOR_EACH(FMT_CAPTURE_ARG_W_, __VA_ARGS__) - -namespace fmt { -FMT_VARIADIC(std::string, format, CStringRef) -FMT_VARIADIC_W(std::wstring, format, WCStringRef) -FMT_VARIADIC(void, print, CStringRef) -FMT_VARIADIC(void, print, std::FILE *, CStringRef) -FMT_VARIADIC(void, print_colored, Color, CStringRef) - -namespace internal { -template -inline bool is_name_start(Char c) { - return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c; -} - -// Parses an unsigned integer advancing s to the end of the parsed input. -// This function assumes that the first character of s is a digit. -template -unsigned parse_nonnegative_int(const Char *&s) { - assert('0' <= *s && *s <= '9'); - unsigned value = 0; - // Convert to unsigned to prevent a warning. - unsigned max_int = (std::numeric_limits::max)(); - unsigned big = max_int / 10; - do { - // Check for overflow. - if (value > big) { - value = max_int + 1; - break; - } - value = value * 10 + (*s - '0'); - ++s; - } while ('0' <= *s && *s <= '9'); - // Convert to unsigned to prevent a warning. - if (value > max_int) - FMT_THROW(FormatError("number is too big")); - return value; -} - -inline void require_numeric_argument(const Arg &arg, char spec) { - if (arg.type > Arg::LAST_NUMERIC_TYPE) { - std::string message = - fmt::format("format specifier '{}' requires numeric argument", spec); - FMT_THROW(fmt::FormatError(message)); - } -} - -template -void check_sign(const Char *&s, const Arg &arg) { - char sign = static_cast(*s); - require_numeric_argument(arg, sign); - if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) { - FMT_THROW(FormatError(fmt::format( - "format specifier '{}' requires signed argument", sign))); - } - ++s; -} -} // namespace internal - -template -inline internal::Arg BasicFormatter::get_arg( - BasicStringRef arg_name, const char *&error) { - if (check_no_auto_index(error)) { - map_.init(args()); - const internal::Arg *arg = map_.find(arg_name); - if (arg) - return *arg; - error = "argument not found"; - } - return internal::Arg(); -} - -template -inline internal::Arg BasicFormatter::parse_arg_index(const Char *&s) { - const char *error = FMT_NULL; - internal::Arg arg = *s < '0' || *s > '9' ? - next_arg(error) : get_arg(internal::parse_nonnegative_int(s), error); - if (error) { - FMT_THROW(FormatError( - *s != '}' && *s != ':' ? "invalid format string" : error)); - } - return arg; -} - -template -inline internal::Arg BasicFormatter::parse_arg_name(const Char *&s) { - assert(internal::is_name_start(*s)); - const Char *start = s; - Char c; - do { - c = *++s; - } while (internal::is_name_start(c) || ('0' <= c && c <= '9')); - const char *error = FMT_NULL; - internal::Arg arg = get_arg(BasicStringRef(start, s - start), error); - if (error) - FMT_THROW(FormatError(error)); - return arg; -} - -template -const Char *BasicFormatter::format( - const Char *&format_str, const internal::Arg &arg) { - using internal::Arg; - const Char *s = format_str; - typename ArgFormatter::SpecType spec; - if (*s == ':') { - if (arg.type == Arg::CUSTOM) { - arg.custom.format(this, arg.custom.value, &s); - return s; - } - ++s; - // Parse fill and alignment. - if (Char c = *s) { - const Char *p = s + 1; - spec.align_ = ALIGN_DEFAULT; - do { - switch (*p) { - case '<': - spec.align_ = ALIGN_LEFT; - break; - case '>': - spec.align_ = ALIGN_RIGHT; - break; - case '=': - spec.align_ = ALIGN_NUMERIC; - break; - case '^': - spec.align_ = ALIGN_CENTER; - break; - } - if (spec.align_ != ALIGN_DEFAULT) { - if (p != s) { - if (c == '}') break; - if (c == '{') - FMT_THROW(FormatError("invalid fill character '{'")); - s += 2; - spec.fill_ = c; - } else ++s; - if (spec.align_ == ALIGN_NUMERIC) - require_numeric_argument(arg, '='); - break; - } - } while (--p >= s); - } - - // Parse sign. - switch (*s) { - case '+': - check_sign(s, arg); - spec.flags_ |= SIGN_FLAG | PLUS_FLAG; - break; - case '-': - check_sign(s, arg); - spec.flags_ |= MINUS_FLAG; - break; - case ' ': - check_sign(s, arg); - spec.flags_ |= SIGN_FLAG; - break; - } - - if (*s == '#') { - require_numeric_argument(arg, '#'); - spec.flags_ |= HASH_FLAG; - ++s; - } - - // Parse zero flag. - if (*s == '0') { - require_numeric_argument(arg, '0'); - spec.align_ = ALIGN_NUMERIC; - spec.fill_ = '0'; - ++s; - } - - // Parse width. - if ('0' <= *s && *s <= '9') { - spec.width_ = internal::parse_nonnegative_int(s); - } else if (*s == '{') { - ++s; - Arg width_arg = internal::is_name_start(*s) ? - parse_arg_name(s) : parse_arg_index(s); - if (*s++ != '}') - FMT_THROW(FormatError("invalid format string")); - ULongLong value = 0; - switch (width_arg.type) { - case Arg::INT: - if (width_arg.int_value < 0) - FMT_THROW(FormatError("negative width")); - value = width_arg.int_value; - break; - case Arg::UINT: - value = width_arg.uint_value; - break; - case Arg::LONG_LONG: - if (width_arg.long_long_value < 0) - FMT_THROW(FormatError("negative width")); - value = width_arg.long_long_value; - break; - case Arg::ULONG_LONG: - value = width_arg.ulong_long_value; - break; - default: - FMT_THROW(FormatError("width is not integer")); - } - unsigned max_int = (std::numeric_limits::max)(); - if (value > max_int) - FMT_THROW(FormatError("number is too big")); - spec.width_ = static_cast(value); - } - - // Parse precision. - if (*s == '.') { - ++s; - spec.precision_ = 0; - if ('0' <= *s && *s <= '9') { - spec.precision_ = internal::parse_nonnegative_int(s); - } else if (*s == '{') { - ++s; - Arg precision_arg = internal::is_name_start(*s) ? - parse_arg_name(s) : parse_arg_index(s); - if (*s++ != '}') - FMT_THROW(FormatError("invalid format string")); - ULongLong value = 0; - switch (precision_arg.type) { - case Arg::INT: - if (precision_arg.int_value < 0) - FMT_THROW(FormatError("negative precision")); - value = precision_arg.int_value; - break; - case Arg::UINT: - value = precision_arg.uint_value; - break; - case Arg::LONG_LONG: - if (precision_arg.long_long_value < 0) - FMT_THROW(FormatError("negative precision")); - value = precision_arg.long_long_value; - break; - case Arg::ULONG_LONG: - value = precision_arg.ulong_long_value; - break; - default: - FMT_THROW(FormatError("precision is not integer")); - } - unsigned max_int = (std::numeric_limits::max)(); - if (value > max_int) - FMT_THROW(FormatError("number is too big")); - spec.precision_ = static_cast(value); - } else { - FMT_THROW(FormatError("missing precision specifier")); - } - if (arg.type <= Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) { - FMT_THROW(FormatError( - fmt::format("precision not allowed in {} format specifier", - arg.type == Arg::POINTER ? "pointer" : "integer"))); - } - } - - // Parse type. - if (*s != '}' && *s) - spec.type_ = static_cast(*s++); - } - - if (*s++ != '}') - FMT_THROW(FormatError("missing '}' in format string")); - - // Format argument. - ArgFormatter(*this, spec, s - 1).visit(arg); - return s; -} - -template -void BasicFormatter::format(BasicCStringRef format_str) { - const Char *s = format_str.c_str(); - const Char *start = s; - while (*s) { - Char c = *s++; - if (c != '{' && c != '}') continue; - if (*s == c) { - write(writer_, start, s); - start = ++s; - continue; - } - if (c == '}') - FMT_THROW(FormatError("unmatched '}' in format string")); - write(writer_, start, s - 1); - internal::Arg arg = internal::is_name_start(*s) ? - parse_arg_name(s) : parse_arg_index(s); - start = s = format(s, arg); - } - write(writer_, start, s); -} - -template -struct ArgJoin { - It first; - It last; - BasicCStringRef sep; - - ArgJoin(It first, It last, const BasicCStringRef& sep) : - first(first), - last(last), - sep(sep) {} -}; - -template -ArgJoin join(It first, It last, const BasicCStringRef& sep) { - return ArgJoin(first, last, sep); -} - -template -ArgJoin join(It first, It last, const BasicCStringRef& sep) { - return ArgJoin(first, last, sep); -} - -#if FMT_HAS_GXX_CXX11 -template -auto join(const Range& range, const BasicCStringRef& sep) - -> ArgJoin { - return join(std::begin(range), std::end(range), sep); -} - -template -auto join(const Range& range, const BasicCStringRef& sep) - -> ArgJoin { - return join(std::begin(range), std::end(range), sep); -} -#endif - -template -void format_arg(fmt::BasicFormatter &f, - const Char *&format_str, const ArgJoin& e) { - const Char* end = format_str; - if (*end == ':') - ++end; - while (*end && *end != '}') - ++end; - if (*end != '}') - FMT_THROW(FormatError("missing '}' in format string")); - - It it = e.first; - if (it != e.last) { - const Char* save = format_str; - f.format(format_str, internal::MakeArg >(*it++)); - while (it != e.last) { - f.writer().write(e.sep); - format_str = save; - f.format(format_str, internal::MakeArg >(*it++)); - } - } - format_str = end + 1; -} -} // namespace fmt - -#if FMT_USE_USER_DEFINED_LITERALS -namespace fmt { -namespace internal { - -template -struct UdlFormat { - const Char *str; - - template - auto operator()(Args && ... args) const - -> decltype(format(str, std::forward(args)...)) { - return format(str, std::forward(args)...); - } -}; - -template -struct UdlArg { - const Char *str; - - template - NamedArgWithType operator=(T &&value) const { - return {str, std::forward(value)}; - } -}; - -} // namespace internal - -inline namespace literals { - -/** - \rst - C++11 literal equivalent of :func:`fmt::format`. - - **Example**:: - - using namespace fmt::literals; - std::string message = "The answer is {}"_format(42); - \endrst - */ -inline internal::UdlFormat -operator"" _format(const char *s, std::size_t) { return {s}; } -inline internal::UdlFormat -operator"" _format(const wchar_t *s, std::size_t) { return {s}; } - -/** - \rst - C++11 literal equivalent of :func:`fmt::arg`. - - **Example**:: - - using namespace fmt::literals; - print("Elapsed time: {s:.2f} seconds", "s"_a=1.23); - \endrst - */ -inline internal::UdlArg -operator"" _a(const char *s, std::size_t) { return {s}; } -inline internal::UdlArg -operator"" _a(const wchar_t *s, std::size_t) { return {s}; } - -} // inline namespace literals -} // namespace fmt -#endif // FMT_USE_USER_DEFINED_LITERALS - -// Restore warnings. -#if FMT_GCC_VERSION >= 406 -# pragma GCC diagnostic pop -#endif - -#if defined(__clang__) && !defined(FMT_ICC_VERSION) -# pragma clang diagnostic pop -#endif - -#ifdef FMT_HEADER_ONLY -# define FMT_FUNC inline -# include "format.cc" -#else -# define FMT_FUNC -#endif - -#endif // FMT_FORMAT_H_ diff --git a/fmt/ostream.cc b/fmt/ostream.cc deleted file mode 100644 index 2d443f73..00000000 --- a/fmt/ostream.cc +++ /dev/null @@ -1,35 +0,0 @@ -/* - Formatting library for C++ - std::ostream support - - Copyright (c) 2012 - 2016, Victor Zverovich - All rights reserved. - - For the license information refer to format.h. - */ - -#include "ostream.h" - -namespace fmt { - -namespace internal { -FMT_FUNC void write(std::ostream &os, Writer &w) { - const char *data = w.data(); - typedef internal::MakeUnsigned::Type UnsignedStreamSize; - UnsignedStreamSize size = w.size(); - UnsignedStreamSize max_size = - internal::to_unsigned((std::numeric_limits::max)()); - do { - UnsignedStreamSize n = size <= max_size ? size : max_size; - os.write(data, static_cast(n)); - data += n; - size -= n; - } while (size != 0); -} -} - -FMT_FUNC void print(std::ostream &os, CStringRef format_str, ArgList args) { - MemoryWriter w; - w.write(format_str, args); - internal::write(os, w); -} -} // namespace fmt diff --git a/fmt/ostream.h b/fmt/ostream.h deleted file mode 100644 index 6848aac2..00000000 --- a/fmt/ostream.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - Formatting library for C++ - std::ostream support - - Copyright (c) 2012 - 2016, Victor Zverovich - All rights reserved. - - For the license information refer to format.h. - */ - -#ifndef FMT_OSTREAM_H_ -#define FMT_OSTREAM_H_ - -#include "format.h" -#include - -namespace fmt { - -namespace internal { - -template -class FormatBuf : public std::basic_streambuf { - private: - typedef typename std::basic_streambuf::int_type int_type; - typedef typename std::basic_streambuf::traits_type traits_type; - - Buffer &buffer_; - - public: - FormatBuf(Buffer &buffer) : buffer_(buffer) {} - - protected: - // The put-area is actually always empty. This makes the implementation - // simpler and has the advantage that the streambuf and the buffer are always - // in sync and sputc never writes into uninitialized memory. The obvious - // disadvantage is that each call to sputc always results in a (virtual) call - // to overflow. There is no disadvantage here for sputn since this always - // results in a call to xsputn. - - int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE { - if (!traits_type::eq_int_type(ch, traits_type::eof())) - buffer_.push_back(static_cast(ch)); - return ch; - } - - std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE { - buffer_.append(s, s + count); - return count; - } -}; - -Yes &convert(std::ostream &); - -struct DummyStream : std::ostream { - DummyStream(); // Suppress a bogus warning in MSVC. - - // Hide all operator<< overloads from std::ostream. - template - typename EnableIf::type operator<<(const T &); -}; - -No &operator<<(std::ostream &, int); - -template -struct ConvertToIntImpl { - // Convert to int only if T doesn't have an overloaded operator<<. - enum { - value = sizeof(convert(get() << get())) == sizeof(No) - }; -}; - -// Write the content of w to os. -FMT_API void write(std::ostream &os, Writer &w); -} // namespace internal - -// Formats a value. -template -void format_arg(BasicFormatter &f, - const Char *&format_str, const T &value) { - internal::MemoryBuffer buffer; - - internal::FormatBuf format_buf(buffer); - std::basic_ostream output(&format_buf); - output.exceptions(std::ios_base::failbit | std::ios_base::badbit); - output << value; - - BasicStringRef str(&buffer[0], buffer.size()); - typedef internal::MakeArg< BasicFormatter > MakeArg; - format_str = f.format(format_str, MakeArg(str)); -} - -/** - \rst - Prints formatted data to the stream *os*. - - **Example**:: - - print(cerr, "Don't {}!", "panic"); - \endrst - */ -FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args); -FMT_VARIADIC(void, print, std::ostream &, CStringRef) -} // namespace fmt - -#ifdef FMT_HEADER_ONLY -# include "ostream.cc" -#endif - -#endif // FMT_OSTREAM_H_ diff --git a/fmt/printf.cc b/fmt/printf.cc deleted file mode 100644 index 95d7a36a..00000000 --- a/fmt/printf.cc +++ /dev/null @@ -1,32 +0,0 @@ -/* - Formatting library for C++ - - Copyright (c) 2012 - 2016, Victor Zverovich - All rights reserved. - - For the license information refer to format.h. - */ - -#include "format.h" -#include "printf.h" - -namespace fmt { - -template -void printf(BasicWriter &w, BasicCStringRef format, ArgList args); - -FMT_FUNC int fprintf(std::FILE *f, CStringRef format, ArgList args) { - MemoryWriter w; - printf(w, format, args); - std::size_t size = w.size(); - return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast(size); -} - -#ifndef FMT_HEADER_ONLY - -template void PrintfFormatter::format(CStringRef format); -template void PrintfFormatter::format(WCStringRef format); - -#endif // FMT_HEADER_ONLY - -} // namespace fmt diff --git a/fmt/printf.h b/fmt/printf.h deleted file mode 100644 index 46205a78..00000000 --- a/fmt/printf.h +++ /dev/null @@ -1,603 +0,0 @@ -/* - Formatting library for C++ - - Copyright (c) 2012 - 2016, Victor Zverovich - All rights reserved. - - For the license information refer to format.h. - */ - -#ifndef FMT_PRINTF_H_ -#define FMT_PRINTF_H_ - -#include // std::fill_n -#include // std::numeric_limits - -#include "ostream.h" - -namespace fmt { -namespace internal { - -// Checks if a value fits in int - used to avoid warnings about comparing -// signed and unsigned integers. -template -struct IntChecker { - template - static bool fits_in_int(T value) { - unsigned max = std::numeric_limits::max(); - return value <= max; - } - static bool fits_in_int(bool) { return true; } -}; - -template <> -struct IntChecker { - template - static bool fits_in_int(T value) { - return value >= std::numeric_limits::min() && - value <= std::numeric_limits::max(); - } - static bool fits_in_int(int) { return true; } -}; - -class PrecisionHandler : public ArgVisitor { - public: - void report_unhandled_arg() { - FMT_THROW(FormatError("precision is not integer")); - } - - template - int visit_any_int(T value) { - if (!IntChecker::is_signed>::fits_in_int(value)) - FMT_THROW(FormatError("number is too big")); - return static_cast(value); - } -}; - -// IsZeroInt::visit(arg) returns true iff arg is a zero integer. -class IsZeroInt : public ArgVisitor { - public: - template - bool visit_any_int(T value) { return value == 0; } -}; - -// returns the default type for format specific "%s" -class DefaultType : public ArgVisitor { - public: - char visit_char(int) { return 'c'; } - - char visit_bool(bool) { return 's'; } - - char visit_pointer(const void *) { return 'p'; } - - template - char visit_any_int(T) { return 'd'; } - - template - char visit_any_double(T) { return 'g'; } - - char visit_unhandled_arg() { return 's'; } -}; - -template -struct is_same { - enum { value = 0 }; -}; - -template -struct is_same { - enum { value = 1 }; -}; - -// An argument visitor that converts an integer argument to T for printf, -// if T is an integral type. If T is void, the argument is converted to -// corresponding signed or unsigned type depending on the type specifier: -// 'd' and 'i' - signed, other - unsigned) -template -class ArgConverter : public ArgVisitor, void> { - private: - internal::Arg &arg_; - wchar_t type_; - - FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter); - - public: - ArgConverter(internal::Arg &arg, wchar_t type) - : arg_(arg), type_(type) {} - - void visit_bool(bool value) { - if (type_ != 's') - visit_any_int(value); - } - - void visit_char(int value) { - if (type_ != 's') - visit_any_int(value); - } - - template - void visit_any_int(U value) { - bool is_signed = type_ == 'd' || type_ == 'i'; - if (type_ == 's') { - is_signed = std::numeric_limits::is_signed; - } - - using internal::Arg; - typedef typename internal::Conditional< - is_same::value, U, T>::type TargetType; - if (const_check(sizeof(TargetType) <= sizeof(int))) { - // Extra casts are used to silence warnings. - if (is_signed) { - arg_.type = Arg::INT; - arg_.int_value = static_cast(static_cast(value)); - } else { - arg_.type = Arg::UINT; - typedef typename internal::MakeUnsigned::Type Unsigned; - arg_.uint_value = static_cast(static_cast(value)); - } - } else { - if (is_signed) { - arg_.type = Arg::LONG_LONG; - // glibc's printf doesn't sign extend arguments of smaller types: - // std::printf("%lld", -42); // prints "4294967254" - // but we don't have to do the same because it's a UB. - arg_.long_long_value = static_cast(value); - } else { - arg_.type = Arg::ULONG_LONG; - arg_.ulong_long_value = - static_cast::Type>(value); - } - } - } -}; - -// Converts an integer argument to char for printf. -class CharConverter : public ArgVisitor { - private: - internal::Arg &arg_; - - FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter); - - public: - explicit CharConverter(internal::Arg &arg) : arg_(arg) {} - - template - void visit_any_int(T value) { - arg_.type = internal::Arg::CHAR; - arg_.int_value = static_cast(value); - } -}; - -// Checks if an argument is a valid printf width specifier and sets -// left alignment if it is negative. -class WidthHandler : public ArgVisitor { - private: - FormatSpec &spec_; - - FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler); - - public: - explicit WidthHandler(FormatSpec &spec) : spec_(spec) {} - - void report_unhandled_arg() { - FMT_THROW(FormatError("width is not integer")); - } - - template - unsigned visit_any_int(T value) { - typedef typename internal::IntTraits::MainType UnsignedType; - UnsignedType width = static_cast(value); - if (internal::is_negative(value)) { - spec_.align_ = ALIGN_LEFT; - width = 0 - width; - } - unsigned int_max = std::numeric_limits::max(); - if (width > int_max) - FMT_THROW(FormatError("number is too big")); - return static_cast(width); - } -}; -} // namespace internal - -/** - \rst - A ``printf`` argument formatter based on the `curiously recurring template - pattern `_. - - To use `~fmt::BasicPrintfArgFormatter` define a subclass that implements some - or all of the visit methods with the same signatures as the methods in - `~fmt::ArgVisitor`, for example, `~fmt::ArgVisitor::visit_int()`. - Pass the subclass as the *Impl* template parameter. When a formatting - function processes an argument, it will dispatch to a visit method - specific to the argument type. For example, if the argument type is - ``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass - will be called. If the subclass doesn't contain a method with this signature, - then a corresponding method of `~fmt::BasicPrintfArgFormatter` or its - superclass will be called. - \endrst - */ -template -class BasicPrintfArgFormatter : - public internal::ArgFormatterBase { - private: - void write_null_pointer() { - this->spec().type_ = 0; - this->write("(nil)"); - } - - typedef internal::ArgFormatterBase Base; - - public: - /** - \rst - Constructs an argument formatter object. - *writer* is a reference to the output writer and *spec* contains format - specifier information for standard argument types. - \endrst - */ - BasicPrintfArgFormatter(BasicWriter &w, Spec &s) - : internal::ArgFormatterBase(w, s) {} - - /** Formats an argument of type ``bool``. */ - void visit_bool(bool value) { - Spec &fmt_spec = this->spec(); - if (fmt_spec.type_ != 's') - return this->visit_any_int(value); - fmt_spec.type_ = 0; - this->write(value); - } - - /** Formats a character. */ - void visit_char(int value) { - const Spec &fmt_spec = this->spec(); - BasicWriter &w = this->writer(); - if (fmt_spec.type_ && fmt_spec.type_ != 'c') - w.write_int(value, fmt_spec); - typedef typename BasicWriter::CharPtr CharPtr; - CharPtr out = CharPtr(); - if (fmt_spec.width_ > 1) { - Char fill = ' '; - out = w.grow_buffer(fmt_spec.width_); - if (fmt_spec.align_ != ALIGN_LEFT) { - std::fill_n(out, fmt_spec.width_ - 1, fill); - out += fmt_spec.width_ - 1; - } else { - std::fill_n(out + 1, fmt_spec.width_ - 1, fill); - } - } else { - out = w.grow_buffer(1); - } - *out = static_cast(value); - } - - /** Formats a null-terminated C string. */ - void visit_cstring(const char *value) { - if (value) - Base::visit_cstring(value); - else if (this->spec().type_ == 'p') - write_null_pointer(); - else - this->write("(null)"); - } - - /** Formats a pointer. */ - void visit_pointer(const void *value) { - if (value) - return Base::visit_pointer(value); - this->spec().type_ = 0; - write_null_pointer(); - } - - /** Formats an argument of a custom (user-defined) type. */ - void visit_custom(internal::Arg::CustomValue c) { - BasicFormatter formatter(ArgList(), this->writer()); - const Char format_str[] = {'}', 0}; - const Char *format = format_str; - c.format(&formatter, c.value, &format); - } -}; - -/** The default printf argument formatter. */ -template -class PrintfArgFormatter : - public BasicPrintfArgFormatter, Char, FormatSpec> { - public: - /** Constructs an argument formatter object. */ - PrintfArgFormatter(BasicWriter &w, FormatSpec &s) - : BasicPrintfArgFormatter, Char, FormatSpec>(w, s) {} -}; - -/** This template formats data and writes the output to a writer. */ -template > -class PrintfFormatter : private internal::FormatterBase { - private: - BasicWriter &writer_; - - void parse_flags(FormatSpec &spec, const Char *&s); - - // Returns the argument with specified index or, if arg_index is equal - // to the maximum unsigned value, the next argument. - internal::Arg get_arg( - const Char *s, - unsigned arg_index = (std::numeric_limits::max)()); - - // Parses argument index, flags and width and returns the argument index. - unsigned parse_header(const Char *&s, FormatSpec &spec); - - public: - /** - \rst - Constructs a ``PrintfFormatter`` object. References to the arguments and - the writer are stored in the formatter object so make sure they have - appropriate lifetimes. - \endrst - */ - explicit PrintfFormatter(const ArgList &al, BasicWriter &w) - : FormatterBase(al), writer_(w) {} - - /** Formats stored arguments and writes the output to the writer. */ - void format(BasicCStringRef format_str); -}; - -template -void PrintfFormatter::parse_flags(FormatSpec &spec, const Char *&s) { - for (;;) { - switch (*s++) { - case '-': - spec.align_ = ALIGN_LEFT; - break; - case '+': - spec.flags_ |= SIGN_FLAG | PLUS_FLAG; - break; - case '0': - spec.fill_ = '0'; - break; - case ' ': - spec.flags_ |= SIGN_FLAG; - break; - case '#': - spec.flags_ |= HASH_FLAG; - break; - default: - --s; - return; - } - } -} - -template -internal::Arg PrintfFormatter::get_arg(const Char *s, - unsigned arg_index) { - (void)s; - const char *error = FMT_NULL; - internal::Arg arg = arg_index == std::numeric_limits::max() ? - next_arg(error) : FormatterBase::get_arg(arg_index - 1, error); - if (error) - FMT_THROW(FormatError(!*s ? "invalid format string" : error)); - return arg; -} - -template -unsigned PrintfFormatter::parse_header( - const Char *&s, FormatSpec &spec) { - unsigned arg_index = std::numeric_limits::max(); - Char c = *s; - if (c >= '0' && c <= '9') { - // Parse an argument index (if followed by '$') or a width possibly - // preceded with '0' flag(s). - unsigned value = internal::parse_nonnegative_int(s); - if (*s == '$') { // value is an argument index - ++s; - arg_index = value; - } else { - if (c == '0') - spec.fill_ = '0'; - if (value != 0) { - // Nonzero value means that we parsed width and don't need to - // parse it or flags again, so return now. - spec.width_ = value; - return arg_index; - } - } - } - parse_flags(spec, s); - // Parse width. - if (*s >= '0' && *s <= '9') { - spec.width_ = internal::parse_nonnegative_int(s); - } else if (*s == '*') { - ++s; - spec.width_ = internal::WidthHandler(spec).visit(get_arg(s)); - } - return arg_index; -} - -template -void PrintfFormatter::format(BasicCStringRef format_str) { - const Char *start = format_str.c_str(); - const Char *s = start; - while (*s) { - Char c = *s++; - if (c != '%') continue; - if (*s == c) { - write(writer_, start, s); - start = ++s; - continue; - } - write(writer_, start, s - 1); - - FormatSpec spec; - spec.align_ = ALIGN_RIGHT; - - // Parse argument index, flags and width. - unsigned arg_index = parse_header(s, spec); - - // Parse precision. - if (*s == '.') { - ++s; - if ('0' <= *s && *s <= '9') { - spec.precision_ = static_cast(internal::parse_nonnegative_int(s)); - } else if (*s == '*') { - ++s; - spec.precision_ = internal::PrecisionHandler().visit(get_arg(s)); - } else { - spec.precision_ = 0; - } - } - - using internal::Arg; - Arg arg = get_arg(s, arg_index); - if (spec.flag(HASH_FLAG) && internal::IsZeroInt().visit(arg)) - spec.flags_ &= ~internal::to_unsigned(HASH_FLAG); - if (spec.fill_ == '0') { - if (arg.type <= Arg::LAST_NUMERIC_TYPE) - spec.align_ = ALIGN_NUMERIC; - else - spec.fill_ = ' '; // Ignore '0' flag for non-numeric types. - } - - // Parse length and convert the argument to the required type. - using internal::ArgConverter; - switch (*s++) { - case 'h': - if (*s == 'h') - ArgConverter(arg, *++s).visit(arg); - else - ArgConverter(arg, *s).visit(arg); - break; - case 'l': - if (*s == 'l') - ArgConverter(arg, *++s).visit(arg); - else - ArgConverter(arg, *s).visit(arg); - break; - case 'j': - ArgConverter(arg, *s).visit(arg); - break; - case 'z': - ArgConverter(arg, *s).visit(arg); - break; - case 't': - ArgConverter(arg, *s).visit(arg); - break; - case 'L': - // printf produces garbage when 'L' is omitted for long double, no - // need to do the same. - break; - default: - --s; - ArgConverter(arg, *s).visit(arg); - } - - // Parse type. - if (!*s) - FMT_THROW(FormatError("invalid format string")); - spec.type_ = static_cast(*s++); - - if (spec.type_ == 's') { - // set the format type to the default if 's' is specified - spec.type_ = internal::DefaultType().visit(arg); - } - - if (arg.type <= Arg::LAST_INTEGER_TYPE) { - // Normalize type. - switch (spec.type_) { - case 'i': case 'u': - spec.type_ = 'd'; - break; - case 'c': - // TODO: handle wchar_t - internal::CharConverter(arg).visit(arg); - break; - } - } - - start = s; - - // Format argument. - AF(writer_, spec).visit(arg); - } - write(writer_, start, s); -} - -inline void printf(Writer &w, CStringRef format, ArgList args) { - PrintfFormatter(args, w).format(format); -} -FMT_VARIADIC(void, printf, Writer &, CStringRef) - -inline void printf(WWriter &w, WCStringRef format, ArgList args) { - PrintfFormatter(args, w).format(format); -} -FMT_VARIADIC(void, printf, WWriter &, WCStringRef) - -/** - \rst - Formats arguments and returns the result as a string. - - **Example**:: - - std::string message = fmt::sprintf("The answer is %d", 42); - \endrst -*/ -inline std::string sprintf(CStringRef format, ArgList args) { - MemoryWriter w; - printf(w, format, args); - return w.str(); -} -FMT_VARIADIC(std::string, sprintf, CStringRef) - -inline std::wstring sprintf(WCStringRef format, ArgList args) { - WMemoryWriter w; - printf(w, format, args); - return w.str(); -} -FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef) - -/** - \rst - Prints formatted data to the file *f*. - - **Example**:: - - fmt::fprintf(stderr, "Don't %s!", "panic"); - \endrst - */ -FMT_API int fprintf(std::FILE *f, CStringRef format, ArgList args); -FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef) - -/** - \rst - Prints formatted data to ``stdout``. - - **Example**:: - - fmt::printf("Elapsed time: %.2f seconds", 1.23); - \endrst - */ -inline int printf(CStringRef format, ArgList args) { - return fprintf(stdout, format, args); -} -FMT_VARIADIC(int, printf, CStringRef) - -/** - \rst - Prints formatted data to the stream *os*. - - **Example**:: - - fprintf(cerr, "Don't %s!", "panic"); - \endrst - */ -inline int fprintf(std::ostream &os, CStringRef format_str, ArgList args) { - MemoryWriter w; - printf(w, format_str, args); - internal::write(os, w); - return static_cast(w.size()); -} -FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef) -} // namespace fmt - -#ifdef FMT_HEADER_ONLY -# include "printf.cc" -#endif - -#endif // FMT_PRINTF_H_ diff --git a/fmt/string.h b/fmt/string.h deleted file mode 100644 index 05996eb5..00000000 --- a/fmt/string.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - Formatting library for C++ - string utilities - - Copyright (c) 2012 - 2016, Victor Zverovich - All rights reserved. - - For the license information refer to format.h. - */ - -#ifdef FMT_INCLUDE -# error "Add the fmt's parent directory and not fmt itself to includes." -#endif - -#ifndef FMT_STRING_H_ -#define FMT_STRING_H_ - -#include "format.h" - -namespace fmt { - -namespace internal { - -// A buffer that stores data in ``std::basic_string``. -template > -class StringBuffer : public Buffer { - public: - typedef std::basic_string, Allocator> StringType; - - private: - StringType data_; - - protected: - virtual void grow(std::size_t size) FMT_OVERRIDE { - data_.resize(size); - this->ptr_ = &data_[0]; - this->capacity_ = size; - } - - public: - explicit StringBuffer(const Allocator &allocator = Allocator()) - : data_(allocator) {} - - // Moves the data to ``str`` clearing the buffer. - void move_to(StringType &str) { - data_.resize(this->size_); - str.swap(data_); - this->capacity_ = this->size_ = 0; - this->ptr_ = FMT_NULL; - } -}; -} // namespace internal - -/** - \rst - This class template provides operations for formatting and writing data - into a character stream. The output is stored in a ``std::basic_string`` - that grows dynamically. - - You can use one of the following typedefs for common character types - and the standard allocator: - - +---------------+----------------------------+ - | Type | Definition | - +===============+============================+ - | StringWriter | BasicStringWriter | - +---------------+----------------------------+ - | WStringWriter | BasicStringWriter | - +---------------+----------------------------+ - - **Example**:: - - StringWriter out; - out << "The answer is " << 42 << "\n"; - - This will write the following output to the ``out`` object: - - .. code-block:: none - - The answer is 42 - - The output can be moved to a ``std::basic_string`` with ``out.move_to()``. - \endrst - */ -template > -class BasicStringWriter : public BasicWriter { - private: - internal::StringBuffer buffer_; - - public: - /** - \rst - Constructs a :class:`fmt::BasicStringWriter` object. - \endrst - */ - explicit BasicStringWriter(const Allocator &allocator = Allocator()) - : BasicWriter(buffer_), buffer_(allocator) {} - - /** - \rst - Moves the buffer content to *str* clearing the buffer. - \endrst - */ - void move_to(std::basic_string, Allocator> &str) { - buffer_.move_to(str); - } -}; - -typedef BasicStringWriter StringWriter; -typedef BasicStringWriter WStringWriter; - -/** - \rst - Converts *value* to ``std::string`` using the default format for type *T*. - - **Example**:: - - #include "fmt/string.h" - - std::string answer = fmt::to_string(42); - \endrst - */ -template -std::string to_string(const T &value) { - fmt::MemoryWriter w; - w << value; - return w.str(); -} - -/** - \rst - Converts *value* to ``std::wstring`` using the default format for type *T*. - - **Example**:: - - #include "fmt/string.h" - - std::wstring answer = fmt::to_wstring(42); - \endrst - */ -template -std::wstring to_wstring(const T &value) { - fmt::WMemoryWriter w; - w << value; - return w.str(); -} -} - -#endif // FMT_STRING_H_ diff --git a/fmt/time.h b/fmt/time.h deleted file mode 100644 index c98b0e01..00000000 --- a/fmt/time.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - Formatting library for C++ - time formatting - - Copyright (c) 2012 - 2016, Victor Zverovich - All rights reserved. - - For the license information refer to format.h. - */ - -#ifndef FMT_TIME_H_ -#define FMT_TIME_H_ - -#include "format.h" -#include - -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4702) // unreachable code -# pragma warning(disable: 4996) // "deprecated" functions -#endif - -namespace fmt { -template -void format_arg(BasicFormatter &f, - const char *&format_str, const std::tm &tm) { - if (*format_str == ':') - ++format_str; - const char *end = format_str; - while (*end && *end != '}') - ++end; - if (*end != '}') - FMT_THROW(FormatError("missing '}' in format string")); - internal::MemoryBuffer format; - format.append(format_str, end + 1); - format[format.size() - 1] = '\0'; - Buffer &buffer = f.writer().buffer(); - std::size_t start = buffer.size(); - for (;;) { - std::size_t size = buffer.capacity() - start; - std::size_t count = std::strftime(&buffer[start], size, &format[0], &tm); - if (count != 0) { - buffer.resize(start + count); - break; - } - if (size >= format.size() * 256) { - // If the buffer is 256 times larger than the format string, assume - // that `strftime` gives an empty result. There doesn't seem to be a - // better way to distinguish the two cases: - // https://github.com/fmtlib/fmt/issues/367 - break; - } - const std::size_t MIN_GROWTH = 10; - buffer.reserve(buffer.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH)); - } - format_str = end + 1; -} - -namespace internal{ -inline Null<> localtime_r(...) { return Null<>(); } -inline Null<> localtime_s(...) { return Null<>(); } -inline Null<> gmtime_r(...) { return Null<>(); } -inline Null<> gmtime_s(...) { return Null<>(); } -} - -// Thread-safe replacement for std::localtime -inline std::tm localtime(std::time_t time) { - struct LocalTime { - std::time_t time_; - std::tm tm_; - - LocalTime(std::time_t t): time_(t) {} - - bool run() { - using namespace fmt::internal; - return handle(localtime_r(&time_, &tm_)); - } - - bool handle(std::tm *tm) { return tm != FMT_NULL; } - - bool handle(internal::Null<>) { - using namespace fmt::internal; - return fallback(localtime_s(&tm_, &time_)); - } - - bool fallback(int res) { return res == 0; } - - bool fallback(internal::Null<>) { - using namespace fmt::internal; - std::tm *tm = std::localtime(&time_); - if (tm) tm_ = *tm; - return tm != FMT_NULL; - } - }; - LocalTime lt(time); - if (lt.run()) - return lt.tm_; - // Too big time values may be unsupported. - FMT_THROW(fmt::FormatError("time_t value out of range")); - return std::tm(); -} - -// Thread-safe replacement for std::gmtime -inline std::tm gmtime(std::time_t time) { - struct GMTime { - std::time_t time_; - std::tm tm_; - - GMTime(std::time_t t): time_(t) {} - - bool run() { - using namespace fmt::internal; - return handle(gmtime_r(&time_, &tm_)); - } - - bool handle(std::tm *tm) { return tm != FMT_NULL; } - - bool handle(internal::Null<>) { - using namespace fmt::internal; - return fallback(gmtime_s(&tm_, &time_)); - } - - bool fallback(int res) { return res == 0; } - - bool fallback(internal::Null<>) { - std::tm *tm = std::gmtime(&time_); - if (tm != FMT_NULL) tm_ = *tm; - return tm != FMT_NULL; - } - }; - GMTime gt(time); - if (gt.run()) - return gt.tm_; - // Too big time values may be unsupported. - FMT_THROW(fmt::FormatError("time_t value out of range")); - return std::tm(); -} -} //namespace fmt - -#ifdef _MSC_VER -# pragma warning(pop) -#endif - -#endif // FMT_TIME_H_ diff --git a/include/fmt/color.h b/include/fmt/color.h new file mode 100644 index 00000000..4973976a --- /dev/null +++ b/include/fmt/color.h @@ -0,0 +1,278 @@ +// Formatting library for C++ - color support +// +// Copyright (c) 2018 - present, Victor Zverovich and fmt contributors +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_COLOR_H_ +#define FMT_COLOR_H_ + +#include "format.h" + +FMT_BEGIN_NAMESPACE + +#ifdef FMT_DEPRECATED_COLORS + +// color and (v)print_colored are deprecated. +enum color { black, red, green, yellow, blue, magenta, cyan, white }; +FMT_API void vprint_colored(color c, string_view format, format_args args); +FMT_API void vprint_colored(color c, wstring_view format, wformat_args args); +template +inline void print_colored(color c, string_view format_str, + const Args & ... args) { + vprint_colored(c, format_str, make_format_args(args...)); +} +template +inline void print_colored(color c, wstring_view format_str, + const Args & ... args) { + vprint_colored(c, format_str, make_format_args(args...)); +} + +inline void vprint_colored(color c, string_view format, format_args args) { + char escape[] = "\x1b[30m"; + escape[3] = static_cast('0' + c); + std::fputs(escape, stdout); + vprint(format, args); + std::fputs(internal::data::RESET_COLOR, stdout); +} + +inline void vprint_colored(color c, wstring_view format, wformat_args args) { + wchar_t escape[] = L"\x1b[30m"; + escape[3] = static_cast('0' + c); + std::fputws(escape, stdout); + vprint(format, args); + std::fputws(internal::data::WRESET_COLOR, stdout); +} + +#else + +// Experimental color support. +enum class color : uint32_t { + alice_blue = 0xF0F8FF, // rgb(240,248,255) + antique_white = 0xFAEBD7, // rgb(250,235,215) + aqua = 0x00FFFF, // rgb(0,255,255) + aquamarine = 0x7FFFD4, // rgb(127,255,212) + azure = 0xF0FFFF, // rgb(240,255,255) + beige = 0xF5F5DC, // rgb(245,245,220) + bisque = 0xFFE4C4, // rgb(255,228,196) + black = 0x000000, // rgb(0,0,0) + blanched_almond = 0xFFEBCD, // rgb(255,235,205) + blue = 0x0000FF, // rgb(0,0,255) + blue_violet = 0x8A2BE2, // rgb(138,43,226) + brown = 0xA52A2A, // rgb(165,42,42) + burly_wood = 0xDEB887, // rgb(222,184,135) + cadet_blue = 0x5F9EA0, // rgb(95,158,160) + chartreuse = 0x7FFF00, // rgb(127,255,0) + chocolate = 0xD2691E, // rgb(210,105,30) + coral = 0xFF7F50, // rgb(255,127,80) + cornflower_blue = 0x6495ED, // rgb(100,149,237) + cornsilk = 0xFFF8DC, // rgb(255,248,220) + crimson = 0xDC143C, // rgb(220,20,60) + cyan = 0x00FFFF, // rgb(0,255,255) + dark_blue = 0x00008B, // rgb(0,0,139) + dark_cyan = 0x008B8B, // rgb(0,139,139) + dark_golden_rod = 0xB8860B, // rgb(184,134,11) + dark_gray = 0xA9A9A9, // rgb(169,169,169) + dark_green = 0x006400, // rgb(0,100,0) + dark_khaki = 0xBDB76B, // rgb(189,183,107) + dark_magenta = 0x8B008B, // rgb(139,0,139) + dark_olive_green = 0x556B2F, // rgb(85,107,47) + dark_orange = 0xFF8C00, // rgb(255,140,0) + dark_orchid = 0x9932CC, // rgb(153,50,204) + dark_red = 0x8B0000, // rgb(139,0,0) + dark_salmon = 0xE9967A, // rgb(233,150,122) + dark_sea_green = 0x8FBC8F, // rgb(143,188,143) + dark_slate_blue = 0x483D8B, // rgb(72,61,139) + dark_slate_gray = 0x2F4F4F, // rgb(47,79,79) + dark_turquoise = 0x00CED1, // rgb(0,206,209) + dark_violet = 0x9400D3, // rgb(148,0,211) + deep_pink = 0xFF1493, // rgb(255,20,147) + deep_sky_blue = 0x00BFFF, // rgb(0,191,255) + dim_gray = 0x696969, // rgb(105,105,105) + dodger_blue = 0x1E90FF, // rgb(30,144,255) + fire_brick = 0xB22222, // rgb(178,34,34) + floral_white = 0xFFFAF0, // rgb(255,250,240) + forest_green = 0x228B22, // rgb(34,139,34) + fuchsia = 0xFF00FF, // rgb(255,0,255) + gainsboro = 0xDCDCDC, // rgb(220,220,220) + ghost_white = 0xF8F8FF, // rgb(248,248,255) + gold = 0xFFD700, // rgb(255,215,0) + golden_rod = 0xDAA520, // rgb(218,165,32) + gray = 0x808080, // rgb(128,128,128) + green = 0x008000, // rgb(0,128,0) + green_yellow = 0xADFF2F, // rgb(173,255,47) + honey_dew = 0xF0FFF0, // rgb(240,255,240) + hot_pink = 0xFF69B4, // rgb(255,105,180) + indian_red = 0xCD5C5C, // rgb(205,92,92) + indigo = 0x4B0082, // rgb(75,0,130) + ivory = 0xFFFFF0, // rgb(255,255,240) + khaki = 0xF0E68C, // rgb(240,230,140) + lavender = 0xE6E6FA, // rgb(230,230,250) + lavender_blush = 0xFFF0F5, // rgb(255,240,245) + lawn_green = 0x7CFC00, // rgb(124,252,0) + lemon_chiffon = 0xFFFACD, // rgb(255,250,205) + light_blue = 0xADD8E6, // rgb(173,216,230) + light_coral = 0xF08080, // rgb(240,128,128) + light_cyan = 0xE0FFFF, // rgb(224,255,255) + light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210) + light_gray = 0xD3D3D3, // rgb(211,211,211) + light_green = 0x90EE90, // rgb(144,238,144) + light_pink = 0xFFB6C1, // rgb(255,182,193) + light_salmon = 0xFFA07A, // rgb(255,160,122) + light_sea_green = 0x20B2AA, // rgb(32,178,170) + light_sky_blue = 0x87CEFA, // rgb(135,206,250) + light_slate_gray = 0x778899, // rgb(119,136,153) + light_steel_blue = 0xB0C4DE, // rgb(176,196,222) + light_yellow = 0xFFFFE0, // rgb(255,255,224) + lime = 0x00FF00, // rgb(0,255,0) + lime_green = 0x32CD32, // rgb(50,205,50) + linen = 0xFAF0E6, // rgb(250,240,230) + magenta = 0xFF00FF, // rgb(255,0,255) + maroon = 0x800000, // rgb(128,0,0) + medium_aquamarine = 0x66CDAA, // rgb(102,205,170) + medium_blue = 0x0000CD, // rgb(0,0,205) + medium_orchid = 0xBA55D3, // rgb(186,85,211) + medium_purple = 0x9370DB, // rgb(147,112,219) + medium_sea_green = 0x3CB371, // rgb(60,179,113) + medium_slate_blue = 0x7B68EE, // rgb(123,104,238) + medium_spring_green = 0x00FA9A, // rgb(0,250,154) + medium_turquoise = 0x48D1CC, // rgb(72,209,204) + medium_violet_red = 0xC71585, // rgb(199,21,133) + midnight_blue = 0x191970, // rgb(25,25,112) + mint_cream = 0xF5FFFA, // rgb(245,255,250) + misty_rose = 0xFFE4E1, // rgb(255,228,225) + moccasin = 0xFFE4B5, // rgb(255,228,181) + navajo_white = 0xFFDEAD, // rgb(255,222,173) + navy = 0x000080, // rgb(0,0,128) + old_lace = 0xFDF5E6, // rgb(253,245,230) + olive = 0x808000, // rgb(128,128,0) + olive_drab = 0x6B8E23, // rgb(107,142,35) + orange = 0xFFA500, // rgb(255,165,0) + orange_red = 0xFF4500, // rgb(255,69,0) + orchid = 0xDA70D6, // rgb(218,112,214) + pale_golden_rod = 0xEEE8AA, // rgb(238,232,170) + pale_green = 0x98FB98, // rgb(152,251,152) + pale_turquoise = 0xAFEEEE, // rgb(175,238,238) + pale_violet_red = 0xDB7093, // rgb(219,112,147) + papaya_whip = 0xFFEFD5, // rgb(255,239,213) + peach_puff = 0xFFDAB9, // rgb(255,218,185) + peru = 0xCD853F, // rgb(205,133,63) + pink = 0xFFC0CB, // rgb(255,192,203) + plum = 0xDDA0DD, // rgb(221,160,221) + powder_blue = 0xB0E0E6, // rgb(176,224,230) + purple = 0x800080, // rgb(128,0,128) + rebecca_purple = 0x663399, // rgb(102,51,153) + red = 0xFF0000, // rgb(255,0,0) + rosy_brown = 0xBC8F8F, // rgb(188,143,143) + royal_blue = 0x4169E1, // rgb(65,105,225) + saddle_brown = 0x8B4513, // rgb(139,69,19) + salmon = 0xFA8072, // rgb(250,128,114) + sandy_brown = 0xF4A460, // rgb(244,164,96) + sea_green = 0x2E8B57, // rgb(46,139,87) + sea_shell = 0xFFF5EE, // rgb(255,245,238) + sienna = 0xA0522D, // rgb(160,82,45) + silver = 0xC0C0C0, // rgb(192,192,192) + sky_blue = 0x87CEEB, // rgb(135,206,235) + slate_blue = 0x6A5ACD, // rgb(106,90,205) + slate_gray = 0x708090, // rgb(112,128,144) + snow = 0xFFFAFA, // rgb(255,250,250) + spring_green = 0x00FF7F, // rgb(0,255,127) + steel_blue = 0x4682B4, // rgb(70,130,180) + tan = 0xD2B48C, // rgb(210,180,140) + teal = 0x008080, // rgb(0,128,128) + thistle = 0xD8BFD8, // rgb(216,191,216) + tomato = 0xFF6347, // rgb(255,99,71) + turquoise = 0x40E0D0, // rgb(64,224,208) + violet = 0xEE82EE, // rgb(238,130,238) + wheat = 0xF5DEB3, // rgb(245,222,179) + white = 0xFFFFFF, // rgb(255,255,255) + white_smoke = 0xF5F5F5, // rgb(245,245,245) + yellow = 0xFFFF00, // rgb(255,255,0) + yellow_green = 0x9ACD32, // rgb(154,205,50) +}; // enum class color + +// rgb is a struct for red, green and blue colors. +// We use rgb as name because some editors will show it as color direct in the +// editor. +struct rgb { + FMT_CONSTEXPR_DECL rgb() : r(0), g(0), b(0) {} + FMT_CONSTEXPR_DECL rgb(uint8_t r_, uint8_t g_, uint8_t b_) + : r(r_), g(g_), b(b_) {} + FMT_CONSTEXPR_DECL rgb(uint32_t hex) + : r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b((hex) & 0xFF) {} + FMT_CONSTEXPR_DECL rgb(color hex) + : r((uint32_t(hex) >> 16) & 0xFF), g((uint32_t(hex) >> 8) & 0xFF), + b(uint32_t(hex) & 0xFF) {} + uint8_t r; + uint8_t g; + uint8_t b; +}; + +void vprint_rgb(rgb fd, string_view format, format_args args); +void vprint_rgb(rgb fd, rgb bg, string_view format, format_args args); + +/** + Formats a string and prints it to stdout using ANSI escape sequences to + specify foreground color 'fd'. + Example: + fmt::print(fmt::color::red, "Elapsed time: {0:.2f} seconds", 1.23); + */ +template +inline void print(rgb fd, string_view format_str, const Args & ... args) { + vprint_rgb(fd, format_str, make_format_args(args...)); +} + +/** + Formats a string and prints it to stdout using ANSI escape sequences to + specify foreground color 'fd' and background color 'bg'. + Example: + fmt::print(fmt::color::red, fmt::color::black, + "Elapsed time: {0:.2f} seconds", 1.23); + */ +template +inline void print(rgb fd, rgb bg, string_view format_str, + const Args & ... args) { + vprint_rgb(fd, bg, format_str, make_format_args(args...)); +} +namespace internal { +FMT_CONSTEXPR void to_esc(uint8_t c, char out[], int offset) { + out[offset + 0] = static_cast('0' + c / 100); + out[offset + 1] = static_cast('0' + c / 10 % 10); + out[offset + 2] = static_cast('0' + c % 10); +} +} // namespace internal + +inline void vprint_rgb(rgb fd, string_view format, format_args args) { + char escape_fd[] = "\x1b[38;2;000;000;000m"; + internal::to_esc(fd.r, escape_fd, 7); + internal::to_esc(fd.g, escape_fd, 11); + internal::to_esc(fd.b, escape_fd, 15); + + std::fputs(escape_fd, stdout); + vprint(format, args); + std::fputs(internal::data::RESET_COLOR, stdout); +} + +inline void vprint_rgb(rgb fd, rgb bg, string_view format, format_args args) { + char escape_fd[] = "\x1b[38;2;000;000;000m"; // foreground color + char escape_bg[] = "\x1b[48;2;000;000;000m"; // background color + internal::to_esc(fd.r, escape_fd, 7); + internal::to_esc(fd.g, escape_fd, 11); + internal::to_esc(fd.b, escape_fd, 15); + + internal::to_esc(bg.r, escape_bg, 7); + internal::to_esc(bg.g, escape_bg, 11); + internal::to_esc(bg.b, escape_bg, 15); + + std::fputs(escape_fd, stdout); + std::fputs(escape_bg, stdout); + vprint(format, args); + std::fputs(internal::data::RESET_COLOR, stdout); +} + +#endif + +FMT_END_NAMESPACE + +#endif // FMT_COLOR_H_ diff --git a/include/fmt/core.h b/include/fmt/core.h new file mode 100644 index 00000000..5912afef --- /dev/null +++ b/include/fmt/core.h @@ -0,0 +1,1502 @@ +// Formatting library for C++ - the core API +// +// Copyright (c) 2012 - present, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_CORE_H_ +#define FMT_CORE_H_ + +#include +#include // std::FILE +#include +#include +#include +#include + +// The fmt library version in the form major * 10000 + minor * 100 + patch. +#define FMT_VERSION 50201 + +#ifdef __has_feature +# define FMT_HAS_FEATURE(x) __has_feature(x) +#else +# define FMT_HAS_FEATURE(x) 0 +#endif + +#if defined(__has_include) && !defined(__INTELLISENSE__) && \ + (!defined(__INTEL_COMPILER) || __INTEL_COMPILER >= 1600) +# define FMT_HAS_INCLUDE(x) __has_include(x) +#else +# define FMT_HAS_INCLUDE(x) 0 +#endif + +#ifdef __has_cpp_attribute +# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#else +# define FMT_HAS_CPP_ATTRIBUTE(x) 0 +#endif + +#if defined(__GNUC__) && !defined(__clang__) +# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) +#else +# define FMT_GCC_VERSION 0 +#endif + +#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) +# define FMT_HAS_GXX_CXX11 FMT_GCC_VERSION +#else +# define FMT_HAS_GXX_CXX11 0 +#endif + +#ifdef _MSC_VER +# define FMT_MSC_VER _MSC_VER +#else +# define FMT_MSC_VER 0 +#endif + +// Check if relaxed C++14 constexpr is supported. +// GCC doesn't allow throw in constexpr until version 6 (bug 67371). +#ifndef FMT_USE_CONSTEXPR +# define FMT_USE_CONSTEXPR \ + (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VER >= 1910 || \ + (FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L)) +#endif +#if FMT_USE_CONSTEXPR +# define FMT_CONSTEXPR constexpr +# define FMT_CONSTEXPR_DECL constexpr +#else +# define FMT_CONSTEXPR inline +# define FMT_CONSTEXPR_DECL +#endif + +#ifndef FMT_USE_CONSTEXPR11 +# define FMT_USE_CONSTEXPR11 \ + (FMT_MSC_VER >= 1900 || FMT_GCC_VERSION >= 406 || FMT_USE_CONSTEXPR) +#endif +#if FMT_USE_CONSTEXPR11 +# define FMT_CONSTEXPR11 constexpr +#else +# define FMT_CONSTEXPR11 +#endif + +#ifndef FMT_OVERRIDE +# if FMT_HAS_FEATURE(cxx_override) || \ + (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900 +# define FMT_OVERRIDE override +# else +# define FMT_OVERRIDE +# endif +#endif + +#if FMT_HAS_FEATURE(cxx_explicit_conversions) || FMT_MSC_VER >= 1800 +# define FMT_EXPLICIT explicit +#else +# define FMT_EXPLICIT +#endif + +#ifndef FMT_NULL +# if FMT_HAS_FEATURE(cxx_nullptr) || \ + (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1600 +# define FMT_NULL nullptr +# define FMT_USE_NULLPTR 1 +# else +# define FMT_NULL NULL +# endif +#endif + +#ifndef FMT_USE_NULLPTR +# define FMT_USE_NULLPTR 0 +#endif + +#if FMT_HAS_CPP_ATTRIBUTE(noreturn) +# define FMT_NORETURN [[noreturn]] +#else +# define FMT_NORETURN +#endif + +// Check if exceptions are disabled. +#if defined(__GNUC__) && !defined(__EXCEPTIONS) +# define FMT_EXCEPTIONS 0 +#elif FMT_MSC_VER && !_HAS_EXCEPTIONS +# define FMT_EXCEPTIONS 0 +#endif +#ifndef FMT_EXCEPTIONS +# define FMT_EXCEPTIONS 1 +#endif + +// Define FMT_USE_NOEXCEPT to make fmt use noexcept (C++11 feature). +#ifndef FMT_USE_NOEXCEPT +# define FMT_USE_NOEXCEPT 0 +#endif + +#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ + (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900 +# define FMT_DETECTED_NOEXCEPT noexcept +# define FMT_HAS_CXX11_NOEXCEPT 1 +#else +# define FMT_DETECTED_NOEXCEPT throw() +# define FMT_HAS_CXX11_NOEXCEPT 0 +#endif + +#ifndef FMT_NOEXCEPT +# if FMT_EXCEPTIONS || FMT_HAS_CXX11_NOEXCEPT +# define FMT_NOEXCEPT FMT_DETECTED_NOEXCEPT +# else +# define FMT_NOEXCEPT +# endif +#endif + +// This is needed because GCC still uses throw() in its headers when exceptions +// are disabled. +#if FMT_GCC_VERSION +# define FMT_DTOR_NOEXCEPT FMT_DETECTED_NOEXCEPT +#else +# define FMT_DTOR_NOEXCEPT FMT_NOEXCEPT +#endif + +#ifndef FMT_BEGIN_NAMESPACE +# if FMT_HAS_FEATURE(cxx_inline_namespaces) || FMT_GCC_VERSION >= 404 || \ + FMT_MSC_VER >= 1900 +# define FMT_INLINE_NAMESPACE inline namespace +# define FMT_END_NAMESPACE }} +# else +# define FMT_INLINE_NAMESPACE namespace +# define FMT_END_NAMESPACE } using namespace v5; } +# endif +# define FMT_BEGIN_NAMESPACE namespace fmt { FMT_INLINE_NAMESPACE v5 { +#endif + +#if !defined(FMT_HEADER_ONLY) && defined(_WIN32) +# ifdef FMT_EXPORT +# define FMT_API __declspec(dllexport) +# elif defined(FMT_SHARED) +# define FMT_API __declspec(dllimport) +# endif +#endif +#ifndef FMT_API +# define FMT_API +#endif + +#ifndef FMT_ASSERT +# define FMT_ASSERT(condition, message) assert((condition) && message) +#endif + +// libc++ supports string_view in pre-c++17. +#if (FMT_HAS_INCLUDE() && \ + (__cplusplus > 201402L || defined(_LIBCPP_VERSION))) || \ + (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910) +# include +# define FMT_USE_STD_STRING_VIEW +#elif (FMT_HAS_INCLUDE() && \ + __cplusplus >= 201402L) +# include +# define FMT_USE_EXPERIMENTAL_STRING_VIEW +#endif + +// std::result_of is defined in in gcc 4.4. +#if FMT_GCC_VERSION && FMT_GCC_VERSION <= 404 +# include +#endif + +FMT_BEGIN_NAMESPACE +namespace internal { + +// An implementation of declval for pre-C++11 compilers such as gcc 4. +template +typename std::add_rvalue_reference::type declval() FMT_NOEXCEPT; + +template +struct result_of; + +template +struct result_of { + // A workaround for gcc 4.4 that doesn't allow F to be a reference. + typedef typename std::result_of< + typename std::remove_reference::type(Args...)>::type type; +}; + +// Casts nonnegative integer to unsigned. +template +FMT_CONSTEXPR typename std::make_unsigned::type to_unsigned(Int value) { + FMT_ASSERT(value >= 0, "negative value"); + return static_cast::type>(value); +} + +// A constexpr std::char_traits::length replacement for pre-C++17. +template +FMT_CONSTEXPR size_t length(const Char *s) { + const Char *start = s; + while (*s) ++s; + return s - start; +} +#if FMT_GCC_VERSION +FMT_CONSTEXPR size_t length(const char *s) { return std::strlen(s); } +#endif +} // namespace internal + +/** + An implementation of ``std::basic_string_view`` for pre-C++17. It provides a + subset of the API. ``fmt::basic_string_view`` is used for format strings even + if ``std::string_view`` is available to prevent issues when a library is + compiled with a different ``-std`` option than the client code (which is not + recommended). + */ +template +class basic_string_view { + private: + const Char *data_; + size_t size_; + + public: + typedef Char char_type; + typedef const Char *iterator; + + // Standard basic_string_view type. +#if defined(FMT_USE_STD_STRING_VIEW) + typedef std::basic_string_view type; +#elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW) + typedef std::experimental::basic_string_view type; +#else + struct type { + const char *data() const { return FMT_NULL; } + size_t size() const { return 0; } + }; +#endif + + FMT_CONSTEXPR basic_string_view() FMT_NOEXCEPT : data_(FMT_NULL), size_(0) {} + + /** Constructs a string reference object from a C string and a size. */ + FMT_CONSTEXPR basic_string_view(const Char *s, size_t count) FMT_NOEXCEPT + : data_(s), size_(count) {} + + /** + \rst + Constructs a string reference object from a C string computing + the size with ``std::char_traits::length``. + \endrst + */ + FMT_CONSTEXPR basic_string_view(const Char *s) + : data_(s), size_(internal::length(s)) {} + + /** Constructs a string reference from a ``std::basic_string`` object. */ + template + FMT_CONSTEXPR basic_string_view( + const std::basic_string &s) FMT_NOEXCEPT + : data_(s.data()), size_(s.size()) {} + + FMT_CONSTEXPR basic_string_view(type s) FMT_NOEXCEPT + : data_(s.data()), size_(s.size()) {} + + /** Returns a pointer to the string data. */ + FMT_CONSTEXPR const Char *data() const { return data_; } + + /** Returns the string size. */ + FMT_CONSTEXPR size_t size() const { return size_; } + + FMT_CONSTEXPR iterator begin() const { return data_; } + FMT_CONSTEXPR iterator end() const { return data_ + size_; } + + FMT_CONSTEXPR void remove_prefix(size_t n) { + data_ += n; + size_ -= n; + } + + // Lexicographically compare this string reference to other. + int compare(basic_string_view other) const { + size_t str_size = size_ < other.size_ ? size_ : other.size_; + int result = std::char_traits::compare(data_, other.data_, str_size); + if (result == 0) + result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1); + return result; + } + + friend bool operator==(basic_string_view lhs, basic_string_view rhs) { + return lhs.compare(rhs) == 0; + } + friend bool operator!=(basic_string_view lhs, basic_string_view rhs) { + return lhs.compare(rhs) != 0; + } + friend bool operator<(basic_string_view lhs, basic_string_view rhs) { + return lhs.compare(rhs) < 0; + } + friend bool operator<=(basic_string_view lhs, basic_string_view rhs) { + return lhs.compare(rhs) <= 0; + } + friend bool operator>(basic_string_view lhs, basic_string_view rhs) { + return lhs.compare(rhs) > 0; + } + friend bool operator>=(basic_string_view lhs, basic_string_view rhs) { + return lhs.compare(rhs) >= 0; + } +}; + +typedef basic_string_view string_view; +typedef basic_string_view wstring_view; + +template +class basic_format_arg; + +template +class basic_format_args; + +template +struct no_formatter_error : std::false_type {}; + +// A formatter for objects of type T. +template +struct formatter { + static_assert(no_formatter_error::value, + "don't know how to format the type, include fmt/ostream.h if it provides " + "an operator<< that should be used"); + + // The following functions are not defined intentionally. + template + typename ParseContext::iterator parse(ParseContext &); + template + auto format(const T &val, FormatContext &ctx) -> decltype(ctx.out()); +}; + +template +struct convert_to_int { + enum { + value = !std::is_arithmetic::value && std::is_convertible::value + }; +}; + +namespace internal { + +/** A contiguous memory buffer with an optional growing ability. */ +template +class basic_buffer { + private: + basic_buffer(const basic_buffer &) = delete; + void operator=(const basic_buffer &) = delete; + + T *ptr_; + std::size_t size_; + std::size_t capacity_; + + protected: + // Don't initialize ptr_ since it is not accessed to save a few cycles. + basic_buffer(std::size_t sz) FMT_NOEXCEPT: size_(sz), capacity_(sz) {} + + basic_buffer(T *p = FMT_NULL, std::size_t sz = 0, std::size_t cap = 0) + FMT_NOEXCEPT: ptr_(p), size_(sz), capacity_(cap) {} + + /** Sets the buffer data and capacity. */ + void set(T *buf_data, std::size_t buf_capacity) FMT_NOEXCEPT { + ptr_ = buf_data; + capacity_ = buf_capacity; + } + + /** Increases the buffer capacity to hold at least *capacity* elements. */ + virtual void grow(std::size_t capacity) = 0; + + public: + typedef T value_type; + typedef const T &const_reference; + + virtual ~basic_buffer() {} + + T *begin() FMT_NOEXCEPT { return ptr_; } + T *end() FMT_NOEXCEPT { return ptr_ + size_; } + + /** Returns the size of this buffer. */ + std::size_t size() const FMT_NOEXCEPT { return size_; } + + /** Returns the capacity of this buffer. */ + std::size_t capacity() const FMT_NOEXCEPT { return capacity_; } + + /** Returns a pointer to the buffer data. */ + T *data() FMT_NOEXCEPT { return ptr_; } + + /** 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(std::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(std::size_t new_capacity) { + if (new_capacity > capacity_) + grow(new_capacity); + } + + void push_back(const T &value) { + reserve(size_ + 1); + ptr_[size_++] = value; + } + + /** Appends data to the end of the buffer. */ + template + void append(const U *begin, const U *end); + + T &operator[](std::size_t index) { return ptr_[index]; } + const T &operator[](std::size_t index) const { return ptr_[index]; } +}; + +typedef basic_buffer buffer; +typedef basic_buffer wbuffer; + +// A container-backed buffer. +template +class container_buffer : public basic_buffer { + private: + Container &container_; + + protected: + void grow(std::size_t capacity) FMT_OVERRIDE { + container_.resize(capacity); + this->set(&container_[0], capacity); + } + + public: + explicit container_buffer(Container &c) + : basic_buffer(c.size()), container_(c) {} +}; + +struct error_handler { + FMT_CONSTEXPR error_handler() {} + FMT_CONSTEXPR error_handler(const error_handler &) {} + + // This function is intentionally not constexpr to give a compile-time error. + FMT_API void on_error(const char *message); +}; + +// Formatting of wide characters and strings into a narrow output is disallowed: +// fmt::format("{}", L"test"); // error +// To fix this, use a wide format string: +// fmt::format(L"{}", L"test"); +template +inline void require_wchar() { + static_assert( + std::is_same::value, + "formatting of wide characters into a narrow output is disallowed"); +} + +template +struct named_arg_base; + +template +struct named_arg; + +template +struct is_named_arg : std::false_type {}; + +template +struct is_named_arg> : std::true_type {}; + +enum type { + none_type, named_arg_type, + // Integer types should go first, + int_type, uint_type, long_long_type, ulong_long_type, bool_type, char_type, + last_integer_type = char_type, + // followed by floating-point types. + double_type, long_double_type, last_numeric_type = long_double_type, + cstring_type, string_type, pointer_type, custom_type +}; + +FMT_CONSTEXPR bool is_integral(type t) { + FMT_ASSERT(t != internal::named_arg_type, "invalid argument type"); + return t > internal::none_type && t <= internal::last_integer_type; +} + +FMT_CONSTEXPR bool is_arithmetic(type t) { + FMT_ASSERT(t != internal::named_arg_type, "invalid argument type"); + return t > internal::none_type && t <= internal::last_numeric_type; +} + +template +struct string_value { + const Char *value; + std::size_t size; +}; + +template +struct custom_value { + const void *value; + void (*format)(const void *arg, Context &ctx); +}; + +// A formatting argument value. +template +class value { + public: + typedef typename Context::char_type char_type; + + union { + int int_value; + unsigned uint_value; + long long long_long_value; + unsigned long long ulong_long_value; + double double_value; + long double long_double_value; + const void *pointer; + string_value string; + string_value sstring; + string_value ustring; + custom_value custom; + }; + + FMT_CONSTEXPR value(int val = 0) : int_value(val) {} + value(unsigned val) { uint_value = val; } + value(long long val) { long_long_value = val; } + value(unsigned long long val) { ulong_long_value = val; } + value(double val) { double_value = val; } + value(long double val) { long_double_value = val; } + value(const char_type *val) { string.value = val; } + value(const signed char *val) { + static_assert(std::is_same::value, + "incompatible string types"); + sstring.value = val; + } + value(const unsigned char *val) { + static_assert(std::is_same::value, + "incompatible string types"); + ustring.value = val; + } + value(basic_string_view val) { + string.value = val.data(); + string.size = val.size(); + } + value(const void *val) { pointer = val; } + + template + explicit value(const T &val) { + custom.value = &val; + custom.format = &format_custom_arg; + } + + const named_arg_base &as_named_arg() { + return *static_cast*>(pointer); + } + + private: + // Formats an argument of a custom type, such as a user-defined class. + template + static void format_custom_arg(const void *arg, Context &ctx) { + // Get the formatter type through the context to allow different contexts + // have different extension points, e.g. `formatter` for `format` and + // `printf_formatter` for `printf`. + typename Context::template formatter_type::type f; + auto &&parse_ctx = ctx.parse_context(); + parse_ctx.advance_to(f.parse(parse_ctx)); + ctx.advance_to(f.format(*static_cast(arg), ctx)); + } +}; + +// Value initializer used to delay conversion to value and reduce memory churn. +template +struct init { + T val; + static const type type_tag = TYPE; + + FMT_CONSTEXPR init(const T &v) : val(v) {} + FMT_CONSTEXPR operator value() const { return value(val); } +}; + +template +FMT_CONSTEXPR basic_format_arg make_arg(const T &value); + +#define FMT_MAKE_VALUE(TAG, ArgType, ValueType) \ + template \ + FMT_CONSTEXPR init make_value(ArgType val) { \ + return static_cast(val); \ + } + +#define FMT_MAKE_VALUE_SAME(TAG, Type) \ + template \ + FMT_CONSTEXPR init make_value(Type val) { return val; } + +FMT_MAKE_VALUE(bool_type, bool, int) +FMT_MAKE_VALUE(int_type, short, int) +FMT_MAKE_VALUE(uint_type, unsigned short, unsigned) +FMT_MAKE_VALUE_SAME(int_type, int) +FMT_MAKE_VALUE_SAME(uint_type, unsigned) + +// To minimize the number of types we need to deal with, long is translated +// either to int or to long long depending on its size. +typedef std::conditional::type + long_type; +FMT_MAKE_VALUE( + (sizeof(long) == sizeof(int) ? int_type : long_long_type), long, long_type) +typedef std::conditional::type ulong_type; +FMT_MAKE_VALUE( + (sizeof(unsigned long) == sizeof(unsigned) ? uint_type : ulong_long_type), + unsigned long, ulong_type) + +FMT_MAKE_VALUE_SAME(long_long_type, long long) +FMT_MAKE_VALUE_SAME(ulong_long_type, unsigned long long) +FMT_MAKE_VALUE(int_type, signed char, int) +FMT_MAKE_VALUE(uint_type, unsigned char, unsigned) +FMT_MAKE_VALUE(char_type, char, int) + +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) +template +inline init make_value(wchar_t val) { + require_wchar(); + return static_cast(val); +} +#endif + +FMT_MAKE_VALUE(double_type, float, double) +FMT_MAKE_VALUE_SAME(double_type, double) +FMT_MAKE_VALUE_SAME(long_double_type, long double) + +// Formatting of wide strings into a narrow buffer and multibyte strings +// into a wide buffer is disallowed (https://github.com/fmtlib/fmt/pull/606). +FMT_MAKE_VALUE(cstring_type, typename C::char_type*, + const typename C::char_type*) +FMT_MAKE_VALUE(cstring_type, const typename C::char_type*, + const typename C::char_type*) + +FMT_MAKE_VALUE(cstring_type, signed char*, const signed char*) +FMT_MAKE_VALUE_SAME(cstring_type, const signed char*) +FMT_MAKE_VALUE(cstring_type, unsigned char*, const unsigned char*) +FMT_MAKE_VALUE_SAME(cstring_type, const unsigned char*) +FMT_MAKE_VALUE_SAME(string_type, basic_string_view) +FMT_MAKE_VALUE(string_type, + typename basic_string_view::type, + basic_string_view) +FMT_MAKE_VALUE(string_type, const std::basic_string&, + basic_string_view) +FMT_MAKE_VALUE(pointer_type, void*, const void*) +FMT_MAKE_VALUE_SAME(pointer_type, const void*) + +#if FMT_USE_NULLPTR +FMT_MAKE_VALUE(pointer_type, std::nullptr_t, const void*) +#endif + +// Formatting of arbitrary pointers is disallowed. If you want to output a +// pointer cast it to "void *" or "const void *". In particular, this forbids +// formatting of "[const] volatile char *" which is printed as bool by +// iostreams. +template +typename std::enable_if::value>::type + make_value(const T *) { + static_assert(!sizeof(T), "formatting of non-void pointers is disallowed"); +} + +template +inline typename std::enable_if< + std::is_enum::value && convert_to_int::value, + init>::type + make_value(const T &val) { return static_cast(val); } + +template +inline typename std::enable_if< + std::is_constructible, T>::value, + init, string_type>>::type + make_value(const T &val) { return basic_string_view(val); } + +template +inline typename std::enable_if< + !convert_to_int::value && + !std::is_convertible>::value && + !std::is_constructible, T>::value, + // Implicit conversion to std::string is not handled here because it's + // unsafe: https://github.com/fmtlib/fmt/issues/729 + init>::type + make_value(const T &val) { return val; } + +template +init + make_value(const named_arg &val) { + basic_format_arg arg = make_arg(val.value); + std::memcpy(val.data, &arg, sizeof(arg)); + return static_cast(&val); +} + +// Maximum number of arguments with packed types. +enum { max_packed_args = 15 }; + +template +class arg_map; +} // namespace internal + +// A formatting argument. It is a trivially copyable/constructible type to +// allow storage in basic_memory_buffer. +template +class basic_format_arg { + private: + internal::value value_; + internal::type type_; + + template + friend FMT_CONSTEXPR basic_format_arg + internal::make_arg(const T &value); + + template + friend FMT_CONSTEXPR typename internal::result_of::type + visit(Visitor &&vis, const basic_format_arg &arg); + + friend class basic_format_args; + friend class internal::arg_map; + + typedef typename Context::char_type char_type; + + public: + class handle { + public: + explicit handle(internal::custom_value custom): custom_(custom) {} + + void format(Context &ctx) const { custom_.format(custom_.value, ctx); } + + private: + internal::custom_value custom_; + }; + + FMT_CONSTEXPR basic_format_arg() : type_(internal::none_type) {} + + FMT_EXPLICIT operator bool() const FMT_NOEXCEPT { + return type_ != internal::none_type; + } + + internal::type type() const { return type_; } + + bool is_integral() const { return internal::is_integral(type_); } + bool is_arithmetic() const { return internal::is_arithmetic(type_); } +}; + +struct monostate {}; + +/** + \rst + Visits an argument dispatching to the appropriate visit method based on + the argument type. For example, if the argument type is ``double`` then + ``vis(value)`` will be called with the value of type ``double``. + \endrst + */ +template +FMT_CONSTEXPR typename internal::result_of::type + visit(Visitor &&vis, const basic_format_arg &arg) { + typedef typename Context::char_type char_type; + switch (arg.type_) { + case internal::none_type: + break; + case internal::named_arg_type: + FMT_ASSERT(false, "invalid argument type"); + break; + case internal::int_type: + return vis(arg.value_.int_value); + case internal::uint_type: + return vis(arg.value_.uint_value); + case internal::long_long_type: + return vis(arg.value_.long_long_value); + case internal::ulong_long_type: + return vis(arg.value_.ulong_long_value); + case internal::bool_type: + return vis(arg.value_.int_value != 0); + case internal::char_type: + return vis(static_cast(arg.value_.int_value)); + case internal::double_type: + return vis(arg.value_.double_value); + case internal::long_double_type: + return vis(arg.value_.long_double_value); + case internal::cstring_type: + return vis(arg.value_.string.value); + case internal::string_type: + return vis(basic_string_view( + arg.value_.string.value, arg.value_.string.size)); + case internal::pointer_type: + return vis(arg.value_.pointer); + case internal::custom_type: + return vis(typename basic_format_arg::handle(arg.value_.custom)); + } + return vis(monostate()); +} + +// Parsing context consisting of a format string range being parsed and an +// argument counter for automatic indexing. +template +class basic_parse_context : private ErrorHandler { + private: + basic_string_view format_str_; + int next_arg_id_; + + public: + typedef Char char_type; + typedef typename basic_string_view::iterator iterator; + + explicit FMT_CONSTEXPR basic_parse_context( + basic_string_view format_str, ErrorHandler eh = ErrorHandler()) + : ErrorHandler(eh), format_str_(format_str), next_arg_id_(0) {} + + // Returns an iterator to the beginning of the format string range being + // parsed. + FMT_CONSTEXPR iterator begin() const FMT_NOEXCEPT { + return format_str_.begin(); + } + + // Returns an iterator past the end of the format string range being parsed. + FMT_CONSTEXPR iterator end() const FMT_NOEXCEPT { return format_str_.end(); } + + // Advances the begin iterator to ``it``. + FMT_CONSTEXPR void advance_to(iterator it) { + format_str_.remove_prefix(internal::to_unsigned(it - begin())); + } + + // Returns the next argument index. + FMT_CONSTEXPR unsigned next_arg_id(); + + FMT_CONSTEXPR bool check_arg_id(unsigned) { + if (next_arg_id_ > 0) { + on_error("cannot switch from automatic to manual argument indexing"); + return false; + } + next_arg_id_ = -1; + return true; + } + void check_arg_id(basic_string_view) {} + + FMT_CONSTEXPR void on_error(const char *message) { + ErrorHandler::on_error(message); + } + + FMT_CONSTEXPR ErrorHandler error_handler() const { return *this; } +}; + +typedef basic_parse_context parse_context; +typedef basic_parse_context wparse_context; + +namespace internal { +// A map from argument names to their values for named arguments. +template +class arg_map { + private: + arg_map(const arg_map &) = delete; + void operator=(const arg_map &) = delete; + + typedef typename Context::char_type char_type; + + struct entry { + basic_string_view name; + basic_format_arg arg; + }; + + entry *map_; + unsigned size_; + + void push_back(value val) { + const internal::named_arg_base &named = val.as_named_arg(); + map_[size_] = entry{named.name, named.template deserialize()}; + ++size_; + } + + public: + arg_map() : map_(FMT_NULL), size_(0) {} + void init(const basic_format_args &args); + ~arg_map() { delete [] map_; } + + basic_format_arg find(basic_string_view name) const { + // The list is unsorted, so just return the first matching name. + for (entry *it = map_, *end = map_ + size_; it != end; ++it) { + if (it->name == name) + return it->arg; + } + return basic_format_arg(); + } +}; + +template +class context_base { + public: + typedef OutputIt iterator; + + private: + basic_parse_context parse_context_; + iterator out_; + basic_format_args args_; + + protected: + typedef Char char_type; + typedef basic_format_arg format_arg; + + context_base(OutputIt out, basic_string_view format_str, + basic_format_args ctx_args) + : parse_context_(format_str), out_(out), args_(ctx_args) {} + + // Returns the argument with specified index. + format_arg do_get_arg(unsigned arg_id) { + format_arg arg = args_.get(arg_id); + if (!arg) + parse_context_.on_error("argument index out of range"); + return arg; + } + + // Checks if manual indexing is used and returns the argument with + // specified index. + format_arg get_arg(unsigned arg_id) { + return this->parse_context().check_arg_id(arg_id) ? + this->do_get_arg(arg_id) : format_arg(); + } + + public: + basic_parse_context &parse_context() { + return parse_context_; + } + + internal::error_handler error_handler() { + return parse_context_.error_handler(); + } + + void on_error(const char *message) { parse_context_.on_error(message); } + + // Returns an iterator to the beginning of the output range. + iterator out() { return out_; } + iterator begin() { return out_; } // deprecated + + // Advances the begin iterator to ``it``. + void advance_to(iterator it) { out_ = it; } + + basic_format_args args() const { return args_; } +}; + +// Extracts a reference to the container from back_insert_iterator. +template +inline Container &get_container(std::back_insert_iterator it) { + typedef std::back_insert_iterator bi_iterator; + struct accessor: bi_iterator { + accessor(bi_iterator iter) : bi_iterator(iter) {} + using bi_iterator::container; + }; + return *accessor(it).container; +} +} // namespace internal + +// Formatting context. +template +class basic_format_context : + public internal::context_base< + OutputIt, basic_format_context, Char> { + public: + /** The character type for the output. */ + typedef Char char_type; + + // using formatter_type = formatter; + template + struct formatter_type { typedef formatter type; }; + + private: + internal::arg_map map_; + + basic_format_context(const basic_format_context &) = delete; + void operator=(const basic_format_context &) = delete; + + typedef internal::context_base base; + typedef typename base::format_arg format_arg; + using base::get_arg; + + public: + using typename base::iterator; + + /** + Constructs a ``basic_format_context`` object. References to the arguments are + stored in the object so make sure they have appropriate lifetimes. + */ + basic_format_context(OutputIt out, basic_string_view format_str, + basic_format_args ctx_args) + : base(out, format_str, ctx_args) {} + + format_arg next_arg() { + return this->do_get_arg(this->parse_context().next_arg_id()); + } + format_arg get_arg(unsigned arg_id) { return this->do_get_arg(arg_id); } + + // Checks if manual indexing is used and returns the argument with the + // specified name. + format_arg get_arg(basic_string_view name); +}; + +template +struct buffer_context { + typedef basic_format_context< + std::back_insert_iterator>, Char> type; +}; +typedef buffer_context::type format_context; +typedef buffer_context::type wformat_context; + +namespace internal { +template +struct get_type { + typedef decltype(make_value( + declval::type&>())) value_type; + static const type value = value_type::type_tag; +}; + +template +FMT_CONSTEXPR11 unsigned long long get_types() { return 0; } + +template +FMT_CONSTEXPR11 unsigned long long get_types() { + return get_type::value | (get_types() << 4); +} + +template +FMT_CONSTEXPR basic_format_arg make_arg(const T &value) { + basic_format_arg arg; + arg.type_ = get_type::value; + arg.value_ = make_value(value); + return arg; +} + +template +inline typename std::enable_if>::type + make_arg(const T &value) { + return make_value(value); +} + +template +inline typename std::enable_if>::type + make_arg(const T &value) { + return make_arg(value); +} +} // namespace internal + +/** + \rst + An array of references to arguments. It can be implicitly converted into + `~fmt::basic_format_args` for passing into type-erased formatting functions + such as `~fmt::vformat`. + \endrst + */ +template +class format_arg_store { + private: + static const size_t NUM_ARGS = sizeof...(Args); + + // Packed is a macro on MinGW so use IS_PACKED instead. + static const bool IS_PACKED = NUM_ARGS < internal::max_packed_args; + + typedef typename std::conditional, basic_format_arg>::type value_type; + + // If the arguments are not packed, add one more element to mark the end. + static const size_t DATA_SIZE = + NUM_ARGS + (IS_PACKED && NUM_ARGS != 0 ? 0 : 1); + value_type data_[DATA_SIZE]; + + friend class basic_format_args; + + static FMT_CONSTEXPR11 long long get_types() { + return IS_PACKED ? + static_cast(internal::get_types()) : + -static_cast(NUM_ARGS); + } + + public: +#if FMT_USE_CONSTEXPR11 + static FMT_CONSTEXPR11 long long TYPES = get_types(); +#else + static const long long TYPES; +#endif + +#if (FMT_GCC_VERSION && FMT_GCC_VERSION <= 405) || \ + (FMT_MSC_VER && FMT_MSC_VER <= 1800) + // Workaround array initialization issues in gcc <= 4.5 and MSVC <= 2013. + format_arg_store(const Args &... args) { + value_type init[DATA_SIZE] = + {internal::make_arg(args)...}; + std::memcpy(data_, init, sizeof(init)); + } +#else + format_arg_store(const Args &... args) + : data_{internal::make_arg(args)...} {} +#endif +}; + +#if !FMT_USE_CONSTEXPR11 +template +const long long format_arg_store::TYPES = get_types(); +#endif + +/** + \rst + Constructs an `~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`. + \endrst + */ +template +inline format_arg_store + make_format_args(const Args & ... args) { + return format_arg_store(args...); +} + +template +inline format_arg_store + make_format_args(const Args & ... args) { + return format_arg_store(args...); +} + +/** Formatting arguments. */ +template +class basic_format_args { + public: + typedef unsigned size_type; + typedef basic_format_arg format_arg; + + private: + // To reduce compiled code size per formatting function call, types of first + // max_packed_args arguments are passed in the types_ field. + unsigned long long types_; + union { + // If the number of arguments is less than max_packed_args, the argument + // values are stored in values_, otherwise they are stored in args_. + // This is done to reduce compiled code size as storing larger objects + // may require more code (at least on x86-64) even if the same amount of + // data is actually copied to stack. It saves ~10% on the bloat test. + const internal::value *values_; + const format_arg *args_; + }; + + typename internal::type type(unsigned index) const { + unsigned shift = index * 4; + unsigned long long mask = 0xf; + return static_cast( + (types_ & (mask << shift)) >> shift); + } + + friend class internal::arg_map; + + void set_data(const internal::value *values) { values_ = values; } + void set_data(const format_arg *args) { args_ = args; } + + format_arg do_get(size_type index) const { + format_arg arg; + long long signed_types = static_cast(types_); + if (signed_types < 0) { + unsigned long long num_args = + static_cast(-signed_types); + if (index < num_args) + arg = args_[index]; + return arg; + } + if (index > internal::max_packed_args) + return arg; + arg.type_ = type(index); + if (arg.type_ == internal::none_type) + return arg; + internal::value &val = arg.value_; + val = values_[index]; + return arg; + } + + public: + basic_format_args() : types_(0) {} + + /** + \rst + Constructs a `basic_format_args` object from `~fmt::format_arg_store`. + \endrst + */ + template + basic_format_args(const format_arg_store &store) + : types_(static_cast(store.TYPES)) { + set_data(store.data_); + } + + /** + \rst + Constructs a `basic_format_args` object from a dynamic set of arguments. + \endrst + */ + basic_format_args(const format_arg *args, size_type count) + : types_(-static_cast(count)) { + set_data(args); + } + + /** Returns the argument at specified index. */ + format_arg get(size_type index) const { + format_arg arg = do_get(index); + if (arg.type_ == internal::named_arg_type) + arg = arg.value_.as_named_arg().template deserialize(); + return arg; + } + + unsigned max_size() const { + long long signed_types = static_cast(types_); + return static_cast( + signed_types < 0 ? + -signed_types : static_cast(internal::max_packed_args)); + } +}; + +/** An alias to ``basic_format_args``. */ +// It is a separate type rather than a typedef to make symbols readable. +struct format_args: basic_format_args { + template + format_args(Args && ... arg) + : basic_format_args(std::forward(arg)...) {} +}; +struct wformat_args : basic_format_args { + template + wformat_args(Args && ... arg) + : basic_format_args(std::forward(arg)...) {} +}; + +namespace internal { +template +struct named_arg_base { + basic_string_view name; + + // Serialized value. + mutable char data[sizeof(basic_format_arg)]; + + named_arg_base(basic_string_view nm) : name(nm) {} + + template + basic_format_arg deserialize() const { + basic_format_arg arg; + std::memcpy(&arg, data, sizeof(basic_format_arg)); + return arg; + } +}; + +template +struct named_arg : named_arg_base { + const T &value; + + named_arg(basic_string_view name, const T &val) + : named_arg_base(name), value(val) {} +}; +} + +/** + \rst + Returns a named argument to be used in a formatting function. + + **Example**:: + + fmt::print("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23)); + \endrst + */ +template +inline internal::named_arg arg(string_view name, const T &arg) { + return internal::named_arg(name, arg); +} + +template +inline internal::named_arg arg(wstring_view name, const T &arg) { + return internal::named_arg(name, arg); +} + +// This function template is deleted intentionally to disable nested named +// arguments as in ``format("{}", arg("a", arg("b", 42)))``. +template +void arg(S, internal::named_arg) = delete; + +// A base class for compile-time strings. It is defined in the fmt namespace to +// make formatting functions visible via ADL, e.g. format(fmt("{}"), 42). +struct compile_string {}; + +namespace internal { +// If S is a format string type, format_string_traints::char_type gives its +// character type. +template +struct format_string_traits { + private: + // Use constructability as a way to detect if format_string_traits is + // specialized because other methods are broken on MSVC2013. + format_string_traits(); +}; + +template +struct format_string_traits_base { typedef Char char_type; }; + +template +struct format_string_traits : format_string_traits_base {}; + +template +struct format_string_traits : format_string_traits_base {}; + +template +struct format_string_traits : format_string_traits_base {}; + +template +struct format_string_traits : format_string_traits_base {}; + +template +struct format_string_traits> : + format_string_traits_base {}; + +template +struct format_string_traits< + S, typename std::enable_if, S>::value>::type> : + format_string_traits_base {}; + +template +struct is_format_string : + std::integral_constant< + bool, std::is_constructible>::value> {}; + +template +struct is_compile_string : + std::integral_constant::value> {}; + +template +inline typename std::enable_if::value>::type + check_format_string(const S &) {} +template +typename std::enable_if::value>::type + check_format_string(S); + +template +std::basic_string vformat( + basic_string_view format_str, + basic_format_args::type> args); +} // namespace internal + +format_context::iterator vformat_to( + internal::buffer &buf, string_view format_str, format_args args); +wformat_context::iterator vformat_to( + internal::wbuffer &buf, wstring_view format_str, wformat_args args); + +template +struct is_contiguous : std::false_type {}; + +template +struct is_contiguous> : std::true_type {}; + +template +struct is_contiguous> : std::true_type {}; + +/** Formats a string and writes the output to ``out``. */ +template +typename std::enable_if< + is_contiguous::value, std::back_insert_iterator>::type + vformat_to(std::back_insert_iterator out, + string_view format_str, format_args args) { + internal::container_buffer buf(internal::get_container(out)); + vformat_to(buf, format_str, args); + return out; +} + +template +typename std::enable_if< + is_contiguous::value, std::back_insert_iterator>::type + vformat_to(std::back_insert_iterator out, + wstring_view format_str, wformat_args args) { + internal::container_buffer buf(internal::get_container(out)); + vformat_to(buf, format_str, args); + return out; +} + +template +inline typename std::enable_if< + is_contiguous::value, std::back_insert_iterator>::type + format_to(std::back_insert_iterator out, + string_view format_str, const Args & ... args) { + format_arg_store as{args...}; + return vformat_to(out, format_str, as); +} + +template +inline typename std::enable_if< + is_contiguous::value, std::back_insert_iterator>::type + format_to(std::back_insert_iterator out, + wstring_view format_str, const Args & ... args) { + return vformat_to(out, format_str, + make_format_args(args...)); +} + +template < + typename String, + typename Char = typename internal::format_string_traits::char_type> +inline std::basic_string vformat( + const String &format_str, + basic_format_args::type> args) { + // Convert format string to string_view to reduce the number of overloads. + return internal::vformat(basic_string_view(format_str), args); +} + +/** + \rst + Formats arguments and returns the result as a string. + + **Example**:: + + #include + std::string message = fmt::format("The answer is {}", 42); + \endrst +*/ +template +inline std::basic_string< + typename internal::format_string_traits::char_type> + format(const String &format_str, const Args & ... args) { + internal::check_format_string(format_str); + // This should be just + // return vformat(format_str, make_format_args(args...)); + // but gcc has trouble optimizing the latter, so break it down. + typedef typename internal::format_string_traits::char_type char_t; + typedef typename buffer_context::type context_t; + format_arg_store as{args...}; + return internal::vformat( + basic_string_view(format_str), basic_format_args(as)); +} + +FMT_API void vprint(std::FILE *f, string_view format_str, format_args args); +FMT_API void vprint(std::FILE *f, wstring_view format_str, wformat_args args); + +/** + \rst + Prints formatted data to the file *f*. + + **Example**:: + + fmt::print(stderr, "Don't {}!", "panic"); + \endrst + */ +template +inline void print(std::FILE *f, string_view format_str, const Args & ... args) { + format_arg_store as(args...); + vprint(f, format_str, as); +} +/** + Prints formatted data to the file *f* which should be in wide-oriented mode + set via ``fwide(f, 1)`` or ``_setmode(_fileno(f), _O_U8TEXT)`` on Windows. + */ +template +inline void print(std::FILE *f, wstring_view format_str, + const Args & ... args) { + format_arg_store as(args...); + vprint(f, format_str, as); +} + +FMT_API void vprint(string_view format_str, format_args args); +FMT_API void vprint(wstring_view format_str, wformat_args args); + +/** + \rst + Prints formatted data to ``stdout``. + + **Example**:: + + fmt::print("Elapsed time: {0:.2f} seconds", 1.23); + \endrst + */ +template +inline void print(string_view format_str, const Args & ... args) { + format_arg_store as{args...}; + vprint(format_str, as); +} + +template +inline void print(wstring_view format_str, const Args & ... args) { + format_arg_store as(args...); + vprint(format_str, as); +} +FMT_END_NAMESPACE + +#endif // FMT_CORE_H_ diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h new file mode 100644 index 00000000..56c4d581 --- /dev/null +++ b/include/fmt/format-inl.h @@ -0,0 +1,866 @@ +// Formatting library for C++ +// +// Copyright (c) 2012 - 2016, Victor Zverovich +// All rights reserved. +// +// For the license information refer to format.h. + +#ifndef FMT_FORMAT_INL_H_ +#define FMT_FORMAT_INL_H_ + +#include "format.h" + +#include + +#include +#include +#include +#include +#include +#include // for std::ptrdiff_t +#include // for std::memmove +#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) +# include +#endif + +#if FMT_USE_WINDOWS_H +# if !defined(FMT_HEADER_ONLY) && !defined(WIN32_LEAN_AND_MEAN) +# define WIN32_LEAN_AND_MEAN +# endif +# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX) +# include +# else +# define NOMINMAX +# include +# undef NOMINMAX +# endif +#endif + +#if FMT_EXCEPTIONS +# define FMT_TRY try +# define FMT_CATCH(x) catch (x) +#else +# define FMT_TRY if (true) +# define FMT_CATCH(x) if (false) +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4127) // conditional expression is constant +# pragma warning(disable: 4702) // unreachable code +// Disable deprecation warning for strerror. The latter is not called but +// MSVC fails to detect it. +# pragma warning(disable: 4996) +#endif + +// Dummy implementations of strerror_r and strerror_s called if corresponding +// system functions are not available. +inline fmt::internal::null<> strerror_r(int, char *, ...) { + return fmt::internal::null<>(); +} +inline fmt::internal::null<> strerror_s(char *, std::size_t, ...) { + return fmt::internal::null<>(); +} + +FMT_BEGIN_NAMESPACE + +namespace { + +#ifndef _MSC_VER +# define FMT_SNPRINTF snprintf +#else // _MSC_VER +inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) { + va_list args; + va_start(args, format); + int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args); + va_end(args); + return result; +} +# define FMT_SNPRINTF fmt_snprintf +#endif // _MSC_VER + +#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) +# define FMT_SWPRINTF snwprintf +#else +# define FMT_SWPRINTF swprintf +#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) + +typedef void (*FormatFunc)(internal::buffer &, int, string_view); + +// Portable thread-safe version of strerror. +// Sets buffer to point to a string describing the error code. +// This can be either a pointer to a string stored in buffer, +// or a pointer to some static immutable string. +// Returns one of the following values: +// 0 - success +// ERANGE - buffer is not large enough to store the error message +// other - failure +// Buffer should be at least of size 1. +int safe_strerror( + int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT { + FMT_ASSERT(buffer != FMT_NULL && buffer_size != 0, "invalid buffer"); + + class dispatcher { + private: + int error_code_; + char *&buffer_; + std::size_t buffer_size_; + + // A noop assignment operator to avoid bogus warnings. + void operator=(const dispatcher &) {} + + // Handle the result of XSI-compliant version of strerror_r. + int handle(int result) { + // glibc versions before 2.13 return result in errno. + return result == -1 ? errno : result; + } + + // Handle the result of GNU-specific version of strerror_r. + int handle(char *message) { + // If the buffer is full then the message is probably truncated. + if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1) + return ERANGE; + buffer_ = message; + return 0; + } + + // Handle the case when strerror_r is not available. + int handle(internal::null<>) { + return fallback(strerror_s(buffer_, buffer_size_, error_code_)); + } + + // Fallback to strerror_s when strerror_r is not available. + int fallback(int result) { + // If the buffer is full then the message is probably truncated. + return result == 0 && strlen(buffer_) == buffer_size_ - 1 ? + ERANGE : result; + } + + // Fallback to strerror if strerror_r and strerror_s are not available. + int fallback(internal::null<>) { + errno = 0; + buffer_ = strerror(error_code_); + return errno; + } + + public: + dispatcher(int err_code, char *&buf, std::size_t buf_size) + : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {} + + int run() { + return handle(strerror_r(error_code_, buffer_, buffer_size_)); + } + }; + return dispatcher(error_code, buffer, buffer_size).run(); +} + +void format_error_code(internal::buffer &out, int error_code, + string_view message) FMT_NOEXCEPT { + // Report error code making sure that the output fits into + // inline_buffer_size to avoid dynamic memory allocation and potential + // bad_alloc. + out.resize(0); + static const char SEP[] = ": "; + static const char ERROR_STR[] = "error "; + // Subtract 2 to account for terminating null characters in SEP and ERROR_STR. + std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2; + typedef internal::int_traits::main_type main_type; + main_type abs_value = static_cast(error_code); + if (internal::is_negative(error_code)) { + abs_value = 0 - abs_value; + ++error_code_size; + } + error_code_size += internal::count_digits(abs_value); + writer w(out); + if (message.size() <= inline_buffer_size - error_code_size) { + w.write(message); + w.write(SEP); + } + w.write(ERROR_STR); + w.write(error_code); + assert(out.size() <= inline_buffer_size); +} + +void report_error(FormatFunc func, int error_code, + string_view message) FMT_NOEXCEPT { + memory_buffer full_message; + func(full_message, error_code, message); + // Use Writer::data instead of Writer::c_str to avoid potential memory + // allocation. + std::fwrite(full_message.data(), full_message.size(), 1, stderr); + std::fputc('\n', stderr); +} +} // namespace + +#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) +class locale { + private: + std::locale locale_; + + public: + explicit locale(std::locale loc = std::locale()) : locale_(loc) {} + std::locale get() { return locale_; } +}; + +FMT_FUNC size_t internal::count_code_points(u8string_view s) { + const char8_t *data = s.data(); + int num_code_points = 0; + for (size_t i = 0, size = s.size(); i != size; ++i) { + if ((data[i].value & 0xc0) != 0x80) + ++num_code_points; + } + return num_code_points; +} + +template +FMT_FUNC Char internal::thousands_sep(locale_provider *lp) { + std::locale loc = lp ? lp->locale().get() : std::locale(); + return std::use_facet>(loc).thousands_sep(); +} +#else +template +FMT_FUNC Char internal::thousands_sep(locale_provider *lp) { + return FMT_STATIC_THOUSANDS_SEPARATOR; +} +#endif + +FMT_FUNC void system_error::init( + int err_code, string_view format_str, format_args args) { + error_code_ = err_code; + memory_buffer buffer; + format_system_error(buffer, err_code, vformat(format_str, args)); + std::runtime_error &base = *this; + base = std::runtime_error(to_string(buffer)); +} + +namespace internal { +template +int char_traits::format_float( + char *buffer, std::size_t size, const char *format, int precision, T value) { + return precision < 0 ? + FMT_SNPRINTF(buffer, size, format, value) : + FMT_SNPRINTF(buffer, size, format, precision, value); +} + +template +int char_traits::format_float( + wchar_t *buffer, std::size_t size, const wchar_t *format, int precision, + T value) { + return precision < 0 ? + FMT_SWPRINTF(buffer, size, format, value) : + FMT_SWPRINTF(buffer, size, format, precision, value); +} + +template +const char basic_data::DIGITS[] = + "0001020304050607080910111213141516171819" + "2021222324252627282930313233343536373839" + "4041424344454647484950515253545556575859" + "6061626364656667686970717273747576777879" + "8081828384858687888990919293949596979899"; + +#define FMT_POWERS_OF_10(factor) \ + factor * 10, \ + factor * 100, \ + factor * 1000, \ + factor * 10000, \ + factor * 100000, \ + factor * 1000000, \ + factor * 10000000, \ + factor * 100000000, \ + factor * 1000000000 + +template +const uint32_t basic_data::POWERS_OF_10_32[] = { + 1, FMT_POWERS_OF_10(1) +}; + +template +const uint32_t basic_data::ZERO_OR_POWERS_OF_10_32[] = { + 0, FMT_POWERS_OF_10(1) +}; + +template +const uint64_t basic_data::ZERO_OR_POWERS_OF_10_64[] = { + 0, + FMT_POWERS_OF_10(1), + FMT_POWERS_OF_10(1000000000ull), + 10000000000000000000ull +}; + +// Normalized 64-bit significands of pow(10, k), for k = -348, -340, ..., 340. +// These are generated by support/compute-powers.py. +template +const uint64_t basic_data::POW10_SIGNIFICANDS[] = { + 0xfa8fd5a0081c0288, 0xbaaee17fa23ebf76, 0x8b16fb203055ac76, + 0xcf42894a5dce35ea, 0x9a6bb0aa55653b2d, 0xe61acf033d1a45df, + 0xab70fe17c79ac6ca, 0xff77b1fcbebcdc4f, 0xbe5691ef416bd60c, + 0x8dd01fad907ffc3c, 0xd3515c2831559a83, 0x9d71ac8fada6c9b5, + 0xea9c227723ee8bcb, 0xaecc49914078536d, 0x823c12795db6ce57, + 0xc21094364dfb5637, 0x9096ea6f3848984f, 0xd77485cb25823ac7, + 0xa086cfcd97bf97f4, 0xef340a98172aace5, 0xb23867fb2a35b28e, + 0x84c8d4dfd2c63f3b, 0xc5dd44271ad3cdba, 0x936b9fcebb25c996, + 0xdbac6c247d62a584, 0xa3ab66580d5fdaf6, 0xf3e2f893dec3f126, + 0xb5b5ada8aaff80b8, 0x87625f056c7c4a8b, 0xc9bcff6034c13053, + 0x964e858c91ba2655, 0xdff9772470297ebd, 0xa6dfbd9fb8e5b88f, + 0xf8a95fcf88747d94, 0xb94470938fa89bcf, 0x8a08f0f8bf0f156b, + 0xcdb02555653131b6, 0x993fe2c6d07b7fac, 0xe45c10c42a2b3b06, + 0xaa242499697392d3, 0xfd87b5f28300ca0e, 0xbce5086492111aeb, + 0x8cbccc096f5088cc, 0xd1b71758e219652c, 0x9c40000000000000, + 0xe8d4a51000000000, 0xad78ebc5ac620000, 0x813f3978f8940984, + 0xc097ce7bc90715b3, 0x8f7e32ce7bea5c70, 0xd5d238a4abe98068, + 0x9f4f2726179a2245, 0xed63a231d4c4fb27, 0xb0de65388cc8ada8, + 0x83c7088e1aab65db, 0xc45d1df942711d9a, 0x924d692ca61be758, + 0xda01ee641a708dea, 0xa26da3999aef774a, 0xf209787bb47d6b85, + 0xb454e4a179dd1877, 0x865b86925b9bc5c2, 0xc83553c5c8965d3d, + 0x952ab45cfa97a0b3, 0xde469fbd99a05fe3, 0xa59bc234db398c25, + 0xf6c69a72a3989f5c, 0xb7dcbf5354e9bece, 0x88fcf317f22241e2, + 0xcc20ce9bd35c78a5, 0x98165af37b2153df, 0xe2a0b5dc971f303a, + 0xa8d9d1535ce3b396, 0xfb9b7cd9a4a7443c, 0xbb764c4ca7a44410, + 0x8bab8eefb6409c1a, 0xd01fef10a657842c, 0x9b10a4e5e9913129, + 0xe7109bfba19c0c9d, 0xac2820d9623bf429, 0x80444b5e7aa7cf85, + 0xbf21e44003acdd2d, 0x8e679c2f5e44ff8f, 0xd433179d9c8cb841, + 0x9e19db92b4e31ba9, 0xeb96bf6ebadf77d9, 0xaf87023b9bf0ee6b, +}; + +// Binary exponents of pow(10, k), for k = -348, -340, ..., 340, corresponding +// to significands above. +template +const int16_t basic_data::POW10_EXPONENTS[] = { + -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954, + -927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661, + -635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369, + -343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77, + -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216, + 242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508, + 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800, + 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066 +}; + +template const char basic_data::RESET_COLOR[] = "\x1b[0m"; +template const wchar_t basic_data::WRESET_COLOR[] = L"\x1b[0m"; + +// A handmade floating-point number f * pow(2, e). +class fp { + private: + typedef uint64_t significand_type; + + // All sizes are in bits. + static FMT_CONSTEXPR_DECL const int char_size = + std::numeric_limits::digits; + // Subtract 1 to account for an implicit most significant bit in the + // normalized form. + static FMT_CONSTEXPR_DECL const int double_significand_size = + std::numeric_limits::digits - 1; + static FMT_CONSTEXPR_DECL const uint64_t implicit_bit = + 1ull << double_significand_size; + + public: + significand_type f; + int e; + + static FMT_CONSTEXPR_DECL const int significand_size = + sizeof(significand_type) * char_size; + + fp(): f(0), e(0) {} + fp(uint64_t f, int e): f(f), e(e) {} + + // Constructs fp from an IEEE754 double. It is a template to prevent compile + // errors on platforms where double is not IEEE754. + template + explicit fp(Double d) { + // Assume double is in the format [sign][exponent][significand]. + typedef std::numeric_limits limits; + const int double_size = static_cast(sizeof(Double) * char_size); + const int exponent_size = + double_size - double_significand_size - 1; // -1 for sign + const uint64_t significand_mask = implicit_bit - 1; + const uint64_t exponent_mask = (~0ull >> 1) & ~significand_mask; + const int exponent_bias = (1 << exponent_size) - limits::max_exponent - 1; + auto u = bit_cast(d); + auto biased_e = (u & exponent_mask) >> double_significand_size; + f = u & significand_mask; + if (biased_e != 0) + f += implicit_bit; + else + biased_e = 1; // Subnormals use biased exponent 1 (min exponent). + e = static_cast(biased_e - exponent_bias - double_significand_size); + } + + // Normalizes the value converted from double and multiplied by (1 << SHIFT). + template + void normalize() { + // Handle subnormals. + auto shifted_implicit_bit = implicit_bit << SHIFT; + while ((f & shifted_implicit_bit) == 0) { + f <<= 1; + --e; + } + // Subtract 1 to account for hidden bit. + auto offset = significand_size - double_significand_size - SHIFT - 1; + f <<= offset; + e -= offset; + } + + // Compute lower and upper boundaries (m^- and m^+ in the Grisu paper), where + // a boundary is a value half way between the number and its predecessor + // (lower) or successor (upper). The upper boundary is normalized and lower + // has the same exponent but may be not normalized. + void compute_boundaries(fp &lower, fp &upper) const { + lower = f == implicit_bit ? + fp((f << 2) - 1, e - 2) : fp((f << 1) - 1, e - 1); + upper = fp((f << 1) + 1, e - 1); + upper.normalize<1>(); // 1 is to account for the exponent shift above. + lower.f <<= lower.e - upper.e; + lower.e = upper.e; + } +}; + +// Returns an fp number representing x - y. Result may not be normalized. +inline fp operator-(fp x, fp y) { + FMT_ASSERT(x.f >= y.f && x.e == y.e, "invalid operands"); + return fp(x.f - y.f, x.e); +} + +// Computes an fp number r with r.f = x.f * y.f / pow(2, 64) rounded to nearest +// with half-up tie breaking, r.e = x.e + y.e + 64. Result may not be normalized. +FMT_API fp operator*(fp x, fp y); + +// Returns cached power (of 10) c_k = c_k.f * pow(2, c_k.e) such that its +// (binary) exponent satisfies min_exponent <= c_k.e <= min_exponent + 3. +FMT_API fp get_cached_power(int min_exponent, int &pow10_exponent); + +FMT_FUNC fp operator*(fp x, fp y) { + // Multiply 32-bit parts of significands. + uint64_t mask = (1ULL << 32) - 1; + uint64_t a = x.f >> 32, b = x.f & mask; + uint64_t c = y.f >> 32, d = y.f & mask; + uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d; + // Compute mid 64-bit of result and round. + uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31); + return fp(ac + (ad >> 32) + (bc >> 32) + (mid >> 32), x.e + y.e + 64); +} + +FMT_FUNC fp get_cached_power(int min_exponent, int &pow10_exponent) { + const double one_over_log2_10 = 0.30102999566398114; // 1 / log2(10) + int index = static_cast(std::ceil( + (min_exponent + fp::significand_size - 1) * one_over_log2_10)); + // Decimal exponent of the first (smallest) cached power of 10. + const int first_dec_exp = -348; + // Difference between 2 consecutive decimal exponents in cached powers of 10. + const int dec_exp_step = 8; + index = (index - first_dec_exp - 1) / dec_exp_step + 1; + pow10_exponent = first_dec_exp + index * dec_exp_step; + return fp(data::POW10_SIGNIFICANDS[index], data::POW10_EXPONENTS[index]); +} + +// Generates output using Grisu2 digit-gen algorithm. +FMT_FUNC void grisu2_gen_digits( + const fp &scaled_value, const fp &scaled_upper, uint64_t delta, + char *buffer, size_t &size, int &dec_exp) { + internal::fp one(1ull << -scaled_upper.e, scaled_upper.e); + // hi (p1 in Grisu) contains the most significant digits of scaled_upper. + // hi = floor(scaled_upper / one). + uint32_t hi = static_cast(scaled_upper.f >> -one.e); + // lo (p2 in Grisu) contains the least significants digits of scaled_upper. + // lo = scaled_upper mod 1. + uint64_t lo = scaled_upper.f & (one.f - 1); + size = 0; + auto exp = count_digits(hi); // kappa in Grisu. + while (exp > 0) { + uint32_t digit = 0; + // This optimization by miloyip reduces the number of integer divisions by + // one per iteration. + switch (exp) { + case 10: digit = hi / 1000000000; hi %= 1000000000; break; + case 9: digit = hi / 100000000; hi %= 100000000; break; + case 8: digit = hi / 10000000; hi %= 10000000; break; + case 7: digit = hi / 1000000; hi %= 1000000; break; + case 6: digit = hi / 100000; hi %= 100000; break; + case 5: digit = hi / 10000; hi %= 10000; break; + case 4: digit = hi / 1000; hi %= 1000; break; + case 3: digit = hi / 100; hi %= 100; break; + case 2: digit = hi / 10; hi %= 10; break; + case 1: digit = hi; hi = 0; break; + default: + FMT_ASSERT(false, "invalid number of digits"); + } + if (digit != 0 || size != 0) + buffer[size++] = static_cast('0' + digit); + --exp; + uint64_t remainder = (static_cast(hi) << -one.e) + lo; + if (remainder <= delta) { + dec_exp += exp; + // TODO: use scaled_value + (void)scaled_value; + return; + } + } + for (;;) { + lo *= 10; + delta *= 10; + char digit = static_cast(lo >> -one.e); + if (digit != 0 || size != 0) + buffer[size++] = static_cast('0' + digit); + lo &= one.f - 1; + --exp; + if (lo < delta) { + dec_exp += exp; + return; + } + } +} + +FMT_FUNC void grisu2_format_positive(double value, char *buffer, size_t &size, + int &dec_exp) { + FMT_ASSERT(value > 0, "value is nonpositive"); + fp fp_value(value); + fp lower, upper; // w^- and w^+ in the Grisu paper. + fp_value.compute_boundaries(lower, upper); + // Find a cached power of 10 close to 1 / upper. + const int min_exp = -60; // alpha in Grisu. + auto dec_pow = get_cached_power( // \tilde{c}_{-k} in Grisu. + min_exp - (upper.e + fp::significand_size), dec_exp); + dec_exp = -dec_exp; + fp_value.normalize(); + fp scaled_value = fp_value * dec_pow; + fp scaled_lower = lower * dec_pow; // \tilde{M}^- in Grisu. + fp scaled_upper = upper * dec_pow; // \tilde{M}^+ in Grisu. + ++scaled_lower.f; // \tilde{M}^- + 1 ulp -> M^-_{\uparrow}. + --scaled_upper.f; // \tilde{M}^+ - 1 ulp -> M^+_{\downarrow}. + uint64_t delta = scaled_upper.f - scaled_lower.f; + grisu2_gen_digits(scaled_value, scaled_upper, delta, buffer, size, dec_exp); +} + +FMT_FUNC void round(char *buffer, size_t &size, int &exp, + int digits_to_remove) { + size -= to_unsigned(digits_to_remove); + exp += digits_to_remove; + int digit = buffer[size] - '0'; + // TODO: proper rounding and carry + if (digit > 5 || (digit == 5 && (digits_to_remove > 1 || + (buffer[size - 1] - '0') % 2) != 0)) { + ++buffer[size - 1]; + } +} + +// Writes the exponent exp in the form "[+-]d{1,3}" to buffer. +FMT_FUNC char *write_exponent(char *buffer, int exp) { + FMT_ASSERT(-1000 < exp && exp < 1000, "exponent out of range"); + if (exp < 0) { + *buffer++ = '-'; + exp = -exp; + } else { + *buffer++ = '+'; + } + if (exp >= 100) { + *buffer++ = static_cast('0' + exp / 100); + exp %= 100; + const char *d = data::DIGITS + exp * 2; + *buffer++ = d[0]; + *buffer++ = d[1]; + } else { + const char *d = data::DIGITS + exp * 2; + *buffer++ = d[0]; + *buffer++ = d[1]; + } + return buffer; +} + +FMT_FUNC void format_exp_notation( + char *buffer, size_t &size, int exp, int precision, bool upper) { + // Insert a decimal point after the first digit and add an exponent. + std::memmove(buffer + 2, buffer + 1, size - 1); + buffer[1] = '.'; + exp += static_cast(size) - 1; + int num_digits = precision - static_cast(size) + 1; + if (num_digits > 0) { + std::uninitialized_fill_n(buffer + size + 1, num_digits, '0'); + size += to_unsigned(num_digits); + } else if (num_digits < 0) { + round(buffer, size, exp, -num_digits); + } + char *p = buffer + size + 1; + *p++ = upper ? 'E' : 'e'; + size = to_unsigned(write_exponent(p, exp) - buffer); +} + +// Prettifies the output of the Grisu2 algorithm. +// The number is given as v = buffer * 10^exp. +FMT_FUNC void grisu2_prettify(char *buffer, size_t &size, int exp, + int precision, bool upper) { + // pow(10, full_exp - 1) <= v <= pow(10, full_exp). + int int_size = static_cast(size); + int full_exp = int_size + exp; + const int exp_threshold = 21; + if (int_size <= full_exp && full_exp <= exp_threshold) { + // 1234e7 -> 12340000000[.0+] + std::uninitialized_fill_n(buffer + int_size, full_exp - int_size, '0'); + char *p = buffer + full_exp; + if (precision > 0) { + *p++ = '.'; + std::uninitialized_fill_n(p, precision, '0'); + p += precision; + } + size = to_unsigned(p - buffer); + } else if (0 < full_exp && full_exp <= exp_threshold) { + // 1234e-2 -> 12.34[0+] + int fractional_size = -exp; + std::memmove(buffer + full_exp + 1, buffer + full_exp, + to_unsigned(fractional_size)); + buffer[full_exp] = '.'; + int num_zeros = precision - fractional_size; + if (num_zeros > 0) { + std::uninitialized_fill_n(buffer + size + 1, num_zeros, '0'); + size += to_unsigned(num_zeros); + } + ++size; + } else if (-6 < full_exp && full_exp <= 0) { + // 1234e-6 -> 0.001234 + int offset = 2 - full_exp; + std::memmove(buffer + offset, buffer, size); + buffer[0] = '0'; + buffer[1] = '.'; + std::uninitialized_fill_n(buffer + 2, -full_exp, '0'); + size = to_unsigned(int_size + offset); + } else { + format_exp_notation(buffer, size, exp, precision, upper); + } +} + +#if FMT_CLANG_VERSION +# define FMT_FALLTHROUGH [[clang::fallthrough]]; +#elif FMT_GCC_VERSION >= 700 +# define FMT_FALLTHROUGH [[gnu::fallthrough]]; +#else +# define FMT_FALLTHROUGH +#endif + +// Formats a nonnegative value using Grisu2 algorithm. Grisu2 doesn't give any +// guarantees on the shortness of the result. +FMT_FUNC void grisu2_format(double value, char *buffer, size_t &size, char type, + int precision, bool write_decimal_point) { + FMT_ASSERT(value >= 0, "value is negative"); + int dec_exp = 0; // K in Grisu. + if (value > 0) { + grisu2_format_positive(value, buffer, size, dec_exp); + } else { + *buffer = '0'; + size = 1; + } + const int default_precision = 6; + if (precision < 0) + precision = default_precision; + bool upper = false; + switch (type) { + case 'G': + upper = true; + FMT_FALLTHROUGH + case '\0': case 'g': { + int digits_to_remove = static_cast(size) - precision; + if (digits_to_remove > 0) { + round(buffer, size, dec_exp, digits_to_remove); + // Remove trailing zeros. + while (size > 0 && buffer[size - 1] == '0') { + --size; + ++dec_exp; + } + } + precision = 0; + break; + } + case 'F': + upper = true; + FMT_FALLTHROUGH + case 'f': { + int digits_to_remove = -dec_exp - precision; + if (digits_to_remove > 0) { + if (digits_to_remove >= static_cast(size)) + digits_to_remove = static_cast(size) - 1; + round(buffer, size, dec_exp, digits_to_remove); + } + break; + } + case 'e': case 'E': + format_exp_notation(buffer, size, dec_exp, precision, type == 'E'); + return; + } + if (write_decimal_point && precision < 1) + precision = 1; + grisu2_prettify(buffer, size, dec_exp, precision, upper); +} +} // namespace internal + +#if FMT_USE_WINDOWS_H + +FMT_FUNC internal::utf8_to_utf16::utf8_to_utf16(string_view s) { + static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16"; + if (s.size() > INT_MAX) + FMT_THROW(windows_error(ERROR_INVALID_PARAMETER, ERROR_MSG)); + int s_size = static_cast(s.size()); + if (s_size == 0) { + // MultiByteToWideChar does not support zero length, handle separately. + buffer_.resize(1); + buffer_[0] = 0; + return; + } + + int length = MultiByteToWideChar( + CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0); + if (length == 0) + FMT_THROW(windows_error(GetLastError(), ERROR_MSG)); + buffer_.resize(length + 1); + length = MultiByteToWideChar( + CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length); + if (length == 0) + FMT_THROW(windows_error(GetLastError(), ERROR_MSG)); + buffer_[length] = 0; +} + +FMT_FUNC internal::utf16_to_utf8::utf16_to_utf8(wstring_view s) { + if (int error_code = convert(s)) { + FMT_THROW(windows_error(error_code, + "cannot convert string from UTF-16 to UTF-8")); + } +} + +FMT_FUNC int internal::utf16_to_utf8::convert(wstring_view s) { + if (s.size() > INT_MAX) + return ERROR_INVALID_PARAMETER; + int s_size = static_cast(s.size()); + if (s_size == 0) { + // WideCharToMultiByte does not support zero length, handle separately. + buffer_.resize(1); + buffer_[0] = 0; + return 0; + } + + int length = WideCharToMultiByte( + CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL); + if (length == 0) + return GetLastError(); + buffer_.resize(length + 1); + length = WideCharToMultiByte( + CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL); + if (length == 0) + return GetLastError(); + buffer_[length] = 0; + return 0; +} + +FMT_FUNC void windows_error::init( + int err_code, string_view format_str, format_args args) { + error_code_ = err_code; + memory_buffer buffer; + internal::format_windows_error(buffer, err_code, vformat(format_str, args)); + std::runtime_error &base = *this; + base = std::runtime_error(to_string(buffer)); +} + +FMT_FUNC void internal::format_windows_error( + internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT { + FMT_TRY { + wmemory_buffer buf; + buf.resize(inline_buffer_size); + for (;;) { + wchar_t *system_message = &buf[0]; + int result = FormatMessageW( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + system_message, static_cast(buf.size()), FMT_NULL); + if (result != 0) { + utf16_to_utf8 utf8_message; + if (utf8_message.convert(system_message) == ERROR_SUCCESS) { + writer w(out); + w.write(message); + w.write(": "); + w.write(utf8_message); + return; + } + break; + } + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) + break; // Can't get error message, report error code instead. + buf.resize(buf.size() * 2); + } + } FMT_CATCH(...) {} + format_error_code(out, error_code, message); +} + +#endif // FMT_USE_WINDOWS_H + +FMT_FUNC void format_system_error( + internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT { + FMT_TRY { + memory_buffer buf; + buf.resize(inline_buffer_size); + for (;;) { + char *system_message = &buf[0]; + int result = safe_strerror(error_code, system_message, buf.size()); + if (result == 0) { + writer w(out); + w.write(message); + w.write(": "); + w.write(system_message); + return; + } + if (result != ERANGE) + break; // Can't get error message, report error code instead. + buf.resize(buf.size() * 2); + } + } FMT_CATCH(...) {} + format_error_code(out, error_code, message); +} + +template +void basic_fixed_buffer::grow(std::size_t) { + FMT_THROW(std::runtime_error("buffer overflow")); +} + +FMT_FUNC void internal::error_handler::on_error(const char *message) { + FMT_THROW(format_error(message)); +} + +FMT_FUNC void report_system_error( + int error_code, fmt::string_view message) FMT_NOEXCEPT { + report_error(format_system_error, error_code, message); +} + +#if FMT_USE_WINDOWS_H +FMT_FUNC void report_windows_error( + int error_code, fmt::string_view message) FMT_NOEXCEPT { + report_error(internal::format_windows_error, error_code, message); +} +#endif + +FMT_FUNC void vprint(std::FILE *f, string_view format_str, format_args args) { + memory_buffer buffer; + vformat_to(buffer, format_str, args); + std::fwrite(buffer.data(), 1, buffer.size(), f); +} + +FMT_FUNC void vprint(std::FILE *f, wstring_view format_str, wformat_args args) { + wmemory_buffer buffer; + vformat_to(buffer, format_str, args); + std::fwrite(buffer.data(), sizeof(wchar_t), buffer.size(), f); +} + +FMT_FUNC void vprint(string_view format_str, format_args args) { + vprint(stdout, format_str, args); +} + +FMT_FUNC void vprint(wstring_view format_str, wformat_args args) { + vprint(stdout, format_str, args); +} + +#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) +FMT_FUNC locale locale_provider::locale() { return fmt::locale(); } +#endif + +FMT_END_NAMESPACE + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif // FMT_FORMAT_INL_H_ diff --git a/include/fmt/format.h b/include/fmt/format.h new file mode 100644 index 00000000..9f522f39 --- /dev/null +++ b/include/fmt/format.h @@ -0,0 +1,3720 @@ +/* + Formatting library for C++ + + Copyright (c) 2012 - present, Victor Zverovich + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef FMT_FORMAT_H_ +#define FMT_FORMAT_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __clang__ +# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) +#else +# define FMT_CLANG_VERSION 0 +#endif + +#ifdef __INTEL_COMPILER +# define FMT_ICC_VERSION __INTEL_COMPILER +#elif defined(__ICL) +# define FMT_ICC_VERSION __ICL +#else +# define FMT_ICC_VERSION 0 +#endif + +#ifdef __NVCC__ +# define FMT_CUDA_VERSION (__CUDACC_VER_MAJOR__ * 100 + __CUDACC_VER_MINOR__) +#else +# define FMT_CUDA_VERSION 0 +#endif + +#include "core.h" + +#if FMT_GCC_VERSION >= 406 || FMT_CLANG_VERSION +# pragma GCC diagnostic push + +// Disable the warning about declaration shadowing because it affects too +// many valid cases. +# pragma GCC diagnostic ignored "-Wshadow" + +// Disable the warning about implicit conversions that may change the sign of +// an integer; silencing it otherwise would require many explicit casts. +# pragma GCC diagnostic ignored "-Wsign-conversion" +#endif + +# if FMT_CLANG_VERSION +# pragma GCC diagnostic ignored "-Wgnu-string-literal-operator-template" +# endif + +#ifdef _SECURE_SCL +# define FMT_SECURE_SCL _SECURE_SCL +#else +# define FMT_SECURE_SCL 0 +#endif + +#if FMT_SECURE_SCL +# include +#endif + +#ifdef __has_builtin +# define FMT_HAS_BUILTIN(x) __has_builtin(x) +#else +# define FMT_HAS_BUILTIN(x) 0 +#endif + +#ifdef __GNUC_LIBSTD__ +# define FMT_GNUC_LIBSTD_VERSION (__GNUC_LIBSTD__ * 100 + __GNUC_LIBSTD_MINOR__) +#endif + +#ifndef FMT_THROW +# if FMT_EXCEPTIONS +# if FMT_MSC_VER +FMT_BEGIN_NAMESPACE +namespace internal { +template +inline void do_throw(const Exception &x) { + // Silence unreachable code warnings in MSVC because these are nearly + // impossible to fix in a generic code. + volatile bool b = true; + if (b) + throw x; +} +} +FMT_END_NAMESPACE +# define FMT_THROW(x) fmt::internal::do_throw(x) +# else +# define FMT_THROW(x) throw x +# endif +# else +# define FMT_THROW(x) do { static_cast(sizeof(x)); assert(false); } while(false); +# endif +#endif + +#ifndef FMT_USE_USER_DEFINED_LITERALS +// For Intel's compiler and NVIDIA's compiler both it and the system gcc/msc +// must support UDLs. +# if (FMT_HAS_FEATURE(cxx_user_literals) || \ + FMT_GCC_VERSION >= 407 || FMT_MSC_VER >= 1900) && \ + (!(FMT_ICC_VERSION || FMT_CUDA_VERSION) || \ + FMT_ICC_VERSION >= 1500 || FMT_CUDA_VERSION >= 700) +# define FMT_USE_USER_DEFINED_LITERALS 1 +# else +# define FMT_USE_USER_DEFINED_LITERALS 0 +# endif +#endif + +// EDG C++ Front End based compilers (icc, nvcc) do not currently support UDL +// templates. +#if FMT_USE_USER_DEFINED_LITERALS && \ + FMT_ICC_VERSION == 0 && \ + FMT_CUDA_VERSION == 0 && \ + ((FMT_GCC_VERSION >= 600 && __cplusplus >= 201402L) || \ + (defined(FMT_CLANG_VERSION) && FMT_CLANG_VERSION >= 304)) +# define FMT_UDL_TEMPLATE 1 +#else +# define FMT_UDL_TEMPLATE 0 +#endif + +#ifndef FMT_USE_EXTERN_TEMPLATES +# ifndef FMT_HEADER_ONLY +# define FMT_USE_EXTERN_TEMPLATES \ + ((FMT_CLANG_VERSION >= 209 && __cplusplus >= 201103L) || \ + (FMT_GCC_VERSION >= 303 && FMT_HAS_GXX_CXX11)) +# else +# define FMT_USE_EXTERN_TEMPLATES 0 +# endif +#endif + +#if FMT_HAS_GXX_CXX11 || FMT_HAS_FEATURE(cxx_trailing_return) || \ + FMT_MSC_VER >= 1600 +# define FMT_USE_TRAILING_RETURN 1 +#else +# define FMT_USE_TRAILING_RETURN 0 +#endif + +#ifndef FMT_USE_GRISU +# define FMT_USE_GRISU 0 +#endif + +// __builtin_clz is broken in clang with Microsoft CodeGen: +// https://github.com/fmtlib/fmt/issues/519 +#ifndef _MSC_VER +# if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz) +# define FMT_BUILTIN_CLZ(n) __builtin_clz(n) +# endif + +# if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll) +# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) +# endif +#endif + +// A workaround for gcc 4.4 that doesn't support union members with ctors. +#if (FMT_GCC_VERSION && FMT_GCC_VERSION <= 404) || \ + (FMT_MSC_VER && FMT_MSC_VER <= 1800) +# define FMT_UNION struct +#else +# define FMT_UNION union +#endif + +// Some compilers masquerade as both MSVC and GCC-likes or otherwise support +// __builtin_clz and __builtin_clzll, so only define FMT_BUILTIN_CLZ using the +// MSVC intrinsics if the clz and clzll builtins are not available. +#if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL) && !defined(_MANAGED) +# include // _BitScanReverse, _BitScanReverse64 + +FMT_BEGIN_NAMESPACE +namespace internal { +// Avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning. +# ifndef __clang__ +# pragma intrinsic(_BitScanReverse) +# endif +inline uint32_t clz(uint32_t x) { + unsigned long r = 0; + _BitScanReverse(&r, x); + + assert(x != 0); + // Static analysis complains about using uninitialized data + // "r", but the only way that can happen is if "x" is 0, + // which the callers guarantee to not happen. +# pragma warning(suppress: 6102) + return 31 - r; +} +# define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n) + +# if defined(_WIN64) && !defined(__clang__) +# pragma intrinsic(_BitScanReverse64) +# endif + +inline uint32_t clzll(uint64_t x) { + unsigned long r = 0; +# ifdef _WIN64 + _BitScanReverse64(&r, x); +# else + // Scan the high 32 bits. + if (_BitScanReverse(&r, static_cast(x >> 32))) + return 63 - (r + 32); + + // Scan the low 32 bits. + _BitScanReverse(&r, static_cast(x)); +# endif + + assert(x != 0); + // Static analysis complains about using uninitialized data + // "r", but the only way that can happen is if "x" is 0, + // which the callers guarantee to not happen. +# pragma warning(suppress: 6102) + return 63 - r; +} +# define FMT_BUILTIN_CLZLL(n) fmt::internal::clzll(n) +} +FMT_END_NAMESPACE +#endif + +FMT_BEGIN_NAMESPACE +namespace internal { + +// An equivalent of `*reinterpret_cast(&source)` that doesn't produce +// undefined behavior (e.g. due to type aliasing). +// Example: uint64_t d = bit_cast(2.718); +template +inline Dest bit_cast(const Source& source) { + static_assert(sizeof(Dest) == sizeof(Source), "size mismatch"); + Dest dest; + std::memcpy(&dest, &source, sizeof(dest)); + return dest; +} + +// An implementation of begin and end for pre-C++11 compilers such as gcc 4. +template +FMT_CONSTEXPR auto begin(const C &c) -> decltype(c.begin()) { + return c.begin(); +} +template +FMT_CONSTEXPR T *begin(T (&array)[N]) FMT_NOEXCEPT { return array; } +template +FMT_CONSTEXPR auto end(const C &c) -> decltype(c.end()) { return c.end(); } +template +FMT_CONSTEXPR T *end(T (&array)[N]) FMT_NOEXCEPT { return array + N; } + +// For std::result_of in gcc 4.4. +template +struct function { + template + struct result { typedef Result type; }; +}; + +struct dummy_int { + int data[2]; + operator int() const { return 0; } +}; +typedef std::numeric_limits fputil; + +// Dummy implementations of system functions such as signbit and ecvt called +// if the latter are not available. +inline dummy_int signbit(...) { return dummy_int(); } +inline dummy_int _ecvt_s(...) { return dummy_int(); } +inline dummy_int isinf(...) { return dummy_int(); } +inline dummy_int _finite(...) { return dummy_int(); } +inline dummy_int isnan(...) { return dummy_int(); } +inline dummy_int _isnan(...) { return dummy_int(); } + +inline bool use_grisu() { + return FMT_USE_GRISU && std::numeric_limits::is_iec559; +} + +// Formats value using Grisu2 algorithm: +// https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf +FMT_API void grisu2_format(double value, char *buffer, size_t &size, char type, + int precision, bool write_decimal_point); + +template +typename Allocator::value_type *allocate(Allocator& alloc, std::size_t n) { +#if __cplusplus >= 201103L || FMT_MSC_VER >= 1700 + return std::allocator_traits::allocate(alloc, n); +#else + return alloc.allocate(n); +#endif +} + +// A helper function to suppress bogus "conditional expression is constant" +// warnings. +template +inline T const_check(T value) { return value; } +} // namespace internal +FMT_END_NAMESPACE + +namespace std { +// Standard permits specialization of std::numeric_limits. This specialization +// is used to resolve ambiguity between isinf and std::isinf in glibc: +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=48891 +// and the same for isnan and signbit. +template <> +class numeric_limits : + public std::numeric_limits { + public: + // Portable version of isinf. + template + static bool isinfinity(T x) { + using namespace fmt::internal; + // The resolution "priority" is: + // isinf macro > std::isinf > ::isinf > fmt::internal::isinf + if (const_check(sizeof(isinf(x)) != sizeof(dummy_int))) + return isinf(x) != 0; + return !_finite(static_cast(x)); + } + + // Portable version of isnan. + template + static bool isnotanumber(T x) { + using namespace fmt::internal; + if (const_check(sizeof(isnan(x)) != sizeof(fmt::internal::dummy_int))) + return isnan(x) != 0; + return _isnan(static_cast(x)) != 0; + } + + // Portable version of signbit. + static bool isnegative(double x) { + using namespace fmt::internal; + if (const_check(sizeof(signbit(x)) != sizeof(fmt::internal::dummy_int))) + return signbit(x) != 0; + if (x < 0) return true; + if (!isnotanumber(x)) return false; + int dec = 0, sign = 0; + char buffer[2]; // The buffer size must be >= 2 or _ecvt_s will fail. + _ecvt_s(buffer, sizeof(buffer), x, 0, &dec, &sign); + return sign != 0; + } +}; +} // namespace std + +FMT_BEGIN_NAMESPACE +template +class basic_writer; + +template +class output_range { + private: + OutputIt it_; + + // Unused yet. + typedef void sentinel; + sentinel end() const; + + public: + typedef OutputIt iterator; + typedef T value_type; + + explicit output_range(OutputIt it): it_(it) {} + OutputIt begin() const { return it_; } +}; + +// A range where begin() returns back_insert_iterator. +template +class back_insert_range: + public output_range> { + typedef output_range> base; + public: + typedef typename Container::value_type value_type; + + back_insert_range(Container &c): base(std::back_inserter(c)) {} + back_insert_range(typename base::iterator it): base(it) {} +}; + +typedef basic_writer> writer; +typedef basic_writer> wwriter; + +/** A formatting error such as invalid format string. */ +class format_error : public std::runtime_error { + public: + explicit format_error(const char *message) + : std::runtime_error(message) {} + + explicit format_error(const std::string &message) + : std::runtime_error(message) {} +}; + +namespace internal { + +#if FMT_SECURE_SCL +template +struct checked { typedef stdext::checked_array_iterator type; }; + +// Make a checked iterator to avoid warnings on MSVC. +template +inline stdext::checked_array_iterator make_checked(T *p, std::size_t size) { + return {p, size}; +} +#else +template +struct checked { typedef T *type; }; +template +inline T *make_checked(T *p, std::size_t) { return p; } +#endif + +template +template +void basic_buffer::append(const U *begin, const U *end) { + std::size_t new_size = size_ + internal::to_unsigned(end - begin); + reserve(new_size); + std::uninitialized_copy(begin, end, + internal::make_checked(ptr_, capacity_) + size_); + size_ = new_size; +} +} // namespace internal + +// A UTF-8 code unit type. +struct char8_t { + char value; + FMT_CONSTEXPR explicit operator bool() const FMT_NOEXCEPT { + return value != 0; + } +}; + +// A UTF-8 string view. +class u8string_view : public basic_string_view { + private: + typedef basic_string_view base; + + public: + using basic_string_view::basic_string_view; + using basic_string_view::char_type; + + u8string_view(const char *s) + : base(reinterpret_cast(s)) {} + + u8string_view(const char *s, size_t count) FMT_NOEXCEPT + : base(reinterpret_cast(s), count) {} +}; + +#if FMT_USE_USER_DEFINED_LITERALS +inline namespace literals { +inline u8string_view operator"" _u(const char *s, std::size_t n) { + return u8string_view(s, n); +} +} +#endif + +// A wrapper around std::locale used to reduce compile times since +// is very heavy. +class locale; + +class locale_provider { + public: + virtual ~locale_provider() {} + virtual fmt::locale locale(); +}; + +// The number of characters to store in the basic_memory_buffer object itself +// to avoid dynamic memory allocation. +enum { inline_buffer_size = 500 }; + +/** + \rst + A dynamically growing memory buffer for trivially copyable/constructible types + with the first ``SIZE`` elements stored in the object itself. + + You can use one of the following typedefs for common character types: + + +----------------+------------------------------+ + | Type | Definition | + +================+==============================+ + | memory_buffer | basic_memory_buffer | + +----------------+------------------------------+ + | wmemory_buffer | basic_memory_buffer | + +----------------+------------------------------+ + + **Example**:: + + fmt::memory_buffer out; + format_to(out, "The answer is {}.", 42); + + This will write the following output to the ``out`` object: + + .. code-block:: none + + The answer is 42. + + The output can be converted to an ``std::string`` with ``to_string(out)``. + \endrst + */ +template > +class basic_memory_buffer: private Allocator, public internal::basic_buffer { + private: + T store_[SIZE]; + + // Deallocate memory allocated by the buffer. + void deallocate() { + T* data = this->data(); + if (data != store_) Allocator::deallocate(data, this->capacity()); + } + + protected: + void grow(std::size_t size) FMT_OVERRIDE; + + public: + explicit basic_memory_buffer(const Allocator &alloc = Allocator()) + : Allocator(alloc) { + this->set(store_, SIZE); + } + ~basic_memory_buffer() { deallocate(); } + + private: + // Move data from other to this buffer. + void move(basic_memory_buffer &other) { + Allocator &this_alloc = *this, &other_alloc = other; + this_alloc = std::move(other_alloc); + T* data = other.data(); + std::size_t size = other.size(), capacity = other.capacity(); + if (data == other.store_) { + this->set(store_, capacity); + std::uninitialized_copy(other.store_, other.store_ + size, + internal::make_checked(store_, capacity)); + } else { + this->set(data, capacity); + // Set pointer to the inline array so that delete is not called + // when deallocating. + other.set(other.store_, 0); + } + this->resize(size); + } + + public: + /** + \rst + Constructs a :class:`fmt::basic_memory_buffer` object moving the content + of the other object to it. + \endrst + */ + basic_memory_buffer(basic_memory_buffer &&other) { + move(other); + } + + /** + \rst + Moves the content of the other ``basic_memory_buffer`` object to this one. + \endrst + */ + basic_memory_buffer &operator=(basic_memory_buffer &&other) { + assert(this != &other); + deallocate(); + move(other); + return *this; + } + + // Returns a copy of the allocator associated with this buffer. + Allocator get_allocator() const { return *this; } +}; + +template +void basic_memory_buffer::grow(std::size_t size) { + std::size_t old_capacity = this->capacity(); + std::size_t new_capacity = old_capacity + old_capacity / 2; + if (size > new_capacity) + new_capacity = size; + T *old_data = this->data(); + T *new_data = internal::allocate(*this, new_capacity); + // The following code doesn't throw, so the raw pointer above doesn't leak. + std::uninitialized_copy(old_data, old_data + this->size(), + internal::make_checked(new_data, new_capacity)); + this->set(new_data, new_capacity); + // deallocate must not throw according to the standard, but even if it does, + // the buffer already uses the new storage and will deallocate it in + // destructor. + if (old_data != store_) + Allocator::deallocate(old_data, old_capacity); +} + +typedef basic_memory_buffer memory_buffer; +typedef basic_memory_buffer wmemory_buffer; + +/** + \rst + A fixed-size memory buffer. For a dynamically growing buffer use + :class:`fmt::basic_memory_buffer`. + + Trying to increase the buffer size past the initial capacity will throw + ``std::runtime_error``. + \endrst + */ +template +class basic_fixed_buffer : public internal::basic_buffer { + public: + /** + \rst + Constructs a :class:`fmt::basic_fixed_buffer` object for *array* of the + given size. + \endrst + */ + basic_fixed_buffer(Char *array, std::size_t size) { + this->set(array, size); + } + + /** + \rst + Constructs a :class:`fmt::basic_fixed_buffer` object for *array* of the + size known at compile time. + \endrst + */ + template + explicit basic_fixed_buffer(Char (&array)[SIZE]) { + this->set(array, SIZE); + } + + protected: + FMT_API void grow(std::size_t size) FMT_OVERRIDE; +}; + +namespace internal { + +template +struct char_traits; + +template <> +struct char_traits { + // Formats a floating-point number. + template + FMT_API static int format_float(char *buffer, std::size_t size, + const char *format, int precision, T value); +}; + +template <> +struct char_traits { + template + FMT_API static int format_float(wchar_t *buffer, std::size_t size, + const wchar_t *format, int precision, T value); +}; + +#if FMT_USE_EXTERN_TEMPLATES +extern template int char_traits::format_float( + char *buffer, std::size_t size, const char* format, int precision, + double value); +extern template int char_traits::format_float( + char *buffer, std::size_t size, const char* format, int precision, + long double value); + +extern template int char_traits::format_float( + wchar_t *buffer, std::size_t size, const wchar_t* format, int precision, + double value); +extern template int char_traits::format_float( + wchar_t *buffer, std::size_t size, const wchar_t* format, int precision, + long double value); +#endif + +template +inline typename std::enable_if< + is_contiguous::value, + typename checked::type>::type + reserve(std::back_insert_iterator &it, std::size_t n) { + Container &c = internal::get_container(it); + std::size_t size = c.size(); + c.resize(size + n); + return make_checked(&c[size], n); +} + +template +inline Iterator &reserve(Iterator &it, std::size_t) { return it; } + +template +class null_terminating_iterator; + +template +FMT_CONSTEXPR_DECL const Char *pointer_from(null_terminating_iterator it); + +// An iterator that produces a null terminator on *end. This simplifies parsing +// and allows comparing the performance of processing a null-terminated string +// vs string_view. +template +class null_terminating_iterator { + public: + typedef std::ptrdiff_t difference_type; + typedef Char value_type; + typedef const Char* pointer; + typedef const Char& reference; + typedef std::random_access_iterator_tag iterator_category; + + null_terminating_iterator() : ptr_(0), end_(0) {} + + FMT_CONSTEXPR null_terminating_iterator(const Char *ptr, const Char *end) + : ptr_(ptr), end_(end) {} + + template + FMT_CONSTEXPR explicit null_terminating_iterator(const Range &r) + : ptr_(r.begin()), end_(r.end()) {} + + FMT_CONSTEXPR null_terminating_iterator &operator=(const Char *ptr) { + assert(ptr <= end_); + ptr_ = ptr; + return *this; + } + + FMT_CONSTEXPR Char operator*() const { + return ptr_ != end_ ? *ptr_ : 0; + } + + FMT_CONSTEXPR null_terminating_iterator operator++() { + ++ptr_; + return *this; + } + + FMT_CONSTEXPR null_terminating_iterator operator++(int) { + null_terminating_iterator result(*this); + ++ptr_; + return result; + } + + FMT_CONSTEXPR null_terminating_iterator operator--() { + --ptr_; + return *this; + } + + FMT_CONSTEXPR null_terminating_iterator operator+(difference_type n) { + return null_terminating_iterator(ptr_ + n, end_); + } + + FMT_CONSTEXPR null_terminating_iterator operator-(difference_type n) { + return null_terminating_iterator(ptr_ - n, end_); + } + + FMT_CONSTEXPR null_terminating_iterator operator+=(difference_type n) { + ptr_ += n; + return *this; + } + + FMT_CONSTEXPR difference_type operator-( + null_terminating_iterator other) const { + return ptr_ - other.ptr_; + } + + FMT_CONSTEXPR bool operator!=(null_terminating_iterator other) const { + return ptr_ != other.ptr_; + } + + bool operator>=(null_terminating_iterator other) const { + return ptr_ >= other.ptr_; + } + + // This should be a friend specialization pointer_from but the latter + // doesn't compile by gcc 5.1 due to a compiler bug. + template + friend FMT_CONSTEXPR_DECL const CharT *pointer_from( + null_terminating_iterator it); + + private: + const Char *ptr_; + const Char *end_; +}; + +template +FMT_CONSTEXPR const T *pointer_from(const T *p) { return p; } + +template +FMT_CONSTEXPR const Char *pointer_from(null_terminating_iterator it) { + return it.ptr_; +} + +// An output iterator that counts the number of objects written to it and +// discards them. +template +class counting_iterator { + private: + std::size_t count_; + mutable T blackhole_; + + public: + typedef std::output_iterator_tag iterator_category; + typedef T value_type; + typedef std::ptrdiff_t difference_type; + typedef T* pointer; + typedef T& reference; + typedef counting_iterator _Unchecked_type; // Mark iterator as checked. + + counting_iterator(): count_(0) {} + + std::size_t count() const { return count_; } + + counting_iterator& operator++() { + ++count_; + return *this; + } + + counting_iterator operator++(int) { + auto it = *this; + ++*this; + return it; + } + + T &operator*() const { return blackhole_; } +}; + +// An output iterator that truncates the output and counts the number of objects +// written to it. +template +class truncating_iterator { + private: + typedef std::iterator_traits traits; + + OutputIt out_; + std::size_t limit_; + std::size_t count_; + mutable typename traits::value_type blackhole_; + + public: + typedef std::output_iterator_tag iterator_category; + typedef typename traits::value_type value_type; + typedef typename traits::difference_type difference_type; + typedef typename traits::pointer pointer; + typedef typename traits::reference reference; + typedef truncating_iterator _Unchecked_type; // Mark iterator as checked. + + truncating_iterator(OutputIt out, std::size_t limit) + : out_(out), limit_(limit), count_(0) {} + + OutputIt base() const { return out_; } + std::size_t count() const { return count_; } + + truncating_iterator& operator++() { + if (count_++ < limit_) + ++out_; + return *this; + } + + truncating_iterator operator++(int) { + auto it = *this; + ++*this; + return it; + } + + reference operator*() const { return count_ < limit_ ? *out_ : blackhole_; } +}; + +// Returns true if value is negative, false otherwise. +// Same as (value < 0) but doesn't produce warnings if T is an unsigned type. +template +FMT_CONSTEXPR typename std::enable_if< + std::numeric_limits::is_signed, bool>::type is_negative(T value) { + return value < 0; +} +template +FMT_CONSTEXPR typename std::enable_if< + !std::numeric_limits::is_signed, bool>::type is_negative(T) { + return false; +} + +template +struct int_traits { + // Smallest of uint32_t and uint64_t that is large enough to represent + // all values of T. + typedef typename std::conditional< + std::numeric_limits::digits <= 32, uint32_t, uint64_t>::type main_type; +}; + +// Static data is placed in this class template to allow header-only +// configuration. +template +struct FMT_API basic_data { + static const uint32_t POWERS_OF_10_32[]; + static const uint32_t ZERO_OR_POWERS_OF_10_32[]; + static const uint64_t ZERO_OR_POWERS_OF_10_64[]; + static const uint64_t POW10_SIGNIFICANDS[]; + static const int16_t POW10_EXPONENTS[]; + static const char DIGITS[]; + static const char RESET_COLOR[]; + static const wchar_t WRESET_COLOR[]; +}; + +#if FMT_USE_EXTERN_TEMPLATES +extern template struct basic_data; +#endif + +typedef basic_data<> data; + +#ifdef FMT_BUILTIN_CLZLL +// Returns the number of decimal digits in n. Leading zeros are not counted +// except for n == 0 in which case count_digits returns 1. +inline unsigned count_digits(uint64_t n) { + // Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 + // and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits. + int t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12; + return to_unsigned(t) - (n < data::ZERO_OR_POWERS_OF_10_64[t]) + 1; +} +#else +// Fallback version of count_digits used when __builtin_clz is not available. +inline unsigned count_digits(uint64_t n) { + unsigned count = 1; + for (;;) { + // Integer division is slow so do it for a group of four digits instead + // of for every digit. The idea comes from the talk by Alexandrescu + // "Three Optimization Tips for C++". See speed-test for a comparison. + if (n < 10) return count; + if (n < 100) return count + 1; + if (n < 1000) return count + 2; + if (n < 10000) return count + 3; + n /= 10000u; + count += 4; + } +} +#endif + +// Counts the number of code points in a UTF-8 string. +FMT_API size_t count_code_points(u8string_view s); + +#if FMT_HAS_CPP_ATTRIBUTE(always_inline) +# define FMT_ALWAYS_INLINE __attribute__((always_inline)) +#else +# define FMT_ALWAYS_INLINE +#endif + +template +inline char *lg(uint32_t n, Handler h) FMT_ALWAYS_INLINE; + +// Computes g = floor(log10(n)) and calls h.on(n); +template +inline char *lg(uint32_t n, Handler h) { + return n < 100 ? n < 10 ? h.template on<0>(n) : h.template on<1>(n) + : n < 1000000 + ? n < 10000 ? n < 1000 ? h.template on<2>(n) + : h.template on<3>(n) + : n < 100000 ? h.template on<4>(n) + : h.template on<5>(n) + : n < 100000000 ? n < 10000000 ? h.template on<6>(n) + : h.template on<7>(n) + : n < 1000000000 ? h.template on<8>(n) + : h.template on<9>(n); +} + +// An lg handler that formats a decimal number. +// Usage: lg(n, decimal_formatter(buffer)); +class decimal_formatter { + private: + char *buffer_; + + void write_pair(unsigned N, uint32_t index) { + std::memcpy(buffer_ + N, data::DIGITS + index * 2, 2); + } + + public: + explicit decimal_formatter(char *buf) : buffer_(buf) {} + + template char *on(uint32_t u) { + if (N == 0) { + *buffer_ = static_cast(u) + '0'; + } else if (N == 1) { + write_pair(0, u); + } else { + // The idea of using 4.32 fixed-point numbers is based on + // https://github.com/jeaiii/itoa + unsigned n = N - 1; + unsigned a = n / 5 * n * 53 / 16; + uint64_t t = ((1ULL << (32 + a)) / + data::ZERO_OR_POWERS_OF_10_32[n] + 1 - n / 9); + t = ((t * u) >> a) + n / 5 * 4; + write_pair(0, t >> 32); + for (unsigned i = 2; i < N; i += 2) { + t = 100ULL * static_cast(t); + write_pair(i, t >> 32); + } + if (N % 2 == 0) { + buffer_[N] = static_cast( + (10ULL * static_cast(t)) >> 32) + '0'; + } + } + return buffer_ += N + 1; + } +}; + +// An lg handler that formats a decimal number with a terminating null. +class decimal_formatter_null : public decimal_formatter { + public: + explicit decimal_formatter_null(char *buf) : decimal_formatter(buf) {} + + template char *on(uint32_t u) { + char *buf = decimal_formatter::on(u); + *buf = '\0'; + return buf; + } +}; + +#ifdef FMT_BUILTIN_CLZ +// Optional version of count_digits for better performance on 32-bit platforms. +inline unsigned count_digits(uint32_t n) { + int t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12; + return to_unsigned(t) - (n < data::ZERO_OR_POWERS_OF_10_32[t]) + 1; +} +#endif + +// A functor that doesn't add a thousands separator. +struct no_thousands_sep { + typedef char char_type; + + template + void operator()(Char *) {} +}; + +// A functor that adds a thousands separator. +template +class add_thousands_sep { + private: + basic_string_view sep_; + + // Index of a decimal digit with the least significant digit having index 0. + unsigned digit_index_; + + public: + typedef Char char_type; + + explicit add_thousands_sep(basic_string_view sep) + : sep_(sep), digit_index_(0) {} + + void operator()(Char *&buffer) { + if (++digit_index_ % 3 != 0) + return; + buffer -= sep_.size(); + std::uninitialized_copy(sep_.data(), sep_.data() + sep_.size(), + internal::make_checked(buffer, sep_.size())); + } +}; + +template +FMT_API Char thousands_sep(locale_provider *lp); + +// Formats a decimal unsigned integer value writing into buffer. +// thousands_sep is a functor that is called after writing each char to +// add a thousands separator if necessary. +template +inline Char *format_decimal(Char *buffer, UInt value, unsigned num_digits, + ThousandsSep thousands_sep) { + buffer += num_digits; + Char *end = buffer; + while (value >= 100) { + // Integer division is slow so do it for a group of two digits instead + // of for every digit. The idea comes from the talk by Alexandrescu + // "Three Optimization Tips for C++". See speed-test for a comparison. + unsigned index = static_cast((value % 100) * 2); + value /= 100; + *--buffer = data::DIGITS[index + 1]; + thousands_sep(buffer); + *--buffer = data::DIGITS[index]; + thousands_sep(buffer); + } + if (value < 10) { + *--buffer = static_cast('0' + value); + return end; + } + unsigned index = static_cast(value * 2); + *--buffer = data::DIGITS[index + 1]; + thousands_sep(buffer); + *--buffer = data::DIGITS[index]; + return end; +} + +template +inline Iterator format_decimal( + Iterator out, UInt value, unsigned num_digits, ThousandsSep sep) { + typedef typename ThousandsSep::char_type char_type; + // Buffer should be large enough to hold all digits (digits10 + 1) and null. + char_type buffer[std::numeric_limits::digits10 + 2]; + format_decimal(buffer, value, num_digits, sep); + return std::copy_n(buffer, num_digits, out); +} + +template +inline It format_decimal(It out, UInt value, unsigned num_digits) { + return format_decimal(out, value, num_digits, no_thousands_sep()); +} + +template +inline Char *format_uint(Char *buffer, UInt value, unsigned num_digits, + bool upper = false) { + buffer += num_digits; + Char *end = buffer; + do { + const char *digits = upper ? "0123456789ABCDEF" : "0123456789abcdef"; + unsigned digit = (value & ((1 << BASE_BITS) - 1)); + *--buffer = BASE_BITS < 4 ? static_cast('0' + digit) : digits[digit]; + } while ((value >>= BASE_BITS) != 0); + return end; +} + +template +inline It format_uint(It out, UInt value, unsigned num_digits, + bool upper = false) { + // Buffer should be large enough to hold all digits (digits / BASE_BITS + 1) + // and null. + char buffer[std::numeric_limits::digits / BASE_BITS + 2]; + format_uint(buffer, value, num_digits, upper); + return std::copy_n(buffer, num_digits, out); +} + +#ifndef _WIN32 +# define FMT_USE_WINDOWS_H 0 +#elif !defined(FMT_USE_WINDOWS_H) +# define FMT_USE_WINDOWS_H 1 +#endif + +// Define FMT_USE_WINDOWS_H to 0 to disable use of windows.h. +// All the functionality that relies on it will be disabled too. +#if FMT_USE_WINDOWS_H +// A converter from UTF-8 to UTF-16. +// It is only provided for Windows since other systems support UTF-8 natively. +class utf8_to_utf16 { + private: + wmemory_buffer buffer_; + + public: + FMT_API explicit utf8_to_utf16(string_view s); + operator wstring_view() const { return wstring_view(&buffer_[0], size()); } + size_t size() const { return buffer_.size() - 1; } + const wchar_t *c_str() const { return &buffer_[0]; } + std::wstring str() const { return std::wstring(&buffer_[0], size()); } +}; + +// A converter from UTF-16 to UTF-8. +// It is only provided for Windows since other systems support UTF-8 natively. +class utf16_to_utf8 { + private: + memory_buffer buffer_; + + public: + utf16_to_utf8() {} + FMT_API explicit utf16_to_utf8(wstring_view s); + operator string_view() const { return string_view(&buffer_[0], size()); } + size_t size() const { return buffer_.size() - 1; } + const char *c_str() const { return &buffer_[0]; } + std::string str() const { return std::string(&buffer_[0], size()); } + + // Performs conversion returning a system error code instead of + // throwing exception on conversion error. This method may still throw + // in case of memory allocation error. + FMT_API int convert(wstring_view s); +}; + +FMT_API void format_windows_error(fmt::internal::buffer &out, int error_code, + fmt::string_view message) FMT_NOEXCEPT; +#endif + +template +struct null {}; +} // namespace internal + +enum alignment { + ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC +}; + +// Flags. +enum {SIGN_FLAG = 1, PLUS_FLAG = 2, MINUS_FLAG = 4, HASH_FLAG = 8}; + +enum format_spec_tag {fill_tag, align_tag, width_tag, type_tag}; + +// Format specifier. +template +class format_spec { + private: + T value_; + + public: + typedef T value_type; + + explicit format_spec(T value) : value_(value) {} + + T value() const { return value_; } +}; + +// template +// typedef format_spec fill_spec; +template +class fill_spec : public format_spec { + public: + explicit fill_spec(Char value) : format_spec(value) {} +}; + +typedef format_spec width_spec; +typedef format_spec type_spec; + +// An empty format specifier. +struct empty_spec {}; + +// An alignment specifier. +struct align_spec : empty_spec { + unsigned width_; + // Fill is always wchar_t and cast to char if necessary to avoid having + // two specialization of AlignSpec and its subclasses. + wchar_t fill_; + alignment align_; + + FMT_CONSTEXPR align_spec( + unsigned width, wchar_t fill, alignment align = ALIGN_DEFAULT) + : width_(width), fill_(fill), align_(align) {} + + FMT_CONSTEXPR unsigned width() const { return width_; } + FMT_CONSTEXPR wchar_t fill() const { return fill_; } + FMT_CONSTEXPR alignment align() const { return align_; } + + int precision() const { return -1; } +}; + +// Format specifiers. +template +class basic_format_specs : public align_spec { + public: + unsigned flags_; + int precision_; + Char type_; + + FMT_CONSTEXPR basic_format_specs( + unsigned width = 0, char type = 0, wchar_t fill = ' ') + : align_spec(width, fill), flags_(0), precision_(-1), type_(type) {} + + FMT_CONSTEXPR bool flag(unsigned f) const { return (flags_ & f) != 0; } + FMT_CONSTEXPR int precision() const { return precision_; } + FMT_CONSTEXPR Char type() const { return type_; } +}; + +typedef basic_format_specs format_specs; + +template +FMT_CONSTEXPR unsigned basic_parse_context::next_arg_id() { + if (next_arg_id_ >= 0) + return internal::to_unsigned(next_arg_id_++); + on_error("cannot switch from manual to automatic argument indexing"); + return 0; +} + +namespace internal { + +template +struct format_string_traits< + S, typename std::enable_if::value>::type>: + format_string_traits_base {}; + +template +FMT_CONSTEXPR void handle_int_type_spec(Char spec, Handler &&handler) { + switch (spec) { + case 0: case 'd': + handler.on_dec(); + break; + case 'x': case 'X': + handler.on_hex(); + break; + case 'b': case 'B': + handler.on_bin(); + break; + case 'o': + handler.on_oct(); + break; + case 'n': + handler.on_num(); + break; + default: + handler.on_error(); + } +} + +template +FMT_CONSTEXPR void handle_float_type_spec(Char spec, Handler &&handler) { + switch (spec) { + case 0: case 'g': case 'G': + handler.on_general(); + break; + case 'e': case 'E': + handler.on_exp(); + break; + case 'f': case 'F': + handler.on_fixed(); + break; + case 'a': case 'A': + handler.on_hex(); + break; + default: + handler.on_error(); + break; + } +} + +template +FMT_CONSTEXPR void handle_char_specs( + const basic_format_specs *specs, Handler &&handler) { + if (!specs) return handler.on_char(); + if (specs->type() && specs->type() != 'c') return handler.on_int(); + if (specs->align() == ALIGN_NUMERIC || specs->flag(~0u) != 0) + handler.on_error("invalid format specifier for char"); + handler.on_char(); +} + +template +FMT_CONSTEXPR void handle_cstring_type_spec(Char spec, Handler &&handler) { + if (spec == 0 || spec == 's') + handler.on_string(); + else if (spec == 'p') + handler.on_pointer(); + else + handler.on_error("invalid type specifier"); +} + +template +FMT_CONSTEXPR void check_string_type_spec(Char spec, ErrorHandler &&eh) { + if (spec != 0 && spec != 's') + eh.on_error("invalid type specifier"); +} + +template +FMT_CONSTEXPR void check_pointer_type_spec(Char spec, ErrorHandler &&eh) { + if (spec != 0 && spec != 'p') + eh.on_error("invalid type specifier"); +} + +template +class int_type_checker : private ErrorHandler { + public: + FMT_CONSTEXPR explicit int_type_checker(ErrorHandler eh) : ErrorHandler(eh) {} + + FMT_CONSTEXPR void on_dec() {} + FMT_CONSTEXPR void on_hex() {} + FMT_CONSTEXPR void on_bin() {} + FMT_CONSTEXPR void on_oct() {} + FMT_CONSTEXPR void on_num() {} + + FMT_CONSTEXPR void on_error() { + ErrorHandler::on_error("invalid type specifier"); + } +}; + +template +class float_type_checker : private ErrorHandler { + public: + FMT_CONSTEXPR explicit float_type_checker(ErrorHandler eh) + : ErrorHandler(eh) {} + + FMT_CONSTEXPR void on_general() {} + FMT_CONSTEXPR void on_exp() {} + FMT_CONSTEXPR void on_fixed() {} + FMT_CONSTEXPR void on_hex() {} + + FMT_CONSTEXPR void on_error() { + ErrorHandler::on_error("invalid type specifier"); + } +}; + +template +class char_specs_checker : public ErrorHandler { + private: + CharType type_; + + public: + FMT_CONSTEXPR char_specs_checker(CharType type, ErrorHandler eh) + : ErrorHandler(eh), type_(type) {} + + FMT_CONSTEXPR void on_int() { + handle_int_type_spec(type_, int_type_checker(*this)); + } + FMT_CONSTEXPR void on_char() {} +}; + +template +class cstring_type_checker : public ErrorHandler { + public: + FMT_CONSTEXPR explicit cstring_type_checker(ErrorHandler eh) + : ErrorHandler(eh) {} + + FMT_CONSTEXPR void on_string() {} + FMT_CONSTEXPR void on_pointer() {} +}; + +template +void arg_map::init(const basic_format_args &args) { + if (map_) + return; + map_ = new entry[args.max_size()]; + bool use_values = args.type(max_packed_args - 1) == internal::none_type; + if (use_values) { + for (unsigned i = 0;/*nothing*/; ++i) { + internal::type arg_type = args.type(i); + switch (arg_type) { + case internal::none_type: + return; + case internal::named_arg_type: + push_back(args.values_[i]); + break; + default: + break; // Do nothing. + } + } + } + for (unsigned i = 0; ; ++i) { + switch (args.args_[i].type_) { + case internal::none_type: + return; + case internal::named_arg_type: + push_back(args.args_[i].value_); + break; + default: + break; // Do nothing. + } + } +} + +template +class arg_formatter_base { + public: + typedef typename Range::value_type char_type; + typedef decltype(internal::declval().begin()) iterator; + typedef basic_format_specs format_specs; + + private: + typedef basic_writer writer_type; + writer_type writer_; + format_specs *specs_; + + struct char_writer { + char_type value; + template + void operator()(It &&it) const { *it++ = value; } + }; + + void write_char(char_type value) { + if (specs_) + writer_.write_padded(1, *specs_, char_writer{value}); + else + writer_.write(value); + } + + void write_pointer(const void *p) { + format_specs specs = specs_ ? *specs_ : format_specs(); + specs.flags_ = HASH_FLAG; + specs.type_ = 'x'; + writer_.write_int(reinterpret_cast(p), specs); + } + + protected: + writer_type &writer() { return writer_; } + format_specs *spec() { return specs_; } + iterator out() { return writer_.out(); } + + void write(bool value) { + string_view sv(value ? "true" : "false"); + specs_ ? writer_.write_str(sv, *specs_) : writer_.write(sv); + } + + void write(const char_type *value) { + if (!value) + FMT_THROW(format_error("string pointer is null")); + auto length = std::char_traits::length(value); + basic_string_view sv(value, length); + specs_ ? writer_.write_str(sv, *specs_) : writer_.write(sv); + } + + public: + arg_formatter_base(Range r, format_specs *s): writer_(r), specs_(s) {} + + iterator operator()(monostate) { + FMT_ASSERT(false, "invalid argument type"); + return out(); + } + + template + typename std::enable_if::value, iterator>::type + operator()(T value) { + // MSVC2013 fails to compile separate overloads for bool and char_type so + // use std::is_same instead. + if (std::is_same::value) { + if (specs_ && specs_->type_) + return (*this)(value ? 1 : 0); + write(value != 0); + } else if (std::is_same::value) { + internal::handle_char_specs( + specs_, char_spec_handler(*this, static_cast(value))); + } else { + specs_ ? writer_.write_int(value, *specs_) : writer_.write(value); + } + return out(); + } + + template + typename std::enable_if::value, iterator>::type + operator()(T value) { + writer_.write_double(value, specs_ ? *specs_ : format_specs()); + return out(); + } + + struct char_spec_handler : internal::error_handler { + arg_formatter_base &formatter; + char_type value; + + char_spec_handler(arg_formatter_base& f, char_type val) + : formatter(f), value(val) {} + + void on_int() { + if (formatter.specs_) + formatter.writer_.write_int(value, *formatter.specs_); + else + formatter.writer_.write(value); + } + void on_char() { formatter.write_char(value); } + }; + + struct cstring_spec_handler : internal::error_handler { + arg_formatter_base &formatter; + const char_type *value; + + cstring_spec_handler(arg_formatter_base &f, const char_type *val) + : formatter(f), value(val) {} + + void on_string() { formatter.write(value); } + void on_pointer() { formatter.write_pointer(value); } + }; + + iterator operator()(const char_type *value) { + if (!specs_) return write(value), out(); + internal::handle_cstring_type_spec( + specs_->type_, cstring_spec_handler(*this, value)); + return out(); + } + + iterator operator()(basic_string_view value) { + if (specs_) { + internal::check_string_type_spec( + specs_->type_, internal::error_handler()); + writer_.write_str(value, *specs_); + } else { + writer_.write(value); + } + return out(); + } + + iterator operator()(const void *value) { + if (specs_) + check_pointer_type_spec(specs_->type_, internal::error_handler()); + write_pointer(value); + return out(); + } +}; + +template +FMT_CONSTEXPR bool is_name_start(Char c) { + return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || '_' == c; +} + +// DEPRECATED: Parses the input as an unsigned integer. This function assumes +// that the first character is a digit and presence of a non-digit character at +// the end. +// it: an iterator pointing to the beginning of the input range. +template +FMT_CONSTEXPR unsigned parse_nonnegative_int(Iterator &it, ErrorHandler &&eh) { + assert('0' <= *it && *it <= '9'); + unsigned value = 0; + // Convert to unsigned to prevent a warning. + unsigned max_int = (std::numeric_limits::max)(); + unsigned big = max_int / 10; + do { + // Check for overflow. + if (value > big) { + value = max_int + 1; + break; + } + value = value * 10 + unsigned(*it - '0'); + // Workaround for MSVC "setup_exception stack overflow" error: + auto next = it; + ++next; + it = next; + } while ('0' <= *it && *it <= '9'); + if (value > max_int) + eh.on_error("number is too big"); + return value; +} + +// Parses the range [begin, end) as an unsigned integer. This function assumes +// that the range is non-empty and the first character is a digit. +template +FMT_CONSTEXPR unsigned parse_nonnegative_int( + const Char *&begin, const Char *end, ErrorHandler &&eh) { + assert(begin != end && '0' <= *begin && *begin <= '9'); + unsigned value = 0; + // Convert to unsigned to prevent a warning. + unsigned max_int = (std::numeric_limits::max)(); + unsigned big = max_int / 10; + do { + // Check for overflow. + if (value > big) { + value = max_int + 1; + break; + } + value = value * 10 + unsigned(*begin++ - '0'); + } while (begin != end && '0' <= *begin && *begin <= '9'); + if (value > max_int) + eh.on_error("number is too big"); + return value; +} + +template +class custom_formatter: public function { + private: + Context &ctx_; + + public: + explicit custom_formatter(Context &ctx): ctx_(ctx) {} + + bool operator()(typename basic_format_arg::handle h) const { + h.format(ctx_); + return true; + } + + template + bool operator()(T) const { return false; } +}; + +template +struct is_integer { + enum { + value = std::is_integral::value && !std::is_same::value && + !std::is_same::value && !std::is_same::value + }; +}; + +template +class width_checker: public function { + public: + explicit FMT_CONSTEXPR width_checker(ErrorHandler &eh) : handler_(eh) {} + + template + FMT_CONSTEXPR + typename std::enable_if< + is_integer::value, unsigned long long>::type operator()(T value) { + if (is_negative(value)) + handler_.on_error("negative width"); + return static_cast(value); + } + + template + FMT_CONSTEXPR typename std::enable_if< + !is_integer::value, unsigned long long>::type operator()(T) { + handler_.on_error("width is not integer"); + return 0; + } + + private: + ErrorHandler &handler_; +}; + +template +class precision_checker: public function { + public: + explicit FMT_CONSTEXPR precision_checker(ErrorHandler &eh) : handler_(eh) {} + + template + FMT_CONSTEXPR typename std::enable_if< + is_integer::value, unsigned long long>::type operator()(T value) { + if (is_negative(value)) + handler_.on_error("negative precision"); + return static_cast(value); + } + + template + FMT_CONSTEXPR typename std::enable_if< + !is_integer::value, unsigned long long>::type operator()(T) { + handler_.on_error("precision is not integer"); + return 0; + } + + private: + ErrorHandler &handler_; +}; + +// A format specifier handler that sets fields in basic_format_specs. +template +class specs_setter { + public: + explicit FMT_CONSTEXPR specs_setter(basic_format_specs &specs): + specs_(specs) {} + + FMT_CONSTEXPR specs_setter(const specs_setter &other) : specs_(other.specs_) {} + + FMT_CONSTEXPR void on_align(alignment align) { specs_.align_ = align; } + FMT_CONSTEXPR void on_fill(Char fill) { specs_.fill_ = fill; } + FMT_CONSTEXPR void on_plus() { specs_.flags_ |= SIGN_FLAG | PLUS_FLAG; } + FMT_CONSTEXPR void on_minus() { specs_.flags_ |= MINUS_FLAG; } + FMT_CONSTEXPR void on_space() { specs_.flags_ |= SIGN_FLAG; } + FMT_CONSTEXPR void on_hash() { specs_.flags_ |= HASH_FLAG; } + + FMT_CONSTEXPR void on_zero() { + specs_.align_ = ALIGN_NUMERIC; + specs_.fill_ = '0'; + } + + FMT_CONSTEXPR void on_width(unsigned width) { specs_.width_ = width; } + FMT_CONSTEXPR void on_precision(unsigned precision) { + specs_.precision_ = static_cast(precision); + } + FMT_CONSTEXPR void end_precision() {} + + FMT_CONSTEXPR void on_type(Char type) { specs_.type_ = type; } + + protected: + basic_format_specs &specs_; +}; + +// A format specifier handler that checks if specifiers are consistent with the +// argument type. +template +class specs_checker : public Handler { + public: + FMT_CONSTEXPR specs_checker(const Handler& handler, internal::type arg_type) + : Handler(handler), arg_type_(arg_type) {} + + FMT_CONSTEXPR specs_checker(const specs_checker &other) + : Handler(other), arg_type_(other.arg_type_) {} + + FMT_CONSTEXPR void on_align(alignment align) { + if (align == ALIGN_NUMERIC) + require_numeric_argument(); + Handler::on_align(align); + } + + FMT_CONSTEXPR void on_plus() { + check_sign(); + Handler::on_plus(); + } + + FMT_CONSTEXPR void on_minus() { + check_sign(); + Handler::on_minus(); + } + + FMT_CONSTEXPR void on_space() { + check_sign(); + Handler::on_space(); + } + + FMT_CONSTEXPR void on_hash() { + require_numeric_argument(); + Handler::on_hash(); + } + + FMT_CONSTEXPR void on_zero() { + require_numeric_argument(); + Handler::on_zero(); + } + + FMT_CONSTEXPR void end_precision() { + if (is_integral(arg_type_) || arg_type_ == pointer_type) + this->on_error("precision not allowed for this argument type"); + } + + private: + FMT_CONSTEXPR void require_numeric_argument() { + if (!is_arithmetic(arg_type_)) + this->on_error("format specifier requires numeric argument"); + } + + FMT_CONSTEXPR void check_sign() { + require_numeric_argument(); + if (is_integral(arg_type_) && arg_type_ != int_type && + arg_type_ != long_long_type && arg_type_ != internal::char_type) { + this->on_error("format specifier requires signed argument"); + } + } + + internal::type arg_type_; +}; + +template