pax_global_header00006660000000000000000000000064136170703630014520gustar00rootroot0000000000000052 comment=b09bbf9cea573ee62aab7eccda896e37961d16cd pog-0.5.3/000077500000000000000000000000001361707036300123125ustar00rootroot00000000000000pog-0.5.3/.appveyor.yml000066400000000000000000000016521361707036300147640ustar00rootroot00000000000000version: '{build}' configuration: - Debug - Release environment: matrix: - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 CMAKE_GENERATOR: Visual Studio 16 2019 CMAKE_ARGS: -A x64 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 CMAKE_GENERATOR: Visual Studio 15 2017 Win64 before_build: - cmd: mkdir build - cmd: cd build - cmd: cmake -G "%CMAKE_GENERATOR%" -DCMAKE_INSTALL_PREFIX=..\install -DPOG_TESTS=ON -DPOG_EXAMPLES=ON -DPOG_BUNDLED_RE2=ON -DPOG_BUNDLED_FMT=ON %CMAKE_ARGS% .. build_script: - cmd: cmake --build . --config "%CONFIGURATION%" --target install -- -m after_build: - cmd: tree ..\install /F test_script: - cmd: tests\%CONFIGURATION%\pog_tests.exe branches: only: - master - /^v?\d+\.\d+.*$/ notifications: - provider: Email to: - '{{commitAuthorEmail}}' on_build_success: false on_build_failure: true on_build_status_changed: true pog-0.5.3/.gitignore000066400000000000000000000000461361707036300143020ustar00rootroot00000000000000build/ install/ coverage.info .ycm* pog-0.5.3/.travis.yml000066400000000000000000000015371361707036300144310ustar00rootroot00000000000000language: cpp matrix: include: - os: linux dist: bionic install: sudo apt-get install -y lcov libfmt-dev libre2-dev tree after_success: - cd build && rm -rf * - cmake -DCMAKE_BUILD_TYPE=Debug -DPOG_TESTS=ON -DPOG_COVERAGE=ON .. - cmake --build . -- -j - cd .. && ./coverage.sh - bash <(curl -s https://codecov.io/bash) -f coverage.info || echo "Codecov did not collect coverage reports" - os: osx osx_image: xcode11 install: brew install fmt re2 tree script: - mkdir build && cd build - cmake -DCMAKE_BUILD_TYPE=Release -DPOG_TESTS=ON -DPOG_EXAMPLES=ON -DCMAKE_INSTALL_PREFIX=../install .. - cmake --build . --target install -- -j - ./tests/pog_tests - tree ../install branches: only: - master - /^v?\d+\.\d+.*$/ notifications: email: on_success: never pog-0.5.3/CHANGELOG.md000066400000000000000000000033151361707036300141250ustar00rootroot00000000000000# v0.5.3 (2020-02-06) * Reusing parser after it has ended unsuccessfully no longer causes crash # v0.5.2 (2019-11-29) * Option to download RE2 and fmt are now replaced with options to use bundled RE2 and fmt # v0.5.1 (2019-11-29) * Added option to specify where to download fmt and re2 from using environment variables `(FMT|RE2)_DOWNLOAD_URL` and `(FMT|RE2)_DOWNLOAD_URL_SHA256` # v0.5.0 (2019-11-10) * Added support for global tokenizer actions * Added option to specify symbol description which can provide more human friendly output for the symbol in case of a syntax error * Improved performance of constructing parser (construction of LR automaton to be precise) * Debugging traces of parser and tokenizer now have no effect when debugging is not turned on # v0.4.0 (2019-09-28) * Fixed calulcation of includes and lookback relations when there are more instances of the same symbol inspected * Added option to define `POG_DEBUG` to print debugging messages from parser adn tokenizer # v0.3.0 (2019-09-22) * Midrule actions and all preceding symbols are now accessible from later actions in that rule * Explicit switching of tokenizer state with `enter_tokenizer_state` method * Implicit end of input token now has modifiable states in which it is active # v0.2.1 (2019-09-13) * Added option `POG_PIC` to build position-independent code # v0.2.0 (2019-08-12) * Added support for tokenizer action when end of input stream is reached * Token actions are now always called exactly once for each individual token * Tokenizer now supports states * Generation of HTML report for parsers * Added support for build on Windows (using MSVC) and macOS * Added support for mid-rule actions # v0.1.0 (2019-07-27) * Initial release pog-0.5.3/CMakeLists.txt000066400000000000000000000124561361707036300150620ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.8) project(pog LANGUAGES CXX VERSION 0.5.2 ) ## Module path for custom finders. list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") ## Options. option(POG_BUNDLED_RE2 "Use bundled re2" OFF) option(POG_BUNDLED_FMT "Use bundled fmt" OFF) option(POG_EXAMPLES "Build examples" OFF) option(POG_TESTS "Build tests" OFF) option(POG_COVERAGE "Enable coverage" OFF) option(POG_PIC "Enable position independent code" OFF) ## Includes. include(CMakePackageConfigHelpers) include(GNUInstallDirs) ## Require C++17 support. set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) ## Variables. set(POG_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/include") set(POG_INSTALL_CMAKE_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/cmake/pog") set(POG_INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") set(POG_INSTALL_INCLUDE_DIR "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}") set(POG_CMAKE_CONFIG_FILE_IN "${CMAKE_CURRENT_SOURCE_DIR}/share/pog-config.cmake.in") set(POG_CMAKE_CONFIG_FILE "${CMAKE_CURRENT_BINARY_DIR}/share/pog-config.cmake") set(POG_CMAKE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/share/pog-config-version.cmake") set(POG_PC_CONFIG_FILE_IN "${CMAKE_CURRENT_SOURCE_DIR}/share/pog.pc.in") set(POG_PC_CONFIG_FILE "${CMAKE_CURRENT_BINARY_DIR}/share/pog.pc") set(POG_CMAKE_INSTALL_FILES "${POG_CMAKE_CONFIG_FILE}" "${POG_CMAKE_VERSION_FILE}") set(POG_PC_INSTALL_FILES "${POG_PC_CONFIG_FILE}") ## Requirements ### Threads - because of RE2 find_package(Threads REQUIRED) ## If bundled RE2 is not being used, try to find it using find_package(). if(NOT POG_BUNDLED_RE2) find_package(re2 REQUIRED) if(RE2_FOUND) message(STATUS "RE2 include directory: ${RE2_INCLUDE_DIR}") message(STATUS "RE2 library: ${RE2_LIBRARY}") endif() ## Install our custom finder in case user system does not contain one. list(APPEND POG_CMAKE_INSTALL_FILES "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Findre2.cmake") endif() ## If bundled fmt is not being used, try to find it using find_package(). if(NOT POG_BUNDLED_FMT) find_package(fmt REQUIRED) if(fmt_FOUND) message(STATUS "Found libfmt") endif() else() ## Install our custom finder in case user system does not contain one. list(APPEND POG_CMAKE_INSTALL_FILES "${CMAKE_CURRENT_SOURCE_DIR}/cmake/fmt/Findfmt.cmake") endif() ## Add deps folder to resolve bundled dependencies. add_subdirectory(deps) ## Library. add_library(pog INTERFACE) target_sources(pog INTERFACE ${POG_FILES}) if(MSVC) target_compile_options(pog INTERFACE /W3) else() target_compile_options(pog INTERFACE -Wall -Wextra -Wno-empty-body) endif() target_include_directories(pog INTERFACE "$" "$" ) target_link_libraries(pog INTERFACE re2::re2 fmt::fmt) if(POG_COVERAGE) target_compile_options(pog INTERFACE --coverage) target_link_libraries(pog INTERFACE --coverage) endif() ## Build examples if requested. if(POG_EXAMPLES) add_subdirectory(examples) endif() ## Build tests if requested. if(POG_TESTS) add_subdirectory(tests) endif() ## We need to set custom RE2 include directory and library path if bundled dependencies are used. ## Also we need to set proper requirements for pkg-config file. if(POG_BUNDLED_RE2) set(RE2_INCLUDE_DIR "${POG_INSTALL_INCLUDE_DIR}/pog") set(RE2_LIBRARY "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}pog_re2${CMAKE_STATIC_LIBRARY_SUFFIX}") set(POG_PC_REQUIREMENT "Libs: -L\$\{libdir\} -lpog_re2 -lpthread") else() set(RE2_INCLUDE_DIR "") set(RE2_LIBRARY "") set(POG_PC_REQUIREMENT "Requires: re2\nLibs: -L\$\{libdir\}") endif() ## Handle also fmt in pkg-config file. if(POG_BUNDLED_FMT) set(FMT_INCLUDE_DIR "${POG_INSTALL_INCLUDE_DIR}/pog") set(FMT_LIBRARY "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}//${CMAKE_STATIC_LIBRARY_PREFIX}pog_fmt${CMAKE_STATIC_LIBRARY_SUFFIX}") set(POG_PC_REQUIREMENT "${POG_PC_REQUIREMENT} -lpog_fmt") else() set(FMT_INCLUDE_DIR "") set(FMT_LIBRARY "") set(POG_PC_REQUIREMENT "${POG_PC_REQUIREMENT} -lfmt") endif() ## Create pog-config.cmake configure_package_config_file( ${POG_CMAKE_CONFIG_FILE_IN} ${POG_CMAKE_CONFIG_FILE} INSTALL_DESTINATION ${POG_INSTALL_CMAKE_DIR} PATH_VARS RE2_INCLUDE_DIR RE2_LIBRARY FMT_INCLUDE_DIR FMT_LIBRARY ) ## Create pog-config-version.cmake write_basic_package_version_file( ${POG_CMAKE_VERSION_FILE} VERSION ${PROJECT_VERSION} COMPATIBILITY AnyNewerVersion ) ## Create pog.pc configure_file( ${POG_PC_CONFIG_FILE_IN} ${POG_PC_CONFIG_FILE} @ONLY ) ## Install. ### Include directory. install( DIRECTORY ${POG_INCLUDE_DIR}/pog DESTINATION ${POG_INSTALL_INCLUDE_DIR} ) ### Export pog::pog target into pog-targets.cmake install(TARGETS pog EXPORT pog) install( EXPORT pog FILE pog-targets.cmake NAMESPACE pog:: DESTINATION ${POG_INSTALL_CMAKE_DIR} ) ### Install CMake related files (cmake-config.cmake, cmake-config-version.cmake) install( FILES ${POG_CMAKE_INSTALL_FILES} DESTINATION ${POG_INSTALL_CMAKE_DIR} ) ### Install pkg-config related files (pog.pc) install( FILES ${POG_PC_CONFIG_FILE} DESTINATION ${POG_INSTALL_LIB_DIR}/pkgconfig ) pog-0.5.3/LICENSE000066400000000000000000000020711361707036300133170ustar00rootroot00000000000000Copyright 2019 Milkovic Marek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. pog-0.5.3/README.md000066400000000000000000000073321361707036300135760ustar00rootroot00000000000000# Pog [![Build Status](https://travis-ci.org/metthal/pog.svg?branch=master)](https://travis-ci.org/metthal/pog) [![Build Status](https://ci.appveyor.com/api/projects/status/84heo43wj4mqoo5y/branch/master?svg=true)](https://ci.appveyor.com/project/metthal/pog/branch/master) [![Documentation Status](https://readthedocs.org/projects/pog/badge/?version=latest)](https://pog.readthedocs.io/en/latest/?badge=latest) [![codecov](https://codecov.io/gh/metthal/pog/branch/master/graph/badge.svg)](https://codecov.io/gh/metthal/pog) Pog is C++17 library for generating LALR(1) parsers. It splits definitions of parser into: 1. Declaration of tokens (regular expressions describing how the input should be tokenized) 2. Grammar rules over tokens from tokenization phase If you are familiar with tools like yacc + lex or bison + flex then this should be already known concept for you. This library is header-only itself but requires RE2 library which does not come with header-only version. The plan is to be completely header-only in the future. See [documentation](https://pog.readthedocs.io/en/stable/) for more information about the installation and usage of the library. ## Why make another parser generator? I had idea for project like this for a few years already, back when I used bison + flex for a school project. The advantage of bison + flex is that it generates LALR(1) parser. These parsers are very good for parsing usual programming languages constructs without any transformations of the grammar (such as removal of left-recursion, making sure that no 2 rules have same prefix). Their approach of splitting the process into tokenization and parsing makes it much easier to write the actual grammar without having it cluttered with things like whitespaces, comments and other things that can be ignored and don't have to be present in the grammar itself. The disadvantage of bison + flex is that you have to have these installed on your system because they are standalone tools which will generate you C/C++ code. Maintaining build system which uses them and works on Linux, Windows and macOS is not an easy task. For a long time, bison was also not able to work with modern C++ features such as move semantics. It should be supported as of now (3.4) but a lot of Linux distributions still don't have this version and some stable distros won't have for a very long time. There are also other options than bison + flex in C++ world such as Boost.Spirit or PEGTL which are all amazing but they all have some drawbacks (LL parsers, cluttered and hard to maintain grammars, inability to specify operator precedence, ...). This library aims to provide what was missing out there -- taking philosophy of bison + flex and putting it into pure C++ while still generating LALR(1) parser. The implemented parser generator is based on algorithms from papers _Efficient computation of LALR(1) look-ahead sets_, _Development of an LALR(1) Parser Generator_, _Simple computation of LALR(1) lookahead sets_ and book _Compilers: Principles, Techniques, and Tools (2nd Edition)_. ## Roadmap Things to do before 1.0.0 - [x] Tokenizer action on end of input - [x] Support for states in tokenizer (`BEGIN`, `END` like behavior in flex) - [x] Generate debugging report (text file parsing table, states, lookahead sets, graphviz LALR automaton, ...) - [x] Windows & macOS Build - [x] Tests - [x] Code Coverage - [x] CI pipeline (Travis CI, AppVeyor) - [ ] Packaging (ZIP, RPM, DEB, ... + getting package into repositories) - [x] Sphinx Docs (+ Read The Docs integration) Things to do after 1.0.0 - [ ] Error Recovery - [ ] Code Cleanup :) - [ ] Own implementation for tokenizer to be header-only (DFA) - [ ] Lightweight iterator ranges ## Requirements * fmt (5.3.0 or newer) * re2 (2019-09-01 or newer) pog-0.5.3/cmake/000077500000000000000000000000001361707036300133725ustar00rootroot00000000000000pog-0.5.3/cmake/Findre2.cmake000066400000000000000000000012631361707036300156670ustar00rootroot00000000000000if(UNIX) find_package(PkgConfig QUIET) pkg_check_modules(PKG_RE2 QUIET re2) endif() find_path( RE2_INCLUDE_DIR NAMES re2.h HINTS ${PKG_RE2_INCLUDEDIR} PATH_SUFFIXES re2 ) find_library( RE2_LIBRARY NAMES re2 HINTS ${PKG_RE2_LIBDIR} PATH_SUFFIXES lib ) mark_as_advanced(RE2_INCLUDE_DIR RE2_LIBRARY) if(RE2_INCLUDE_DIR AND RE2_LIBRARY) set(RE2_FOUND 1) if(NOT TARGET re2::re2) add_library(re2::re2 UNKNOWN IMPORTED) set_target_properties(re2::re2 PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${RE2_INCLUDE_DIR}" IMPORTED_LOCATION "${RE2_LIBRARY}" ) endif() endif() find_package_handle_standard_args( RE2 REQUIRED_VARS RE2_INCLUDE_DIR RE2_LIBRARY ) pog-0.5.3/cmake/fmt/000077500000000000000000000000001361707036300141605ustar00rootroot00000000000000pog-0.5.3/cmake/fmt/Findfmt.cmake000066400000000000000000000012771361707036300165600ustar00rootroot00000000000000if(UNIX) find_package(PkgConfig QUIET) pkg_check_modules(PKG_FMT QUIET fmt) endif() find_path( FMT_INCLUDE_DIR NAMES format.h HINTS ${PKG_FMT_INCLUDEDIR} PATH_SUFFIXES fmt ) find_library( FMT_LIBRARY NAMES fmt HINTS ${PKG_FMT_LIBDIR} PATH_SUFFIXES lib lib64 ) mark_as_advanced(FMT_INCLUDE_DIR FMT_LIBRARY) if(FMT_INCLUDE_DIR AND FMT_LIBRARY) set(FMT_FOUND 1) if(NOT TARGET fmt::fmt) add_library(fmt::fmt UNKNOWN IMPORTED) set_target_properties(fmt::fmt PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FMT_INCLUDE_DIR}" IMPORTED_LOCATION "${FMT_LIBRARY}" ) endif() endif() find_package_handle_standard_args( FMT REQUIRED_VARS FMT_INCLUDE_DIR FMT_LIBRARY ) pog-0.5.3/coverage.sh000077500000000000000000000003271361707036300144460ustar00rootroot00000000000000#!/bin/bash ./build/tests/pog_tests && \ lcov --directory . --capture --output-file coverage.info && \ lcov --remove coverage.info '/usr/*' '*/tests/*' --output-file coverage.info && \ lcov --list coverage.info pog-0.5.3/deps/000077500000000000000000000000001361707036300132455ustar00rootroot00000000000000pog-0.5.3/deps/CMakeLists.txt000066400000000000000000000001461361707036300160060ustar00rootroot00000000000000if(POG_BUNDLED_RE2) add_subdirectory(re2) endif() if(POG_BUNDLED_FMT) add_subdirectory(fmt) endif() pog-0.5.3/deps/fmt/000077500000000000000000000000001361707036300140335ustar00rootroot00000000000000pog-0.5.3/deps/fmt/CMakeLists.txt000066400000000000000000000035231361707036300165760ustar00rootroot00000000000000include(GNUInstallDirs) include(ExternalProject) set(FMT_INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/fmt) set(FMT_INCLUDE_DIR ${FMT_INSTALL_DIR}/include) set(FMT_INSTALLED_LIBRARY ${FMT_INSTALL_DIR}/${CMAKE_INSTALL_LIBDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}fmt${CMAKE_STATIC_LIBRARY_SUFFIX}) set(FMT_INSTALLED_LIBRARY_DEBUG ${FMT_INSTALL_DIR}/${CMAKE_INSTALL_LIBDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}fmtd${CMAKE_STATIC_LIBRARY_SUFFIX}) set(FMT_LIBRARY ${FMT_INSTALL_DIR}/${CMAKE_INSTALL_LIBDIR}/${CMAKE_STATIC_LIBRARY_PREFIX}pog_fmt${CMAKE_STATIC_LIBRARY_SUFFIX}) if(MSVC) set(FMT_BUILD_COMMAND ${CMAKE_COMMAND} --build . --config $ -- -m) set(FMT_INSTALL_COMMAND ${CMAKE_COMMAND} --build . --target install --config $) else() set(FMT_BUILD_COMMAND ${CMAKE_COMMAND} --build . -- -j) set(FMT_INSTALL_COMMAND ${CMAKE_COMMAND} --build . --target install) endif() ExternalProject_Add( fmt-dep PREFIX "fmt" SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/fmt" CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${FMT_INSTALL_DIR} -DCMAKE_BUILD_TYPE=Release -DCMAKE_POSITION_INDEPENDENT_CODE=${POG_PIC} -DFMT_TEST=OFF -DFMT_DOC=OFF BUILD_COMMAND ${FMT_BUILD_COMMAND} INSTALL_COMMAND ${FMT_INSTALL_COMMAND} ) ExternalProject_Add_Step( fmt-dep rename DEPENDEES install COMMAND ${CMAKE_COMMAND} -E rename $,${FMT_INSTALLED_LIBRARY_DEBUG},${FMT_INSTALLED_LIBRARY}> ${FMT_LIBRARY} ) add_library(fmt::fmt STATIC IMPORTED GLOBAL) set_target_properties(fmt::fmt PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${FMT_INCLUDE_DIR}" IMPORTED_LOCATION "${FMT_LIBRARY}" ) add_dependencies(fmt::fmt fmt-dep) install( FILES ${FMT_LIBRARY} DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR} ) install( DIRECTORY ${FMT_INCLUDE_DIR}/fmt/ DESTINATION ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/pog/fmt ) pog-0.5.3/deps/fmt/fmt/000077500000000000000000000000001361707036300146215ustar00rootroot00000000000000pog-0.5.3/deps/fmt/fmt/CMakeLists.txt000066400000000000000000000246671361707036300174000ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.1.0) # 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}. function(join result_var) set(result ) foreach (arg ${ARGN}) set(result "${result}${arg}") endforeach () set(${result_var} "${result}" PARENT_SCOPE) endfunction() # Set the default CMAKE_BUILD_TYPE to Release. # This should be done before the project command since the latter can set # CMAKE_BUILD_TYPE itself (it does so for nmake). if (MASTER_PROJECT AND NOT CMAKE_BUILD_TYPE) join(doc "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or " "CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.") set(CMAKE_BUILD_TYPE Release CACHE STRING ${doc}) 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_FUZZ "Generate the fuzz target." OFF) project(FMT CXX) # 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}) math(EXPR CPACK_PACKAGE_VERSION_MINOR ${CMAKE_MATCH_2}) math(EXPR CPACK_PACKAGE_VERSION_PATCH ${CMAKE_MATCH_3}) join(FMT_VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}. ${CPACK_PACKAGE_VERSION_PATCH}) message(STATUS "Version: ${FMT_VERSION}") message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/support/cmake") include(cxx14) include(CheckCXXCompilerFlag) set(FMT_REQUIRED_FEATURES cxx_auto_type cxx_variadic_templates) if (CMAKE_CXX_COMPILER_ID MATCHES "GNU") set(PEDANTIC_COMPILE_FLAGS -pedantic-errors -Wall -Wextra -pedantic -Wold-style-cast -Wundef -Wredundant-decls -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 -Wconversion -Wno-ctor-dtor-privacy -Wno-format-nonliteral -Wno-shadow) if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6) set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wnoexcept -Wno-dangling-else -Wno-unused-local-typedefs) 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 -Wall -Wextra -pedantic -Wconversion -Wno-sign-conversion) check_cxx_compiler_flag(-Wzero-as-null-pointer-constant HAS_NULLPTR_WARNING) if (HAS_NULLPTR_WARNING) set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wzero-as-null-pointer-constant) endif () set(WERROR_FLAG -Werror) endif () if (MSVC) set(PEDANTIC_COMPILE_FLAGS /W3) set(WERROR_FLAG /WX) endif () if (MASTER_PROJECT AND CMAKE_GENERATOR MATCHES "Visual Studio") # If Microsoft SDK is installed create script run-msbuild.bat that # calls SetEnv.cmd to set up build environment and runs msbuild. # It is useful when building Visual Studio projects with the SDK # toolchain rather than Visual Studio. include(FindSetEnv) if (WINSDK_SETENV) set(MSBUILD_SETUP "call \"${WINSDK_SETENV}\"") endif () # Set FrameworkPathOverride to get rid of MSB3644 warnings. set(netfxpath "C:\\Program Files\\Reference Assemblies\\Microsoft\\Framework\\.NETFramework\\v4.0") file(WRITE run-msbuild.bat " ${MSBUILD_SETUP} ${CMAKE_MAKE_PROGRAM} -p:FrameworkPathOverride=\"${netfxpath}\" %*") endif () set(strtod_l_headers stdlib.h) if (APPLE) set(strtod_l_headers ${strtod_l_headers} xlocale.h) endif () include(CheckSymbolExists) if (WIN32) check_symbol_exists(open io.h HAVE_OPEN) check_symbol_exists(_strtod_l "${strtod_l_headers}" HAVE_STRTOD_L) else () check_symbol_exists(open fcntl.h HAVE_OPEN) check_symbol_exists(strtod_l "${strtod_l_headers}" HAVE_STRTOD_L) endif () 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 chrono.h color.h compile.h core.h format.h format-inl.h locale.h ostream.h printf.h ranges.h safe-duration-cast.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 (HAVE_STRTOD_L) target_compile_definitions(fmt PUBLIC FMT_LOCALE) endif () if (FMT_WERROR) target_compile_options(fmt PRIVATE ${WERROR_FLAG}) endif () if (FMT_PEDANTIC) target_compile_options(fmt PRIVATE ${PEDANTIC_COMPILE_FLAGS}) endif () target_compile_features(fmt INTERFACE ${FMT_REQUIRED_FEATURES}) 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 () if (FMT_SAFE_DURATION_CAST) target_compile_definitions(fmt PUBLIC FMT_SAFE_DURATION_CAST) 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_compile_features(fmt-header-only INTERFACE ${FMT_REQUIRED_FEATURES}) 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(pkgconfig ${PROJECT_BINARY_DIR}/fmt.pc) 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}.") set(FMT_PKGCONFIG_DIR ${CMAKE_INSTALL_LIBDIR}/pkgconfig CACHE PATH "Installation directory for pkgconfig (.pc) files, relative to ${CMAKE_INSTALL_PREFIX}.") # Generate the version, config and target files into the build directory. write_basic_package_version_file( ${version_config} VERSION ${FMT_VERSION} COMPATIBILITY AnyNewerVersion) configure_file( "${PROJECT_SOURCE_DIR}/support/cmake/fmt.pc.in" "${pkgconfig}" @ONLY) 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 $ DESTINATION ${FMT_LIB_DIR} OPTIONAL) install(FILES ${FMT_HEADERS} DESTINATION ${FMT_INC_DIR}) install(FILES "${pkgconfig}" DESTINATION "${FMT_PKGCONFIG_DIR}") endif () if (FMT_DOC) add_subdirectory(doc) endif () if (FMT_TEST) enable_testing() add_subdirectory(test) endif () # Control fuzzing independent of the unit tests. if (FMT_FUZZ) add_subdirectory(test/fuzzing) endif () set(gitignore ${PROJECT_SOURCE_DIR}/.gitignore) if (MASTER_PROJECT AND EXISTS ${gitignore}) # Get the list of ignored files from .gitignore. file (STRINGS ${gitignore} lines) LIST(REMOVE_ITEM lines /doc/html) foreach (line ${lines}) string(REPLACE "." "[.]" line "${line}") string(REPLACE "*" ".*" line "${line}") set(ignored_files ${ignored_files} "${line}$" "${line}/") endforeach () set(ignored_files ${ignored_files} /.git /breathe /format-benchmark sphinx/ .buildinfo .doctrees) set(CPACK_SOURCE_GENERATOR ZIP) set(CPACK_SOURCE_IGNORE_FILES ${ignored_files}) set(CPACK_SOURCE_PACKAGE_FILE_NAME fmt-${FMT_VERSION}) set(CPACK_PACKAGE_NAME fmt) set(CPACK_RESOURCE_FILE_README ${PROJECT_SOURCE_DIR}/README.rst) include(CPack) endif () pog-0.5.3/deps/fmt/fmt/ChangeLog.rst000066400000000000000000002665431361707036300172220ustar00rootroot000000000000006.0.0 - 2019-08-26 ------------------ * Switched to the `MIT license `_ with an optional exception that allows distributing binary code without attribution. * Floating-point formatting is now locale-independent by default: .. code:: c++ #include #include int main() { std::locale::global(std::locale("ru_RU.UTF-8")); fmt::print("value = {}", 4.2); } prints "value = 4.2" regardless of the locale. For locale-specific formatting use the ``n`` specifier: .. code:: c++ std::locale::global(std::locale("ru_RU.UTF-8")); fmt::print("value = {:n}", 4.2); prints "value = 4,2". * Added an experimental Grisu floating-point formatting algorithm implementation (disabled by default). To enable it compile with the ``FMT_USE_GRISU`` macro defined to 1: .. code:: c++ #define FMT_USE_GRISU 1 #include auto s = fmt::format("{}", 4.2); // formats 4.2 using Grisu With Grisu enabled, {fmt} is 13x faster than ``std::ostringstream`` (libc++) and 10x faster than ``sprintf`` on `dtoa-benchmark `_ (`full results `_): .. image:: https://user-images.githubusercontent.com/576385/ 54883977-9fe8c000-4e28-11e9-8bde-272d122e7c52.jpg * Separated formatting and parsing contexts for consistency with `C++20 std::format `_, removing the undocumented ``basic_format_context::parse_context()`` function. * Added `oss-fuzz `_ support (`#1199 `_). Thanks `@pauldreik (Paul Dreik) `_. * ``formatter`` specializations now always take precedence over ``operator<<`` (`#952 `_): .. code:: c++ #include #include struct S {}; std::ostream& operator<<(std::ostream& os, S) { return os << 1; } template <> struct fmt::formatter : fmt::formatter { auto format(S, format_context& ctx) { return formatter::format(2, ctx); } }; int main() { std::cout << S() << "\n"; // prints 1 using operator<< fmt::print("{}\n", S()); // prints 2 using formatter } * Introduced the experimental ``fmt::compile`` function that does format string compilation (`#618 `_, `#1169 `_, `#1171 `_): .. code:: c++ #include auto f = fmt::compile("{}"); std::string s = fmt::format(f, 42); // can be called multiple times to format // different values // s == "42" It moves the cost of parsing a format string outside of the format function which can be beneficial when identically formatting many objects of the same types. Thanks `@stryku (Mateusz Janek) `_. * Added the ``%`` format specifier that formats floating-point values as percentages (`#1060 `_, `#1069 `_, `#1071 `_): .. code:: c++ auto s = fmt::format("{:.1%}", 0.42); // s == "42.0%" Thanks `@gawain-bolton (Gawain Bolton) `_. * Implemented precision for floating-point durations (`#1004 `_, `#1012 `_): .. code:: c++ auto s = fmt::format("{:.1}", std::chrono::duration(1.234)); // s == 1.2s Thanks `@DanielaE (Daniela Engert) `_. * Implemented ``chrono`` format specifiers ``%Q`` and ``%q`` that give the value and the unit respectively (`#1019 `_): .. code:: c++ auto value = fmt::format("{:%Q}", 42s); // value == "42" auto unit = fmt::format("{:%q}", 42s); // unit == "s" Thanks `@DanielaE (Daniela Engert) `_. * Fixed handling of dynamic width in chrono formatter: .. code:: c++ auto s = fmt::format("{0:{1}%H:%M:%S}", std::chrono::seconds(12345), 12); // ^ width argument index ^ width // s == "03:25:45 " Thanks Howard Hinnant. * Removed deprecated ``fmt/time.h``. Use ``fmt/chrono.h`` instead. * Added ``fmt::format`` and ``fmt::vformat`` overloads that take ``text_style`` (`#993 `_, `#994 `_): .. code:: c++ #include std::string message = fmt::format(fmt::emphasis::bold | fg(fmt::color::red), "The answer is {}.", 42); Thanks `@Naios (Denis Blank) `_. * Removed the deprecated color API (``print_colored``). Use the new API, namely ``print`` overloads that take ``text_style`` instead. * Made ``std::unique_ptr`` and ``std::shared_ptr`` formattable as pointers via ``fmt::ptr`` (`#1121 `_): .. code:: c++ std::unique_ptr p = ...; fmt::print("{}", fmt::ptr(p)); // prints p as a pointer Thanks `@sighingnow (Tao He) `_. * Made ``print`` and ``vprint`` report I/O errors (`#1098 `_, `#1099 `_). Thanks `@BillyDonahue (Billy Donahue) `_. * Marked deprecated APIs with the ``[[deprecated]]`` attribute and removed internal uses of deprecated APIs (`#1022 `_). Thanks `@eliaskosunen (Elias Kosunen) `_. * Modernized the codebase using more C++11 features and removing workarounds. Most importantly, ``buffer_context`` is now an alias template, so use ``buffer_context`` instead of ``buffer_context::type``. * ``formatter`` specializations now always take precedence over implicit conversions to ``int`` and the undocumented ``convert_to_int`` trait is now deprecated. * Moved the undocumented ``basic_writer``, ``writer``, and ``wwriter`` types to the ``internal`` namespace. * Removed deprecated ``basic_format_context::begin()``. Use ``out()`` instead. * Disallowed passing the result of ``join`` as an lvalue to prevent misuse. * Refactored the undocumented structs that represent parsed format specifiers to simplify the API and allow multibyte fill. * Moved SFINAE to template parameters to reduce symbol sizes. * Switched to ``fputws`` for writing wide strings so that it's no longer required to call ``_setmode`` on Windows (`#1229 `_, `#1243 `_). Thanks `@jackoalan (Jack Andersen) `_. * Improved literal-based API (`#1254 `_). Thanks `@sylveon (Charles Milette) `_. * Added support for exotic platforms without ``uintptr_t`` such as IBM i (AS/400) which has 128-bit pointers and only 64-bit integers (`#1059 `_). * Added `Sublime Text syntax highlighting config `_ (`#1037 `_). Thanks `@Kronuz (Germán Méndez Bravo) `_. * Added the ``FMT_ENFORCE_COMPILE_STRING`` macro to enforce the use of compile-time format strings (`#1231 `_). Thanks `@jackoalan (Jack Andersen) `_. * Stopped setting ``CMAKE_BUILD_TYPE`` if {fmt} is a subproject (`#1081 `_). * Various build improvements (`#1039 `_, `#1078 `_, `#1091 `_, `#1103 `_, `#1177 `_). Thanks `@luncliff (Park DongHa) `_, `@jasonszang (Jason Shuo Zang) `_, `@olafhering (Olaf Hering) `_, `@Lecetem `_, `@pauldreik (Paul Dreik) `_. * Improved documentation (`#1049 `_, `#1051 `_, `#1083 `_, `#1113 `_, `#1114 `_, `#1146 `_, `#1180 `_, `#1250 `_, `#1252 `_, `#1265 `_). Thanks `@mikelui (Michael Lui) `_, `@foonathan (Jonathan Müller) `_, `@BillyDonahue (Billy Donahue) `_, `@jwakely (Jonathan Wakely) `_, `@kaisbe (Kais Ben Salah) `_, `@sdebionne (Samuel Debionne) `_. * Fixed ambiguous formatter specialization in ``fmt/ranges.h`` (`#1123 `_). * Fixed formatting of a non-empty ``std::filesystem::path`` which is an infinitely deep range of its components (`#1268 `_). * Fixed handling of general output iterators when formatting characters (`#1056 `_, `#1058 `_). Thanks `@abolz (Alexander Bolz) `_. * Fixed handling of output iterators in ``formatter`` specialization for ranges (`#1064 `_). * Fixed handling of exotic character types (`#1188 `_). * Made chrono formatting work with exceptions disabled (`#1062 `_). * Fixed DLL visibility issues (`#1134 `_, `#1147 `_). Thanks `@denchat `_. * Disabled the use of UDL template extension on GCC 9 (`#1148 `_). * Removed misplaced ``format`` compile-time checks from ``printf`` (`#1173 `_). * Fixed issues in the experimental floating-point formatter (`#1072 `_, `#1129 `_, `#1153 `_, `#1155 `_, `#1210 `_, `#1222 `_). Thanks `@alabuzhev (Alex Alabuzhev) `_. * Fixed bugs discovered by fuzzing or during fuzzing integation (`#1124 `_, `#1127 `_, `#1132 `_, `#1135 `_, `#1136 `_, `#1141 `_, `#1142 `_, `#1178 `_, `#1179 `_, `#1194 `_). Thanks `@pauldreik (Paul Dreik) `_. * Fixed building tests on FreeBSD and Hurd (`#1043 `_). Thanks `@jackyf (Eugene V. Lyubimkin) `_. * Fixed various warnings and compilation issues (`#998 `_, `#1006 `_, `#1008 `_, `#1011 `_, `#1025 `_, `#1027 `_, `#1028 `_, `#1029 `_, `#1030 `_, `#1031 `_, `#1054 `_, `#1063 `_, `#1068 `_, `#1074 `_, `#1075 `_, `#1079 `_, `#1086 `_, `#1088 `_, `#1089 `_, `#1094 `_, `#1101 `_, `#1102 `_, `#1105 `_, `#1107 `_, `#1115 `_, `#1117 `_, `#1118 `_, `#1120 `_, `#1123 `_, `#1139 `_, `#1140 `_, `#1143 `_, `#1144 `_, `#1150 `_, `#1151 `_, `#1152 `_, `#1154 `_, `#1156 `_, `#1159 `_, `#1175 `_, `#1181 `_, `#1186 `_, `#1187 `_, `#1191 `_, `#1197 `_, `#1200 `_, `#1203 `_, `#1205 `_, `#1206 `_, `#1213 `_, `#1214 `_, `#1217 `_, `#1228 `_, `#1230 `_, `#1232 `_, `#1235 `_, `#1236 `_, `#1240 `_). Thanks `@DanielaE (Daniela Engert) `_, `@mwinterb `_, `@eliaskosunen (Elias Kosunen) `_, `@morinmorin `_, `@ricco19 (Brian Ricciardelli) `_, `@waywardmonkeys (Bruce Mitchener) `_, `@chronoxor (Ivan Shynkarenka) `_, `@remyabel `_, `@pauldreik (Paul Dreik) `_, `@gsjaardema (Greg Sjaardema) `_, `@rcane (Ronny Krüger) `_, `@mocabe `_, `@denchat `_, `@cjdb (Christopher Di Bella) `_, `@HazardyKnusperkeks (Björn Schäpers) `_, `@vedranmiletic (Vedran Miletić) `_, `@jackoalan (Jack Andersen) `_, `@DaanDeMeyer (Daan De Meyer) `_, `@starkmapper (Mark Stapper) `_. 5.3.0 - 2018-12-28 ------------------ * Introduced experimental chrono formatting support: .. code:: c++ #include int main() { using namespace std::literals::chrono_literals; fmt::print("Default format: {} {}\n", 42s, 100ms); fmt::print("strftime-like format: {:%H:%M:%S}\n", 3h + 15min + 30s); } prints:: Default format: 42s 100ms strftime-like format: 03:15:30 * Added experimental support for emphasis (bold, italic, underline, strikethrough), colored output to a file stream, and improved colored formatting API (`#961 `_, `#967 `_, `#973 `_): .. code:: c++ #include int main() { print(fg(fmt::color::crimson) | fmt::emphasis::bold, "Hello, {}!\n", "world"); print(fg(fmt::color::floral_white) | bg(fmt::color::slate_gray) | fmt::emphasis::underline, "Hello, {}!\n", "мир"); print(fg(fmt::color::steel_blue) | fmt::emphasis::italic, "Hello, {}!\n", "世界"); } prints the following on modern terminals with RGB color support: .. image:: https://user-images.githubusercontent.com/576385/ 50405788-b66e7500-076e-11e9-9592-7324d1f951d8.png Thanks `@Rakete1111 (Nicolas) `_. * Added support for 4-bit terminal colors (`#968 `_, `#974 `_) .. code:: c++ #include int main() { print(fg(fmt::terminal_color::red), "stop\n"); } Note that these colors vary by terminal: .. image:: https://user-images.githubusercontent.com/576385/ 50405925-dbfc7e00-0770-11e9-9b85-333fab0af9ac.png Thanks `@Rakete1111 (Nicolas) `_. * Parameterized formatting functions on the type of the format string (`#880 `_, `#881 `_, `#883 `_, `#885 `_, `#897 `_, `#920 `_). Any object of type ``S`` that has an overloaded ``to_string_view(const S&)`` returning ``fmt::string_view`` can be used as a format string: .. code:: c++ namespace my_ns { inline string_view to_string_view(const my_string& s) { return {s.data(), s.length()}; } } std::string message = fmt::format(my_string("The answer is {}."), 42); Thanks `@DanielaE (Daniela Engert) `_. * Made ``std::string_view`` work as a format string (`#898 `_): .. code:: c++ auto message = fmt::format(std::string_view("The answer is {}."), 42); Thanks `@DanielaE (Daniela Engert) `_. * Added wide string support to compile-time format string checks (`#924 `_): .. code:: c++ print(fmt(L"{:f}"), 42); // compile-time error: invalid type specifier Thanks `@XZiar `_. * Made colored print functions work with wide strings (`#867 `_): .. code:: c++ #include int main() { print(fg(fmt::color::red), L"{}\n", 42); } Thanks `@DanielaE (Daniela Engert) `_. * Introduced experimental Unicode support (`#628 `_, `#891 `_): .. code:: c++ using namespace fmt::literals; auto s = fmt::format("{:*^5}"_u, "🤡"_u); // s == "**🤡**"_u * Improved locale support: .. code:: c++ #include struct numpunct : std::numpunct { protected: char do_thousands_sep() const override { return '~'; } }; std::locale loc; auto s = fmt::format(std::locale(loc, new numpunct()), "{:n}", 1234567); // s == "1~234~567" * Constrained formatting functions on proper iterator types (`#921 `_). Thanks `@DanielaE (Daniela Engert) `_. * Added ``make_printf_args`` and ``make_wprintf_args`` functions (`#934 `_). Thanks `@tnovotny `_. * Deprecated ``fmt::visit``, ``parse_context``, and ``wparse_context``. Use ``fmt::visit_format_arg``, ``format_parse_context``, and ``wformat_parse_context`` instead. * Removed undocumented ``basic_fixed_buffer`` which has been superseded by the iterator-based API (`#873 `_, `#902 `_). Thanks `@superfunc (hollywood programmer) `_. * Disallowed repeated leading zeros in an argument ID: .. code:: c++ fmt::print("{000}", 42); // error * Reintroduced support for gcc 4.4. * Fixed compilation on platforms with exotic ``double`` (`#878 `_). * Improved documentation (`#164 `_, `#877 `_, `#901 `_, `#906 `_, `#979 `_). Thanks `@kookjr (Mathew Cucuzella) `_, `@DarkDimius (Dmitry Petrashko) `_, `@HecticSerenity `_. * Added pkgconfig support which makes it easier to consume the library from meson and other build systems (`#916 `_). Thanks `@colemickens (Cole Mickens) `_. * Various build improvements (`#909 `_, `#926 `_, `#937 `_, `#953 `_, `#959 `_). Thanks `@tchaikov (Kefu Chai) `_, `@luncliff (Park DongHa) `_, `@AndreasSchoenle (Andreas Schönle) `_, `@hotwatermorning `_, `@Zefz (JohanJansen) `_. * Improved ``string_view`` construction performance (`#914 `_). Thanks `@gabime (Gabi Melman) `_. * Fixed non-matching char types (`#895 `_). Thanks `@DanielaE (Daniela Engert) `_. * Fixed ``format_to_n`` with ``std::back_insert_iterator`` (`#913 `_). Thanks `@DanielaE (Daniela Engert) `_. * Fixed locale-dependent formatting (`#905 `_). * Fixed various compiler warnings and errors (`#882 `_, `#886 `_, `#933 `_, `#941 `_, `#931 `_, `#943 `_, `#954 `_, `#956 `_, `#962 `_, `#965 `_, `#977 `_, `#983 `_, `#989 `_). Thanks `@Luthaf (Guillaume Fraux) `_, `@stevenhoving (Steven Hoving) `_, `@christinaa (Kristina Brooks) `_, `@lgritz (Larry Gritz) `_, `@DanielaE (Daniela Engert) `_, `@0x8000-0000 (Sign Bit) `_, `@liuping1997 `_. 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 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 `_. * 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 `_. * 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) `_. * 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) `_. 4.0.0 - 2017-06-27 ------------------ * 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 `_): .. code:: c++ #include "fmt/string.h" std::string answer = fmt::to_string(42); 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 `_): .. code:: c++ #include "fmt/printf.h" // %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 `_. * 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 `_): .. code:: c++ #include "fmt/format.h" std::vector v = {1.2, 3.4, 5.6}; // Prints "(+01.20, +03.40, +05.60)". fmt::print("({:+06.2f})", fmt::join(v.begin(), v.end(), ", ")); 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 ``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 `_. * 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 handling of wide strings in ``fmt::StringWriter``. * Improved compiler error messages (`#357 `_). * 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 documentation. Thanks to `@pwm1234 (Phil) `_ for `#393 `_. 3.0.2 - 2017-06-14 ------------------ * Added ``FMT_VERSION`` macro (`#411 `_). * Used ``FMT_NULL`` instead of literal ``0`` (`#409 `_). Thanks `@alabuzhev (Alex Alabuzhev) `_. * Added extern templates for ``format_float`` (`#413 `_). * 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 Android detection (`#458 `_). Thanks `@Gachapen (Magnus Bjerke Vik) `_. * 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 nvcc and MSVC compiler bug and MinGW (`#505 `_). * Fixed DLL issues (`#469 `_ and `#502 `_). Thanks `@richardeakin (Richard Eakin) `_ and `@AndreasSchoenle (Andreas Schönle) `_. * Fixed test compilation under FreeBSD (`#433 `_). * Fixed various warnings (`#403 `_, `#410 `_ and `#510 `_). Thanks `@Lecetem `_, `@chenhayat (Chen Hayat) `_ and `@trozen `_. * 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 separator (`#353 `_). * Fixed handling of ``unsigned char`` strings (`#373 `_). * 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) `_. * 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 ------------------ * The project has been renamed from C++ Format (cppformat) to fmt for consistency with the used namespace and macro prefix (`#307 `_). Library headers are now located in the ``fmt`` directory: .. code:: c++ #include "fmt/format.h" Including ``format.h`` from the ``cppformat`` directory is deprecated but works via a proxy header which will be removed in the next major version. The documentation is now available at https://fmt.dev. * Added support for `strftime `_-like `date and time formatting `_ (`#283 `_): .. code:: c++ #include "fmt/time.h" std::time_t t = std::time(nullptr); // Prints "The date is 2016-04-29." (with the current date) fmt::print("The date is {:%Y-%m-%d}.", *std::localtime(&t)); * ``std::ostream`` support including formatting of user-defined types that provide overloaded ``operator<<`` has been moved to ``fmt/ostream.h``: .. code:: c++ #include "fmt/ostream.h" class Date { int year_, month_, day_; public: Date(int year, int month, int day) : year_(year), month_(month), day_(day) {} friend std::ostream &operator<<(std::ostream &os, const Date &d) { return os << d.year_ << '-' << d.month_ << '-' << d.day_; } }; std::string s = fmt::format("The date is {}", Date(2012, 12, 9)); // s == "The date is 2012-12-9" * Added support for `custom argument formatters `_ (`#235 `_). * Added support for locale-specific integer formatting with the ``n`` specifier (`#305 `_): .. code:: c++ std::setlocale(LC_ALL, "en_US.utf8"); fmt::print("cppformat: {:n}\n", 1234567); // prints 1,234,567 * Sign is now preserved when formatting an integer with an incorrect ``printf`` format specifier (`#265 `_): .. code:: c++ fmt::printf("%lld", -42); // prints -42 Note that it would be an undefined behavior in ``std::printf``. * Length modifiers such as ``ll`` are now optional in printf formatting functions and the correct type is determined automatically (`#255 `_): .. code:: c++ fmt::printf("%d", std::numeric_limits::max()); Note that it would be an undefined behavior in ``std::printf``. * Added initial support for custom formatters (`#231 `_). * Fixed detection of user-defined literal support on Intel C++ compiler (`#311 `_, `#312 `_). Thanks to `@dean0x7d (Dean Moldovan) `_ and `@speth (Ray Speth) `_. * Reduced compile time (`#243 `_, `#249 `_, `#317 `_): .. image:: https://cloud.githubusercontent.com/assets/4831417/11614060/ b9e826d2-9c36-11e5-8666-d4131bf503ef.png .. image:: https://cloud.githubusercontent.com/assets/4831417/11614080/ 6ac903cc-9c37-11e5-8165-26df6efae364.png Thanks to `@dean0x7d (Dean Moldovan) `_. * Compile test fixes (`#313 `_). Thanks to `@dean0x7d (Dean Moldovan) `_. * Documentation fixes (`#239 `_, `#248 `_, `#252 `_, `#258 `_, `#260 `_, `#301 `_, `#309 `_). Thanks to `@ReadmeCritic `_ `@Gachapen (Magnus Bjerke Vik) `_ and `@jwilk (Jakub Wilk) `_. * Fixed compiler and sanitizer warnings (`#244 `_, `#256 `_, `#259 `_, `#263 `_, `#274 `_, `#277 `_, `#286 `_, `#291 `_, `#296 `_, `#308 `_) Thanks to `@mwinterb `_, `@pweiskircher (Patrik Weiskircher) `_, `@Naios `_. * Improved compatibility with Windows Store apps (`#280 `_, `#285 `_) Thanks to `@mwinterb `_. * Added tests of compatibility with older C++ standards (`#273 `_). Thanks to `@niosHD `_. * Fixed Android build (`#271 `_). Thanks to `@newnon `_. * Changed ``ArgMap`` to be backed by a vector instead of a map. (`#261 `_, `#262 `_). Thanks to `@mwinterb `_. * Added ``fprintf`` overload that writes to a ``std::ostream`` (`#251 `_). Thanks to `nickhutchinson (Nicholas Hutchinson) `_. * Export symbols when building a Windows DLL (`#245 `_). Thanks to `macdems (Maciek Dems) `_. * Fixed compilation on Cygwin (`#304 `_). * Implemented a workaround for a bug in Apple LLVM version 4.2 of clang (`#276 `_). * Implemented a workaround for Google Test bug `#705 `_ on gcc 6 (`#268 `_). Thanks to `octoploid `_. * Removed Biicode support because the latter has been discontinued. 2.1.1 - 2016-04-11 ------------------ * The install location for generated CMake files is now configurable via the ``FMT_CMAKE_DIR`` CMake variable (`#299 `_). Thanks to `@niosHD `_. * Documentation fixes (`#252 `_). 2.1.0 - 2016-03-21 ------------------ * Project layout and build system improvements (`#267 `_): * The code have been moved to the ``cppformat`` directory. Including ``format.h`` from the top-level directory is deprecated but works via a proxy header which will be removed in the next major version. * C++ Format CMake targets now have proper interface definitions. * Installed version of the library now supports the header-only configuration. * Targets ``doc``, ``install``, and ``test`` are now disabled if C++ Format is included as a CMake subproject. They can be enabled by setting ``FMT_DOC``, ``FMT_INSTALL``, and ``FMT_TEST`` in the parent project. Thanks to `@niosHD `_. 2.0.1 - 2016-03-13 ------------------ * Improved CMake find and package support (`#264 `_). Thanks to `@niosHD `_. * Fix compile error with Android NDK and mingw32 (`#241 `_). Thanks to `@Gachapen (Magnus Bjerke Vik) `_. * Documentation fixes (`#248 `_, `#260 `_). 2.0.0 - 2015-12-01 ------------------ General ~~~~~~~ * [Breaking] Named arguments (`#169 `_, `#173 `_, `#174 `_): .. code:: c++ fmt::print("The answer is {answer}.", fmt::arg("answer", 42)); Thanks to `@jamboree `_. * [Experimental] User-defined literals for format and named arguments (`#204 `_, `#206 `_, `#207 `_): .. code:: c++ using namespace fmt::literals; fmt::print("The answer is {answer}.", "answer"_a=42); Thanks to `@dean0x7d (Dean Moldovan) `_. * [Breaking] Formatting of more than 16 arguments is now supported when using variadic templates (`#141 `_). Thanks to `@Shauren `_. * Runtime width specification (`#168 `_): .. code:: c++ fmt::format("{0:{1}}", 42, 5); // gives " 42" Thanks to `@jamboree `_. * [Breaking] Enums are now formatted with an overloaded ``std::ostream`` insertion operator (``operator<<``) if available (`#232 `_). * [Breaking] Changed default ``bool`` format to textual, "true" or "false" (`#170 `_): .. code:: c++ fmt::print("{}", true); // prints "true" To print ``bool`` as a number use numeric format specifier such as ``d``: .. code:: c++ fmt::print("{:d}", true); // prints "1" * ``fmt::printf`` and ``fmt::sprintf`` now support formatting of ``bool`` with the ``%s`` specifier giving textual output, "true" or "false" (`#223 `_): .. code:: c++ fmt::printf("%s", true); // prints "true" Thanks to `@LarsGullik `_. * [Breaking] ``signed char`` and ``unsigned char`` are now formatted as integers by default (`#217 `_). * [Breaking] Pointers to C strings can now be formatted with the ``p`` specifier (`#223 `_): .. code:: c++ fmt::print("{:p}", "test"); // prints pointer value Thanks to `@LarsGullik `_. * [Breaking] ``fmt::printf`` and ``fmt::sprintf`` now print null pointers as ``(nil)`` and null strings as ``(null)`` for consistency with glibc (`#226 `_). Thanks to `@LarsGullik `_. * [Breaking] ``fmt::(s)printf`` now supports formatting of objects of user-defined types that provide an overloaded ``std::ostream`` insertion operator (``operator<<``) (`#201 `_): .. code:: c++ fmt::printf("The date is %s", Date(2012, 12, 9)); * [Breaking] The ``Buffer`` template is now part of the public API and can be used to implement custom memory buffers (`#140 `_). Thanks to `@polyvertex (Jean-Charles Lefebvre) `_. * [Breaking] Improved compatibility between ``BasicStringRef`` and `std::experimental::basic_string_view `_ (`#100 `_, `#159 `_, `#183 `_): - Comparison operators now compare string content, not pointers - ``BasicStringRef::c_str`` replaced by ``BasicStringRef::data`` - ``BasicStringRef`` is no longer assumed to be null-terminated References to null-terminated strings are now represented by a new class, ``BasicCStringRef``. * Dependency on pthreads introduced by Google Test is now optional (`#185 `_). * New CMake options ``FMT_DOC``, ``FMT_INSTALL`` and ``FMT_TEST`` to control generation of ``doc``, ``install`` and ``test`` targets respectively, on by default (`#197 `_, `#198 `_, `#200 `_). Thanks to `@maddinat0r (Alex Martin) `_. * ``noexcept`` is now used when compiling with MSVC2015 (`#215 `_). Thanks to `@dmkrepo (Dmitriy) `_. * Added an option to disable use of ``windows.h`` when ``FMT_USE_WINDOWS_H`` is defined as 0 before including ``format.h`` (`#171 `_). Thanks to `@alfps (Alf P. Steinbach) `_. * [Breaking] ``windows.h`` is now included with ``NOMINMAX`` unless ``FMT_WIN_MINMAX`` is defined. This is done to prevent breaking code using ``std::min`` and ``std::max`` and only affects the header-only configuration (`#152 `_, `#153 `_, `#154 `_). Thanks to `@DevO2012 `_. * Improved support for custom character types (`#171 `_). Thanks to `@alfps (Alf P. Steinbach) `_. * Added an option to disable use of IOStreams when ``FMT_USE_IOSTREAMS`` is defined as 0 before including ``format.h`` (`#205 `_, `#208 `_). Thanks to `@JodiTheTigger `_. * Improved detection of ``isnan``, ``isinf`` and ``signbit``. Optimization ~~~~~~~~~~~~ * Made formatting of user-defined types more efficient with a custom stream buffer (`#92 `_, `#230 `_). Thanks to `@NotImplemented `_. * Further improved performance of ``fmt::Writer`` on integer formatting and fixed a minor regression. Now it is ~7% faster than ``karma::generate`` on Karma's benchmark (`#186 `_). * [Breaking] Reduced `compiled code size `_ (`#143 `_, `#149 `_). Distribution ~~~~~~~~~~~~ * [Breaking] Headers are now installed in ``${CMAKE_INSTALL_PREFIX}/include/cppformat`` (`#178 `_). Thanks to `@jackyf (Eugene V. Lyubimkin) `_. * [Breaking] Changed the library name from ``format`` to ``cppformat`` for consistency with the project name and to avoid potential conflicts (`#178 `_). Thanks to `@jackyf (Eugene V. Lyubimkin) `_. * C++ Format is now available in `Debian `_ GNU/Linux (`stretch `_, `sid `_) and derived distributions such as `Ubuntu `_ 15.10 and later (`#155 `_):: $ sudo apt-get install libcppformat1-dev Thanks to `@jackyf (Eugene V. Lyubimkin) `_. * `Packages for Fedora and RHEL `_ are now available. Thanks to Dave Johansen. * C++ Format can now be installed via `Homebrew `_ on OS X (`#157 `_):: $ brew install cppformat Thanks to `@ortho `_, Anatoliy Bulukin. Documentation ~~~~~~~~~~~~~ * Migrated from ReadTheDocs to GitHub Pages for better responsiveness and reliability (`#128 `_). New documentation address is http://cppformat.github.io/. * Added `Building the documentation `_ section to the documentation. * Documentation build script is now compatible with Python 3 and newer pip versions. (`#189 `_, `#209 `_). Thanks to `@JodiTheTigger `_ and `@xentec `_. * Documentation fixes and improvements (`#36 `_, `#75 `_, `#125 `_, `#160 `_, `#161 `_, `#162 `_, `#165 `_, `#210 `_). Thanks to `@syohex (Syohei YOSHIDA) `_ and bug reporters. * Fixed out-of-tree documentation build (`#177 `_). Thanks to `@jackyf (Eugene V. Lyubimkin) `_. Fixes ~~~~~ * Fixed ``initializer_list`` detection (`#136 `_). Thanks to `@Gachapen (Magnus Bjerke Vik) `_. * [Breaking] Fixed formatting of enums with numeric format specifiers in ``fmt::(s)printf`` (`#131 `_, `#139 `_): .. code:: c++ enum { ANSWER = 42 }; fmt::printf("%d", ANSWER); Thanks to `@Naios `_. * Improved compatibility with old versions of MinGW (`#129 `_, `#130 `_, `#132 `_). Thanks to `@cstamford (Christopher Stamford) `_. * Fixed a compile error on MSVC with disabled exceptions (`#144 `_). * Added a workaround for broken implementation of variadic templates in MSVC2012 (`#148 `_). * Placed the anonymous namespace within ``fmt`` namespace for the header-only configuration (`#171 `_). Thanks to `@alfps (Alf P. Steinbach) `_. * Fixed issues reported by Coverity Scan (`#187 `_, `#192 `_). * Implemented a workaround for a name lookup bug in MSVC2010 (`#188 `_). * Fixed compiler warnings (`#95 `_, `#96 `_, `#114 `_, `#135 `_, `#142 `_, `#145 `_, `#146 `_, `#158 `_, `#163 `_, `#175 `_, `#190 `_, `#191 `_, `#194 `_, `#196 `_, `#216 `_, `#218 `_, `#220 `_, `#229 `_, `#233 `_, `#234 `_, `#236 `_, `#281 `_, `#289 `_). Thanks to `@seanmiddleditch (Sean Middleditch) `_, `@dixlorenz (Dix Lorenz) `_, `@CarterLi (李通洲) `_, `@Naios `_, `@fmatthew5876 (Matthew Fioravante) `_, `@LevskiWeng (Levski Weng) `_, `@rpopescu `_, `@gabime (Gabi Melman) `_, `@cubicool (Jeremy Moles) `_, `@jkflying (Julian Kent) `_, `@LogicalKnight (Sean L) `_, `@inguin (Ingo van Lil) `_ and `@Jopie64 (Johan) `_. * Fixed portability issues (mostly causing test failures) on ARM, ppc64, ppc64le, s390x and SunOS 5.11 i386 (`#138 `_, `#179 `_, `#180 `_, `#202 `_, `#225 `_, `Red Hat Bugzilla Bug 1260297 `_). Thanks to `@Naios `_, `@jackyf (Eugene V. Lyubimkin) `_ and Dave Johansen. * Fixed a name conflict with macro ``free`` defined in ``crtdbg.h`` when ``_CRTDBG_MAP_ALLOC`` is set (`#211 `_). * Fixed shared library build on OS X (`#212 `_). Thanks to `@dean0x7d (Dean Moldovan) `_. * Fixed an overload conflict on MSVC when ``/Zc:wchar_t-`` option is specified (`#214 `_). Thanks to `@slavanap (Vyacheslav Napadovsky) `_. * Improved compatibility with MSVC 2008 (`#236 `_). Thanks to `@Jopie64 (Johan) `_. * Improved compatibility with bcc32 (`#227 `_). * Fixed ``static_assert`` detection on Clang (`#228 `_). Thanks to `@dean0x7d (Dean Moldovan) `_. 1.1.0 - 2015-03-06 ------------------ * Added ``BasicArrayWriter``, a class template that provides operations for formatting and writing data into a fixed-size array (`#105 `_ and `#122 `_): .. code:: c++ char buffer[100]; fmt::ArrayWriter w(buffer); w.write("The answer is {}", 42); * Added `0 A.D. `_ and `PenUltima Online (POL) `_ to the list of notable projects using C++ Format. * C++ Format now uses MSVC intrinsics for better formatting performance (`#115 `_, `#116 `_, `#118 `_ and `#121 `_). Previously these optimizations where only used on GCC and Clang. Thanks to `@CarterLi `_ and `@objectx `_. * CMake install target (`#119 `_). Thanks to `@TrentHouliston `_. You can now install C++ Format with ``make install`` command. * Improved `Biicode `_ support (`#98 `_ and `#104 `_). Thanks to `@MariadeAnton `_ and `@franramirez688 `_. * Improved support for building with `Android NDK `_ (`#107 `_). Thanks to `@newnon `_. The `android-ndk-example `_ repository provides and example of using C++ Format with Android NDK: .. image:: https://raw.githubusercontent.com/fmtlib/android-ndk-example/ master/screenshot.png * Improved documentation of ``SystemError`` and ``WindowsError`` (`#54 `_). * Various code improvements (`#110 `_, `#111 `_ `#112 `_). Thanks to `@CarterLi `_. * Improved compile-time errors when formatting wide into narrow strings (`#117 `_). * Fixed ``BasicWriter::write`` without formatting arguments when C++11 support is disabled (`#109 `_). * Fixed header-only build on OS X with GCC 4.9 (`#124 `_). * Fixed packaging issues (`#94 `_). * Added `changelog `_ (`#103 `_). 1.0.0 - 2015-02-05 ------------------ * Add support for a header-only configuration when ``FMT_HEADER_ONLY`` is defined before including ``format.h``: .. code:: c++ #define FMT_HEADER_ONLY #include "format.h" * Compute string length in the constructor of ``BasicStringRef`` instead of the ``size`` method (`#79 `_). This eliminates size computation for string literals on reasonable optimizing compilers. * Fix formatting of types with overloaded ``operator <<`` for ``std::wostream`` (`#86 `_): .. code:: c++ fmt::format(L"The date is {0}", Date(2012, 12, 9)); * Fix linkage of tests on Arch Linux (`#89 `_). * Allow precision specifier for non-float arguments (`#90 `_): .. code:: c++ fmt::print("{:.3}\n", "Carpet"); // prints "Car" * Fix build on Android NDK (`#93 `_) * Improvements to documentation build procedure. * Remove ``FMT_SHARED`` CMake variable in favor of standard `BUILD_SHARED_LIBS `_. * Fix error handling in ``fmt::fprintf``. * Fix a number of warnings. 0.12.0 - 2014-10-25 ------------------- * [Breaking] Improved separation between formatting and buffer management. ``Writer`` is now a base class that cannot be instantiated directly. The new ``MemoryWriter`` class implements the default buffer management with small allocations done on stack. So ``fmt::Writer`` should be replaced with ``fmt::MemoryWriter`` in variable declarations. Old code: .. code:: c++ fmt::Writer w; New code: .. code:: c++ fmt::MemoryWriter w; If you pass ``fmt::Writer`` by reference, you can continue to do so: .. code:: c++ void f(fmt::Writer &w); This doesn't affect the formatting API. * Support for custom memory allocators (`#69 `_) * Formatting functions now accept `signed char` and `unsigned char` strings as arguments (`#73 `_): .. code:: c++ auto s = format("GLSL version: {}", glGetString(GL_VERSION)); * Reduced code bloat. According to the new `benchmark results `_, cppformat is close to ``printf`` and by the order of magnitude better than Boost Format in terms of compiled code size. * Improved appearance of the documentation on mobile by using the `Sphinx Bootstrap theme `_: .. |old| image:: https://cloud.githubusercontent.com/assets/576385/4792130/ cd256436-5de3-11e4-9a62-c077d0c2b003.png .. |new| image:: https://cloud.githubusercontent.com/assets/576385/4792131/ cd29896c-5de3-11e4-8f59-cac952942bf0.png +-------+-------+ | Old | New | +-------+-------+ | |old| | |new| | +-------+-------+ 0.11.0 - 2014-08-21 ------------------- * Safe printf implementation with a POSIX extension for positional arguments: .. code:: c++ fmt::printf("Elapsed time: %.2f seconds", 1.23); fmt::printf("%1$s, %3$d %2$s", weekday, month, day); * Arguments of ``char`` type can now be formatted as integers (Issue `#55 `_): .. code:: c++ fmt::format("0x{0:02X}", 'a'); * Deprecated parts of the API removed. * The library is now built and tested on MinGW with Appveyor in addition to existing test platforms Linux/GCC, OS X/Clang, Windows/MSVC. 0.10.0 - 2014-07-01 ------------------- **Improved API** * All formatting methods are now implemented as variadic functions instead of using ``operator<<`` for feeding arbitrary arguments into a temporary formatter object. This works both with C++11 where variadic templates are used and with older standards where variadic functions are emulated by providing lightweight wrapper functions defined with the ``FMT_VARIADIC`` macro. You can use this macro for defining your own portable variadic functions: .. code:: c++ void report_error(const char *format, const fmt::ArgList &args) { fmt::print("Error: {}"); fmt::print(format, args); } FMT_VARIADIC(void, report_error, const char *) report_error("file not found: {}", path); Apart from a more natural syntax, this also improves performance as there is no need to construct temporary formatter objects and control arguments' lifetimes. Because the wrapper functions are very lightweight, this doesn't cause code bloat even in pre-C++11 mode. * Simplified common case of formatting an ``std::string``. Now it requires a single function call: .. code:: c++ std::string s = format("The answer is {}.", 42); Previously it required 2 function calls: .. code:: c++ std::string s = str(Format("The answer is {}.") << 42); Instead of unsafe ``c_str`` function, ``fmt::Writer`` should be used directly to bypass creation of ``std::string``: .. code:: c++ fmt::Writer w; w.write("The answer is {}.", 42); w.c_str(); // returns a C string This doesn't do dynamic memory allocation for small strings and is less error prone as the lifetime of the string is the same as for ``std::string::c_str`` which is well understood (hopefully). * Improved consistency in naming functions that are a part of the public API. Now all public functions are lowercase following the standard library conventions. Previously it was a combination of lowercase and CapitalizedWords. Issue `#50 `_. * Old functions are marked as deprecated and will be removed in the next release. **Other Changes** * Experimental support for printf format specifications (work in progress): .. code:: c++ fmt::printf("The answer is %d.", 42); std::string s = fmt::sprintf("Look, a %s!", "string"); * Support for hexadecimal floating point format specifiers ``a`` and ``A``: .. code:: c++ print("{:a}", -42.0); // Prints -0x1.5p+5 print("{:A}", -42.0); // Prints -0X1.5P+5 * CMake option ``FMT_SHARED`` that specifies whether to build format as a shared library (off by default). 0.9.0 - 2014-05-13 ------------------ * More efficient implementation of variadic formatting functions. * ``Writer::Format`` now has a variadic overload: .. code:: c++ Writer out; out.Format("Look, I'm {}!", "variadic"); * For efficiency and consistency with other overloads, variadic overload of the ``Format`` function now returns ``Writer`` instead of ``std::string``. Use the ``str`` function to convert it to ``std::string``: .. code:: c++ std::string s = str(Format("Look, I'm {}!", "variadic")); * Replaced formatter actions with output sinks: ``NoAction`` -> ``NullSink``, ``Write`` -> ``FileSink``, ``ColorWriter`` -> ``ANSITerminalSink``. This improves naming consistency and shouldn't affect client code unless these classes are used directly which should be rarely needed. * Added ``ThrowSystemError`` function that formats a message and throws ``SystemError`` containing the formatted message and system-specific error description. For example, the following code .. code:: c++ FILE *f = fopen(filename, "r"); if (!f) ThrowSystemError(errno, "Failed to open file '{}'") << filename; will throw ``SystemError`` exception with description "Failed to open file '': No such file or directory" if file doesn't exist. * Support for AppVeyor continuous integration platform. * ``Format`` now throws ``SystemError`` in case of I/O errors. * Improve test infrastructure. Print functions are now tested by redirecting the output to a pipe. 0.8.0 - 2014-04-14 ------------------ * Initial release pog-0.5.3/deps/fmt/fmt/LICENSE.rst000066400000000000000000000026001361707036300164330ustar00rootroot00000000000000Copyright (c) 2012 - present, Victor Zverovich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --- Optional exception to the license --- As an exception, if, as a result of your compiling your source code, portions of this Software are embedded into a machine-executable object form of such source code, you may redistribute such embedded portions in such object form without including the above copyright and permission notices. pog-0.5.3/deps/fmt/fmt/README.rst000066400000000000000000000464011361707036300163150ustar00rootroot00000000000000{fmt} ===== .. image:: https://travis-ci.org/fmtlib/fmt.png?branch=master :target: https://travis-ci.org/fmtlib/fmt .. image:: https://ci.appveyor.com/api/projects/status/ehjkiefde6gucy1v :target: https://ci.appveyor.com/project/vitaut/fmt .. image:: https://img.shields.io/badge/stackoverflow-fmt-blue.svg :alt: Ask questions at StackOverflow with the tag fmt :target: http://stackoverflow.com/questions/tagged/fmt **{fmt}** is an open-source formatting library for C++. It can be used as a safe and fast alternative to (s)printf and iostreams. `Documentation `__ Q&A: ask questions on `StackOverflow with the tag fmt `_. Features -------- * 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. * Implementation of `C++20 std::format `__. * Support for user-defined types. * High performance: faster than common standard library implementations of `printf `_ and iostreams. See `Speed tests`_ and `Fast integer to string conversion in C++ `_. * 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 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. * Clean warning-free codebase even on high warning levels (``-Wall -Wextra -pedantic``). * Support for wide strings. * Optional header-only configuration enabled with the ``FMT_HEADER_ONLY`` macro. See the `documentation `_ for more details. Examples -------- Print ``Hello, world!`` to ``stdout``: .. code:: c++ fmt::print("Hello, {}!", "world"); // Python-like format string syntax fmt::printf("Hello, %s!", "world"); // printf format string syntax Format a string and use positional arguments: .. code:: c++ std::string s = fmt::format("I'd rather be {1} than {0}.", "right", "happy"); // s == "I'd rather be happy than right." Check a format string at compile time: .. code:: c++ // test.cc #define FMT_STRING_ALIAS 1 #include std::string s = format(fmt("{2}"), 42); .. 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"); ^ Use {fmt} as a safe portable replacement for ``itoa`` (`godbolt `_): .. code:: c++ fmt::memory_buffer buf; format_to(buf, "{}", 42); // replaces itoa(42, buffer, 10) format_to(buf, "{:x}", 42); // replaces itoa(42, buffer, 16) // access the string with to_string(buf) or buf.data() Format objects of user-defined types via a simple `extension API `_: .. 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.out(), "{}-{}-{}", d.year, d.month, d.day); } }; std::string s = fmt::format("The date is {}", date{2012, 12, 9}); // s == "The date is 2012-12-9" Create your own functions similar to `format `_ and `print `_ which take arbitrary arguments (`godbolt `_): .. 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...)); } report_error("file not found: {}", path); Note that ``vreport_error`` is not parameterized on argument types which can improve compile times and reduce code size compared to a fully parameterized version. Benchmarks ---------- Speed tests ~~~~~~~~~~~ ================= ============= =========== Library Method Run Time, s ================= ============= =========== libc printf 1.01 libc++ std::ostream 3.04 {fmt} 1632f72 fmt::print 0.86 tinyformat 2.0.1 tfm::printf 3.23 Boost Format 1.67 boost::format 7.98 Folly Format folly::format 2.23 ================= ============= =========== {fmt} is the fastest of the benchmarked methods, ~17% faster than ``printf``. The above results were generated by building ``tinyformat_test.cpp`` on macOS 10.14.3 with ``clang++ -O3 -DSPEED_TEST -DHAVE_FORMAT``, and taking the best of three runs. In the test, the format string ``"%0.10f:%04d:%+g:%s:%p:%c:%%\n"`` or equivalent is filled 2,000,000 times with output sent to ``/dev/null``; for further details refer to the `source `_. {fmt} is 10x faster than ``std::ostringstream`` and ``sprintf`` on floating-point formatting (`dtoa-benchmark `_) and as fast as `double-conversion `_: .. image:: https://user-images.githubusercontent.com/576385/54883977-9fe8c000-4e28-11e9-8bde-272d122e7c52.jpg :target: https://fmt.dev/unknown_mac64_clang10.0.html Compile time and code bloat ~~~~~~~~~~~~~~~~~~~~~~~~~~~ The script `bloat-test.py `_ 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 (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 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 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.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``, ``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. Running the tests ~~~~~~~~~~~~~~~~~ Please refer to `Building the library`__ for the instructions on how to build the library and run the unit tests. __ https://fmt.dev/latest/usage.html#building-the-library Benchmarks reside in a separate repository, `format-benchmarks `_, so to run the benchmarks you first need to clone this repository and generate Makefiles with CMake:: $ git clone --recursive https://github.com/fmtlib/format-benchmark.git $ cd format-benchmark $ cmake . Then you can run the speed test:: $ make speed-test or the bloat test:: $ make bloat-test Projects using this library --------------------------- * `0 A.D. `_: A free, open-source, cross-platform real-time strategy game * `AMPL/MP `_: An open-source library for mathematical programming * `AvioBook `_: A comprehensive aircraft operations suite * `Celestia `_: Real-time 3D visualization of space * `Ceph `_: A scalable distributed storage system * `CUAUV `_: Cornell University's autonomous underwater vehicle * `HarpyWar/pvpgn `_: Player vs Player Gaming Network with tweaks * `KBEngine `_: An open-source MMOG server engine * `Keypirinha `_: A semantic launcher for Windows * `Kodi `_ (formerly xbmc): Home theater software * `Lifeline `_: A 2D game * `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 * `MongoDB `_: Distributed document database * `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 * `readpe `_: Read Portable Executable * `redis-cerberus `_: A Redis cluster proxy * `rpclib `_: A modern C++ msgpack-RPC server and client library * `Saddy `_: Small crossplatform 2D graphic engine * `Salesforce Analytics Cloud `_: Business intelligence software * `Scylla `_: A Cassandra-compatible NoSQL data store that can handle 1 million transactions per second on a single server * `Seastar `_: An advanced, open-source C++ framework for high-performance server applications on modern hardware * `spdlog `_: Super fast C++ logging library * `Stellar `_: Financial platform * `Touch Surgery `_: Surgery simulator * `TrinityCore `_: Open-source MMORPG framework `More... `_ If you are aware of other projects using this library, please let me know by `email `_ or by submitting an `issue `_. Motivation ---------- So why yet another formatting library? There are plenty of methods for doing this task, from standard ones like the printf family of function and iostreams to Boost Format and FastFormat libraries. The reason for creating a new library is that every existing solution that I found either had serious issues or didn't provide all the features I needed. printf ~~~~~~ The good thing about ``printf`` is that it is pretty fast and readily available being a part of the C standard library. The main drawback is that it doesn't support user-defined types. ``printf`` also has safety issues although they are somewhat mitigated with `__attribute__ ((format (printf, ...)) `_ in GCC. There is a POSIX extension that adds positional arguments required for `i18n `_ to ``printf`` but it is not a part of C99 and may not be available on some platforms. iostreams ~~~~~~~~~ The main issue with iostreams is best illustrated with an example: .. code:: c++ std::cout << std::setprecision(2) << std::fixed << 1.23456 << "\n"; which is a lot of typing compared to printf: .. code:: c++ printf("%.2f\n", 1.23456); Matthew Wilson, the author of FastFormat, called this "chevron hell". iostreams don't support positional arguments by design. The good part is that iostreams support user-defined types and are safe although error handling is awkward. Boost Format ~~~~~~~~~~~~ This is a very powerful library which supports both ``printf``-like format strings and positional arguments. Its main drawback is performance. According to various benchmarks it is much slower than other methods considered here. Boost Format also has excessive build times and severe code bloat issues (see `Benchmarks`_). FastFormat ~~~~~~~~~~ This is an interesting library which is fast, safe and has positional arguments. However it has significant limitations, citing its author: Three features that have no hope of being accommodated within the current design are: * Leading zeros (or any other non-space padding) * Octal/hexadecimal encoding * Runtime width/alignment specification It is also quite big and has a heavy dependency, STLSoft, which might be too restrictive for using it in some projects. Loki SafeFormat ~~~~~~~~~~~~~~~ SafeFormat is a formatting library which uses ``printf``-like format strings and is type safe. It doesn't support user-defined types or positional arguments and makes unconventional use of ``operator()`` for passing format arguments. Tinyformat ~~~~~~~~~~ This library supports ``printf``-like format strings and is very small . It doesn't support positional arguments and wrapping it in C++98 is somewhat difficult. Tinyformat relies on iostreams which limits its performance. Boost Spirit.Karma ~~~~~~~~~~~~~~~~~~ This is not really a formatting library but I decided to include it here for completeness. As iostreams, it suffers from the problem of mixing verbatim text with arguments. The library is pretty fast, but slower on integer formatting than ``fmt::format_int`` on Karma's own benchmark, see `Fast integer to string conversion in C++ `_. 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 ------- {fmt} is distributed under the BSD `license `_. The `Format String Syntax `_ section in the documentation is based on the one from Python `string module documentation `_ adapted for the current library. For this reason the documentation is distributed under the Python Software Foundation license available in `doc/python-license.txt `_. 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 benchmark section of this readme file and the performance tests are taken from the excellent `tinyformat `_ library written by Chris Foster. Boost Format library is acknowledged transitively since it had some influence on tinyformat. Some ideas used in the implementation are borrowed from `Loki `_ SafeFormat and `Diagnostic API `_ in `Clang `_. Format string syntax and the documentation are based on Python's `str.format `_. Thanks `Doug Turnbull `_ for his valuable comments and contribution to the design of the type-safe API and `Gregory Czajkowski `_ for implementing binary formatting. Thanks `Ruslan Baratov `_ for comprehensive `comparison of integer formatting algorithms `_ and useful comments regarding performance, `Boris Kaul `_ for `C++ counting digits benchmark `_. Thanks to `CarterLi `_ for contributing various improvements to the code. pog-0.5.3/deps/fmt/fmt/include/000077500000000000000000000000001361707036300162445ustar00rootroot00000000000000pog-0.5.3/deps/fmt/fmt/include/fmt/000077500000000000000000000000001361707036300170325ustar00rootroot00000000000000pog-0.5.3/deps/fmt/fmt/include/fmt/chrono.h000066400000000000000000000622511361707036300205010ustar00rootroot00000000000000// Formatting library for C++ - chrono support // // Copyright (c) 2012 - present, Victor Zverovich // All rights reserved. // // For the license information refer to format.h. #ifndef FMT_CHRONO_H_ #define FMT_CHRONO_H_ #include "format.h" #include "locale.h" #include #include #include #include // enable safe chrono durations, unless explicitly disabled #ifndef FMT_SAFE_DURATION_CAST # define FMT_SAFE_DURATION_CAST 1 #endif #if FMT_SAFE_DURATION_CAST # include "safe-duration-cast.h" #endif FMT_BEGIN_NAMESPACE // Prevents expansion of a preceding token as a function-style macro. // Usage: f FMT_NOMACRO() #define FMT_NOMACRO namespace internal { inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); } inline null<> localtime_s(...) { return null<>(); } inline null<> gmtime_r(...) { return null<>(); } inline null<> gmtime_s(...) { return null<>(); } } // namespace internal // Thread-safe replacement for std::localtime inline std::tm localtime(std::time_t time) { struct dispatcher { std::time_t time_; std::tm tm_; dispatcher(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 != nullptr; } bool handle(internal::null<>) { using namespace fmt::internal; return fallback(localtime_s(&tm_, &time_)); } bool fallback(int res) { return res == 0; } #if !FMT_MSC_VER bool fallback(internal::null<>) { using namespace fmt::internal; std::tm* tm = std::localtime(&time_); if (tm) tm_ = *tm; return tm != nullptr; } #endif }; dispatcher lt(time); // Too big time values may be unsupported. if (!lt.run()) FMT_THROW(format_error("time_t value out of range")); return lt.tm_; } // Thread-safe replacement for std::gmtime inline std::tm gmtime(std::time_t time) { struct dispatcher { std::time_t time_; std::tm tm_; dispatcher(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 != nullptr; } bool handle(internal::null<>) { using namespace fmt::internal; return fallback(gmtime_s(&tm_, &time_)); } bool fallback(int res) { return res == 0; } #if !FMT_MSC_VER bool fallback(internal::null<>) { std::tm* tm = std::gmtime(&time_); if (tm) tm_ = *tm; return tm != nullptr; } #endif }; dispatcher gt(time); // Too big time values may be unsupported. if (!gt.run()) FMT_THROW(format_error("time_t value out of range")); return gt.tm_; } namespace internal { inline std::size_t strftime(char* str, std::size_t count, const char* format, const std::tm* time) { return std::strftime(str, count, format, time); } inline std::size_t strftime(wchar_t* str, std::size_t count, const wchar_t* format, const std::tm* time) { return std::wcsftime(str, count, format, time); } } // namespace internal template struct formatter { template auto parse(ParseContext& ctx) -> decltype(ctx.begin()) { auto it = ctx.begin(); if (it != ctx.end() && *it == ':') ++it; auto end = it; while (end != ctx.end() && *end != '}') ++end; tm_format.reserve(internal::to_unsigned(end - it + 1)); tm_format.append(it, end); tm_format.push_back('\0'); return end; } template auto format(const std::tm& tm, FormatContext& ctx) -> decltype(ctx.out()) { basic_memory_buffer buf; std::size_t start = buf.size(); for (;;) { std::size_t size = buf.capacity() - start; std::size_t count = internal::strftime(&buf[start], size, &tm_format[0], &tm); if (count != 0) { buf.resize(start + count); break; } if (size >= tm_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; buf.reserve(buf.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH)); } return std::copy(buf.begin(), buf.end(), ctx.out()); } basic_memory_buffer tm_format; }; namespace internal { template FMT_CONSTEXPR const char* get_units() { return nullptr; } template <> FMT_CONSTEXPR const char* get_units() { return "as"; } template <> FMT_CONSTEXPR const char* get_units() { return "fs"; } template <> FMT_CONSTEXPR const char* get_units() { return "ps"; } template <> FMT_CONSTEXPR const char* get_units() { return "ns"; } template <> FMT_CONSTEXPR const char* get_units() { return "µs"; } template <> FMT_CONSTEXPR const char* get_units() { return "ms"; } template <> FMT_CONSTEXPR const char* get_units() { return "cs"; } template <> FMT_CONSTEXPR const char* get_units() { return "ds"; } template <> FMT_CONSTEXPR const char* get_units>() { return "s"; } template <> FMT_CONSTEXPR const char* get_units() { return "das"; } template <> FMT_CONSTEXPR const char* get_units() { return "hs"; } template <> FMT_CONSTEXPR const char* get_units() { return "ks"; } template <> FMT_CONSTEXPR const char* get_units() { return "Ms"; } template <> FMT_CONSTEXPR const char* get_units() { return "Gs"; } template <> FMT_CONSTEXPR const char* get_units() { return "Ts"; } template <> FMT_CONSTEXPR const char* get_units() { return "Ps"; } template <> FMT_CONSTEXPR const char* get_units() { return "Es"; } template <> FMT_CONSTEXPR const char* get_units>() { return "m"; } template <> FMT_CONSTEXPR const char* get_units>() { return "h"; } enum class numeric_system { standard, // Alternative numeric system, e.g. 十二 instead of 12 in ja_JP locale. alternative }; // Parses a put_time-like format string and invokes handler actions. template FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin, const Char* end, Handler&& handler) { auto ptr = begin; while (ptr != end) { auto c = *ptr; if (c == '}') break; if (c != '%') { ++ptr; continue; } if (begin != ptr) handler.on_text(begin, ptr); ++ptr; // consume '%' if (ptr == end) FMT_THROW(format_error("invalid format")); c = *ptr++; switch (c) { case '%': handler.on_text(ptr - 1, ptr); break; case 'n': { const char newline[] = "\n"; handler.on_text(newline, newline + 1); break; } case 't': { const char tab[] = "\t"; handler.on_text(tab, tab + 1); break; } // Day of the week: case 'a': handler.on_abbr_weekday(); break; case 'A': handler.on_full_weekday(); break; case 'w': handler.on_dec0_weekday(numeric_system::standard); break; case 'u': handler.on_dec1_weekday(numeric_system::standard); break; // Month: case 'b': handler.on_abbr_month(); break; case 'B': handler.on_full_month(); break; // Hour, minute, second: case 'H': handler.on_24_hour(numeric_system::standard); break; case 'I': handler.on_12_hour(numeric_system::standard); break; case 'M': handler.on_minute(numeric_system::standard); break; case 'S': handler.on_second(numeric_system::standard); break; // Other: case 'c': handler.on_datetime(numeric_system::standard); break; case 'x': handler.on_loc_date(numeric_system::standard); break; case 'X': handler.on_loc_time(numeric_system::standard); break; case 'D': handler.on_us_date(); break; case 'F': handler.on_iso_date(); break; case 'r': handler.on_12_hour_time(); break; case 'R': handler.on_24_hour_time(); break; case 'T': handler.on_iso_time(); break; case 'p': handler.on_am_pm(); break; case 'Q': handler.on_duration_value(); break; case 'q': handler.on_duration_unit(); break; case 'z': handler.on_utc_offset(); break; case 'Z': handler.on_tz_name(); break; // Alternative representation: case 'E': { if (ptr == end) FMT_THROW(format_error("invalid format")); c = *ptr++; switch (c) { case 'c': handler.on_datetime(numeric_system::alternative); break; case 'x': handler.on_loc_date(numeric_system::alternative); break; case 'X': handler.on_loc_time(numeric_system::alternative); break; default: FMT_THROW(format_error("invalid format")); } break; } case 'O': if (ptr == end) FMT_THROW(format_error("invalid format")); c = *ptr++; switch (c) { case 'w': handler.on_dec0_weekday(numeric_system::alternative); break; case 'u': handler.on_dec1_weekday(numeric_system::alternative); break; case 'H': handler.on_24_hour(numeric_system::alternative); break; case 'I': handler.on_12_hour(numeric_system::alternative); break; case 'M': handler.on_minute(numeric_system::alternative); break; case 'S': handler.on_second(numeric_system::alternative); break; default: FMT_THROW(format_error("invalid format")); } break; default: FMT_THROW(format_error("invalid format")); } begin = ptr; } if (begin != ptr) handler.on_text(begin, ptr); return ptr; } struct chrono_format_checker { FMT_NORETURN void report_no_date() { FMT_THROW(format_error("no date")); } template void on_text(const Char*, const Char*) {} FMT_NORETURN void on_abbr_weekday() { report_no_date(); } FMT_NORETURN void on_full_weekday() { report_no_date(); } FMT_NORETURN void on_dec0_weekday(numeric_system) { report_no_date(); } FMT_NORETURN void on_dec1_weekday(numeric_system) { report_no_date(); } FMT_NORETURN void on_abbr_month() { report_no_date(); } FMT_NORETURN void on_full_month() { report_no_date(); } void on_24_hour(numeric_system) {} void on_12_hour(numeric_system) {} void on_minute(numeric_system) {} void on_second(numeric_system) {} FMT_NORETURN void on_datetime(numeric_system) { report_no_date(); } FMT_NORETURN void on_loc_date(numeric_system) { report_no_date(); } FMT_NORETURN void on_loc_time(numeric_system) { report_no_date(); } FMT_NORETURN void on_us_date() { report_no_date(); } FMT_NORETURN void on_iso_date() { report_no_date(); } void on_12_hour_time() {} void on_24_hour_time() {} void on_iso_time() {} void on_am_pm() {} void on_duration_value() {} void on_duration_unit() {} FMT_NORETURN void on_utc_offset() { report_no_date(); } FMT_NORETURN void on_tz_name() { report_no_date(); } }; template ::value)> inline bool isnan(T) { return false; } template ::value)> inline bool isnan(T value) { return std::isnan(value); } template ::value)> inline bool isfinite(T) { return true; } template ::value)> inline bool isfinite(T value) { return std::isfinite(value); } // Convers value to int and checks that it's in the range [0, upper). template ::value)> inline int to_nonnegative_int(T value, int upper) { FMT_ASSERT(value >= 0 && value <= upper, "invalid value"); (void)upper; return static_cast(value); } template ::value)> inline int to_nonnegative_int(T value, int upper) { FMT_ASSERT( std::isnan(value) || (value >= 0 && value <= static_cast(upper)), "invalid value"); (void)upper; return static_cast(value); } template ::value)> inline T mod(T x, int y) { return x % y; } template ::value)> inline T mod(T x, int y) { return std::fmod(x, static_cast(y)); } // If T is an integral type, maps T to its unsigned counterpart, otherwise // leaves it unchanged (unlike std::make_unsigned). template ::value> struct make_unsigned_or_unchanged { using type = T; }; template struct make_unsigned_or_unchanged { using type = typename std::make_unsigned::type; }; #if FMT_SAFE_DURATION_CAST // throwing version of safe_duration_cast template To fmt_safe_duration_cast(std::chrono::duration from) { int ec; To to = safe_duration_cast::safe_duration_cast(from, ec); if (ec) FMT_THROW(format_error("cannot format duration")); return to; } #endif template ::value)> inline std::chrono::duration get_milliseconds( std::chrono::duration d) { // this may overflow and/or the result may not fit in the // target type. #if FMT_SAFE_DURATION_CAST using CommonSecondsType = typename std::common_type::type; const auto d_as_common = fmt_safe_duration_cast(d); const auto d_as_whole_seconds = fmt_safe_duration_cast(d_as_common); // this conversion should be nonproblematic const auto diff = d_as_common - d_as_whole_seconds; const auto ms = fmt_safe_duration_cast>(diff); return ms; #else auto s = std::chrono::duration_cast(d); return std::chrono::duration_cast(d - s); #endif } template ::value)> inline std::chrono::duration get_milliseconds( std::chrono::duration d) { using common_type = typename std::common_type::type; auto ms = mod(d.count() * static_cast(Period::num) / static_cast(Period::den) * 1000, 1000); return std::chrono::duration(static_cast(ms)); } template OutputIt format_chrono_duration_value(OutputIt out, Rep val, int precision) { if (precision >= 0) return format_to(out, "{:.{}f}", val, precision); return format_to(out, std::is_floating_point::value ? "{:g}" : "{}", val); } template static OutputIt format_chrono_duration_unit(OutputIt out) { if (const char* unit = get_units()) return format_to(out, "{}", unit); if (Period::den == 1) return format_to(out, "[{}]s", Period::num); return format_to(out, "[{}/{}]s", Period::num, Period::den); } template struct chrono_formatter { FormatContext& context; OutputIt out; int precision; // rep is unsigned to avoid overflow. using rep = conditional_t::value && sizeof(Rep) < sizeof(int), unsigned, typename make_unsigned_or_unchanged::type>; rep val; using seconds = std::chrono::duration; seconds s; using milliseconds = std::chrono::duration; bool negative; using char_type = typename FormatContext::char_type; explicit chrono_formatter(FormatContext& ctx, OutputIt o, std::chrono::duration d) : context(ctx), out(o), val(d.count()), negative(false) { if (d.count() < 0) { val = 0 - val; negative = true; } // this may overflow and/or the result may not fit in the // target type. #if FMT_SAFE_DURATION_CAST // might need checked conversion (rep!=Rep) auto tmpval = std::chrono::duration(val); s = fmt_safe_duration_cast(tmpval); #else s = std::chrono::duration_cast( std::chrono::duration(val)); #endif } // returns true if nan or inf, writes to out. bool handle_nan_inf() { if (isfinite(val)) { return false; } if (isnan(val)) { write_nan(); return true; } // must be +-inf if (val > 0) { write_pinf(); } else { write_ninf(); } return true; } Rep hour() const { return static_cast(mod((s.count() / 3600), 24)); } Rep hour12() const { Rep hour = static_cast(mod((s.count() / 3600), 12)); return hour <= 0 ? 12 : hour; } Rep minute() const { return static_cast(mod((s.count() / 60), 60)); } Rep second() const { return static_cast(mod(s.count(), 60)); } std::tm time() const { auto time = std::tm(); time.tm_hour = to_nonnegative_int(hour(), 24); time.tm_min = to_nonnegative_int(minute(), 60); time.tm_sec = to_nonnegative_int(second(), 60); return time; } void write_sign() { if (negative) { *out++ = '-'; negative = false; } } void write(Rep value, int width) { write_sign(); if (isnan(value)) return write_nan(); uint32_or_64_t n = to_unsigned( to_nonnegative_int(value, (std::numeric_limits::max)())); int num_digits = internal::count_digits(n); if (width > num_digits) out = std::fill_n(out, width - num_digits, '0'); out = format_decimal(out, n, num_digits); } void write_nan() { std::copy_n("nan", 3, out); } void write_pinf() { std::copy_n("inf", 3, out); } void write_ninf() { std::copy_n("-inf", 4, out); } void format_localized(const tm& time, const char* format) { if (isnan(val)) return write_nan(); auto locale = context.locale().template get(); auto& facet = std::use_facet>(locale); std::basic_ostringstream os; os.imbue(locale); facet.put(os, os, ' ', &time, format, format + std::strlen(format)); auto str = os.str(); std::copy(str.begin(), str.end(), out); } void on_text(const char_type* begin, const char_type* end) { std::copy(begin, end, out); } // These are not implemented because durations don't have date information. void on_abbr_weekday() {} void on_full_weekday() {} void on_dec0_weekday(numeric_system) {} void on_dec1_weekday(numeric_system) {} void on_abbr_month() {} void on_full_month() {} void on_datetime(numeric_system) {} void on_loc_date(numeric_system) {} void on_loc_time(numeric_system) {} void on_us_date() {} void on_iso_date() {} void on_utc_offset() {} void on_tz_name() {} void on_24_hour(numeric_system ns) { if (handle_nan_inf()) return; if (ns == numeric_system::standard) return write(hour(), 2); auto time = tm(); time.tm_hour = to_nonnegative_int(hour(), 24); format_localized(time, "%OH"); } void on_12_hour(numeric_system ns) { if (handle_nan_inf()) return; if (ns == numeric_system::standard) return write(hour12(), 2); auto time = tm(); time.tm_hour = to_nonnegative_int(hour12(), 12); format_localized(time, "%OI"); } void on_minute(numeric_system ns) { if (handle_nan_inf()) return; if (ns == numeric_system::standard) return write(minute(), 2); auto time = tm(); time.tm_min = to_nonnegative_int(minute(), 60); format_localized(time, "%OM"); } void on_second(numeric_system ns) { if (handle_nan_inf()) return; if (ns == numeric_system::standard) { write(second(), 2); #if FMT_SAFE_DURATION_CAST // convert rep->Rep using duration_rep = std::chrono::duration; using duration_Rep = std::chrono::duration; auto tmpval = fmt_safe_duration_cast(duration_rep{val}); #else auto tmpval = std::chrono::duration(val); #endif auto ms = get_milliseconds(tmpval); if (ms != std::chrono::milliseconds(0)) { *out++ = '.'; write(ms.count(), 3); } return; } auto time = tm(); time.tm_sec = to_nonnegative_int(second(), 60); format_localized(time, "%OS"); } void on_12_hour_time() { if (handle_nan_inf()) return; format_localized(time(), "%r"); } void on_24_hour_time() { if (handle_nan_inf()) { *out++ = ':'; handle_nan_inf(); return; } write(hour(), 2); *out++ = ':'; write(minute(), 2); } void on_iso_time() { on_24_hour_time(); *out++ = ':'; if (handle_nan_inf()) return; write(second(), 2); } void on_am_pm() { if (handle_nan_inf()) return; format_localized(time(), "%p"); } void on_duration_value() { if (handle_nan_inf()) return; write_sign(); out = format_chrono_duration_value(out, val, precision); } void on_duration_unit() { out = format_chrono_duration_unit(out); } }; } // namespace internal template struct formatter, Char> { private: basic_format_specs specs; int precision; using arg_ref_type = internal::arg_ref; arg_ref_type width_ref; arg_ref_type precision_ref; mutable basic_string_view format_str; using duration = std::chrono::duration; struct spec_handler { formatter& f; basic_parse_context& context; basic_string_view format_str; template FMT_CONSTEXPR arg_ref_type make_arg_ref(Id arg_id) { context.check_arg_id(arg_id); return arg_ref_type(arg_id); } FMT_CONSTEXPR arg_ref_type make_arg_ref(basic_string_view arg_id) { context.check_arg_id(arg_id); const auto str_val = internal::string_view_metadata(format_str, arg_id); return arg_ref_type(str_val); } FMT_CONSTEXPR arg_ref_type make_arg_ref(internal::auto_id) { return arg_ref_type(context.next_arg_id()); } void on_error(const char* msg) { FMT_THROW(format_error(msg)); } void on_fill(Char fill) { f.specs.fill[0] = fill; } void on_align(align_t align) { f.specs.align = align; } void on_width(unsigned width) { f.specs.width = width; } void on_precision(unsigned precision) { f.precision = precision; } void end_precision() {} template void on_dynamic_width(Id arg_id) { f.width_ref = make_arg_ref(arg_id); } template void on_dynamic_precision(Id arg_id) { f.precision_ref = make_arg_ref(arg_id); } }; using iterator = typename basic_parse_context::iterator; struct parse_range { iterator begin; iterator end; }; FMT_CONSTEXPR parse_range do_parse(basic_parse_context& ctx) { auto begin = ctx.begin(), end = ctx.end(); if (begin == end || *begin == '}') return {begin, begin}; spec_handler handler{*this, ctx, format_str}; begin = internal::parse_align(begin, end, handler); if (begin == end) return {begin, begin}; begin = internal::parse_width(begin, end, handler); if (begin == end) return {begin, begin}; if (*begin == '.') { if (std::is_floating_point::value) begin = internal::parse_precision(begin, end, handler); else handler.on_error("precision not allowed for this argument type"); } end = parse_chrono_format(begin, end, internal::chrono_format_checker()); return {begin, end}; } public: formatter() : precision(-1) {} FMT_CONSTEXPR auto parse(basic_parse_context& ctx) -> decltype(ctx.begin()) { auto range = do_parse(ctx); format_str = basic_string_view( &*range.begin, internal::to_unsigned(range.end - range.begin)); return range.end; } template auto format(const duration& d, FormatContext& ctx) -> decltype(ctx.out()) { auto begin = format_str.begin(), end = format_str.end(); // As a possible future optimization, we could avoid extra copying if width // is not specified. basic_memory_buffer buf; auto out = std::back_inserter(buf); using range = internal::output_range; internal::basic_writer w(range(ctx.out())); internal::handle_dynamic_spec( specs.width, width_ref, ctx, format_str.begin()); internal::handle_dynamic_spec( precision, precision_ref, ctx, format_str.begin()); if (begin == end || *begin == '}') { out = internal::format_chrono_duration_value(out, d.count(), precision); internal::format_chrono_duration_unit(out); } else { internal::chrono_formatter f( ctx, out, d); f.precision = precision; parse_chrono_format(begin, end, f); } w.write(buf.data(), buf.size(), specs); return w.out(); } }; FMT_END_NAMESPACE #endif // FMT_CHRONO_H_ pog-0.5.3/deps/fmt/fmt/include/fmt/color.h000066400000000000000000000545171361707036300203350ustar00rootroot00000000000000// 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 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 enum class terminal_color : uint8_t { black = 30, red, green, yellow, blue, magenta, cyan, white, bright_black = 90, bright_red, bright_green, bright_yellow, bright_blue, bright_magenta, bright_cyan, bright_white }; enum class emphasis : uint8_t { bold = 1, italic = 1 << 1, underline = 1 << 2, strikethrough = 1 << 3 }; // rgb is a struct for red, green and blue colors. // Using the name "rgb" makes some editors show the color in a tooltip. struct rgb { FMT_CONSTEXPR rgb() : r(0), g(0), b(0) {} FMT_CONSTEXPR rgb(uint8_t r_, uint8_t g_, uint8_t b_) : r(r_), g(g_), b(b_) {} FMT_CONSTEXPR rgb(uint32_t hex) : r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b(hex & 0xFF) {} FMT_CONSTEXPR 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; }; namespace internal { // color is a struct of either a rgb color or a terminal color. struct color_type { FMT_CONSTEXPR color_type() FMT_NOEXCEPT : is_rgb(), value{} {} FMT_CONSTEXPR color_type(color rgb_color) FMT_NOEXCEPT : is_rgb(true), value{} { value.rgb_color = static_cast(rgb_color); } FMT_CONSTEXPR color_type(rgb rgb_color) FMT_NOEXCEPT : is_rgb(true), value{} { value.rgb_color = (static_cast(rgb_color.r) << 16) | (static_cast(rgb_color.g) << 8) | rgb_color.b; } FMT_CONSTEXPR color_type(terminal_color term_color) FMT_NOEXCEPT : is_rgb(), value{} { value.term_color = static_cast(term_color); } bool is_rgb; union color_union { uint8_t term_color; uint32_t rgb_color; } value; }; } // namespace internal // Experimental text formatting support. class text_style { public: FMT_CONSTEXPR text_style(emphasis em = emphasis()) FMT_NOEXCEPT : set_foreground_color(), set_background_color(), ems(em) {} FMT_CONSTEXPR text_style& operator|=(const text_style& rhs) { if (!set_foreground_color) { set_foreground_color = rhs.set_foreground_color; foreground_color = rhs.foreground_color; } else if (rhs.set_foreground_color) { if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb) FMT_THROW(format_error("can't OR a terminal color")); foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color; } if (!set_background_color) { set_background_color = rhs.set_background_color; background_color = rhs.background_color; } else if (rhs.set_background_color) { if (!background_color.is_rgb || !rhs.background_color.is_rgb) FMT_THROW(format_error("can't OR a terminal color")); background_color.value.rgb_color |= rhs.background_color.value.rgb_color; } ems = static_cast(static_cast(ems) | static_cast(rhs.ems)); return *this; } friend FMT_CONSTEXPR text_style operator|(text_style lhs, const text_style& rhs) { return lhs |= rhs; } FMT_CONSTEXPR text_style& operator&=(const text_style& rhs) { if (!set_foreground_color) { set_foreground_color = rhs.set_foreground_color; foreground_color = rhs.foreground_color; } else if (rhs.set_foreground_color) { if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb) FMT_THROW(format_error("can't AND a terminal color")); foreground_color.value.rgb_color &= rhs.foreground_color.value.rgb_color; } if (!set_background_color) { set_background_color = rhs.set_background_color; background_color = rhs.background_color; } else if (rhs.set_background_color) { if (!background_color.is_rgb || !rhs.background_color.is_rgb) FMT_THROW(format_error("can't AND a terminal color")); background_color.value.rgb_color &= rhs.background_color.value.rgb_color; } ems = static_cast(static_cast(ems) & static_cast(rhs.ems)); return *this; } friend FMT_CONSTEXPR text_style operator&(text_style lhs, const text_style& rhs) { return lhs &= rhs; } FMT_CONSTEXPR bool has_foreground() const FMT_NOEXCEPT { return set_foreground_color; } FMT_CONSTEXPR bool has_background() const FMT_NOEXCEPT { return set_background_color; } FMT_CONSTEXPR bool has_emphasis() const FMT_NOEXCEPT { return static_cast(ems) != 0; } FMT_CONSTEXPR internal::color_type get_foreground() const FMT_NOEXCEPT { assert(has_foreground() && "no foreground specified for this style"); return foreground_color; } FMT_CONSTEXPR internal::color_type get_background() const FMT_NOEXCEPT { assert(has_background() && "no background specified for this style"); return background_color; } FMT_CONSTEXPR emphasis get_emphasis() const FMT_NOEXCEPT { assert(has_emphasis() && "no emphasis specified for this style"); return ems; } private: FMT_CONSTEXPR text_style(bool is_foreground, internal::color_type text_color) FMT_NOEXCEPT : set_foreground_color(), set_background_color(), ems() { if (is_foreground) { foreground_color = text_color; set_foreground_color = true; } else { background_color = text_color; set_background_color = true; } } friend FMT_CONSTEXPR_DECL text_style fg(internal::color_type foreground) FMT_NOEXCEPT; friend FMT_CONSTEXPR_DECL text_style bg(internal::color_type background) FMT_NOEXCEPT; internal::color_type foreground_color; internal::color_type background_color; bool set_foreground_color; bool set_background_color; emphasis ems; }; FMT_CONSTEXPR text_style fg(internal::color_type foreground) FMT_NOEXCEPT { return text_style(/*is_foreground=*/true, foreground); } FMT_CONSTEXPR text_style bg(internal::color_type background) FMT_NOEXCEPT { return text_style(/*is_foreground=*/false, background); } FMT_CONSTEXPR text_style operator|(emphasis lhs, emphasis rhs) FMT_NOEXCEPT { return text_style(lhs) | rhs; } namespace internal { template struct ansi_color_escape { FMT_CONSTEXPR ansi_color_escape(internal::color_type text_color, const char* esc) FMT_NOEXCEPT { // If we have a terminal color, we need to output another escape code // sequence. if (!text_color.is_rgb) { bool is_background = esc == internal::data::background_color; uint32_t value = text_color.value.term_color; // Background ASCII codes are the same as the foreground ones but with // 10 more. if (is_background) value += 10u; std::size_t index = 0; buffer[index++] = static_cast('\x1b'); buffer[index++] = static_cast('['); if (value >= 100u) { buffer[index++] = static_cast('1'); value %= 100u; } buffer[index++] = static_cast('0' + value / 10u); buffer[index++] = static_cast('0' + value % 10u); buffer[index++] = static_cast('m'); buffer[index++] = static_cast('\0'); return; } for (int i = 0; i < 7; i++) { buffer[i] = static_cast(esc[i]); } rgb color(text_color.value.rgb_color); to_esc(color.r, buffer + 7, ';'); to_esc(color.g, buffer + 11, ';'); to_esc(color.b, buffer + 15, 'm'); buffer[19] = static_cast(0); } FMT_CONSTEXPR ansi_color_escape(emphasis em) FMT_NOEXCEPT { uint8_t em_codes[4] = {}; uint8_t em_bits = static_cast(em); if (em_bits & static_cast(emphasis::bold)) em_codes[0] = 1; if (em_bits & static_cast(emphasis::italic)) em_codes[1] = 3; if (em_bits & static_cast(emphasis::underline)) em_codes[2] = 4; if (em_bits & static_cast(emphasis::strikethrough)) em_codes[3] = 9; std::size_t index = 0; for (int i = 0; i < 4; ++i) { if (!em_codes[i]) continue; buffer[index++] = static_cast('\x1b'); buffer[index++] = static_cast('['); buffer[index++] = static_cast('0' + em_codes[i]); buffer[index++] = static_cast('m'); } buffer[index++] = static_cast(0); } FMT_CONSTEXPR operator const Char*() const FMT_NOEXCEPT { return buffer; } FMT_CONSTEXPR const Char* begin() const FMT_NOEXCEPT { return buffer; } FMT_CONSTEXPR const Char* end() const FMT_NOEXCEPT { return buffer + std::strlen(buffer); } private: Char buffer[7u + 3u * 4u + 1u]; static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out, char delimiter) FMT_NOEXCEPT { out[0] = static_cast('0' + c / 100); out[1] = static_cast('0' + c / 10 % 10); out[2] = static_cast('0' + c % 10); out[3] = static_cast(delimiter); } }; template FMT_CONSTEXPR ansi_color_escape make_foreground_color( internal::color_type foreground) FMT_NOEXCEPT { return ansi_color_escape(foreground, internal::data::foreground_color); } template FMT_CONSTEXPR ansi_color_escape make_background_color( internal::color_type background) FMT_NOEXCEPT { return ansi_color_escape(background, internal::data::background_color); } template FMT_CONSTEXPR ansi_color_escape make_emphasis(emphasis em) FMT_NOEXCEPT { return ansi_color_escape(em); } template inline void fputs(const Char* chars, FILE* stream) FMT_NOEXCEPT { std::fputs(chars, stream); } template <> inline void fputs(const wchar_t* chars, FILE* stream) FMT_NOEXCEPT { std::fputws(chars, stream); } template inline void reset_color(FILE* stream) FMT_NOEXCEPT { fputs(internal::data::reset_color, stream); } template <> inline void reset_color(FILE* stream) FMT_NOEXCEPT { fputs(internal::data::wreset_color, stream); } template inline void reset_color(basic_memory_buffer& buffer) FMT_NOEXCEPT { const char* begin = data::reset_color; const char* end = begin + sizeof(data::reset_color) - 1; buffer.append(begin, end); } template std::basic_string vformat(const text_style& ts, basic_string_view format_str, basic_format_args > args) { basic_memory_buffer buffer; bool has_style = false; if (ts.has_emphasis()) { has_style = true; ansi_color_escape escape = make_emphasis(ts.get_emphasis()); buffer.append(escape.begin(), escape.end()); } if (ts.has_foreground()) { has_style = true; ansi_color_escape escape = make_foreground_color(ts.get_foreground()); buffer.append(escape.begin(), escape.end()); } if (ts.has_background()) { has_style = true; ansi_color_escape escape = make_background_color(ts.get_background()); buffer.append(escape.begin(), escape.end()); } internal::vformat_to(buffer, format_str, args); if (has_style) { reset_color(buffer); } return fmt::to_string(buffer); } } // namespace internal template > void vprint(std::FILE* f, const text_style& ts, const S& format, basic_format_args > args) { bool has_style = false; if (ts.has_emphasis()) { has_style = true; internal::fputs(internal::make_emphasis(ts.get_emphasis()), f); } if (ts.has_foreground()) { has_style = true; internal::fputs( internal::make_foreground_color(ts.get_foreground()), f); } if (ts.has_background()) { has_style = true; internal::fputs( internal::make_background_color(ts.get_background()), f); } vprint(f, format, args); if (has_style) { internal::reset_color(f); } } /** Formats a string and prints it to the specified file stream using ANSI escape sequences to specify text formatting. Example: fmt::print(fmt::emphasis::bold | fg(fmt::color::red), "Elapsed time: {0:.2f} seconds", 1.23); */ template ::value)> void print(std::FILE* f, const text_style& ts, const S& format_str, const Args&... args) { internal::check_format_string(format_str); using context = buffer_context >; format_arg_store as{args...}; vprint(f, ts, format_str, basic_format_args(as)); } /** Formats a string and prints it to stdout using ANSI escape sequences to specify text formatting. Example: fmt::print(fmt::emphasis::bold | fg(fmt::color::red), "Elapsed time: {0:.2f} seconds", 1.23); */ template ::value)> void print(const text_style& ts, const S& format_str, const Args&... args) { return print(stdout, ts, format_str, args...); } template > inline std::basic_string vformat( const text_style& ts, const S& format_str, basic_format_args > args) { return internal::vformat(ts, to_string_view(format_str), args); } /** \rst Formats arguments and returns the result as a string using ANSI escape sequences to specify text formatting. **Example**:: #include std::string message = fmt::format(fmt::emphasis::bold | fg(fmt::color::red), "The answer is {}", 42); \endrst */ template > inline std::basic_string format(const text_style& ts, const S& format_str, const Args&... args) { return internal::vformat(ts, to_string_view(format_str), {internal::make_args_checked(format_str, args...)}); } FMT_END_NAMESPACE #endif // FMT_COLOR_H_ pog-0.5.3/deps/fmt/fmt/include/fmt/compile.h000066400000000000000000000365111361707036300206410ustar00rootroot00000000000000// Formatting library for C++ - experimental format string compilation // // Copyright (c) 2012 - present, Victor Zverovich and fmt contributors // All rights reserved. // // For the license information refer to format.h. #ifndef FMT_COMPILE_H_ #define FMT_COMPILE_H_ #include #include "format.h" FMT_BEGIN_NAMESPACE namespace internal { template struct format_part { public: struct named_argument_id { FMT_CONSTEXPR named_argument_id(internal::string_view_metadata id) : id(id) {} internal::string_view_metadata id; }; struct argument_id { FMT_CONSTEXPR argument_id() : argument_id(0u) {} FMT_CONSTEXPR argument_id(unsigned id) : which(which_arg_id::index), val(id) {} FMT_CONSTEXPR argument_id(internal::string_view_metadata id) : which(which_arg_id::named_index), val(id) {} enum class which_arg_id { index, named_index }; which_arg_id which; union value { FMT_CONSTEXPR value() : index(0u) {} FMT_CONSTEXPR value(unsigned id) : index(id) {} FMT_CONSTEXPR value(internal::string_view_metadata id) : named_index(id) {} unsigned index; internal::string_view_metadata named_index; } val; }; struct specification { FMT_CONSTEXPR specification() : arg_id(0u) {} FMT_CONSTEXPR specification(unsigned id) : arg_id(id) {} FMT_CONSTEXPR specification(internal::string_view_metadata id) : arg_id(id) {} argument_id arg_id; internal::dynamic_format_specs parsed_specs; }; FMT_CONSTEXPR format_part() : which(kind::argument_id), end_of_argument_id(0u), val(0u) {} FMT_CONSTEXPR format_part(internal::string_view_metadata text) : which(kind::text), end_of_argument_id(0u), val(text) {} FMT_CONSTEXPR format_part(unsigned id) : which(kind::argument_id), end_of_argument_id(0u), val(id) {} FMT_CONSTEXPR format_part(named_argument_id arg_id) : which(kind::named_argument_id), end_of_argument_id(0u), val(arg_id) {} FMT_CONSTEXPR format_part(specification spec) : which(kind::specification), end_of_argument_id(0u), val(spec) {} enum class kind { argument_id, named_argument_id, text, specification }; kind which; std::size_t end_of_argument_id; union value { FMT_CONSTEXPR value() : arg_id(0u) {} FMT_CONSTEXPR value(unsigned id) : arg_id(id) {} FMT_CONSTEXPR value(named_argument_id named_id) : named_arg_id(named_id.id) {} FMT_CONSTEXPR value(internal::string_view_metadata t) : text(t) {} FMT_CONSTEXPR value(specification s) : spec(s) {} unsigned arg_id; internal::string_view_metadata named_arg_id; internal::string_view_metadata text; specification spec; } val; }; template class format_preparation_handler : public internal::error_handler { private: using part = format_part; public: using iterator = typename basic_string_view::iterator; FMT_CONSTEXPR format_preparation_handler(basic_string_view format, PartsContainer& parts) : parts_(parts), format_(format), parse_context_(format) {} FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) { if (begin == end) return; const auto offset = begin - format_.data(); const auto size = end - begin; parts_.push_back(part(string_view_metadata(offset, size))); } FMT_CONSTEXPR void on_arg_id() { parts_.push_back(part(parse_context_.next_arg_id())); } FMT_CONSTEXPR void on_arg_id(unsigned id) { parse_context_.check_arg_id(id); parts_.push_back(part(id)); } FMT_CONSTEXPR void on_arg_id(basic_string_view id) { const auto view = string_view_metadata(format_, id); const auto arg_id = typename part::named_argument_id(view); parts_.push_back(part(arg_id)); } FMT_CONSTEXPR void on_replacement_field(const Char* ptr) { parts_.back().end_of_argument_id = ptr - format_.begin(); } FMT_CONSTEXPR const Char* on_format_specs(const Char* begin, const Char* end) { const auto specs_offset = to_unsigned(begin - format_.begin()); using parse_context = basic_parse_context; internal::dynamic_format_specs parsed_specs; dynamic_specs_handler handler(parsed_specs, parse_context_); begin = parse_format_specs(begin, end, handler); if (*begin != '}') on_error("missing '}' in format string"); auto& last_part = parts_.back(); auto specs = last_part.which == part::kind::argument_id ? typename part::specification(last_part.val.arg_id) : typename part::specification(last_part.val.named_arg_id); specs.parsed_specs = parsed_specs; last_part = part(specs); last_part.end_of_argument_id = specs_offset; return begin; } private: PartsContainer& parts_; basic_string_view format_; basic_parse_context parse_context_; }; template class prepared_format { public: using char_type = char_t; using format_part_t = format_part; constexpr prepared_format(Format f) : format_(std::move(f)), parts_provider_(to_string_view(format_)) {} prepared_format() = delete; using context = buffer_context; template auto vformat_to(Range out, basic_format_args args) const -> typename Context::iterator { const auto format_view = internal::to_string_view(format_); basic_parse_context parse_ctx(format_view); Context ctx(out.begin(), args); const auto& parts = parts_provider_.parts(); for (auto part_it = parts.begin(); part_it != parts.end(); ++part_it) { const auto& part = *part_it; const auto& value = part.val; switch (part.which) { case format_part_t::kind::text: { const auto text = value.text.to_view(format_view.data()); auto output = ctx.out(); auto&& it = internal::reserve(output, text.size()); it = std::copy_n(text.begin(), text.size(), it); ctx.advance_to(output); } break; case format_part_t::kind::argument_id: { advance_parse_context_to_specification(parse_ctx, part); format_arg(parse_ctx, ctx, value.arg_id); } break; case format_part_t::kind::named_argument_id: { advance_parse_context_to_specification(parse_ctx, part); const auto named_arg_id = value.named_arg_id.to_view(format_view.data()); format_arg(parse_ctx, ctx, named_arg_id); } break; case format_part_t::kind::specification: { const auto& arg_id_value = value.spec.arg_id.val; const auto arg = value.spec.arg_id.which == format_part_t::argument_id::which_arg_id::index ? ctx.arg(arg_id_value.index) : ctx.arg(arg_id_value.named_index.to_view( to_string_view(format_).data())); auto specs = value.spec.parsed_specs; handle_dynamic_spec( specs.width, specs.width_ref, ctx, format_view.begin()); handle_dynamic_spec( specs.precision, specs.precision_ref, ctx, format_view.begin()); check_prepared_specs(specs, arg.type()); advance_parse_context_to_specification(parse_ctx, part); ctx.advance_to( visit_format_arg(arg_formatter(ctx, nullptr, &specs), arg)); } break; } } return ctx.out(); } private: void advance_parse_context_to_specification( basic_parse_context& parse_ctx, const format_part_t& part) const { const auto view = to_string_view(format_); const auto specification_begin = view.data() + part.end_of_argument_id; advance_to(parse_ctx, specification_begin); } template void format_arg(basic_parse_context& parse_ctx, Context& ctx, Id arg_id) const { parse_ctx.check_arg_id(arg_id); const auto stopped_at = visit_format_arg(arg_formatter(ctx), ctx.arg(arg_id)); ctx.advance_to(stopped_at); } template void check_prepared_specs(const basic_format_specs& specs, internal::type arg_type) const { internal::error_handler h; numeric_specs_checker checker(h, arg_type); if (specs.align == align::numeric) checker.require_numeric_argument(); if (specs.sign != sign::none) checker.check_sign(); if (specs.alt) checker.require_numeric_argument(); if (specs.precision >= 0) checker.check_precision(); } private: Format format_; PreparedPartsProvider parts_provider_; }; template struct part_counter { unsigned num_parts = 0; FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) { if (begin != end) ++num_parts; } FMT_CONSTEXPR void on_arg_id() { ++num_parts; } FMT_CONSTEXPR void on_arg_id(unsigned) { ++num_parts; } FMT_CONSTEXPR void on_arg_id(basic_string_view) { ++num_parts; } FMT_CONSTEXPR void on_replacement_field(const Char*) {} FMT_CONSTEXPR const Char* on_format_specs(const Char* begin, const Char* end) { // Find the matching brace. unsigned braces_counter = 0; for (; begin != end; ++begin) { if (*begin == '{') { ++braces_counter; } else if (*begin == '}') { if (braces_counter == 0u) break; --braces_counter; } } return begin; } FMT_CONSTEXPR void on_error(const char*) {} }; template class compiletime_prepared_parts_type_provider { private: using char_type = char_t; static FMT_CONSTEXPR unsigned count_parts() { FMT_CONSTEXPR_DECL const auto text = to_string_view(Format{}); part_counter counter; internal::parse_format_string(text, counter); return counter.num_parts; } // Workaround for old compilers. Compiletime parts preparation will not be // performed with them anyway. #if FMT_USE_CONSTEXPR static FMT_CONSTEXPR_DECL const unsigned number_of_format_parts = compiletime_prepared_parts_type_provider::count_parts(); #else static const unsigned number_of_format_parts = 0u; #endif public: template struct format_parts_array { using value_type = format_part; FMT_CONSTEXPR format_parts_array() : arr{} {} FMT_CONSTEXPR value_type& operator[](unsigned ind) { return arr[ind]; } FMT_CONSTEXPR const value_type* begin() const { return arr; } FMT_CONSTEXPR const value_type* end() const { return begin() + N; } private: value_type arr[N]; }; struct empty { // Parts preparator will search for it using value_type = format_part; }; using type = conditional_t, empty>; }; template class compiletime_prepared_parts_collector { private: using format_part = typename Parts::value_type; public: FMT_CONSTEXPR explicit compiletime_prepared_parts_collector(Parts& parts) : parts_{parts}, counter_{0u} {} FMT_CONSTEXPR void push_back(format_part part) { parts_[counter_++] = part; } FMT_CONSTEXPR format_part& back() { return parts_[counter_ - 1]; } private: Parts& parts_; unsigned counter_; }; template FMT_CONSTEXPR PartsContainer prepare_parts(basic_string_view format) { PartsContainer parts; internal::parse_format_string( format, format_preparation_handler(format, parts)); return parts; } template FMT_CONSTEXPR PartsContainer prepare_compiletime_parts(basic_string_view format) { using collector = compiletime_prepared_parts_collector; PartsContainer parts; collector c(parts); internal::parse_format_string( format, format_preparation_handler(format, c)); return parts; } template class runtime_parts_provider { public: runtime_parts_provider() = delete; template runtime_parts_provider(basic_string_view format) : parts_(prepare_parts(format)) {} const PartsContainer& parts() const { return parts_; } private: PartsContainer parts_; }; template struct compiletime_parts_provider { compiletime_parts_provider() = delete; template FMT_CONSTEXPR compiletime_parts_provider(basic_string_view) {} const PartsContainer& parts() const { static FMT_CONSTEXPR_DECL const PartsContainer prepared_parts = prepare_compiletime_parts( internal::to_string_view(Format{})); return prepared_parts; } }; } // namespace internal #if FMT_USE_CONSTEXPR template ::value)> FMT_CONSTEXPR auto compile(S format_str) -> internal::prepared_format< S, internal::compiletime_parts_provider< S, typename internal::compiletime_prepared_parts_type_provider::type>, Args...> { return format_str; } #endif template auto compile(const Char (&format_str)[N]) -> internal::prepared_format< std::basic_string, internal::runtime_parts_provider>>, Args...> { return std::basic_string(format_str, N - 1); } template std::basic_string format(const CompiledFormat& cf, const Args&... args) { basic_memory_buffer buffer; using range = internal::buffer_range; using context = buffer_context; cf.template vformat_to(range(buffer), {make_format_args(args...)}); return to_string(buffer); } template OutputIt format_to(OutputIt out, const CompiledFormat& cf, const Args&... args) { using char_type = typename CompiledFormat::char_type; using range = internal::output_range; using context = format_context_t; return cf.template vformat_to( range(out), {make_format_args(args...)}); } template ::value)> format_to_n_result format_to_n(OutputIt out, size_t n, const CompiledFormat& cf, const Args&... args) { auto it = format_to(internal::truncating_iterator(out, n), cf, args...); return {it.base(), it.count()}; } template std::size_t formatted_size(const CompiledFormat& cf, const Args&... args) { return fmt::format_to( internal::counting_iterator(), cf, args...) .count(); } FMT_END_NAMESPACE #endif // FMT_COMPILE_H_ pog-0.5.3/deps/fmt/fmt/include/fmt/core.h000066400000000000000000001334101361707036300201350ustar00rootroot00000000000000// 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 60000 #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_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 // Check if exceptions are disabled. #ifndef FMT_EXCEPTIONS # if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || \ FMT_MSC_VER && !_HAS_EXCEPTIONS # define FMT_EXCEPTIONS 0 # else # define FMT_EXCEPTIONS 1 # 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 # 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 // [[noreturn]] is disabled on MSVC because of bogus unreachable code warnings. #if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VER # define FMT_NORETURN [[noreturn]] #else # define FMT_NORETURN #endif #ifndef FMT_DEPRECATED # if (FMT_HAS_CPP_ATTRIBUTE(deprecated) && __cplusplus >= 201402L) || \ FMT_MSC_VER >= 1900 # define FMT_DEPRECATED [[deprecated]] # else # if defined(__GNUC__) || defined(__clang__) # define FMT_DEPRECATED __attribute__((deprecated)) # elif FMT_MSC_VER # define FMT_DEPRECATED __declspec(deprecated) # else # define FMT_DEPRECATED /* deprecated */ # endif # endif #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 v6; \ } # endif # define FMT_BEGIN_NAMESPACE \ namespace fmt { \ FMT_INLINE_NAMESPACE v6 { #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) # define FMT_EXTERN_TEMPLATE_API FMT_API # endif #endif #ifndef FMT_API # define FMT_API #endif #ifndef FMT_EXTERN_TEMPLATE_API # define FMT_EXTERN_TEMPLATE_API #endif #ifndef FMT_HEADER_ONLY # define FMT_EXTERN extern #else # define FMT_EXTERN #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_STRING_VIEW #elif FMT_HAS_INCLUDE("experimental/string_view") && __cplusplus >= 201402L # include # define FMT_USE_EXPERIMENTAL_STRING_VIEW #endif FMT_BEGIN_NAMESPACE // Implementations of enable_if_t and other types for pre-C++14 systems. template using enable_if_t = typename std::enable_if::type; template using conditional_t = typename std::conditional::type; template using bool_constant = std::integral_constant; template using remove_reference_t = typename std::remove_reference::type; template using remove_const_t = typename std::remove_const::type; struct monostate {}; // An enable_if helper to be used in template parameters which results in much // shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed // to workaround a bug in MSVC 2019 (see #1140 and #1186). #define FMT_ENABLE_IF(...) enable_if_t<(__VA_ARGS__), int> = 0 namespace internal { // A workaround for gcc 4.8 to make void_t work in a SFINAE context. template struct void_t_impl { using type = void; }; #if defined(FMT_USE_STRING_VIEW) template using std_string_view = std::basic_string_view; #elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW) template using std_string_view = std::experimental::basic_string_view; #else template struct std_string_view {}; #endif // 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); } } // namespace internal template using void_t = typename internal::void_t_impl::type; /** 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: using char_type = Char; using iterator = const Char*; FMT_CONSTEXPR basic_string_view() FMT_NOEXCEPT : data_(nullptr), 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 */ basic_string_view(const Char* s) : data_(s), size_(std::char_traits::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()) {} template < typename S, FMT_ENABLE_IF(std::is_same>::value)> FMT_CONSTEXPR basic_string_view(S 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; } }; using string_view = basic_string_view; using wstring_view = basic_string_view; #ifndef __cpp_char8_t // A UTF-8 code unit type. enum char8_t : unsigned char {}; #endif /** Specifies if ``T`` is a character type. Can be specialized by users. */ template struct is_char : std::false_type {}; template <> struct is_char : std::true_type {}; template <> struct is_char : std::true_type {}; template <> struct is_char : std::true_type {}; template <> struct is_char : std::true_type {}; template <> struct is_char : std::true_type {}; /** \rst Returns a string view of `s`. In order to add custom string type support to {fmt} provide an overload of `to_string_view` for it in the same namespace as the type for the argument-dependent lookup to work. **Example**:: namespace my_ns { inline string_view to_string_view(const my_string& s) { return {s.data(), s.length()}; } } std::string message = fmt::format(my_string("The answer is {}"), 42); \endrst */ template ::value)> inline basic_string_view to_string_view(const Char* s) { return s; } template inline basic_string_view to_string_view( const std::basic_string& s) { return {s.data(), s.size()}; } template inline basic_string_view to_string_view(basic_string_view s) { return s; } template >::value)> inline basic_string_view to_string_view( internal::std_string_view s) { return s; } // 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 {}; template struct is_compile_string : std::is_base_of {}; template ::value)> constexpr basic_string_view to_string_view(const S& s) { return s; } namespace internal { void to_string_view(...); using fmt::v6::to_string_view; // Specifies whether S is a string type convertible to fmt::basic_string_view. // It should be a constexpr function but MSVC 2017 fails to compile it in // enable_if and MSVC 2015 fails to compile it as an alias template. template struct is_string : std::is_class()))> { }; template struct char_t_impl {}; template struct char_t_impl::value>> { using result = decltype(to_string_view(std::declval())); using type = typename result::char_type; }; 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_NORETURN FMT_API void on_error(const char* message); }; } // namespace internal /** String's character type. */ template using char_t = typename internal::char_t_impl::type; // 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: using char_type = Char; using iterator = typename basic_string_view::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 int next_arg_id() { if (next_arg_id_ >= 0) return next_arg_id_++; on_error("cannot switch from manual to automatic argument indexing"); return 0; } FMT_CONSTEXPR bool check_arg_id(int) { if (next_arg_id_ > 0) { on_error("cannot switch from automatic to manual argument indexing"); return false; } next_arg_id_ = -1; return true; } FMT_CONSTEXPR 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; } }; using format_parse_context = basic_parse_context; using wformat_parse_context = basic_parse_context; using parse_context FMT_DEPRECATED = basic_parse_context; using wparse_context FMT_DEPRECATED = basic_parse_context; template class basic_format_arg; template class basic_format_args; // A formatter for objects of type T. template struct formatter { // A deleted default constructor indicates a disabled formatter. formatter() = delete; }; template struct FMT_DEPRECATED convert_to_int : bool_constant::value && std::is_convertible::value> {}; namespace internal { // Specifies if T has an enabled formatter specialization. A type can be // formattable even if it doesn't have a formatter e.g. via a conversion. template using has_formatter = std::is_constructible>; /** A contiguous memory buffer with an optional growing ability. */ template class buffer { private: buffer(const buffer&) = delete; void operator=(const 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. buffer(std::size_t sz) FMT_NOEXCEPT : size_(sz), capacity_(sz) {} buffer(T* p = nullptr, 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: using value_type = T; using const_reference = const T&; virtual ~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]; } }; // A container-backed buffer. template class container_buffer : public 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) : buffer(c.size()), container_(c) {} }; // Extracts a reference to the container from back_insert_iterator. template inline Container& get_container(std::back_insert_iterator it) { using bi_iterator = std::back_insert_iterator; struct accessor : bi_iterator { accessor(bi_iterator iter) : bi_iterator(iter) {} using bi_iterator::container; }; return *accessor(it).container; } template struct fallback_formatter { fallback_formatter() = delete; }; // Specifies if T has an enabled fallback_formatter specialization. template using has_fallback_formatter = std::is_constructible>; template struct named_arg_base; template struct named_arg; 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 }; // Maps core type T to the corresponding type enum constant. template struct type_constant : std::integral_constant {}; #define FMT_TYPE_CONSTANT(Type, constant) \ template \ struct type_constant : std::integral_constant {} FMT_TYPE_CONSTANT(const named_arg_base&, named_arg_type); FMT_TYPE_CONSTANT(int, int_type); FMT_TYPE_CONSTANT(unsigned, uint_type); FMT_TYPE_CONSTANT(long long, long_long_type); FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type); FMT_TYPE_CONSTANT(bool, bool_type); FMT_TYPE_CONSTANT(Char, char_type); FMT_TYPE_CONSTANT(double, double_type); FMT_TYPE_CONSTANT(long double, long_double_type); FMT_TYPE_CONSTANT(const Char*, cstring_type); FMT_TYPE_CONSTANT(basic_string_view, string_type); FMT_TYPE_CONSTANT(const void*, pointer_type); FMT_CONSTEXPR bool is_integral(type t) { FMT_ASSERT(t != named_arg_type, "invalid argument type"); return t > none_type && t <= last_integer_type; } FMT_CONSTEXPR bool is_arithmetic(type t) { FMT_ASSERT(t != named_arg_type, "invalid argument type"); return t > none_type && t <= last_numeric_type; } template struct string_value { const Char* data; std::size_t size; }; template struct custom_value { using parse_context = basic_parse_context; const void* value; void (*format)(const void* arg, parse_context& parse_ctx, Context& ctx); }; // A formatting argument value. template class value { public: using char_type = typename Context::char_type; union { int int_value; unsigned uint_value; long long long_long_value; unsigned long long ulong_long_value; bool bool_value; char_type char_value; double double_value; long double long_double_value; const void* pointer; string_value string; custom_value custom; const named_arg_base* named_arg; }; FMT_CONSTEXPR value(int val = 0) : int_value(val) {} FMT_CONSTEXPR 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(bool val) : bool_value(val) {} value(char_type val) : char_value(val) {} value(const char_type* val) { string.data = val; } value(basic_string_view val) { string.data = val.data(); string.size = val.size(); } value(const void* val) : pointer(val) {} template value(const T& val) { custom.value = &val; // 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`. custom.format = format_custom_arg< T, conditional_t::value, typename Context::template formatter_type, fallback_formatter>>; } value(const named_arg_base& val) { named_arg = &val; } private: // Formats an argument of a custom type, such as a user-defined class. template static void format_custom_arg(const void* arg, basic_parse_context& parse_ctx, Context& ctx) { Formatter f; parse_ctx.advance_to(f.parse(parse_ctx)); ctx.advance_to(f.format(*static_cast(arg), ctx)); } }; template FMT_CONSTEXPR basic_format_arg make_arg(const T& 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. enum { long_short = sizeof(long) == sizeof(int) }; using long_type = conditional_t; using ulong_type = conditional_t; // Maps formatting arguments to core types. template struct arg_mapper { using char_type = typename Context::char_type; FMT_CONSTEXPR int map(signed char val) { return val; } FMT_CONSTEXPR unsigned map(unsigned char val) { return val; } FMT_CONSTEXPR int map(short val) { return val; } FMT_CONSTEXPR unsigned map(unsigned short val) { return val; } FMT_CONSTEXPR int map(int val) { return val; } FMT_CONSTEXPR unsigned map(unsigned val) { return val; } FMT_CONSTEXPR long_type map(long val) { return val; } FMT_CONSTEXPR ulong_type map(unsigned long val) { return val; } FMT_CONSTEXPR long long map(long long val) { return val; } FMT_CONSTEXPR unsigned long long map(unsigned long long val) { return val; } FMT_CONSTEXPR bool map(bool val) { return val; } template ::value)> FMT_CONSTEXPR char_type map(T val) { static_assert( std::is_same::value || std::is_same::value, "mixing character types is disallowed"); return val; } FMT_CONSTEXPR double map(float val) { return static_cast(val); } FMT_CONSTEXPR double map(double val) { return val; } FMT_CONSTEXPR long double map(long double val) { return val; } FMT_CONSTEXPR const char_type* map(char_type* val) { return val; } FMT_CONSTEXPR const char_type* map(const char_type* val) { return val; } template ::value)> FMT_CONSTEXPR basic_string_view map(const T& val) { static_assert(std::is_same>::value, "mixing character types is disallowed"); return to_string_view(val); } template , T>::value && !is_string::value)> FMT_CONSTEXPR basic_string_view map(const T& val) { return basic_string_view(val); } FMT_CONSTEXPR const char* map(const signed char* val) { static_assert(std::is_same::value, "invalid string type"); return reinterpret_cast(val); } FMT_CONSTEXPR const char* map(const unsigned char* val) { static_assert(std::is_same::value, "invalid string type"); return reinterpret_cast(val); } FMT_CONSTEXPR const void* map(void* val) { return val; } FMT_CONSTEXPR const void* map(const void* val) { return val; } FMT_CONSTEXPR const void* map(std::nullptr_t val) { return val; } template FMT_CONSTEXPR int map(const T*) { // 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. static_assert(!sizeof(T), "formatting of non-void pointers is disallowed"); return 0; } template ::value && !has_formatter::value && !has_fallback_formatter::value)> FMT_CONSTEXPR int map(const T& val) { return static_cast(val); } template ::value && !is_char::value && (has_formatter::value || has_fallback_formatter::value))> FMT_CONSTEXPR const T& map(const T& val) { return val; } template FMT_CONSTEXPR const named_arg_base& map( const named_arg& val) { auto arg = make_arg(val.value); std::memcpy(val.data, &arg, sizeof(arg)); return val; } }; // A type constant after applying arg_mapper. template using mapped_type_constant = type_constant().map(std::declval())), typename Context::char_type>; // Maximum number of arguments with packed types. enum { max_packed_args = 15 }; enum : unsigned long long { is_unpacked_bit = 1ull << 63 }; 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 auto visit_format_arg(Visitor&& vis, const basic_format_arg& arg) -> decltype(vis(0)); friend class basic_format_args; friend class internal::arg_map; using char_type = typename Context::char_type; public: class handle { public: explicit handle(internal::custom_value custom) : custom_(custom) {} void format(basic_parse_context& parse_ctx, Context& ctx) const { custom_.format(custom_.value, parse_ctx, ctx); } private: internal::custom_value custom_; }; FMT_CONSTEXPR basic_format_arg() : type_(internal::none_type) {} FMT_CONSTEXPR 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_); } }; /** \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 auto visit_format_arg(Visitor&& vis, const basic_format_arg& arg) -> decltype(vis(0)) { using char_type = typename Context::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_.bool_value); case internal::char_type: return vis(arg.value_.char_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.data); case internal::string_type: return vis(basic_string_view(arg.value_.string.data, 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()); } 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; using char_type = typename Context::char_type; struct entry { basic_string_view name; basic_format_arg arg; }; entry* map_; unsigned size_; void push_back(value val) { const auto& named = *val.named_arg; map_[size_] = {named.name, named.template deserialize()}; ++size_; } public: arg_map() : map_(nullptr), 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 {}; } }; // A type-erased reference to an std::locale to avoid heavy include. class locale_ref { private: const void* locale_; // A type-erased pointer to std::locale. public: locale_ref() : locale_(nullptr) {} template explicit locale_ref(const Locale& loc); template Locale get() const; }; template constexpr unsigned long long encode_types() { return 0; } template constexpr unsigned long long encode_types() { return mapped_type_constant::value | (encode_types() << 4); } template FMT_CONSTEXPR basic_format_arg make_arg(const T& value) { basic_format_arg arg; arg.type_ = mapped_type_constant::value; arg.value_ = arg_mapper().map(value); return arg; } template inline value make_arg(const T& val) { return arg_mapper().map(val); } template inline basic_format_arg make_arg(const T& value) { return make_arg(value); } } // namespace internal // Formatting context. template class basic_format_context { public: /** The character type for the output. */ using char_type = Char; private: OutputIt out_; basic_format_args args_; internal::arg_map map_; internal::locale_ref loc_; basic_format_context(const basic_format_context&) = delete; void operator=(const basic_format_context&) = delete; public: using iterator = OutputIt; using format_arg = basic_format_arg; template using formatter_type = formatter; /** 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_format_args ctx_args, internal::locale_ref loc = internal::locale_ref()) : out_(out), args_(ctx_args), loc_(loc) {} format_arg arg(int id) const { return args_.get(id); } // Checks if manual indexing is used and returns the argument with the // specified name. format_arg arg(basic_string_view name); internal::error_handler error_handler() { return {}; } void on_error(const char* message) { error_handler().on_error(message); } // Returns an iterator to the beginning of the output range. iterator out() { return out_; } // Advances the begin iterator to ``it``. void advance_to(iterator it) { out_ = it; } internal::locale_ref locale() { return loc_; } }; template using buffer_context = basic_format_context>, Char>; using format_context = buffer_context; using wformat_context = buffer_context; /** \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); static const bool is_packed = num_args < internal::max_packed_args; using value_type = conditional_t, basic_format_arg>; // If the arguments are not packed, add one more element to mark the end. value_type data_[num_args + (num_args == 0 ? 1 : 0)]; friend class basic_format_args; public: static constexpr unsigned long long types = is_packed ? internal::encode_types() : internal::is_unpacked_bit | num_args; FMT_DEPRECATED static constexpr unsigned long long TYPES = types; format_arg_store(const Args&... args) : data_{internal::make_arg(args)...} {} }; /** \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`. See `~fmt::arg` for lifetime considerations. \endrst */ template inline format_arg_store make_format_args( const Args&... args) { return {args...}; } /** Formatting arguments. */ template class basic_format_args { public: using size_type = int; using format_arg = basic_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_; }; bool is_packed() const { return (types_ & internal::is_unpacked_bit) == 0; } internal::type type(int index) const { int shift = index * 4; return static_cast((types_ & (0xfull << 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(int index) const { format_arg arg; if (!is_packed()) { auto num_args = max_size(); 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, int count) : types_(internal::is_unpacked_bit | internal::to_unsigned(count)) { set_data(args); } /** Returns the argument at specified index. */ format_arg get(int index) const { format_arg arg = do_get(index); if (arg.type_ == internal::named_arg_type) arg = arg.value_.named_arg->template deserialize(); return arg; } int max_size() const { unsigned long long max_packed = internal::max_packed_args; return static_cast(is_packed() ? max_packed : types_ & ~internal::is_unpacked_bit); } }; /** An alias to ``basic_format_args``. */ // It is a separate type rather than an alias to make symbols readable. struct format_args : basic_format_args { template format_args(Args&&... args) : basic_format_args(std::forward(args)...) {} }; struct wformat_args : basic_format_args { template wformat_args(Args&&... args) : basic_format_args(std::forward(args)...) {} }; template struct is_contiguous : std::false_type {}; template struct is_contiguous> : std::true_type {}; template struct is_contiguous> : std::true_type {}; namespace internal { template struct is_contiguous_back_insert_iterator : std::false_type {}; template struct is_contiguous_back_insert_iterator> : is_contiguous {}; 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) {} }; template ::value)> inline void check_format_string(const S&) { #if defined(FMT_ENFORCE_COMPILE_STRING) static_assert(is_compile_string::value, "FMT_ENFORCE_COMPILE_STRING requires all format strings to " "utilize FMT_STRING() or fmt()."); #endif } template ::value)> void check_format_string(S); struct view {}; template struct bool_pack; template using all_true = std::is_same, bool_pack>; template > inline format_arg_store, remove_reference_t...> make_args_checked(const S& format_str, const remove_reference_t&... args) { static_assert(all_true<(!std::is_base_of>() || !std::is_reference())...>::value, "passing views as lvalues is disallowed"); check_format_string>...>(format_str); return {args...}; } template std::basic_string vformat(basic_string_view format_str, basic_format_args> args); template typename buffer_context::iterator vformat_to( buffer& buf, basic_string_view format_str, basic_format_args> args); } // namespace internal /** \rst Returns a named argument to be used in a formatting function. The named argument holds a reference and does not extend the lifetime of its arguments. Consequently, a dangling reference can accidentally be created. The user should take care to only pass this function temporaries when the named argument is itself a temporary, as per the following example. **Example**:: fmt::print("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23)); \endrst */ template > inline internal::named_arg arg(const S& name, const T& arg) { static_assert(internal::is_string::value, ""); return {name, arg}; } // Disable nested named arguments, e.g. ``arg("a", arg("b", 42))``. template void arg(S, internal::named_arg) = delete; /** Formats a string and writes the output to ``out``. */ // GCC 8 and earlier cannot handle std::back_insert_iterator with // vformat_to(...) overload, so SFINAE on iterator type instead. template , FMT_ENABLE_IF( internal::is_contiguous_back_insert_iterator::value)> OutputIt vformat_to(OutputIt out, const S& format_str, basic_format_args> args) { using container = remove_reference_t; internal::container_buffer buf((internal::get_container(out))); internal::vformat_to(buf, to_string_view(format_str), args); return out; } template ::value&& internal::is_string::value)> inline std::back_insert_iterator format_to( std::back_insert_iterator out, const S& format_str, Args&&... args) { return vformat_to( out, to_string_view(format_str), {internal::make_args_checked(format_str, args...)}); } template > inline std::basic_string vformat( const S& format_str, basic_format_args> args) { return internal::vformat(to_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 */ // Pass char_t as a default template parameter instead of using // std::basic_string> to reduce the symbol size. template > inline std::basic_string format(const S& format_str, Args&&... args) { return internal::vformat( to_string_view(format_str), {internal::make_args_checked(format_str, args...)}); } 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*. For wide format strings, *f* should be in wide-oriented mode set via ``fwide(f, 1)`` or ``_setmode(_fileno(f), _O_U8TEXT)`` on Windows. **Example**:: fmt::print(stderr, "Don't {}!", "panic"); \endrst */ template ::value)> inline void print(std::FILE* f, const S& format_str, Args&&... args) { vprint(f, to_string_view(format_str), internal::make_args_checked(format_str, args...)); } 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 ::value)> inline void print(const S& format_str, Args&&... args) { vprint(to_string_view(format_str), internal::make_args_checked(format_str, args...)); } FMT_END_NAMESPACE #endif // FMT_CORE_H_ pog-0.5.3/deps/fmt/fmt/include/fmt/format-inl.h000066400000000000000000001062741361707036300212650ustar00rootroot00000000000000// 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 #include #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 internal { #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 using format_func = void (*)(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. FMT_FUNC int safe_strerror(int error_code, char*& buffer, std::size_t buffer_size) FMT_NOEXCEPT { FMT_ASSERT(buffer != nullptr && 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; } #if !FMT_MSC_VER // Fallback to strerror if strerror_r and strerror_s are not available. int fallback(internal::null<>) { errno = 0; buffer_ = strerror(error_code_); return errno; } #endif 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(); } FMT_FUNC 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; auto abs_value = static_cast>(error_code); if (internal::is_negative(error_code)) { abs_value = 0 - abs_value; ++error_code_size; } error_code_size += internal::to_unsigned(internal::count_digits(abs_value)); internal::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); } // A wrapper around fwrite that throws on error. FMT_FUNC void fwrite_fully(const void* ptr, size_t size, size_t count, FILE* stream) { size_t written = std::fwrite(ptr, size, count, stream); if (written < count) { FMT_THROW(system_error(errno, "cannot write to file")); } } FMT_FUNC void report_error(format_func func, int error_code, string_view message) FMT_NOEXCEPT { memory_buffer full_message; func(full_message, error_code, message); // Don't use fwrite_fully because the latter may throw. (void)std::fwrite(full_message.data(), full_message.size(), 1, stderr); std::fputc('\n', stderr); } } // namespace internal #if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) namespace internal { template locale_ref::locale_ref(const Locale& loc) : locale_(&loc) { static_assert(std::is_same::value, ""); } template Locale locale_ref::get() const { static_assert(std::is_same::value, ""); return locale_ ? *static_cast(locale_) : std::locale(); } template FMT_FUNC Char thousands_sep_impl(locale_ref loc) { return std::use_facet>(loc.get()) .thousands_sep(); } template FMT_FUNC Char decimal_point_impl(locale_ref loc) { return std::use_facet>(loc.get()) .decimal_point(); } } // namespace internal #else template FMT_FUNC Char internal::thousands_sep_impl(locale_ref) { return FMT_STATIC_THOUSANDS_SEPARATOR; } template FMT_FUNC Char internal::decimal_point_impl(locale_ref) { return '.'; } #endif FMT_API FMT_FUNC format_error::~format_error() FMT_NOEXCEPT {} FMT_API FMT_FUNC system_error::~system_error() FMT_NOEXCEPT {} 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 <> FMT_FUNC int count_digits<4>(internal::fallback_uintptr n) { // Assume little endian; pointer formatting is implementation-defined anyway. int i = static_cast(sizeof(void*)) - 1; while (i > 0 && n.value[i] == 0) --i; auto char_digits = std::numeric_limits::digits / 4; return i >= 0 ? i * char_digits + count_digits<4, unsigned>(n.value[i]) : 1; } template int format_float(char* buf, std::size_t size, const char* format, int precision, T value) { #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION if (precision > 100000) throw std::runtime_error( "fuzz mode - avoid large allocation inside snprintf"); #endif // Suppress the warning about nonliteral format string. auto snprintf_ptr = FMT_SNPRINTF; return precision < 0 ? snprintf_ptr(buf, size, format, value) : snprintf_ptr(buf, size, format, precision, value); } template const char basic_data::digits[] = "0001020304050607080910111213141516171819" "2021222324252627282930313233343536373839" "4041424344454647484950515253545556575859" "6061626364656667686970717273747576777879" "8081828384858687888990919293949596979899"; template const char basic_data::hex_digits[] = "0123456789abcdef"; #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 uint64_t basic_data::powers_of_10_64[] = { 1, FMT_POWERS_OF_10(1), FMT_POWERS_OF_10(1000000000ull), 10000000000000000000ull}; 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::foreground_color[] = "\x1b[38;2;"; template const char basic_data::background_color[] = "\x1b[48;2;"; template const char basic_data::reset_color[] = "\x1b[0m"; template const wchar_t basic_data::wreset_color[] = L"\x1b[0m"; template struct bits { static FMT_CONSTEXPR_DECL const int value = static_cast(sizeof(T) * std::numeric_limits::digits); }; // A handmade floating-point number f * pow(2, e). class fp { private: using significand_type = uint64_t; // All sizes are in bits. // 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 = bits::value; fp() : f(0), e(0) {} fp(uint64_t f_val, int e_val) : f(f_val), e(e_val) {} // 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]. using limits = std::numeric_limits; const int exponent_size = bits::value - 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_FUNC fp operator*(fp x, fp y) { int exp = x.e + y.e + 64; #if FMT_USE_INT128 auto product = static_cast<__uint128_t>(x.f) * y.f; auto f = static_cast(product >> 64); if ((static_cast(product) & (1ULL << 63)) != 0) ++f; return fp(f, exp); #else // 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), exp); #endif } // 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 + 28. 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]); } enum round_direction { unknown, up, down }; // Given the divisor (normally a power of 10), the remainder = v % divisor for // some number v and the error, returns whether v should be rounded up, down, or // whether the rounding direction can't be determined due to error. // error should be less than divisor / 2. inline round_direction get_round_direction(uint64_t divisor, uint64_t remainder, uint64_t error) { FMT_ASSERT(remainder < divisor, ""); // divisor - remainder won't overflow. FMT_ASSERT(error < divisor, ""); // divisor - error won't overflow. FMT_ASSERT(error < divisor - error, ""); // error * 2 won't overflow. // Round down if (remainder + error) * 2 <= divisor. if (remainder <= divisor - remainder && error * 2 <= divisor - remainder * 2) return down; // Round up if (remainder - error) * 2 >= divisor. if (remainder >= error && remainder - error >= divisor - (remainder - error)) { return up; } return unknown; } namespace digits { enum result { more, // Generate more digits. done, // Done generating digits. error // Digit generation cancelled due to an error. }; } // Generates output using the Grisu digit-gen algorithm. // error: the size of the region (lower, upper) outside of which numbers // definitely do not round to value (Delta in Grisu3). template digits::result grisu_gen_digits(fp value, uint64_t error, int& exp, Handler& handler) { fp one(1ull << -value.e, value.e); // The integral part of scaled value (p1 in Grisu) = value / one. It cannot be // zero because it contains a product of two 64-bit numbers with MSB set (due // to normalization) - 1, shifted right by at most 60 bits. uint32_t integral = static_cast(value.f >> -one.e); FMT_ASSERT(integral != 0, ""); FMT_ASSERT(integral == value.f >> -one.e, ""); // The fractional part of scaled value (p2 in Grisu) c = value % one. uint64_t fractional = value.f & (one.f - 1); exp = count_digits(integral); // kappa in Grisu. // Divide by 10 to prevent overflow. auto result = handler.on_start(data::powers_of_10_64[exp - 1] << -one.e, value.f / 10, error * 10, exp); if (result != digits::more) return result; // Generate digits for the integral part. This can produce up to 10 digits. do { uint32_t digit = 0; // This optimization by miloyip reduces the number of integer divisions by // one per iteration. switch (exp) { case 10: digit = integral / 1000000000; integral %= 1000000000; break; case 9: digit = integral / 100000000; integral %= 100000000; break; case 8: digit = integral / 10000000; integral %= 10000000; break; case 7: digit = integral / 1000000; integral %= 1000000; break; case 6: digit = integral / 100000; integral %= 100000; break; case 5: digit = integral / 10000; integral %= 10000; break; case 4: digit = integral / 1000; integral %= 1000; break; case 3: digit = integral / 100; integral %= 100; break; case 2: digit = integral / 10; integral %= 10; break; case 1: digit = integral; integral = 0; break; default: FMT_ASSERT(false, "invalid number of digits"); } --exp; uint64_t remainder = (static_cast(integral) << -one.e) + fractional; result = handler.on_digit(static_cast('0' + digit), data::powers_of_10_64[exp] << -one.e, remainder, error, exp, true); if (result != digits::more) return result; } while (exp > 0); // Generate digits for the fractional part. for (;;) { fractional *= 10; error *= 10; char digit = static_cast('0' + static_cast(fractional >> -one.e)); fractional &= one.f - 1; --exp; result = handler.on_digit(digit, one.f, fractional, error, exp, false); if (result != digits::more) return result; } } // The fixed precision digit handler. struct fixed_handler { char* buf; int size; int precision; int exp10; bool fixed; digits::result on_start(uint64_t divisor, uint64_t remainder, uint64_t error, int& exp) { // Non-fixed formats require at least one digit and no precision adjustment. if (!fixed) return digits::more; // Adjust fixed precision by exponent because it is relative to decimal // point. precision += exp + exp10; // Check if precision is satisfied just by leading zeros, e.g. // format("{:.2f}", 0.001) gives "0.00" without generating any digits. if (precision > 0) return digits::more; if (precision < 0) return digits::done; auto dir = get_round_direction(divisor, remainder, error); if (dir == unknown) return digits::error; buf[size++] = dir == up ? '1' : '0'; return digits::done; } digits::result on_digit(char digit, uint64_t divisor, uint64_t remainder, uint64_t error, int, bool integral) { FMT_ASSERT(remainder < divisor, ""); buf[size++] = digit; if (size < precision) return digits::more; if (!integral) { // Check if error * 2 < divisor with overflow prevention. // The check is not needed for the integral part because error = 1 // and divisor > (1 << 32) there. if (error >= divisor || error >= divisor - error) return digits::error; } else { FMT_ASSERT(error == 1 && divisor > 2, ""); } auto dir = get_round_direction(divisor, remainder, error); if (dir != up) return dir == down ? digits::done : digits::error; ++buf[size - 1]; for (int i = size - 1; i > 0 && buf[i] > '9'; --i) { buf[i] = '0'; ++buf[i - 1]; } if (buf[0] > '9') { buf[0] = '1'; buf[size++] = '0'; } return digits::done; } }; // The shortest representation digit handler. template struct grisu_shortest_handler { char* buf; int size; // Distance between scaled value and upper bound (wp_W in Grisu3). uint64_t diff; digits::result on_start(uint64_t, uint64_t, uint64_t, int&) { return digits::more; } // Decrement the generated number approaching value from above. void round(uint64_t d, uint64_t divisor, uint64_t& remainder, uint64_t error) { while ( remainder < d && error - remainder >= divisor && (remainder + divisor < d || d - remainder >= remainder + divisor - d)) { --buf[size - 1]; remainder += divisor; } } // Implements Grisu's round_weed. digits::result on_digit(char digit, uint64_t divisor, uint64_t remainder, uint64_t error, int exp, bool integral) { buf[size++] = digit; if (remainder >= error) return digits::more; if (GRISU_VERSION != 3) { uint64_t d = integral ? diff : diff * data::powers_of_10_64[-exp]; round(d, divisor, remainder, error); return digits::done; } uint64_t unit = integral ? 1 : data::powers_of_10_64[-exp]; uint64_t up = (diff - 1) * unit; // wp_Wup round(up, divisor, remainder, error); uint64_t down = (diff + 1) * unit; // wp_Wdown if (remainder < down && error - remainder >= divisor && (remainder + divisor < down || down - remainder > remainder + divisor - down)) { return digits::error; } return 2 * unit <= remainder && remainder <= error - 4 * unit ? digits::done : digits::error; } }; template > FMT_API bool grisu_format(Double value, buffer& buf, int precision, unsigned options, int& exp) { FMT_ASSERT(value >= 0, "value is negative"); bool fixed = (options & grisu_options::fixed) != 0; if (value <= 0) { // <= instead of == to silence a warning. if (precision <= 0 || !fixed) { exp = 0; buf.push_back('0'); } else { exp = -precision; buf.resize(precision); std::uninitialized_fill_n(buf.data(), precision, '0'); } return true; } fp fp_value(value); const int min_exp = -60; // alpha in Grisu. int cached_exp10 = 0; // K in Grisu. if (precision != -1) { if (precision > 17) return false; fp_value.normalize(); auto cached_pow = get_cached_power( min_exp - (fp_value.e + fp::significand_size), cached_exp10); fp_value = fp_value * cached_pow; fixed_handler handler{buf.data(), 0, precision, -cached_exp10, fixed}; if (grisu_gen_digits(fp_value, 1, exp, handler) == digits::error) return false; buf.resize(to_unsigned(handler.size)); } else { fp lower, upper; // w^- and w^+ in the Grisu paper. fp_value.compute_boundaries(lower, upper); // Find a cached power of 10 such that multiplying upper by it will bring // the exponent in the range [min_exp, -32]. auto cached_pow = get_cached_power( // \tilde{c}_{-k} in Grisu. min_exp - (upper.e + fp::significand_size), cached_exp10); fp_value.normalize(); fp_value = fp_value * cached_pow; lower = lower * cached_pow; // \tilde{M}^- in Grisu. upper = upper * cached_pow; // \tilde{M}^+ in Grisu. assert(min_exp <= upper.e && upper.e <= -32); auto result = digits::result(); int size = 0; if ((options & grisu_options::grisu3) != 0) { --lower.f; // \tilde{M}^- - 1 ulp -> M^-_{\downarrow}. ++upper.f; // \tilde{M}^+ + 1 ulp -> M^+_{\uparrow}. // Numbers outside of (lower, upper) definitely do not round to value. grisu_shortest_handler<3> handler{buf.data(), 0, (upper - fp_value).f}; result = grisu_gen_digits(upper, upper.f - lower.f, exp, handler); size = handler.size; } else { ++lower.f; // \tilde{M}^- + 1 ulp -> M^-_{\uparrow}. --upper.f; // \tilde{M}^+ - 1 ulp -> M^+_{\downarrow}. grisu_shortest_handler<2> handler{buf.data(), 0, (upper - fp_value).f}; result = grisu_gen_digits(upper, upper.f - lower.f, exp, handler); size = handler.size; } if (result == digits::error) return false; buf.resize(to_unsigned(size)); } exp -= cached_exp10; return true; } template char* sprintf_format(Double value, internal::buffer& buf, sprintf_specs specs) { // Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail. FMT_ASSERT(buf.capacity() != 0, "empty buffer"); // Build format string. enum { max_format_size = 10 }; // longest format: %#-*.*Lg char format[max_format_size]; char* format_ptr = format; *format_ptr++ = '%'; if (specs.alt || !specs.type) *format_ptr++ = '#'; if (specs.precision >= 0) { *format_ptr++ = '.'; *format_ptr++ = '*'; } if (std::is_same::value) *format_ptr++ = 'L'; char type = specs.type; if (type == '%') type = 'f'; else if (type == 0 || type == 'n') type = 'g'; #if FMT_MSC_VER if (type == 'F') { // MSVC's printf doesn't support 'F'. type = 'f'; } #endif *format_ptr++ = type; *format_ptr = '\0'; // Format using snprintf. char* start = nullptr; char* decimal_point_pos = nullptr; for (;;) { std::size_t buffer_size = buf.capacity(); start = &buf[0]; int result = format_float(start, buffer_size, format, specs.precision, value); if (result >= 0) { unsigned n = internal::to_unsigned(result); if (n < buf.capacity()) { // Find the decimal point. auto p = buf.data(), end = p + n; if (*p == '+' || *p == '-') ++p; if (specs.type != 'a' && specs.type != 'A') { while (p < end && *p >= '0' && *p <= '9') ++p; if (p < end && *p != 'e' && *p != 'E') { decimal_point_pos = p; if (!specs.type) { // Keep only one trailing zero after the decimal point. ++p; if (*p == '0') ++p; while (p != end && *p >= '1' && *p <= '9') ++p; char* where = p; while (p != end && *p == '0') ++p; if (p == end || *p < '0' || *p > '9') { if (p != end) std::memmove(where, p, to_unsigned(end - p)); n -= static_cast(p - where); } } } } buf.resize(n); break; // The buffer is large enough - continue with formatting. } buf.reserve(n + 1); } else { // If result is negative we ask to increase the capacity by at least 1, // but as std::vector, the buffer grows exponentially. buf.reserve(buf.capacity() + 1); } } return decimal_point_pos; } } // namespace internal #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, nullptr, 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, nullptr, 0, nullptr, nullptr); if (length == 0) return GetLastError(); buffer_.resize(length + 1); length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, nullptr, nullptr); if (length == 0) return GetLastError(); buffer_[length] = 0; return 0; } 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, nullptr, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), system_message, static_cast(buf.size()), nullptr); if (result != 0) { utf16_to_utf8 utf8_message; if (utf8_message.convert(system_message) == ERROR_SUCCESS) { internal::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 = internal::safe_strerror(error_code, system_message, buf.size()); if (result == 0) { internal::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); } 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; internal::vformat_to(buffer, format_str, basic_format_args>(args)); internal::fwrite_fully(buffer.data(), 1, buffer.size(), f); } FMT_FUNC void vprint(std::FILE* f, wstring_view format_str, wformat_args args) { wmemory_buffer buffer; internal::vformat_to(buffer, format_str, args); buffer.push_back(L'\0'); if (std::fputws(buffer.data(), f) == -1) { FMT_THROW(system_error(errno, "cannot write to file")); } } 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); } FMT_END_NAMESPACE #ifdef _MSC_VER # pragma warning(pop) #endif #endif // FMT_FORMAT_INL_H_ pog-0.5.3/deps/fmt/fmt/include/fmt/format.h000066400000000000000000003454771361707036300205170ustar00rootroot00000000000000/* Formatting library for C++ Copyright (c) 2012 - present, Victor Zverovich Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --- Optional exception to the license --- As an exception, if, as a result of your compiling your source code, portions of this Software are embedded into a machine-executable object form of such source code, you may redistribute such embedded portions in such object form without including the above copyright and permission notices. */ #ifndef FMT_FORMAT_H_ #define FMT_FORMAT_H_ #include #include #include #include #include #include #include #include #include #include "core.h" #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 #ifdef __has_builtin # define FMT_HAS_BUILTIN(x) __has_builtin(x) #else # define FMT_HAS_BUILTIN(x) 0 #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; } } // namespace internal 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 and NVIDIA compilers both they and the system gcc/msc 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 #ifndef FMT_USE_UDL_TEMPLATE // EDG front end based compilers (icc, nvcc) do not support UDL templates yet // and GCC 9 warns about them. # if FMT_USE_USER_DEFINED_LITERALS && FMT_ICC_VERSION == 0 && \ FMT_CUDA_VERSION == 0 && \ ((FMT_GCC_VERSION >= 600 && FMT_GCC_VERSION <= 900 && \ __cplusplus >= 201402L) || \ FMT_CLANG_VERSION >= 304) # define FMT_USE_UDL_TEMPLATE 1 # else # define FMT_USE_UDL_TEMPLATE 0 # endif #endif #ifdef FMT_USE_INT128 // Do nothing. #elif defined(__SIZEOF_INT128__) # define FMT_USE_INT128 1 #else # define FMT_USE_INT128 0 #endif // __builtin_clz is broken in clang with Microsoft CodeGen: // https://github.com/fmtlib/fmt/issues/519 #if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_clz)) && !FMT_MSC_VER # define FMT_BUILTIN_CLZ(n) __builtin_clz(n) #endif #if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_clzll)) && !FMT_MSC_VER # define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) #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) } // namespace internal FMT_END_NAMESPACE #endif FMT_BEGIN_NAMESPACE namespace internal { // A fallback implementation of uintptr_t for systems that lack it. struct fallback_uintptr { unsigned char value[sizeof(void*)]; }; #ifdef UINTPTR_MAX using uintptr_t = ::uintptr_t; #else using uintptr_t = fallback_uintptr; #endif // 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 approximation of iterator_t for pre-C++20 systems. template using iterator_t = decltype(std::begin(std::declval())); // Detect the iterator category of *any* given type in a SFINAE-friendly way. // Unfortunately, older implementations of std::iterator_traits are not safe // for use in a SFINAE-context. template struct iterator_category : std::false_type {}; template struct iterator_category { using type = std::random_access_iterator_tag; }; template struct iterator_category> { using type = typename It::iterator_category; }; // Detect if *any* given type models the OutputIterator concept. template class is_output_iterator { // Check for mutability because all iterator categories derived from // std::input_iterator_tag *may* also meet the requirements of an // OutputIterator, thereby falling into the category of 'mutable iterators' // [iterator.requirements.general] clause 4. The compiler reveals this // property only at the point of *actually dereferencing* the iterator! template static decltype(*(std::declval())) test(std::input_iterator_tag); template static char& test(std::output_iterator_tag); template static const char& test(...); using type = decltype(test(typename iterator_category::type{})); public: static const bool value = !std::is_const>::value; }; // A workaround for std::string not having mutable data() until C++17. template inline Char* get_data(std::basic_string& s) { return &s[0]; } template inline typename Container::value_type* get_data(Container& c) { return c.data(); } #ifdef _SECURE_SCL // Make a checked iterator to avoid MSVC warnings. template using checked_ptr = stdext::checked_array_iterator; template checked_ptr make_checked(T* p, std::size_t size) { return {p, size}; } #else template using checked_ptr = T*; template inline T* make_checked(T* p, std::size_t) { return p; } #endif template ::value)> inline checked_ptr reserve( std::back_insert_iterator& it, std::size_t n) { Container& c = get_container(it); std::size_t size = c.size(); c.resize(size + n); return make_checked(get_data(c) + size, n); } template inline Iterator& reserve(Iterator& it, std::size_t) { return it; } // 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: using iterator_category = std::output_iterator_tag; using value_type = T; using difference_type = std::ptrdiff_t; using pointer = T*; using reference = T&; using _Unchecked_type = counting_iterator; // 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_; } }; template class truncating_iterator_base { protected: OutputIt out_; std::size_t limit_; std::size_t count_; truncating_iterator_base(OutputIt out, std::size_t limit) : out_(out), limit_(limit), count_(0) {} public: using iterator_category = std::output_iterator_tag; using difference_type = void; using pointer = void; using reference = void; using _Unchecked_type = truncating_iterator_base; // Mark iterator as checked. OutputIt base() const { return out_; } std::size_t count() const { return count_; } }; // An output iterator that truncates the output and counts the number of objects // written to it. template ::value_type>::type> class truncating_iterator; template class truncating_iterator : public truncating_iterator_base { using traits = std::iterator_traits; mutable typename traits::value_type blackhole_; public: using value_type = typename traits::value_type; truncating_iterator(OutputIt out, std::size_t limit) : truncating_iterator_base(out, limit) {} truncating_iterator& operator++() { if (this->count_++ < this->limit_) ++this->out_; return *this; } truncating_iterator operator++(int) { auto it = *this; ++*this; return it; } value_type& operator*() const { return this->count_ < this->limit_ ? *this->out_ : blackhole_; } }; template class truncating_iterator : public truncating_iterator_base { public: using value_type = typename OutputIt::container_type::value_type; truncating_iterator(OutputIt out, std::size_t limit) : truncating_iterator_base(out, limit) {} truncating_iterator& operator=(value_type val) { if (this->count_++ < this->limit_) this->out_ = val; return *this; } truncating_iterator& operator++() { return *this; } truncating_iterator& operator++(int) { return *this; } truncating_iterator& operator*() { return *this; } }; // A range with the specified output iterator and value type. template class output_range { private: OutputIt it_; public: using value_type = T; using iterator = OutputIt; struct sentinel {}; explicit output_range(OutputIt it) : it_(it) {} OutputIt begin() const { return it_; } sentinel end() const { return {}; } // Sentinel is not used yet. }; // A range with an iterator appending to a buffer. template class buffer_range : public output_range>, T> { public: using iterator = std::back_insert_iterator>; using output_range::output_range; buffer_range(buffer& buf) : output_range(std::back_inserter(buf)) {} }; template inline size_t count_code_points(basic_string_view s) { return s.size(); } // Counts the number of code points in a UTF-8 string. inline size_t count_code_points(basic_string_view s) { const char8_t* data = s.data(); size_t num_code_points = 0; for (size_t i = 0, size = s.size(); i != size; ++i) { if ((data[i] & 0xc0) != 0x80) ++num_code_points; } return num_code_points; } inline char8_t to_char8_t(char c) { return static_cast(c); } template using needs_conversion = bool_constant< std::is_same::value_type, char>::value && std::is_same::value>; template ::value)> OutputIt copy_str(InputIt begin, InputIt end, OutputIt it) { return std::copy(begin, end, it); } template ::value)> OutputIt copy_str(InputIt begin, InputIt end, OutputIt it) { return std::transform(begin, end, it, to_char8_t); } #ifndef FMT_USE_GRISU # define FMT_USE_GRISU 0 #endif template constexpr bool use_grisu() { return FMT_USE_GRISU && std::numeric_limits::is_iec559 && sizeof(T) <= sizeof(double); } template template void buffer::append(const U* begin, const U* end) { std::size_t new_size = size_ + to_unsigned(end - begin); reserve(new_size); std::uninitialized_copy(begin, end, make_checked(ptr_, capacity_) + size_); size_ = new_size; } } // namespace internal // A UTF-8 string view. class u8string_view : public basic_string_view { public: u8string_view(const char* s) : basic_string_view(reinterpret_cast(s)) {} u8string_view(const char* s, size_t count) FMT_NOEXCEPT : basic_string_view(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 {s, n}; } } // namespace literals #endif // 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 type aliases 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 append 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::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: using value_type = T; using const_reference = const T&; 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) { #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION if (size > 1000) throw std::runtime_error("fuzz mode - won't grow that much"); #endif 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 = std::allocator_traits::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); } using memory_buffer = basic_memory_buffer; using wmemory_buffer = basic_memory_buffer; /** A formatting error such as invalid format string. */ class FMT_API 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) {} ~format_error() FMT_NOEXCEPT; }; namespace internal { // Returns true if value is negative, false otherwise. // Same as `value < 0` but doesn't produce warnings if T is an unsigned type. template ::is_signed)> FMT_CONSTEXPR bool is_negative(T value) { return value < 0; } template ::is_signed)> FMT_CONSTEXPR bool is_negative(T) { return false; } // Smallest of uint32_t and uint64_t that is large enough to represent all // values of T. template using uint32_or_64_t = conditional_t::digits <= 32, uint32_t, uint64_t>; // Static data is placed in this class template for the header-only config. template struct FMT_EXTERN_TEMPLATE_API basic_data { static const uint64_t powers_of_10_64[]; 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 hex_digits[]; static const char foreground_color[]; static const char background_color[]; static const char reset_color[5]; static const wchar_t wreset_color[5]; }; FMT_EXTERN template struct basic_data; // This is a struct rather than an alias to avoid shadowing warnings in gcc. struct data : basic_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 int 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 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 int count_digits(uint64_t n) { int 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 digits in n. BITS = log2(radix). template inline int count_digits(UInt n) { int num_digits = 0; do { ++num_digits; } while ((n >>= BITS) != 0); return num_digits; } template <> int count_digits<4>(internal::fallback_uintptr n); #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; } }; #ifdef FMT_BUILTIN_CLZ // Optional version of count_digits for better performance on 32-bit platforms. inline int count_digits(uint32_t n) { int t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12; return t - (n < data::zero_or_powers_of_10_32[t]) + 1; } #endif template FMT_API Char thousands_sep_impl(locale_ref loc); template inline Char thousands_sep(locale_ref loc) { return Char(thousands_sep_impl(loc)); } template <> inline wchar_t thousands_sep(locale_ref loc) { return thousands_sep_impl(loc); } template FMT_API Char decimal_point_impl(locale_ref loc); template inline Char decimal_point(locale_ref loc) { return Char(decimal_point_impl(loc)); } template <> inline wchar_t decimal_point(locale_ref loc) { return decimal_point_impl(loc); } // Formats a decimal unsigned integer value writing into buffer. // add_thousands_sep is called after writing each char to add a thousands // separator if necessary. template inline Char* format_decimal(Char* buffer, UInt value, int num_digits, F add_thousands_sep) { FMT_ASSERT(num_digits >= 0, "invalid digit count"); 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 = static_cast(data::digits[index + 1]); add_thousands_sep(buffer); *--buffer = static_cast(data::digits[index]); add_thousands_sep(buffer); } if (value < 10) { *--buffer = static_cast('0' + value); return end; } unsigned index = static_cast(value * 2); *--buffer = static_cast(data::digits[index + 1]); add_thousands_sep(buffer); *--buffer = static_cast(data::digits[index]); return end; } template inline Iterator format_decimal(Iterator out, UInt value, int num_digits, F add_thousands_sep) { FMT_ASSERT(num_digits >= 0, "invalid digit count"); // Buffer should be large enough to hold all digits (<= digits10 + 1). enum { max_size = std::numeric_limits::digits10 + 1 }; Char buffer[max_size + max_size / 3]; auto end = format_decimal(buffer, value, num_digits, add_thousands_sep); return internal::copy_str(buffer, end, out); } template inline It format_decimal(It out, UInt value, int num_digits) { return format_decimal(out, value, num_digits, [](Char*) {}); } template inline Char* format_uint(Char* buffer, UInt value, int num_digits, bool upper = false) { buffer += num_digits; Char* end = buffer; do { const char* digits = upper ? "0123456789ABCDEF" : data::hex_digits; unsigned digit = (value & ((1 << BASE_BITS) - 1)); *--buffer = static_cast(BASE_BITS < 4 ? static_cast('0' + digit) : digits[digit]); } while ((value >>= BASE_BITS) != 0); return end; } template Char* format_uint(Char* buffer, internal::fallback_uintptr n, int num_digits, bool = false) { auto char_digits = std::numeric_limits::digits / 4; int start = (num_digits + char_digits - 1) / char_digits - 1; if (int start_digits = num_digits % char_digits) { unsigned value = n.value[start--]; buffer = format_uint(buffer, value, start_digits); } for (; start >= 0; --start) { unsigned value = n.value[start]; buffer += char_digits; auto p = buffer; for (int i = 0; i < char_digits; ++i) { unsigned digit = (value & ((1 << BASE_BITS) - 1)); *--p = static_cast(data::hex_digits[digit]); value >>= BASE_BITS; } } return buffer; } template inline It format_uint(It out, UInt value, int num_digits, bool upper = false) { // Buffer should be large enough to hold all digits (digits / BASE_BITS + 1). char buffer[std::numeric_limits::digits / BASE_BITS + 1]; format_uint(buffer, value, num_digits, upper); return internal::copy_str(buffer, 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 {}; // Workaround an array initialization issue in gcc 4.8. template struct fill_t { private: Char data_[6]; public: FMT_CONSTEXPR Char& operator[](size_t index) { return data_[index]; } FMT_CONSTEXPR const Char& operator[](size_t index) const { return data_[index]; } static FMT_CONSTEXPR fill_t make() { auto fill = fill_t(); fill[0] = Char(' '); return fill; } }; } // namespace internal // We cannot use enum classes as bit fields because of a gcc bug // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414. namespace align { enum type { none, left, right, center, numeric }; } using align_t = align::type; namespace sign { enum type { none, minus, plus, space }; } using sign_t = sign::type; // Format specifiers for built-in and string types. template struct basic_format_specs { int width; int precision; char type; align_t align : 4; sign_t sign : 3; bool alt : 1; // Alternate form ('#'). internal::fill_t fill; constexpr basic_format_specs() : width(0), precision(-1), type(0), align(align::none), sign(sign::none), alt(false), fill(internal::fill_t::make()) {} }; using format_specs = basic_format_specs; namespace internal { // Writes the exponent exp in the form "[+-]d{2,3}" to buffer. template It write_exponent(int exp, It it) { FMT_ASSERT(-1000 < exp && exp < 1000, "exponent out of range"); if (exp < 0) { *it++ = static_cast('-'); exp = -exp; } else { *it++ = static_cast('+'); } if (exp >= 100) { *it++ = static_cast(static_cast('0' + exp / 100)); exp %= 100; } const char* d = data::digits + exp * 2; *it++ = static_cast(d[0]); *it++ = static_cast(d[1]); return it; } struct gen_digits_params { int num_digits; bool fixed; bool upper; bool trailing_zeros; }; // The number is given as v = digits * pow(10, exp). template It grisu_prettify(const char* digits, int size, int exp, It it, gen_digits_params params, Char decimal_point) { // pow(10, full_exp - 1) <= v <= pow(10, full_exp). int full_exp = size + exp; if (!params.fixed) { // Insert a decimal point after the first digit and add an exponent. *it++ = static_cast(*digits); if (size > 1) *it++ = decimal_point; exp += size - 1; it = copy_str(digits + 1, digits + size, it); if (size < params.num_digits) it = std::fill_n(it, params.num_digits - size, static_cast('0')); *it++ = static_cast(params.upper ? 'E' : 'e'); return write_exponent(exp, it); } if (size <= full_exp) { // 1234e7 -> 12340000000[.0+] it = copy_str(digits, digits + size, it); it = std::fill_n(it, full_exp - size, static_cast('0')); int num_zeros = (std::max)(params.num_digits - full_exp, 1); if (params.trailing_zeros) { *it++ = decimal_point; #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION if (num_zeros > 1000) throw std::runtime_error("fuzz mode - avoiding excessive cpu use"); #endif it = std::fill_n(it, num_zeros, static_cast('0')); } } else if (full_exp > 0) { // 1234e-2 -> 12.34[0+] it = copy_str(digits, digits + full_exp, it); if (!params.trailing_zeros) { // Remove trailing zeros. while (size > full_exp && digits[size - 1] == '0') --size; if (size != full_exp) *it++ = decimal_point; return copy_str(digits + full_exp, digits + size, it); } *it++ = decimal_point; it = copy_str(digits + full_exp, digits + size, it); if (params.num_digits > size) { // Add trailing zeros. int num_zeros = params.num_digits - size; it = std::fill_n(it, num_zeros, static_cast('0')); } } else { // 1234e-6 -> 0.001234 *it++ = static_cast('0'); int num_zeros = -full_exp; if (params.num_digits >= 0 && params.num_digits < num_zeros) num_zeros = params.num_digits; if (!params.trailing_zeros) while (size > 0 && digits[size - 1] == '0') --size; if (num_zeros != 0 || size != 0) { *it++ = decimal_point; it = std::fill_n(it, num_zeros, static_cast('0')); it = copy_str(digits, digits + size, it); } } return it; } namespace grisu_options { enum { fixed = 1, grisu3 = 2 }; } // Formats value using the Grisu algorithm: // https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf template FMT_API bool grisu_format(Double, buffer&, int, unsigned, int&); template inline bool grisu_format(Double, buffer&, int, unsigned, int&) { return false; } struct sprintf_specs { int precision; char type; bool alt : 1; template constexpr sprintf_specs(basic_format_specs specs) : precision(specs.precision), type(specs.type), alt(specs.alt) {} constexpr bool has_precision() const { return precision >= 0; } }; template char* sprintf_format(Double, internal::buffer&, sprintf_specs); 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 '%': handler.on_percent(); break; case 'a': case 'A': handler.on_hex(); break; case 'n': handler.on_num(); 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->sign != sign::none || specs->alt) 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_percent() {} FMT_CONSTEXPR void on_hex() {} FMT_CONSTEXPR void on_num() {} FMT_CONSTEXPR void on_error() { ErrorHandler::on_error("invalid type specifier"); } }; template class char_specs_checker : public ErrorHandler { private: char type_; public: FMT_CONSTEXPR char_specs_checker(char 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[internal::to_unsigned(args.max_size())]; if (args.is_packed()) { for (int i = 0;; ++i) { internal::type arg_type = args.type(i); if (arg_type == internal::none_type) return; if (arg_type == internal::named_arg_type) push_back(args.values_[i]); } } for (int i = 0, n = args.max_size(); i < n; ++i) { auto type = args.args_[i].type_; if (type == internal::named_arg_type) push_back(args.args_[i].value_); } } // This template provides operations for formatting and writing data into a // character range. template class basic_writer { public: using char_type = typename Range::value_type; using iterator = typename Range::iterator; using format_specs = basic_format_specs; private: iterator out_; // Output iterator. internal::locale_ref locale_; // Attempts to reserve space for n extra characters in the output range. // Returns a pointer to the reserved range or a reference to out_. auto reserve(std::size_t n) -> decltype(internal::reserve(out_, n)) { return internal::reserve(out_, n); } template struct padded_int_writer { size_t size_; string_view prefix; char_type fill; std::size_t padding; F f; size_t size() const { return size_; } size_t width() const { return size_; } template void operator()(It&& it) const { if (prefix.size() != 0) it = internal::copy_str(prefix.begin(), prefix.end(), it); it = std::fill_n(it, padding, fill); f(it); } }; // Writes an integer in the format // // where are written by f(it). template void write_int(int num_digits, string_view prefix, format_specs specs, F f) { std::size_t size = prefix.size() + internal::to_unsigned(num_digits); char_type fill = specs.fill[0]; std::size_t padding = 0; if (specs.align == align::numeric) { auto unsiged_width = internal::to_unsigned(specs.width); if (unsiged_width > size) { padding = unsiged_width - size; size = unsiged_width; } } else if (specs.precision > num_digits) { size = prefix.size() + internal::to_unsigned(specs.precision); padding = internal::to_unsigned(specs.precision - num_digits); fill = static_cast('0'); } if (specs.align == align::none) specs.align = align::right; write_padded(specs, padded_int_writer{size, prefix, fill, padding, f}); } // Writes a decimal integer. template void write_decimal(Int value) { auto abs_value = static_cast>(value); bool is_negative = internal::is_negative(value); if (is_negative) abs_value = 0 - abs_value; int num_digits = internal::count_digits(abs_value); auto&& it = reserve((is_negative ? 1 : 0) + static_cast(num_digits)); if (is_negative) *it++ = static_cast('-'); it = internal::format_decimal(it, abs_value, num_digits); } // The handle_int_type_spec handler that writes an integer. template struct int_writer { using unsigned_type = uint32_or_64_t; basic_writer& writer; const Specs& specs; unsigned_type abs_value; char prefix[4]; unsigned prefix_size; string_view get_prefix() const { return string_view(prefix, prefix_size); } int_writer(basic_writer& w, Int value, const Specs& s) : writer(w), specs(s), abs_value(static_cast(value)), prefix_size(0) { if (internal::is_negative(value)) { prefix[0] = '-'; ++prefix_size; abs_value = 0 - abs_value; } else if (specs.sign != sign::none && specs.sign != sign::minus) { prefix[0] = specs.sign == sign::plus ? '+' : ' '; ++prefix_size; } } struct dec_writer { unsigned_type abs_value; int num_digits; template void operator()(It&& it) const { it = internal::format_decimal(it, abs_value, num_digits); } }; void on_dec() { int num_digits = internal::count_digits(abs_value); writer.write_int(num_digits, get_prefix(), specs, dec_writer{abs_value, num_digits}); } struct hex_writer { int_writer& self; int num_digits; template void operator()(It&& it) const { it = internal::format_uint<4, char_type>(it, self.abs_value, num_digits, self.specs.type != 'x'); } }; void on_hex() { if (specs.alt) { prefix[prefix_size++] = '0'; prefix[prefix_size++] = specs.type; } int num_digits = internal::count_digits<4>(abs_value); writer.write_int(num_digits, get_prefix(), specs, hex_writer{*this, num_digits}); } template struct bin_writer { unsigned_type abs_value; int num_digits; template void operator()(It&& it) const { it = internal::format_uint(it, abs_value, num_digits); } }; void on_bin() { if (specs.alt) { prefix[prefix_size++] = '0'; prefix[prefix_size++] = static_cast(specs.type); } int num_digits = internal::count_digits<1>(abs_value); writer.write_int(num_digits, get_prefix(), specs, bin_writer<1>{abs_value, num_digits}); } void on_oct() { int num_digits = internal::count_digits<3>(abs_value); if (specs.alt && specs.precision <= num_digits) { // Octal prefix '0' is counted as a digit, so only add it if precision // is not greater than the number of digits. prefix[prefix_size++] = '0'; } writer.write_int(num_digits, get_prefix(), specs, bin_writer<3>{abs_value, num_digits}); } enum { sep_size = 1 }; struct num_writer { unsigned_type abs_value; int size; char_type sep; template void operator()(It&& it) const { basic_string_view s(&sep, sep_size); // Index of a decimal digit with the least significant digit having // index 0. unsigned digit_index = 0; it = internal::format_decimal( it, abs_value, size, [s, &digit_index](char_type*& buffer) { if (++digit_index % 3 != 0) return; buffer -= s.size(); std::uninitialized_copy(s.data(), s.data() + s.size(), internal::make_checked(buffer, s.size())); }); } }; void on_num() { char_type sep = internal::thousands_sep(writer.locale_); if (!sep) return on_dec(); int num_digits = internal::count_digits(abs_value); int size = num_digits + sep_size * ((num_digits - 1) / 3); writer.write_int(size, get_prefix(), specs, num_writer{abs_value, size, sep}); } FMT_NORETURN void on_error() { FMT_THROW(format_error("invalid type specifier")); } }; enum { inf_size = 3 }; // This is an enum to workaround a bug in MSVC. struct inf_or_nan_writer { char sign; bool as_percentage; const char* str; size_t size() const { return static_cast(inf_size + (sign ? 1 : 0) + (as_percentage ? 1 : 0)); } size_t width() const { return size(); } template void operator()(It&& it) const { if (sign) *it++ = static_cast(sign); it = internal::copy_str( str, str + static_cast(inf_size), it); if (as_percentage) *it++ = static_cast('%'); } }; struct double_writer { char sign; internal::buffer& buffer; char* decimal_point_pos; char_type decimal_point; size_t size() const { return buffer.size() + (sign ? 1 : 0); } size_t width() const { return size(); } template void operator()(It&& it) { if (sign) *it++ = static_cast(sign); auto begin = buffer.begin(); if (decimal_point_pos) { it = internal::copy_str(begin, decimal_point_pos, it); *it++ = decimal_point; begin = decimal_point_pos + 1; } it = internal::copy_str(begin, buffer.end(), it); } }; class grisu_writer { private: internal::buffer& digits_; size_t size_; char sign_; int exp_; internal::gen_digits_params params_; char_type decimal_point_; public: grisu_writer(char sign, internal::buffer& digits, int exp, const internal::gen_digits_params& params, char_type decimal_point) : digits_(digits), sign_(sign), exp_(exp), params_(params), decimal_point_(decimal_point) { int num_digits = static_cast(digits.size()); int full_exp = num_digits + exp - 1; int precision = params.num_digits > 0 ? params.num_digits : 11; params_.fixed |= full_exp >= -4 && full_exp < precision; auto it = internal::grisu_prettify( digits.data(), num_digits, exp, internal::counting_iterator(), params_, '.'); size_ = it.count(); } size_t size() const { return size_ + (sign_ ? 1 : 0); } size_t width() const { return size(); } template void operator()(It&& it) { if (sign_) *it++ = static_cast(sign_); int num_digits = static_cast(digits_.size()); it = internal::grisu_prettify(digits_.data(), num_digits, exp_, it, params_, decimal_point_); } }; template struct str_writer { const Char* s; size_t size_; size_t size() const { return size_; } size_t width() const { return internal::count_code_points(basic_string_view(s, size_)); } template void operator()(It&& it) const { it = internal::copy_str(s, s + size_, it); } }; template struct pointer_writer { UIntPtr value; int num_digits; size_t size() const { return to_unsigned(num_digits) + 2; } size_t width() const { return size(); } template void operator()(It&& it) const { *it++ = static_cast('0'); *it++ = static_cast('x'); it = internal::format_uint<4, char_type>(it, value, num_digits); } }; public: /** Constructs a ``basic_writer`` object. */ explicit basic_writer(Range out, internal::locale_ref loc = internal::locale_ref()) : out_(out.begin()), locale_(loc) {} iterator out() const { return out_; } // Writes a value in the format // // where is written by f(it). template void write_padded(const format_specs& specs, F&& f) { // User-perceived width (in code points). unsigned width = to_unsigned(specs.width); size_t size = f.size(); // The number of code units. size_t num_code_points = width != 0 ? f.width() : size; if (width <= num_code_points) return f(reserve(size)); auto&& it = reserve(width + (size - num_code_points)); char_type fill = specs.fill[0]; std::size_t padding = width - num_code_points; if (specs.align == align::right) { it = std::fill_n(it, padding, fill); f(it); } else if (specs.align == align::center) { std::size_t left_padding = padding / 2; it = std::fill_n(it, left_padding, fill); f(it); it = std::fill_n(it, padding - left_padding, fill); } else { f(it); it = std::fill_n(it, padding, fill); } } void write(int value) { write_decimal(value); } void write(long value) { write_decimal(value); } void write(long long value) { write_decimal(value); } void write(unsigned value) { write_decimal(value); } void write(unsigned long value) { write_decimal(value); } void write(unsigned long long value) { write_decimal(value); } // Writes a formatted integer. template void write_int(T value, const Spec& spec) { internal::handle_int_type_spec(spec.type, int_writer(*this, value, spec)); } void write(double value, const format_specs& specs = format_specs()) { write_double(value, specs); } /** \rst Formats *value* using the general format for floating-point numbers (``'g'``) and writes it to the buffer. \endrst */ void write(long double value, const format_specs& specs = format_specs()) { write_double(value, specs); } // Formats a floating-point number (double or long double). template ()> void write_double(T value, const format_specs& specs); /** Writes a character to the buffer. */ void write(char value) { auto&& it = reserve(1); *it++ = value; } template ::value)> void write(Char value) { auto&& it = reserve(1); *it++ = value; } /** \rst Writes *value* to the buffer. \endrst */ void write(string_view value) { auto&& it = reserve(value.size()); it = internal::copy_str(value.begin(), value.end(), it); } void write(wstring_view value) { static_assert(std::is_same::value, ""); auto&& it = reserve(value.size()); it = std::copy(value.begin(), value.end(), it); } // Writes a formatted string. template void write(const Char* s, std::size_t size, const format_specs& specs) { write_padded(specs, str_writer{s, size}); } template void write(basic_string_view s, const format_specs& specs = format_specs()) { const Char* data = s.data(); std::size_t size = s.size(); if (specs.precision >= 0 && internal::to_unsigned(specs.precision) < size) size = internal::to_unsigned(specs.precision); write(data, size, specs); } template void write_pointer(UIntPtr value, const format_specs* specs) { int num_digits = internal::count_digits<4>(value); auto pw = pointer_writer{value, num_digits}; if (!specs) return pw(reserve(to_unsigned(num_digits) + 2)); format_specs specs_copy = *specs; if (specs_copy.align == align::none) specs_copy.align = align::right; write_padded(specs_copy, pw); } }; using writer = basic_writer>; template class arg_formatter_base { public: using char_type = typename Range::value_type; using iterator = typename Range::iterator; using format_specs = basic_format_specs; private: using writer_type = basic_writer; writer_type writer_; format_specs* specs_; struct char_writer { char_type value; size_t size() const { return 1; } size_t width() const { return 1; } template void operator()(It&& it) const { *it++ = value; } }; void write_char(char_type value) { if (specs_) writer_.write_padded(*specs_, char_writer{value}); else writer_.write(value); } void write_pointer(const void* p) { writer_.write_pointer(internal::bit_cast(p), specs_); } protected: writer_type& writer() { return writer_; } FMT_DEPRECATED format_specs* spec() { return specs_; } format_specs* specs() { return specs_; } iterator out() { return writer_.out(); } void write(bool value) { string_view sv(value ? "true" : "false"); specs_ ? writer_.write(sv, *specs_) : writer_.write(sv); } void write(const char_type* value) { if (!value) { FMT_THROW(format_error("string pointer is null")); } else { auto length = std::char_traits::length(value); basic_string_view sv(value, length); specs_ ? writer_.write(sv, *specs_) : writer_.write(sv); } } public: arg_formatter_base(Range r, format_specs* s, locale_ref loc) : writer_(r, loc), specs_(s) {} iterator operator()(monostate) { FMT_ASSERT(false, "invalid argument type"); return out(); } template ::value)> iterator operator()(T value) { if (specs_) writer_.write_int(value, *specs_); else writer_.write(value); return out(); } iterator operator()(char_type value) { internal::handle_char_specs( specs_, char_spec_handler(*this, static_cast(value))); return out(); } iterator operator()(bool value) { if (specs_ && specs_->type) return (*this)(value ? 1 : 0); write(value != 0); return out(); } template ::value)> iterator operator()(T value) { writer_.write_double(value, specs_ ? *specs_ : format_specs()); return out(); } struct char_spec_handler : ErrorHandler { 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(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; } // 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 int parse_nonnegative_int(const Char*& begin, const Char* end, ErrorHandler&& eh) { assert(begin != end && '0' <= *begin && *begin <= '9'); if (*begin == '0') { ++begin; return 0; } unsigned value = 0; // Convert to unsigned to prevent a warning. constexpr 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'); ++begin; } while (begin != end && '0' <= *begin && *begin <= '9'); if (value > max_int) eh.on_error("number is too big"); return static_cast(value); } template class custom_formatter { private: using char_type = typename Context::char_type; basic_parse_context& parse_ctx_; Context& ctx_; public: explicit custom_formatter(basic_parse_context& parse_ctx, Context& ctx) : parse_ctx_(parse_ctx), ctx_(ctx) {} bool operator()(typename basic_format_arg::handle h) const { h.format(parse_ctx_, ctx_); return true; } template bool operator()(T) const { return false; } }; template using is_integer = bool_constant::value && !std::is_same::value && !std::is_same::value && !std::is_same::value>; template class width_checker { public: explicit FMT_CONSTEXPR width_checker(ErrorHandler& eh) : handler_(eh) {} template ::value)> FMT_CONSTEXPR unsigned long long operator()(T value) { if (is_negative(value)) handler_.on_error("negative width"); return static_cast(value); } template ::value)> FMT_CONSTEXPR unsigned long long operator()(T) { handler_.on_error("width is not integer"); return 0; } private: ErrorHandler& handler_; }; template class precision_checker { public: explicit FMT_CONSTEXPR precision_checker(ErrorHandler& eh) : handler_(eh) {} template ::value)> FMT_CONSTEXPR unsigned long long operator()(T value) { if (is_negative(value)) handler_.on_error("negative precision"); return static_cast(value); } template ::value)> FMT_CONSTEXPR unsigned long long 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(align_t align) { specs_.align = align; } FMT_CONSTEXPR void on_fill(Char fill) { specs_.fill[0] = fill; } FMT_CONSTEXPR void on_plus() { specs_.sign = sign::plus; } FMT_CONSTEXPR void on_minus() { specs_.sign = sign::minus; } FMT_CONSTEXPR void on_space() { specs_.sign = sign::space; } FMT_CONSTEXPR void on_hash() { specs_.alt = true; } FMT_CONSTEXPR void on_zero() { specs_.align = align::numeric; specs_.fill[0] = Char('0'); } FMT_CONSTEXPR void on_width(int width) { specs_.width = width; } FMT_CONSTEXPR void on_precision(int precision) { specs_.precision = precision; } FMT_CONSTEXPR void end_precision() {} FMT_CONSTEXPR void on_type(Char type) { specs_.type = static_cast(type); } protected: basic_format_specs& specs_; }; template class numeric_specs_checker { public: FMT_CONSTEXPR numeric_specs_checker(ErrorHandler& eh, internal::type arg_type) : error_handler_(eh), arg_type_(arg_type) {} FMT_CONSTEXPR void require_numeric_argument() { if (!is_arithmetic(arg_type_)) error_handler_.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) { error_handler_.on_error("format specifier requires signed argument"); } } FMT_CONSTEXPR void check_precision() { if (is_integral(arg_type_) || arg_type_ == internal::pointer_type) error_handler_.on_error("precision not allowed for this argument type"); } private: ErrorHandler& error_handler_; internal::type arg_type_; }; // 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), checker_(*this, arg_type) {} FMT_CONSTEXPR specs_checker(const specs_checker& other) : Handler(other), checker_(*this, other.arg_type_) {} FMT_CONSTEXPR void on_align(align_t align) { if (align == align::numeric) checker_.require_numeric_argument(); Handler::on_align(align); } FMT_CONSTEXPR void on_plus() { checker_.check_sign(); Handler::on_plus(); } FMT_CONSTEXPR void on_minus() { checker_.check_sign(); Handler::on_minus(); } FMT_CONSTEXPR void on_space() { checker_.check_sign(); Handler::on_space(); } FMT_CONSTEXPR void on_hash() { checker_.require_numeric_argument(); Handler::on_hash(); } FMT_CONSTEXPR void on_zero() { checker_.require_numeric_argument(); Handler::on_zero(); } FMT_CONSTEXPR void end_precision() { checker_.check_precision(); } private: numeric_specs_checker checker_; }; template