soci-4.1.4/0000775000175000017500000000000015215337540012402 5ustar zeitlinzeitlinsoci-4.1.4/AUTHORS0000664000175000017500000000736515215337514013466 0ustar zeitlinzeitlinVisit https://github.com/SOCI/soci/graphs/contributors for complete list of contributors. We would like to thank you for your contributions - they allowed us to improve the quality of the SOCI library: === SOCI Team === Current maintainer: [Vadim Zeitlin](https://github.com/vadz) Previous maintainer: [Mateusz Å�oskot](https://github.com/mloskot) List of committers: Alex Ott Denis Arnaud Denis Chapligin Julian Taylor Maciej Sobczak Mateusz Å�oskot PaweÅ‚ Aleksander FedoryÅ„ski Sergei Nikulov Vadim Zeitlin Viacheslav Naydenov === SOCI Contributors === Many thanks to all the contributors to the last release: alex (at staticlibs.net) Alexey Palienko Benjamin Oldenburg Carsten Stiborg Christian Kröhnert Cosmin Cremarenco Dan Church Davy Durham Denis Arnaud Derek Huang Dmitry Arkhipkin gaocheng3 (at asiainfo.sg) George Rhoten gypsy5oul (at github.com) Ilya Sinitsyn Innokentiy Alaytsev Iqbal Hassan Ivan Kuvaldin JaroslawCendrowski Jiahao XU Joel Bodenmann Joshua Vanitha Juan Jose Castellanos Jörn Reimerdes Kyle Edwards Lorenz Brun Lukas Zanner Mariana Meireles Matheus Gabriel Werny de Lima Mathäus Mendel Michael Kaes mkkang Noah Shutty Oleg Endo Ondrej Hojdysz Robert Adam Sam Hartsfield Stefan van Kessel Thibault Fresnet Thibault Martinez Tomas R Moreno P Vittorio Parrella Will Watts Full list of users and developers who contributed countless features, enhancements and fixes: Adesmier Alejandro Alvarez Ayllon alex (at staticlibs.net) Alex Volanis Alexander Kulikov Alexey Palienko Andrei Lebedev Andrey Belobrov Andrey Utkin Andriy Gapon Artyom Beilis Artyom Tonkikh Astrinus avg-I b-s-a Benjamin Blundell Benjamin Oldenburg Brian R. Toonen Carsten Stiborg Cavaler Cengizhan PaÅŸaoÄŸlu Сергей Сергеевич Журавлев Chris Kaminski Chris Weed Christian Kröhnert Colin Steifel Cory Bennett Cosmin Cremarenco creste Dan Church Daniel Grafe Daniel Lidström Daniel Walter David Courtney davidsummers Davy Durham Denis Arnaud Denis Dowling Derek Huang Dirk Grambow Dirk Vanden Boer Dmitry Arkhipkin DraconPern Eli Green enrico.detoma Faik Uygur Fedor Muratov Fedor Trushkin fly2xj Frank Bielig Frantisek Comorek Frederic Chateau gaocheng3 (at asiainfo.sg) George Rhoten Gevorg Voskanyan gypsy5oul Joshua Vanitha Heiko Rabe Henning Basold Howard Butler Huang Youchuan Ilia Barahovski Illia Gorbatiuk Ilya Sinitsyn Innokentiy Alaytsev Iqbal Hassan Ivan Kuvaldin Jakub Stachowski jamercee James E. King, III JaroslawCendrowski javerskulpa Jiahao XU Joel Bodenmann Joerg Sonnenberger Johan Pascal joshua-15639 Juan Jose Castellanos Jörn Reimerdes Kévin SzkudÅ‚apski Krzysztof BieleÅ„ Kyle Edwards Lemme Lorenz Brun Lukas Zanner Maciej Cencora Mariana Meireles Mario Valesco Martin Muenstermann Mathäus Mendel Matheus Gabriel Werny de Lima Mathias Hasselmann Matt Arsenault Matt Budish Matthieu Kermagoret Michael Davidsaver Miha Ravselj Mika Fischer mitant Michael Kaes mkkang Mohan Sella MonsieurNicolas musopr myd7349 Nik Bougalis Noah Shutty NobodyXu ohojdysz Oleg Endo pacocamberos parvit (Vittorio Parrella) Paul Bondo Petr Vanek Philip Pemberton RafaÅ‚ Bobrowski Rainer Bauer Rémi Piotaix Ricardo Andrade Robert Adam Robert Massaioli Roger Orr Rommel Trindade root (at begeton.com) Ross Marwood ryandesign Sam Hartsfield Sergey Belyashov Shelomentsev Dmitriy Shridhar Daithankar Sören Meyer-Eppler soyer soyersoyer Stefan Chrobot Stefan van Kessel Steve Hutton Takatoshi Kondo Theo van Klaveren Thibault Fresnet Thibault Martinez Tomas R Moreno P Tomasz Olszewski Tomay tt4g Vaclav Slavik Vaughn Draughon wdavilaneto Will Watts William Blough XiaoGuang Zeng xol Xuewen Wang There are a lot of people that help to drive SOCI project forward, if we have forgot to mention someone in here, if you would like to be listed by name instead of GitHub username, send us an email! soci-4.1.4/LICENSE_1_0.txt0000664000175000017500000000247215215337514014672 0ustar zeitlinzeitlinBoost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. soci-4.1.4/CMakeLists.txt0000664000175000017500000001764115215337514015154 0ustar zeitlinzeitlin# Note: we need >= v3.23 in order to make use of file sets for header installation cmake_minimum_required(VERSION 3.23...3.31 FATAL_ERROR) set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/find_modules") include(soci_parse_version) soci_parse_version( ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}" OUTPUT_VARIABLE SOCI_VERSION ) project(SOCI VERSION ${SOCI_VERSION} DESCRIPTION "C++ database access library" HOMEPAGE_URL "https://soci.sourceforge.net/" LANGUAGES C CXX ) include(soci_utils) if (NOT DEFINED CMAKE_CXX_STANDARD OR CMAKE_CXX_STANDARD LESS 14) set(CMAKE_CXX_STANDARD 14) endif() set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_CXX_VISIBILITY_PRESET hidden) include(CMakeDependentOption) include(CheckIPOSupported) check_ipo_supported(RESULT LTO_AVAILABLE) if (SOCI_STATIC) set(SHARED_DEFAULT OFF) elseif(DEFINED BUILD_SHARED_LIBS) set(SHARED_DEFAULT ${BUILD_SHARED_LIBS}) else() set(SHARED_DEFAULT ON) endif() option(SOCI_SHARED "Enable building SOCI as a shared library" ${SHARED_DEFAULT}) option(SOCI_TESTS "Enable building SOCI test cases" ${PROJECT_IS_TOP_LEVEL}) option(SOCI_INSTALL "Generate the install target." ${PROJECT_IS_TOP_LEVEL}) option(WITH_BOOST "Enable Boost support" ON) cmake_dependent_option(SOCI_LTO "Enable link time optimizations in release builds" ON "LTO_AVAILABLE" OFF) # Determine if the CMake generator is single or multi config. This will be # useful later when printing the SOCI configuration in show_config. get_property(SOCI_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) # Default build type to Release for single-config generators if(NOT SOCI_IS_MULTI_CONFIG AND NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) endif() # Configure LTO for anything but Debug builds (if enabled in the first place) set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ${SOCI_LTO}) set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_DEBUG OFF) if (NOT APPLE) # This makes runtime loaders look for library dependencies # in the same directory as the library is located in. # For details see Craig Scott's CppCon 2019 talk # Note: The variable's content is set to $ORIGIN literally, # this is NOT a butchered cmake variable expansion set(CMAKE_INSTALL_RPATH "$ORIGIN") endif() if (NOT DEFINED CMAKE_RUNTIME_OUTPUT_DIRECTORY) # Ensure that build artifacts are easy to find. And on Windows this # guarantees that the built DLLs end up next to applications # linking to them as otherwise they won't be found. set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) if (NOT PROJECT_IS_TOP_LEVEL) # If the embedding project does not define these variables, this can lead to # inconsistencies which can cause issues on Windows when e.g. the embedding # project has an executable that links to a SOCI DLL which will be put into # a different directory which will lead to the exe not finding the DLL. message(WARNING "Setting CMAKE_{LIBRARY, ARCHIVE, RUNTIME}_DIRECTORY variables which should have done by the embedding cmake project") endif() endif() if (SOCI_SHARED) set(SOCI_LIB_TYPE "SHARED") else() set(SOCI_LIB_TYPE "STATIC") endif() # When using shared libraries, use version-dependent suffix in their names. if (SOCI_SHARED) if (WIN32) # Use the full version number as ABI version on Windows, different minor # versions are not ABI-compatible. set(ABI_VERSION "${PROJECT_VERSION_MAJOR}_${PROJECT_VERSION_MINOR}") # Also use it in the library name by default to ensure that the DLLs of # different versions are called differently as there is no SOVERSION on # Windows to prevent this from happening. set(soci_default_suffix "_${ABI_VERSION}") elseif(UNIX) # Use same value as for SOVERSION, which is only the major version (and is # used automatically to construct the shared libraries names, so there is # no need for any suffix). set(ABI_VERSION "${PROJECT_VERSION_MAJOR}") endif() endif() set(SOCI_NAME_PREFIX "" CACHE STRING "Optional prefix to add before 'soci_' in library names") set(SOCI_NAME_SUFFIX "${soci_default_suffix}" CACHE STRING "Optional suffix to add to the library names") # By default, we use system fmt if available, otherwise the bundled one, but # this option can be used to either force or forbid using the bundled one. set(SOCI_FMT_BUILTIN "" CACHE STRING "Prefer, or forbid, using the bundled fmt library") set(soci_use_bundled_fmt ON) # Skip searching for fmt if the superproject has already defined it. if(TARGET fmt::fmt) message(STATUS "Using already existing fmt target") set(soci_use_bundled_fmt OFF) elseif(NOT SOCI_FMT_BUILTIN) find_package(fmt QUIET) if (fmt_FOUND) message(STATUS "Using system fmt library ${fmt_VERSION}") set(soci_use_bundled_fmt OFF) else() if ("${SOCI_FMT_BUILTIN}" STREQUAL "OFF") message( FATAL_ERROR "System fmt library not found and using built-in version was disabled." ) endif() endif() endif() # Name of the library to link with. set(soci_fmt fmt::fmt) if(soci_use_bundled_fmt) if (NOT EXISTS ${PROJECT_SOURCE_DIR}/3rdparty/fmt/CMakeLists.txt) message( FATAL_ERROR "fmt library submodule not found.\n" "Please ensure that you have cloned the SOCI repository with --recurse-submodules." ) endif() if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.25) set(SYSTEM_FLAG "SYSTEM") endif() add_subdirectory(3rdparty/fmt ${SYSTEM_FLAG}) set(soci_fmt "fmt::fmt-header-only") endif() # Helper function appending prefix and suffix to the library name. function(soci_build_library_name result basename) set(${result} "${SOCI_NAME_PREFIX}${basename}${SOCI_NAME_SUFFIX}" PARENT_SCOPE) endfunction() include(soci_compiler_options) if (SOCI_INSTALL) include(soci_install_dirs) endif() add_subdirectory(src) include(soci_compat) if (SOCI_TESTS) include(CTest) enable_testing() add_subdirectory(tests) endif() # Packaging if (SOCI_INSTALL) include(CMakePackageConfigHelpers) configure_package_config_file("soci-config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/soci-config.cmake" INSTALL_DESTINATION "${SOCI_INSTALL_CMAKEDIR}" ) write_basic_package_version_file(soci-config-version.cmake VERSION ${PROJECT_VERSION} COMPATIBILITY SameMajorVersion ) install( FILES "${CMAKE_CURRENT_BINARY_DIR}/soci-config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/soci-config-version.cmake" DESTINATION "${SOCI_INSTALL_CMAKEDIR}" ) endif() # Give build summary at the end but only if it's the first time we're running, # as indicated by SOCI_SUMMARY not being cached yet, or if it has changed. set(SOCI_SUMMARY_NOW "${SOCI_VERSION}-${SOCI_LIB_TYPE}-${SOCI_ENABLED_BACKENDS}-${CMAKE_BUILD_TYPE}" ) if(NOT "${SOCI_SUMMARY_NOW}" STREQUAL "${SOCI_SUMMARY}") set(SOCI_SUMMARY ${SOCI_SUMMARY_NOW} CACHE INTERNAL "SOCI internal build summary") if (CMAKE_BUILD_TYPE) set(SOCI_CONFIG_DESCRIPTION " in ${CMAKE_BUILD_TYPE} configuration") endif() message(STATUS "SOCI ${SOCI_VERSION} will be built as ${SOCI_LIB_TYPE} library${SOCI_CONFIG_DESCRIPTION}.") message(STATUS "Enabled SOCI backends are: ${SOCI_ENABLED_BACKENDS}") endif() # Also make it possible to see SOCI configuration later. add_custom_target(show_config COMMAND ${CMAKE_COMMAND} -E echo "SOCI ${SOCI_VERSION} configured with:" COMMAND ${CMAKE_COMMAND} -E echo # If using multi-config generator CMAKE_BUILD_TYPE is not meaningful. One # would instead select a build type from CMAKE_CONFIGURATION_TYPES. " Build type: $" COMMAND ${CMAKE_COMMAND} -E echo " Library type: ${SOCI_LIB_TYPE}" COMMAND ${CMAKE_COMMAND} -E echo " Enabled backends: ${SOCI_ENABLED_BACKENDS}" COMMENT "Show SOCI build configuration summary" VERBATIM ) soci-4.1.4/Vagrantfile0000664000175000017500000000305715215337514014575 0ustar zeitlinzeitlin# -*- mode: ruby -*- # vi: set ft=ruby : # Vagrant virtual development environments for SOCI Vagrant.configure(2) do |config| config.vm.box = "bento/ubuntu-14.04" config.vm.box_check_update = true # Main SOCI development box with build essentials, FOSS DBs config.vm.define "soci", primary: true do |soci| soci.vm.hostname = "vmsoci" soci.vm.network "private_network", type: "dhcp" soci.vm.provider :virtualbox do |vb| vb.customize ["modifyvm", :id, "--memory", "1024"] end scripts = [ "bootstrap.sh", "devel.sh", "db2cli.sh", "firebird.sh", "mysql.sh", "postgresql.sh", "build.sh" ] scripts.each { |script| soci.vm.provision :shell, privileged: false, :path => "scripts/vagrant/" << script } end # Database box with IBM DB2 Express-C config.vm.define "db2", autostart: false do |db2| db2.vm.hostname = "vmdb2" db2.vm.network "private_network", type: "dhcp" # Access to DB2 instance from host db2.vm.network :forwarded_port, host: 50000, guest: 50000 db2.vm.provider :virtualbox do |vb| vb.customize ["modifyvm", :id, "--memory", "1024"] end scripts = [ "bootstrap.sh", "db2.sh" ] scripts.each { |script| db2.vm.provision :shell, privileged: false, :path => "scripts/vagrant/" << script } end # Database box with Oracle XE # config.vm.define "oracle", autostart: false do |oracle| # oracle.vm.provision "database", type: "shell" do |s| # s.inline = "echo Installing Oracle'" # end # end end soci-4.1.4/.editorconfig0000664000175000017500000000131715215337514015062 0ustar zeitlinzeitlin# This is the EditorConfig (https://editorconfig.org/) coding style file for SOCI. root = true [*] end_of_line = lf insert_final_newline = true charset = utf-8 indent_style = space indent_size = 4 trim_trailing_whitespace = true # CMake configuration files [{CMakeLists.txt,*.cmake}] indent_size = 2 indent_style = space trim_trailing_whitespace = true insert_final_newline = true # CI configuration files [{.github/workflows/*.yml,appveyor.yml,Vagrantfile}] indent_size = 2 indent_style = space trim_trailing_whitespace = true insert_final_newline = true # Windows shell scripts [*.{cmd,bat,ps1}] end_of_line = crlf indent_size = 4 indent_style = space insert_final_newline = false trim_trailing_whitespace = true soci-4.1.4/cmake/0000775000175000017500000000000015215337514013463 5ustar zeitlinzeitlinsoci-4.1.4/cmake/soci_compiler_options.cmake0000664000175000017500000001037515215337514021075 0ustar zeitlinzeitlininclude(CheckCXXCompilerFlag) add_library(soci_compiler_interface INTERFACE) # # Force compilation flags and set desired warnings level # option(SOCI_ENABLE_WERROR "Enables turning compiler warnings into errors" OFF) option(SOCI_ASAN "Enable building SOCI with enabled address sanitizers" OFF) option(SOCI_UBSAN "Enable undefined behaviour sanitizer" OFF) set(SOCI_LD "" CACHE STRING "Specify a non-default linker") if (WIN32) # Prevent the Windows header files from defining annoying macros # and also cut down on the definitions in general target_compile_definitions(soci_compiler_interface INTERFACE NOMINMAX WIN32_LEAN_AND_MEAN ) endif() # We want to use warning-related options only for C++ source files (this # excludes 3rdparty/sqlite3/sqlite3.c) and only when compiling SOCI itself and # not an application using it. set(soci_cxx_source "$,$>") if (MSVC) # Configure warnings target_compile_options(soci_compiler_interface INTERFACE "$<${soci_cxx_source}:/W4>" "$<${soci_cxx_source}:/we4266>" "$<${soci_cxx_source}:/wd4702>" # we get many bogus "unreachable code" ) if (SOCI_ENABLE_WERROR) target_compile_options(soci_compiler_interface INTERFACE "$<${soci_cxx_source}:/WX>" ) endif() if (SOCI_LD) message(FATAL_ERROR "Using a non-default linker is not supported when using MSVC") endif() target_compile_options(soci_compiler_interface INTERFACE "/nologo" "/bigobj" "/utf-8") else() if (SOCI_ENABLE_WERROR) target_compile_options(soci_compiler_interface INTERFACE "$<${soci_cxx_source}:-Werror>" ) endif() if (SOCI_UBSAN) target_compile_options(soci_compiler_interface INTERFACE "-fsanitize=undefined") target_link_options(soci_compiler_interface INTERFACE "-fsanitize=undefined") endif() if (SOCI_LD) # CMake asks the compiler to do the linking so we have to pass the desired linker to the compiler set(USE_LD_FLAG "-fuse-ld=${SOCI_LD}") check_cxx_compiler_flag("${USE_LD_FLAG}" CAN_USE_CUSTOM_LD) if (NOT CAN_USE_CUSTOM_LD) message(FATAL_ERROR "Can't use custom linker '${SOCI_LD}' - compiler doesn't accept flag '${USE_LD_FLAG}'") endif() target_link_options(soci_compiler_interface INTERFACE "${USE_LD_FLAG}") endif() if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" OR "${CMAKE_CXX_COMPILER}" MATCHES "clang") if(SOCI_ASAN AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 3.1) # This can also be used to set a linker flag target_link_libraries(soci_compiler_interface INTERFACE "-fsanitize=address") target_compile_options(soci_compiler_interface INTERFACE "-fsanitize=address") endif() set(SOCI_USE_STD_FLAGS ON) elseif (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) if (SOCI_ASAN AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 4.8) # This can also be used to set a linker flag target_link_libraries(soci_compiler_interface INTERFACE "-fsanitize=address") target_compile_options(soci_compiler_interface INTERFACE "-fsanitize=address") endif() if (CMAKE_COMPILER_IS_GNUCXX) if (NOT (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")) target_compile_options(soci_compiler_interface INTERFACE "$<${soci_cxx_source}:-Wno-variadic-macros>") endif() endif() set(SOCI_USE_STD_FLAGS ON) else() message(WARNING "Unknown toolset - using default flags to build SOCI") endif() if (SOCI_USE_STD_FLAGS) target_compile_options(soci_compiler_interface INTERFACE "$<${soci_cxx_source}:-pedantic>" "$<${soci_cxx_source}:-Wno-error=parentheses>" "$<${soci_cxx_source}:-Wall>" "$<${soci_cxx_source}:-Wextra>" "$<${soci_cxx_source}:-Wpointer-arith>" "$<${soci_cxx_source}:-Wcast-align>" "$<${soci_cxx_source}:-Wcast-qual>" "$<${soci_cxx_source}:-Woverloaded-virtual>" "$<${soci_cxx_source}:-Wredundant-decls>" "$<${soci_cxx_source}:-Wno-long-long>" ) # We can't use this when using header-only fmt as it gives this warning. if(NOT soci_use_bundled_fmt) target_compile_options(soci_compiler_interface INTERFACE "$<${soci_cxx_source}:-Wfloat-equal>" ) endif() endif() endif() soci-4.1.4/cmake/soci_install_dirs.cmake0000664000175000017500000000144115215337514020171 0ustar zeitlinzeitlininclude(GNUInstallDirs) set(SOCI_INSTALL_CMAKEDIR "${CMAKE_INSTALL_LIBDIR}/cmake/soci-${PROJECT_VERSION}" CACHE FILEPATH "Directory into which cmake related files (e.g. SOCIConfig.cmake) are installed") set(SOCI_INSTALL_BINDIR "${CMAKE_INSTALL_BINDIR}" CACHE FILEPATH "Directory into which to install any SOCI executables") set(SOCI_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}" CACHE FILEPATH "Directory into which any SOCI libraries (except DLLs on Windows) are installed") # Note that our headers are installed via a file set that already has the headers # in a dedicated "soci" subdirectory (which will be part of the installation) set(SOCI_INSTALL_INCLUDEDIR "${CMAKE_INSTALL_INCLUDEDIR}" CACHE FILEPATH "Directory into which the 'soci' directory with all SOCI header files is installed") soci-4.1.4/cmake/soci_define_backend_target.cmake0000664000175000017500000002106015215337514021750 0ustar zeitlinzeitlininclude(soci_utils) # Defines a CMake target for a database backend. # # This function takes care of orchestrating the boilerplate that is needed in order to set up # a library target as used for different DB backends. The corresponding # SOCI__SOURCE macro is defined during compilation to control # symbol visibility and for build-time use for conditional compilation. # # Accepted arguments are the following: # # NAME Name of the backend. This function will create an alias target using this name with "SOCI::" prefix. # MISSING_DEPENDENCY_BEHAVIOR What to do if a dependency is not found. Valid values are "ERROR", "DISABLE" and "BUILTIN". # TARGET_NAME Name of the CMake target that shall be created for this backend # DEPENDENCIES [... ] List of dependency specifications. Each specification has to be a single # argument (single string) following the syntax # YIELDS # where will be passed to find_package to find the dependency. Upon # success, all targets defined in are expected to exist. # For now, all dependencies are expected to be public and required. # FIND_PACKAGE_FILES [... ] List of files used by find_package to locate one of the dependencies. Specified # files will be installed alongside SOCI in order to be usable from the install tree. # HEADER_FILES [... ] List of public header files associated with this backend target. # SOURCE_FILES [... ] List of source files that shall be part of this backend component # # It sets SOCI_ cache variable to ON if the backend dependencies are available and OFF otherwise. function(soci_define_backend_target) set(FLAGS "") set(ONE_VAL_OPTIONS "NAME" "MISSING_DEPENDENCY_BEHAVIOR" "TARGET_NAME" ) set(MULTI_VAL_OPTIONS "DEPENDENCIES" "FIND_PACKAGE_FILES" "HEADER_FILES" "SOURCE_FILES" ) cmake_parse_arguments(DEFINE_BACKEND "${FLAGS}" "${ONE_VAL_OPTIONS}" "${MULTI_VAL_OPTIONS}" ${ARGV}) soci_verify_parsed_arguments( PREFIX "DEFINE_BACKEND" FUNCTION_NAME "soci_define_backend_target" REQUIRED "NAME" "SOURCE_FILES" "TARGET_NAME" ) if (NOT DEFINE_BACKEND_MISSING_DEPENDENCY_BEHAVIOR) set(DEFINE_BACKEND_MISSING_DEPENDENCY_BEHAVIOR "ERROR") else() string(TOUPPER "${DEFINE_BACKEND_MISSING_DEPENDENCY_BEHAVIOR}" DEFINE_BACKEND_MISSING_DEPENDENCY_BEHAVIOR) endif() if (DEFINE_BACKEND_MISSING_DEPENDENCY_BEHAVIOR STREQUAL "ERROR") set(REQUIRE_FLAG "REQUIRED") set(ERROR_ON_MISSING_DEPENDENCY ON) elseif(DEFINE_BACKEND_MISSING_DEPENDENCY_BEHAVIOR STREQUAL "DISABLE") set(DISABLE_ON_MISSING_DEPENDENCY ON) elseif(DEFINE_BACKEND_MISSING_DEPENDENCY_BEHAVIOR STREQUAL "BUILTIN") set(REQUIRE_FLAG "QUIET") set(BUILTIN_ON_MISSING_DEPENDENCY ON) else() message(FATAL_ERROR "Invalid value '${DEFINE_BACKEND_MISSING_DEPENDENCY_BEHAVIOR}' for option 'MISSING_DEPENDENCY_BEHAVIOR'") endif() set(PUBLIC_DEP_CALL_ARGS "") # This variable indicates whether the backend is enabled or not. string(TOUPPER "${DEFINE_BACKEND_NAME}" BACKEND_UPPER) set(DEFINE_BACKEND_ENABLED_VARIABLE "SOCI_${BACKEND_UPPER}") # Skip looking for dependencies if built-in version is preferred. if (${SOCI_${BACKEND_UPPER}_BUILTIN}) unset(DEFINE_BACKEND_DEPENDENCIES) endif() foreach(CURRENT_DEP_SPEC IN LISTS DEFINE_BACKEND_DEPENDENCIES) if (NOT "${CURRENT_DEP_SPEC}" MATCHES "^([a-zA-Z0-9_:-;]+) YIELDS ([a-zA-Z0-9_:-;]+)$") message(FATAL_ERROR "Invalid format for dependency specification in '${CURRENT_DEP_SPEC}'") endif() set(CURRENT_DEP_SEARCH ${CMAKE_MATCH_1}) set(CURRENT_DEP_TARGETS ${CMAKE_MATCH_2}) list(GET CURRENT_DEP_SEARCH 0 CURRENT_DEP) # Don't search for the dependency if it had been already predefined. set(SKIP_DEP_SEARCH ON) foreach (CURRENT IN LISTS CURRENT_DEP_TARGETS) if(NOT TARGET ${CURRENT}) set(SKIP_DEP_SEARCH OFF) break() endif() endforeach() if(SKIP_DEP_SEARCH) list(APPEND PUBLIC_DEP_CALL_ARGS "NAME ${CURRENT_DEP} DEP_TARGETS ${CURRENT_DEP_TARGETS} TARGET SOCI::${DEFINE_BACKEND_NAME}" ) continue() endif() find_package(${CURRENT_DEP_SEARCH} ${REQUIRE_FLAG}) if (NOT ${CURRENT_DEP}_FOUND) if (ERROR_ON_MISSING_DEPENDENCY) message(FATAL_ERROR "Expected find_package to error due to unmet dependency '${CURRENT_DEP}'") elseif(DISABLE_ON_MISSING_DEPENDENCY) message(STATUS "Disabling SOCI backend '${DEFINE_BACKEND_NAME}' due to unsatisfied dependency on '${CURRENT_DEP}'") # Set this backend to disabled by overwriting the corresponding cache variable # (without overwriting its description) get_property(DESCRIPTION CACHE "${DEFINE_BACKEND_ENABLED_VARIABLE}" PROPERTY HELPSTRING) set(${DEFINE_BACKEND_ENABLED_VARIABLE} OFF CACHE STRING "${DESCRIPTION}" FORCE) return() elseif(BUILTIN_ON_MISSING_DEPENDENCY) break() else() message(FATAL_ERROR "Unspecified handling of unmet dependency") endif() else() # Dependency was found. # This is wasteful, but do it again without "QUIET" flag to show the result if it succeeded. if (REQUIRE_FLAG STREQUAL "QUIET") find_package(${CURRENT_DEP_SEARCH}) endif() foreach (CURRENT IN LISTS CURRENT_DEP_TARGETS) if (NOT TARGET "${CURRENT}") message(FATAL_ERROR "Expected successful find_package call with '${CURRENT_DEP_SEARCH}' to define target '${CURRENT}'") endif() endforeach() list(APPEND PUBLIC_DEP_CALL_ARGS "NAME ${CURRENT_DEP} DEP_TARGETS ${CURRENT_DEP_TARGETS} TARGET SOCI::${DEFINE_BACKEND_NAME}" ) endif() endforeach() add_library(${DEFINE_BACKEND_TARGET_NAME} ${SOCI_LIB_TYPE} ${DEFINE_BACKEND_SOURCE_FILES}) add_library(SOCI::${DEFINE_BACKEND_NAME} ALIAS ${DEFINE_BACKEND_TARGET_NAME}) # defined during compilation to control symbol visibility/export target_compile_definitions(${DEFINE_BACKEND_TARGET_NAME} PRIVATE SOCI_${BACKEND_UPPER}_SOURCE) foreach(CURRENT_ARG_SET IN LISTS PUBLIC_DEP_CALL_ARGS) # Convert space-separated string to list string(REPLACE " " ";" CURRENT_ARG_SET "${CURRENT_ARG_SET}") soci_public_dependency(${CURRENT_ARG_SET}) endforeach() # Set settings common to all backends. target_link_libraries(${DEFINE_BACKEND_TARGET_NAME} PUBLIC SOCI::Core) target_include_directories(${DEFINE_BACKEND_TARGET_NAME} PRIVATE "${PROJECT_SOURCE_DIR}/include/private") soci_private_dependency( NAME fmt DEP_TARGETS "${soci_fmt}" TARGET "SOCI::${DEFINE_BACKEND_NAME}" ) soci_build_library_name(full_backend_target_name "${DEFINE_BACKEND_TARGET_NAME}") set_target_properties(${DEFINE_BACKEND_TARGET_NAME} PROPERTIES OUTPUT_NAME ${full_backend_target_name} SOVERSION ${PROJECT_VERSION_MAJOR} VERSION ${PROJECT_VERSION} EXPORT_NAME ${DEFINE_BACKEND_NAME} ) if (DEFINE_BACKEND_HEADER_FILES) target_sources(${DEFINE_BACKEND_TARGET_NAME} PUBLIC FILE_SET headers TYPE HEADERS BASE_DIRS "${PROJECT_SOURCE_DIR}/include/" FILES ${DEFINE_BACKEND_HEADER_FILES} ) endif() target_link_libraries(soci_interface INTERFACE SOCI::${DEFINE_BACKEND_NAME}) if (NOT SOCI_INSTALL) return() endif() # Setup installation rules for this backend install( TARGETS ${DEFINE_BACKEND_TARGET_NAME} EXPORT SOCI${DEFINE_BACKEND_NAME}Targets RUNTIME DESTINATION "${SOCI_INSTALL_BINDIR}" COMPONENT soci_runtime LIBRARY DESTINATION "${SOCI_INSTALL_LIBDIR}" COMPONENT soci_runtime NAMELINK_COMPONENT soci_development ARCHIVE DESTINATION "${SOCI_INSTALL_LIBDIR}" COMPONENT soci_development FILE_SET headers DESTINATION "${SOCI_INSTALL_INCLUDEDIR}" COMPONENT soci_development ) # Generate and install a targets file install( EXPORT SOCI${DEFINE_BACKEND_NAME}Targets DESTINATION "${SOCI_INSTALL_CMAKEDIR}" FILE SOCI${DEFINE_BACKEND_NAME}Targets.cmake NAMESPACE SOCI:: COMPONENT soci_development ) foreach(FIND_FILE IN LISTS DEFINE_BACKEND_FIND_PACKAGE_FILES) install( FILES "${FIND_FILE}" DESTINATION "${SOCI_INSTALL_CMAKEDIR}/find_package_files/" COMPONENT soci_development ) endforeach() endfunction() soci-4.1.4/cmake/soci_utils.cmake0000664000175000017500000002011115215337514016635 0ustar zeitlinzeitlin# This function is meant to be called by other cmake functions that use the cmake_parse_arguments function. # It implements the boilerplate that is associated with validating the parsed arguments (e.g. no unknown arguments used; # ensuring all required options have been set). # # Use as # soci_verify_parsed_arguments( # PREFIX # FUNCTION_NAME # [REQUIRED …] # ) # where # - is the prefix used in the cmake_parse_arguments call that shall be validated # - is the name of the calling function or macro - this will be part of error mesages # - are names of options **without** the prefix function(soci_verify_parsed_arguments) set(FLAGS "") set(ONE_VAL_OPTIONS "PREFIX" "FUNCTION_NAME") set(MULTI_VAL_OPTIONS "REQUIRED") cmake_parse_arguments(VERIFY_PARSED_ARGS "${FLAGS}" "${ONE_VAL_OPTIONS}" "${MULTI_VAL_OPTIONS}" ${ARGV}) # First, verify own arguments if (DEFINED VERIFY_PARSED_ARGS_UNPARSED_ARGUMENTS) message(FATAL_ERROR "verify_parsed_arguments - Received unrecognized options: ${VERIFY_PARSED_ARGS_UNPARSED_ARGUMENTS}") endif() if (DEFINED VERIFY_PARSED_ARGS_KEYWORDS_MISSING_VALUES) message(FATAL_ERROR "verify_parsed_arguments - The following options are missing argumens: ${VERIFY_PARSED_ARGS_KEYWORDS_MISSING_VALUES}") endif() if (NOT DEFINED VERIFY_PARSED_ARGS_PREFIX) message(FATAL_ERROR "verify_parsed_arguments - Missing required option 'PREFIX'") endif() if (NOT DEFINED VERIFY_PARSED_ARGS_FUNCTION_NAME) message(FATAL_ERROR "verify_parsed_arguments - Missing required option 'FUNCTION_NAME'") endif() # Now start the function's actual job: Verifying a top-level function's call to cmake_parse_arguments if (DEFINED ${VERIFY_PARSED_ARGS_PREFIX}_UNPARSED_ARGUMENTS) message(FATAL_ERROR "${VERIFY_PARSED_ARGS_FUNCTION_NAME} - Received unrecognized options: ${${VERIFY_PARSED_ARGS_PREFIX}_UNPARSED_ARGUMENTS}") endif() if (DEFINED ${VERIFY_PARSED_ARGS_PREFIX}_KEYWORDS_MISSING_VALUES) message(FATAL_ERROR "${VERIFY_PARSED_ARGS_FUNCTION_NAME} - The following options are missing arguments: ${${VERIFY_PARSED_ARGS_PREFIX}_KEYWORDS_MISSING_VALUES}") endif() if (DEFINED VERIFY_PARSED_ARGS_REQUIRED) foreach(CURRENT_ARG IN LISTS VERIFY_PARSED_ARGS_REQUIRED) set(CURRENT_ARG "${VERIFY_PARSED_ARGS_PREFIX}_${CURRENT_ARG}") if (NOT DEFINED ${CURRENT_ARG}) message(FATAL_ERROR "${VERIFY_PARSED_ARGS_FUNCTION_NAME} - Missing required option '${CURRENT_ARG}'") endif() endforeach() endif() endfunction() # This function declares a public dependency of a given target in such a way that # the dependency is automatically populated to a generated SOCI config file. # # Use as # soci_public_dependency( # NAME # DEP_TARGETS ... # TARGET # ) # where # - is the name of the dependency (used for lookup via find_package) # - is the name of the target that will be imported upon a # successful find_package call # - is the name of the ALIAS target to link the found dependency to function(soci_public_dependency) soci_declare_dependency_impl(${ARGV} SCOPE PUBLIC) endfunction() # This function declares a private dependency of a given target in such a way that # the dependency is automatically populated to a generated SOCI config file if needed. # # Use as # soci_private_dependency( # NAME # DEP_TARGETS ... # TARGET # ) # where # - is the name of the dependency (used for lookup via find_package) # - is the name of the target that will be imported upon a # successful find_package call # - is the name of the ALIAS target to link the found dependency to function(soci_private_dependency) soci_declare_dependency_impl(${ARGV} SCOPE PRIVATE) endfunction() # Initialize variables populated by soci_declare_dependency_impl set(SOCI_DEPENDENCY_VARIABLES "SOCI_DEPENDENCY_SOCI_COMPONENTS" "SOCI_DEPENDENCY_NAMES" "SOCI_DEPENDENCY_TARGETS" ) if (NOT DEFINED SOCI_UTILS_ALREADY_INCLUDED) foreach(VAR_NAME IN LISTS SOCI_DEPENDENCY_VARIABLES) set("${VAR_NAME}" "" CACHE INTERNAL "") endforeach() endif() # This function declares a dependency of a given target in such a way that # the dependency is automatically populated to a generated SOCI config file if necessary. # Normally, you shouldn't be calling this function directly and instead use one of # soci_public_dependency() or soci_private_dependency(). # # Use as # soci_declare_dependency_impl( # NAME # DEP_TARGETS ... # TARGET # SCOPE [PUBLIC | PRIVATE] # ) # where # - is the name of the dependency (used for lookup via find_package) # - is the name of the target that will be imported upon a # successful find_package call # - is the name of the ALIAS target to link the found dependency to # - is the scope (public or private) of the dependency function(soci_declare_dependency_impl) set(ONE_VAL_OPTIONS "TARGET" "NAME" "SCOPE") set(MULTI_VAL_OPTIONS "DEP_TARGETS") cmake_parse_arguments(SOCI_DEP "${FLAGS}" "${ONE_VAL_OPTIONS}" "${MULTI_VAL_OPTIONS}" ${ARGV}) soci_verify_parsed_arguments( PREFIX "SOCI_DEP" FUNCTION_NAME "soci_public_dependency" REQUIRED "TARGET" "NAME" "DEP_TARGETS" "SCOPE" ) # Sanity checking if (NOT TARGET "${SOCI_DEP_TARGET}") message(FATAL_ERROR "Provided TARGET '${SOCI_DEP_TARGET}' does not exist") endif() get_target_property(UNDERLYING_TARGET "${SOCI_DEP_TARGET}" ALIASED_TARGET) if (NOT UNDERLYING_TARGET) message(FATAL_ERROR "Provided TARGET '${SOCI_DEP_TARGET}' is expected to be an ALIAS target") endif() get_target_property(UNDERLYING_TYPE "${UNDERLYING_TARGET}" TYPE) # Search for the package now set(SKIP_SEARCH ON) foreach (TGT IN LISTS SOCI_DEP_DEP_TARGETS) if (NOT TARGET "${TGT}") set(SKIP_SEARCH OFF) break() endif() endforeach() if (NOT SKIP_SEARCH) find_package("${SOCI_DEP_NAME}" REQUIRED) endif() set(INSTALLED_DEPENDENCIES "") set(FOUND_ONE OFF) foreach (TGT IN LISTS SOCI_DEP_DEP_TARGETS) if (NOT TARGET "${TGT}") if (FOUND_ONE) message(DEBUG "The following SOCI dependencies have been found only partially: ${SOCI_DEP_DEP_TARGETS}") endif() return() endif() set(FOUND_ONE ON) get_target_property(TGT_TYPE "${TGT}" TYPE) if ("${TGT_TYPE}" STREQUAL "INTERFACE_LIBRARY") get_target_property(TGT_LIBS "${TGT}" INTERFACE_LINK_LIBRARIES) if (NOT TGT_LIBS) set(TGT_HEADER_ONLY TRUE) endif() endif() if (NOT TGT_HEADER_ONLY AND ((NOT "${SOCI_DEP_SCOPE}" STREQUAL "PRIVATE") OR "${UNDERLYING_TYPE}" STREQUAL "STATIC_LIBRARY" OR NOT "${TGT_TYPE}" STREQUAL "STATIC_LIBRARY")) # - Header-only dependencies never have to be propagated # - Public (aka: non-private) dependencies are always required # - If SOCI is built as a static library, all dependencies (including static private) are required # at link time and hence must be find_package'd by the installed config file # - Static libraries used only by SOCI internals are only needed when linking SOCI itself. Hence, # if SOCI isn't built as a static library (which implies linking only happens at the downstream # consumer) these dependencies don't have to be present when consuming the installed config file. list(APPEND INSTALLED_DEPENDENCIES "${TGT}") endif() target_link_libraries("${UNDERLYING_TARGET}" ${SOCI_DEP_SCOPE} "$") endforeach() # Bookkeeping if (INSTALLED_DEPENDENCIES) list(APPEND SOCI_DEPENDENCY_SOCI_COMPONENTS "${SOCI_DEP_TARGET}") list(APPEND SOCI_DEPENDENCY_NAMES "${SOCI_DEP_NAME}") list(JOIN INSTALLED_DEPENDENCIES "|" STORED_TARGETS) list(APPEND SOCI_DEPENDENCY_TARGETS "${STORED_TARGETS}") foreach(VAR_NAME IN LISTS SOCI_DEPENDENCY_VARIABLES) set("${VAR_NAME}" "${${VAR_NAME}}" CACHE INTERNAL "") endforeach() endif() endfunction() set(SOCI_UTILS_ALREADY_INCLUDED TRUE) soci-4.1.4/cmake/soci_parse_version.cmake0000664000175000017500000000274515215337514020371 0ustar zeitlinzeitlininclude(soci_utils) # This function extracts the current SOCI version from the version header file # # Use as # soci_parse_version( # ROOT_DIR # OUTPUT_VARIABLE # ) # where # - is the path to SOCI's source tree root directory # - is the name of the variable used to make the parsed version available. This variable # will contain the version in a cmake-compatible format function(soci_parse_version) set(FLAGS "") set(ONE_VAL_OPTIONS "OUTPUT_VARIABLE" "ROOT_DIR") set(MULTI_VAL_OPTIONS "") cmake_parse_arguments(PARSE_VERSION "${FLAGS}" "${ONE_VAL_OPTIONS}" "${MULTI_VAL_OPTIONS}" ${ARGV}) soci_verify_parsed_arguments( PREFIX "PARSE_VERSION" FUNCTION_NAME "soci_parse_version" REQUIRED "OUTPUT_VARIABLE" "ROOT_DIR" ) set(VERSION_REGEX "^#define[ \\t]*SOCI_VERSION[ \\t]*([0-9]+)") file(STRINGS "${PARSE_VERSION_ROOT_DIR}/include/soci/version.h" VERSION_LINE REGEX ${VERSION_REGEX} LIMIT_COUNT 1 ) if (NOT VERSION_LINE MATCHES "${VERSION_REGEX}") message(STATUS "${PARSE_VERSION_ROOT_DIR}") message(FATAL_ERROR "Failed at parsing version from header file") endif() set(RAW_VERSION "${CMAKE_MATCH_1}") math(EXPR MAJOR_VERSION "${RAW_VERSION} / 100000") math(EXPR MINOR_VERSION "(${RAW_VERSION} / 100) % 1000") math(EXPR PATCH_VERSION "${RAW_VERSION} % 100") set("${PARSE_VERSION_OUTPUT_VARIABLE}" "${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}" PARENT_SCOPE) endfunction() soci-4.1.4/cmake/soci_compat.cmake0000664000175000017500000000142315215337514016765 0ustar zeitlinzeitlin# Take care of defining ALIAS targets to keep old target names working if (SOCI_SHARED) set(SUFFIX "") else() set(SUFFIX "_static") endif() set(OLD_NAMES core db2 empty firebird mysql odbc oracle postgresql sqlite3) set(ALIAS_NAMES Core DB2 Empty Firebird MySQL ODBC Oracle PostgreSQL SQLite3) list(LENGTH ALIAS_NAMES N_ITEMS) math(EXPR LAST_ITEM "${N_ITEMS} - 1") foreach (I RANGE ${LAST_ITEM}) list(GET OLD_NAMES ${I} CURRENT_NAME) list(GET ALIAS_NAMES ${I} CURRENT_ALIAS) if (NOT TARGET SOCI::${CURRENT_ALIAS}) continue() endif() get_target_property(UNDERLYING_LIB SOCI::${CURRENT_ALIAS} ALIASED_TARGET) add_library(Soci::${CURRENT_NAME}${SUFFIX} ALIAS ${UNDERLYING_LIB}) add_library(SOCI::${CURRENT_NAME}${SUFFIX} ALIAS ${UNDERLYING_LIB}) endforeach() soci-4.1.4/cmake/find_modules/0000775000175000017500000000000015215337514016133 5ustar zeitlinzeitlinsoci-4.1.4/cmake/find_modules/FindFirebird.cmake0000664000175000017500000000322515215337514021466 0ustar zeitlinzeitlin############################################################## # Copyright (c) 2008 Daniel Pfeifer # # # # Distributed under the Boost Software License, Version 1.0. # ############################################################## # This module defines # Firebird_INCLUDE_DIRS - where to find ibase.h # Firebird_LIBRARIES - the libraries to link against to use Firebird # Firebird_FOUND - true if Firebird was found if (DEFINED FIREBIRD_INCLUDE_DIR) message(DEPRECATION "FIREBIRD_INCLUDE_DIR has been deprecated. Use Firebird_INCLUDE_DIRS instead.") set(Firebird_INCLUDE_DIRS "${FIREBIRD_INCLUDE_DIR}") endif() if (DEFINED FIREBIRD_LIBRARIES) message(DEPRECATION "FIREBIRD_LIBRARIES has been deprecated. Use Firebird_LIBRARIES instead.") set(Firebird_LIBRARIES "${FIREBIRD_LIBRARIES}") endif() find_path(Firebird_INCLUDE_DIRS ibase.h /usr/include $ENV{ProgramFiles}/Firebird/*/include ) if (Firebird_SEARCH_EMBEDDED) set(Firebird_LIB_NAMES fbembed) else() set(Firebird_LIB_NAMES fbclient fbclient_ms) endif() find_library(Firebird_LIBRARIES NAMES ${Firebird_LIB_NAMES} PATHS /usr/lib $ENV{ProgramFiles}/Firebird/*/lib ) include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Firebird REQUIRED_VARS Firebird_LIBRARIES Firebird_INCLUDE_DIRS ) if (Firebird_FOUND AND NOT TARGET Firebird::Firebird) add_library(Firebird::Firebird UNKNOWN IMPORTED) set_target_properties(Firebird::Firebird PROPERTIES IMPORTED_LOCATION "${Firebird_LIBRARIES}") target_include_directories(Firebird::Firebird SYSTEM INTERFACE ${Firebird_INCLUDE_DIRS}) endif() soci-4.1.4/cmake/find_modules/FindMySQL.cmake0000664000175000017500000001777115215337514020720 0ustar zeitlinzeitlin# - Try to find MariaDB / MySQL library # Find the MySQL includes and client library # This module defines # MySQL_FOUND # An interface target MySQL::MySQL to be used in a target_link_libraries call if (DEFINED MYSQL_INCLUDE_DIR) message(DEPRECATION "MYSQL_INCLUDE_DIR has been deprecated. Use MySQL_INCLUDE_DIRS instead") set(MySQL_INCLUDE_DIRS "${MYSQL_INCLUDE_DIR}") endif() if (DEFINED MYSQL_LIBRARIES) message(DEPRECATION "MYSQL_LIBRARIES has been deprecated. Use MySQL_LIBRARIES instead") set(MySQL_LIBRARIES "${MYSQL_LIBRARIES}") endif() if (DEFINED VCPKG_TARGET_TRIPLET) # In vcpg the MySQL packages are called unofficial-libmysql find_package(unofficial-libmysql) set(FOUND_VAR "unofficial-libmysql_FOUND") set(LIBRARY_TARGET "unofficial::libmysql::libmysql") if (NOT ${FOUND_VAR}) find_package(unofficial-libmariadb QUIET) set(FOUND_VAR "unofficial-libmariadb_FOUND") set(LIBRARY_TARGET "unofficial::libmariadb::libmariadb") endif() if (${FOUND_VAR}) add_library(MySQL::MySQL ALIAS ${LIBRARY_TARGET}) get_target_property(INCLUDE_DIRS ${LIBRARY_TARGET} INTERFACE_INCLUDE_DIRECTORIES) if (NOT INCLUDE_DIRS) message(FATAL_ERROR "Expected include paths to be set") endif() foreach(current IN LISTS INCLUDE_DIRS) # In SOCI we include the MySQL headers as mysql.h (no prefix) as this is how most MySQL # packages seem to be set up and also this seems to be the way MySQL itself advocates. # However, the unofficial vcpkg package configures the include path in such a way that # we would have to explicitly include mysql/mysql.h (with prefix). Since this is # incompatible with the way we include MySQL, we have to modify the include path such # that we can omit the prefix as well. This is achieved by appending the mysql directory # to the configured include path. # In case vcpkg changes this at any point and we end up adding a non-existent directory # to the include path, no harm is done (we still keep the original vcpkg paths as well). target_include_directories(${LIBRARY_TARGET} SYSTEM INTERFACE "${current}/mysql") endforeach() endif() endif() if (NOT TARGET MySQL::MySQL) find_package(PkgConfig QUIET) if (PKG_CONFIG_FOUND) # Try via PkgConfig pkg_search_module(MySQL IMPORTED_TARGET QUIET mysqlclient libmariadb) if (TARGET PkgConfig::MySQL) add_library(MySQL::MySQL ALIAS PkgConfig::MySQL) endif() endif() endif() if (NOT TARGET MySQL::MySQL) # Try using config exe find_program(CONFIG_EXE NAMES mysql_config mariadb_config PATHS $ENV{MYSQL_DIR} $ENV{MYSQL_DIRS} $ENV{ProgramFiles}/MySQL/ $ENV{ProgramFiles}/MariaDB/ ) if (CONFIG_EXE) if (NOT MySQL_INCLUDE_DIRS) execute_process(COMMAND ${CONFIG_EXE} --include OUTPUT_VARIABLE MySQL_INCLUDE_DIRS OUTPUT_STRIP_TRAILING_WHITESPACE) # Convert include options of the form -I/dir into just the directories. string(REGEX REPLACE "(^| )(-I|-isystem ?)" " " MySQL_INCLUDE_DIRS "${MySQL_INCLUDE_DIRS}") # And convert the space-separated string into list. separate_arguments(MySQL_INCLUDE_DIRS NATIVE_COMMAND "${MySQL_INCLUDE_DIRS}") endif() if (NOT MySQL_LIBRARIES) execute_process(COMMAND ${CONFIG_EXE} --libs OUTPUT_VARIABLE MySQL_LIBRARIES OUTPUT_STRIP_TRAILING_WHITESPACE) # Note that we can't remove the -l and/or -L options here, as we can # have both of them intermixed, but, luckily, target_link_libraries() # accepts both of them directly. separate_arguments(MySQL_LIBRARIES NATIVE_COMMAND "${MySQL_LIBRARIES}") endif() if (NOT MySQL_VERSION) execute_process(COMMAND ${CONFIG_EXE} --version OUTPUT_VARIABLE MySQL_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) endif() endif() # Under Windows, it's normal to not have neither pkg-config nor mysql_config, # so don't warn about it, it's just annoying. if (NOT MySQL_LIBRARIES AND NOT WIN32) message(WARNING "Falling back to manual MySQL search -> this might miss dependencies") endif() set(MySQL_COMPILE_DEFINITIONS "") if(WIN32) find_path(MySQL_INCLUDE_DIRS mysql.h PATHS $ENV{MYSQL_INCLUDE_DIR} $ENV{MYSQL_INCLUDE_DIRS} $ENV{MYSQL_DIR}/include $ENV{MYSQL_DIRS}/include $ENV{ProgramFiles}/MySQL/*/include $ENV{SystemDrive}/MySQL/*/include $ENV{ProgramW6432}/MySQL/*/include ) else() find_path(MySQL_INCLUDE_DIRS mysql.h PATHS $ENV{MYSQL_INCLUDE_DIR} $ENV{MYSQL_INCLUDE_DIRS} $ENV{MYSQL_DIR}/include $ENV{MYSQL_DIRS}/include PATH_SUFFIXES mariadb mysql ) endif() if (MySQL_INCLUDE_DIRS) set(VERSION_FILE "${MySQL_INCLUDE_DIRS}/mysql_version.h") if (EXISTS "${VERSION_FILE}") # Parse out MySQL version file(READ "${VERSION_FILE}" VERSION_CONTENT) string(REGEX MATCH "#define[ \t]+LIBMYSQL_VERSION[ \t]+\"([^\"]+)\"" VERSION_CONTENT "${VERSION_CONTENT}") set(MySQL_VERSION "${CMAKE_MATCH_1}") endif() endif() if(WIN32) if (CMAKE_BUILD_TYPE) string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_TOLOWER) endif() # path suffix for debug/release mode # binary_dist: mysql binary distribution # build_dist: custom build if(CMAKE_BUILD_TYPE_TOLOWER MATCHES "debug") set(binary_dist debug) set(build_dist Debug) else() list(APPEND MySQL_COMPILE_DEFINITIONS DBUG_OFF) set(binary_dist opt) set(build_dist Release) endif() set(MySQL_LIB_PATHS $ENV{MYSQL_DIR}/lib/${binary_dist} $ENV{MYSQL_DIR}/libmysql/${build_dist} $ENV{MYSQL_DIR}/client/${build_dist} $ENV{ProgramFiles}/MySQL/*/lib/${binary_dist} $ENV{SystemDrive}/MySQL/*/lib/${binary_dist} $ENV{MYSQL_DIR}/lib/opt $ENV{MYSQL_DIR}/client/release $ENV{ProgramFiles}/MySQL/*/lib/opt $ENV{SystemDrive}/MySQL/*/lib/opt $ENV{ProgramW6432}/MySQL/*/lib ) find_library(MySQL_LIBRARIES NAMES libmysql PATHS ${MySQL_LIB_PATHS} ) else() set(MySQL_LIB_PATHS $ENV{MySQL_DIR}/lib PATH_SUFFIXES mariadb mysql ) find_library(MySQL_LIBRARIES NAMES mariadbclient mysqlclient PATHS ${MySQL_LIB_PATHS} ) endif() endif() if (TARGET MySQL::MySQL) set(LIB_TARGET MySQL::MySQL) set(UNDERLYING_TARGET MySQL::MySQL) while (UNDERLYING_TARGET) set(LIB_TARGET "${UNDERLYING_TARGET}") get_target_property(UNDERLYING_TARGET ${LIB_TARGET} ALIASED_TARGET) endwhile() if (NOT MySQL_VERSION) get_target_property(MySQL_VERSION ${LIB_TARGET} VERSION) endif() if (NOT MySQL_INCLUDE_DIRS) get_target_property(MySQL_INCLUDE_DIRS ${LIB_TARGET} INTERFACE_INCLUDE_DIRECTORIES) endif() if (NOT MySQL_INCLUDE_DIRS) get_target_property(MySQL_INCLUDE_DIRS ${LIB_TARGET} INTERFACE_SYSTEM_INCLUDE_DIRECTORIES) endif() if (NOT MySQL_INCLUDE_DIRS) get_target_property(MySQL_INCLUDE_DIRS ${LIB_TARGET} INCLUDE_DIRECTORIES) endif() if (NOT MySQL_LIBRARIES) get_target_property(MySQL_LIBRARIES ${LIB_TARGET} INTERFACE_LINK_LIBRARIES) endif() if (NOT MySQL_LIBRARIES) get_target_property(MySQL_LIBRARIES ${LIB_TARGET} LINK_LIBRARIES) endif() if (NOT MySQL_VERSION) # To prevent printing a weird xyz-NOTFOUND as the version number unset(MySQL_VERSION) endif() endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(MySQL REQUIRED_VARS MySQL_LIBRARIES MySQL_INCLUDE_DIRS VERSION_VAR MySQL_VERSION ) if (MySQL_FOUND AND NOT TARGET MySQL::MySQL) add_library(MySQL::MySQL UNKNOWN IMPORTED) set_target_properties(MySQL::MySQL PROPERTIES IMPORTED_LOCATION "${MySQL_LIBRARIES}") target_include_directories(MySQL::MySQL SYSTEM INTERFACE ${MySQL_INCLUDE_DIRS}) target_compile_options(MySQL::MySQL INTERFACE ${MySQL_CFLAGS}) target_link_options(MySQL::MySQL INTERFACE ${MySQL_LDFLAGS}) target_compile_definitions(MySQL::MySQL INTERFACE ${MySQL_COMPILE_DEFINITIONS}) endif() soci-4.1.4/cmake/find_modules/FindOracle.cmake0000664000175000017500000001022515215337514021143 0ustar zeitlinzeitlin############################################################################### # # CMake module to search for Oracle client library (OCI) # # On success, the macro sets the following variables: # Oracle_FOUND = if the library found # Oracle_LIBRARY = full path to the library # Oracle_LIBRARIES = full path to the library # Oracle_INCLUDE_DIRS = where to find the library headers also defined, # but not for general use are # Oracle_VERSION = version of library which was found, e.g. "1.2.5" # # Copyright (c) 2009-2013 Mateusz Loskot # # Developed with inspiration from Petr Vanek # who wrote similar macro for TOra - https://torasql.com/ # # Module source: https://github.com/mloskot/workshop/tree/master/cmake/ # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # ############################################################################### if (DEFINED ORACLE_INCLUDE_DIR) message(DEPRECATION "ORACLE_INCLUDE_DIR has been deprecated. Use Oracle_INCLUDE_DIRS instead") set(Oracle_INCLUDE_DIRS "${ORACLE_INCLUDE_DIR}") endif() if (DEFINED ORACLE_LIBRARY) message(DEPRECATION "ORACLE_LIBRARY has been deprecated. Use Oracle_LIBRARIES instead") set(Oracle_LIBRARIES "${ORACLE_LIBRARY}") endif() # First check for CMAKE variable if(NOT ORACLE_HOME AND NOT Oracle_HOME) if(EXISTS $ENV{ORACLE_HOME}) set(Oracle_HOME $ENV{ORACLE_HOME}) endif() if(EXISTS $ENV{Oracle_HOME}) set(Oracle_HOME $ENV{Oracle_HOME}) endif() endif() if (ORACLE_HOME) set(Oracle_HOME "${ORACLE_HOME}") endif() find_path(Oracle_INCLUDE_DIRS NAMES oci.h PATHS ${Oracle_HOME}/rdbms/public ${Oracle_HOME}/include ${Oracle_HOME}/sdk/include # Oracle SDK ${Oracle_HOME}/OCI/include # Oracle XE on Windows # instant client from rpm /usr/include/oracle/*/client${LIB_SUFFIX}) set(Oracle_VERSIONS 21 20 19 18 12 11 10) set(Oracle_OCI_NAMES clntsh libclntsh oci) # Dirty trick might help on OSX, see issues/89 set(Oracle_OCCI_NAMES libocci occi) set(Oracle_NNZ_NAMES ociw32) foreach(loop_var IN LISTS Oracle_VERSIONS) set(Oracle_OCCI_NAMES ${Oracle_OCCI_NAMES} oraocci${loop_var}) set(Oracle_NNZ_NAMES ${Oracle_NNZ_NAMES} nnz${loop_var} libnnz${loop_var}) endforeach(loop_var) set(Oracle_LIB_DIR ${Oracle_HOME} ${Oracle_HOME}/lib ${Oracle_HOME}/sdk/lib # Oracle SDK ${Oracle_HOME}/sdk/lib/msvc ${Oracle_HOME}/OCI/lib/msvc # Oracle XE on Windows # Instant client from rpm /usr/lib/oracle/*/client${LIB_SUFFIX}/lib) find_library(Oracle_OCI_LIBRARY NAMES ${Oracle_OCI_NAMES} PATHS ${Oracle_LIB_DIR}) find_library(Oracle_OCCI_LIBRARY NAMES ${Oracle_OCCI_NAMES} PATHS ${Oracle_LIB_DIR}) find_library(Oracle_NNZ_LIBRARY NAMES ${Oracle_NNZ_NAMES} PATHS ${Oracle_LIB_DIR}) if (Oracle_OCI_LIBRARY AND Oracle_OCCI_LIBRARY AND Oracle_NNZ_LIBRARY) set(Oracle_LIBRARIES ${Oracle_OCI_LIBRARY} ${Oracle_OCCI_LIBRARY} ${Oracle_NNZ_LIBRARY}) endif() if(NOT WIN32 AND Oracle_CLNTSH_LIBRARY) list(APPEND Oracle_LIBRARIES ${Oracle_CLNTSH_LIBRARY}) endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(Oracle REQUIRED_VARS Oracle_LIBRARIES Oracle_INCLUDE_DIRS) if(Oracle_FOUND AND NOT TARGET Oracle::Oracle) add_library(Oracle::OCI UNKNOWN IMPORTED) set_target_properties(Oracle::OCI PROPERTIES IMPORTED_LOCATION "${Oracle_OCI_LIBRARY}") add_library(Oracle::OCCI UNKNOWN IMPORTED) set_target_properties(Oracle::OCCI PROPERTIES IMPORTED_LOCATION "${Oracle_OCCI_LIBRARY}") add_library(Oracle::NNZ UNKNOWN IMPORTED) set_target_properties(Oracle::NNZ PROPERTIES IMPORTED_LOCATION "${Oracle_NNZ_LIBRARY}") add_library(Oracle_interface INTERFACE) target_include_directories(Oracle_interface SYSTEM INTERFACE ${Oracle_INCLUDE_DIRS}) target_link_libraries(Oracle_interface INTERFACE Oracle::OCI Oracle::OCCI Oracle::NNZ) add_library(Oracle::Oracle ALIAS Oracle_interface) elseif(NOT TARGET Oracle::Oracle) message(STATUS "None of the supported Oracle versions (${Oracle_VERSIONS}) could be found, consider updating Oracle_VERSIONS if the version you use is not among them.") endif() soci-4.1.4/cmake/find_modules/FindDB2.cmake0000664000175000017500000000607115215337514020311 0ustar zeitlinzeitlin############################################################################### # CMake module to search for DB2 client library # # On success, the macro sets the following variables: # DB2_FOUND = if the library found # DB2_LIBRARIES = full path to the library # DB2_INCLUDE_DIRS = where to find the library headers # # Copyright (c) 2013 Denis Chapligin # # Redistribution and use is allowed according to the terms of the BSD license. # For details see the accompanying COPYING-CMAKE-SCRIPTS file. # ############################################################################### if(UNIX) set(DB2_INSTALL_PATHS /opt/ibm/db2/V11.5 /opt/ibm/db2/V10.1 /opt/ibm/db2/V9.7 /opt/ibm/db2/V9.5 /opt/ibm/db2/V9.1 /opt/ibm/clidriver /opt/clidriver) if(CMAKE_SIZEOF_VOID_P EQUAL 4) set(DB2_LIBDIRS "lib32" "lib") else() set(DB2_LIBDIRS "lib64" "lib") endif() set(DB2_FIND_INCLUDE_PATHS) set(DB2_FIND_LIB_PATHS) foreach(db2_install_path ${DB2_INSTALL_PATHS}) if (IS_DIRECTORY ${db2_install_path}/include) set(DB2_FIND_INCLUDE_PATHS ${DB2_FIND_INCLUDE_PATHS} ${db2_install_path}/include) endif() foreach(db2_libdir ${DB2_LIBDIRS}) if (IS_DIRECTORY ${db2_install_path}/${db2_libdir}) set(DB2_FIND_LIB_PATHS ${DB2_FIND_LIB_PATHS} ${db2_install_path}/${db2_libdir}) endif() endforeach(db2_libdir) endforeach(db2_install_path) elseif(WIN32) if (CMAKE_CL_64) # 64-bit build, DB2 64-bit installed set(DB2_FIND_INCLUDE_PATHS $ENV{ProgramW6432}/IBM/SQLLIB/include) set(DB2_FIND_LIB_PATHS $ENV{ProgramW6432}/IBM/SQLLIB/lib) else() # 32-bit build, DB2 64-bit or DB2 32-bit installed if(EXISTS "$ENV{ProgramW6432}/IBM/SQLLIB/lib") # On 64-bit Windows with DB2 64-bit installed: # LIB environment points to {DB2}/IBM/SQLLIB/lib with64-bit db2api.lib, # this flag prevents checking paths in LIB, so Win32 version can be detected set(DB2_FIND_LIB_NO_LIB NO_SYSTEM_ENVIRONMENT_PATH) endif() set(DB2_FIND_INCLUDE_PATHS $ENV{ProgramW6432}/IBM/SQLLIB/include $ENV{ProgramFiles}/IBM/SQLLIB/include) set(DB2_FIND_LIB_PATHS $ENV{ProgramFiles}/IBM/SQLLIB/lib $ENV{ProgramFiles}/IBM/SQLLIB/lib/win32 $ENV{ProgramW6432}/IBM/SQLLIB/lib/win32) endif() endif() find_path(DB2_INCLUDE_DIRS sqlcli1.h $ENV{DB2_INCLUDE_DIR} $ENV{DB2_INCLUDE_DIRS} $ENV{DB2_DIR}/include $ENV{DB2_HOME} $ENV{IBM_DB_INCLUDE} ${DB2_FIND_INCLUDE_PATHS}) find_library(DB2_LIBRARIES NAMES db2 db2api PATHS $ENV{DB2LIB} $ENV{IBM_DB_LIB} ${DB2_FIND_LIB_PATHS} ${DB2_FIND_LIB_NO_LIB}) if(DB2_LIBRARIES) get_filename_component(DB2_LIBRARY_DIR ${DB2_LIBRARIES} PATH) endif() include(FindPackageHandleStandardArgs) find_package_handle_standard_args(DB2 REQUIRED_VARS DB2_INCLUDE_DIRS DB2_LIBRARIES ) if (DB2_FOUND AND NOT TARGET DB2:DB2) add_library(DB2::DB2 UNKNOWN IMPORTED) set_target_properties(DB2::DB2 PROPERTIES IMPORTED_LOCATION "${DB2_LIBRARIES}") target_include_directories(DB2::DB2 SYSTEM INTERFACE ${DB2_INCLUDE_DIRS}) endif() soci-4.1.4/examples/0000775000175000017500000000000015215337514014221 5ustar zeitlinzeitlinsoci-4.1.4/examples/subdir-include/0000775000175000017500000000000015215337514017132 5ustar zeitlinzeitlinsoci-4.1.4/examples/subdir-include/CMakeLists.txt0000664000175000017500000000341315215337514021673 0ustar zeitlinzeitlin# This is a very simple example of using SOCI in a CMake-based project # when placing SOCI in a subdirectory lib/soci/ of your project. # For this example, the SOCI backend called Empty is used. cmake_minimum_required(VERSION 3.23 FATAL_ERROR) project(SOCIExampleSubdirectoryInclude) set(SOCI_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/soci) # All compile options need to be set before the SOCI directory gets included. # The backend you want to use needs to be enabled here. Available options are # - SOCI_DB2 # - SOCI_EMPTY # - SOCI_FIREBIRD # - SOCI_MYSQL # - SOCI_ODBC # - SOCI_ORACLE # - SOCI_POSTGRESQL # - SOCI_SQLITE3 # each of these options can be set to "ON" or "OFF" or to # "AUTO" (the default) in which case the backend is included only # if all of its dependencies are satisfied. If not, the backend # is disabled but no error is emitted (which is what would happen # in this case if the backend was set to "ON"). set(SOCI_EMPTY ON CACHE INTERNAL "" FORCE) # In order to not run into cross-platform issues, the **top-level** project # should define these variables to ensure all build artefacts (of a given kind) # end up in the same place. if (PROJECT_IS_TOP_LEVEL) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}") set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}") set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}") endif() # This line needs to be changed to include the directory you placed SOCI in, e.g. # add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/lib/soci ${SOCI_BINARY_DIR}) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../.. ${SOCI_BINARY_DIR}) add_executable(subdir_include subdir-include.cpp) # Link to SOCI (SOCI::SOCI will resolve all requested dependencies automatically) target_link_libraries(subdir_include PRIVATE SOCI::SOCI ) soci-4.1.4/examples/subdir-include/lib/0000775000175000017500000000000015215337514017700 5ustar zeitlinzeitlinsoci-4.1.4/examples/subdir-include/lib/soci/0000775000175000017500000000000015215337514020635 5ustar zeitlinzeitlinsoci-4.1.4/examples/subdir-include/lib/soci/README.md0000664000175000017500000000017715215337514022121 0ustar zeitlinzeitlin# Example of using SOCI with CMake For this example, we assume, that the whole SOCI repository is located in this repository. soci-4.1.4/examples/subdir-include/subdir-include.cpp0000664000175000017500000000203015215337514022542 0ustar zeitlinzeitlin#include #include #include #include #include #include int main(int argc, char* argv[]) { if (argc != 2) { std::cerr << "usage: " << argv[0] << " \n"; return EXIT_FAILURE; } std::string connectString{argv[1]}; try { soci::session sql(soci::empty, connectString); std::cout << "Successfully connected to \"" << connectString << "\", " << "using \"" << sql.get_backend_name() << "\" backend.\n"; return EXIT_SUCCESS; } catch (const soci::soci_error& e) { std::cerr << "Connection to \"" << connectString << "\" failed: " << e.what() << "\n"; } catch (const std::runtime_error& e) { std::cerr << "Unexpected standard exception occurred: " << e.what() << "\n"; } catch (...) { std::cerr << "Unexpected unknown exception occurred.\n"; } return EXIT_FAILURE; } soci-4.1.4/examples/connect/0000775000175000017500000000000015215337514015652 5ustar zeitlinzeitlinsoci-4.1.4/examples/connect/CMakeLists.txt0000664000175000017500000000214015215337514020407 0ustar zeitlinzeitlin# # Copyright (C) 2021 Vadim Zeitlin # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # https://www.boost.org/LICENSE_1_0.txt) # # This is a very simple example of using SOCI in a CMake-based project. cmake_minimum_required(VERSION 3.10...3.31 FATAL_ERROR) project(SOCIExampleConnect) # Note: SOCI versions before 4.1 rely on hand-written FindSOCI.cmake files to be # present in downstream projects as SOCI didn't use to ship a config file. # This is changed in 4.1 thanks to which the desired database backends can # be specified as components. Known component names are # - Empty # - DB2 # - Firebird # - MySQL # - ODBC # - Oracle # - PostgreSQL # - SQLite3 # note that some components may still be undefined if the corresponding library is # not included in the SOCI version installed on your system. find_package(SOCI 4.1 COMPONENTS Empty REQUIRED) add_executable(connect connect.cpp) # Note that linking to SOCI::SOCI is enough to inherit # all of SOCI's dependencies, include directories, etc. target_link_libraries(connect PRIVATE SOCI::SOCI) soci-4.1.4/examples/connect/connect.cpp0000664000175000017500000000242615215337514020013 0ustar zeitlinzeitlin// // Copyright (C) 2021 Vadim Zeitlin // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // https://www.boost.org/LICENSE_1_0.txt) // // // This is the simplest possible example of using SOCI: just connect to the // database using the provided command line argument. #include #include #include int main(int argc, char* argv[]) { if (argc != 2) { std::cerr << "usage: " << argv[0] << " \n"; return EXIT_FAILURE; } char const* const connectString = argv[1]; try { soci::session sql(connectString); std::cout << "Successfully connected to \"" << connectString << "\", " << "using \"" << sql.get_backend_name() << "\" backend.\n"; return EXIT_SUCCESS; } catch (soci::soci_error const& e) { std::cerr << "Connection to \"" << connectString << "\" failed: " << e.what() << "\n"; } catch (std::runtime_error const& e) { std::cerr << "Unexpected standard exception occurred: " << e.what() << "\n"; } catch (...) { std::cerr << "Unexpected unknown exception occurred.\n"; } return EXIT_FAILURE; } soci-4.1.4/3rdparty/0000775000175000017500000000000015215337514014153 5ustar zeitlinzeitlinsoci-4.1.4/3rdparty/fmt/0000775000175000017500000000000015100423533014727 5ustar zeitlinzeitlinsoci-4.1.4/3rdparty/fmt/LICENSE0000664000175000017500000000262715100423533015743 0ustar zeitlinzeitlinCopyright (c) 2012 - present, Victor Zverovich and {fmt} contributors 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. soci-4.1.4/3rdparty/fmt/CMakeLists.txt0000664000175000017500000004634015100423533017476 0ustar zeitlinzeitlincmake_minimum_required(VERSION 3.8...3.28) # Fallback for using newer policies on CMake <3.12. if (${CMAKE_VERSION} VERSION_LESS 3.12) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) endif () # Determine if fmt is built as a subproject (using add_subdirectory) # or if it is the master project. if (NOT DEFINED FMT_MASTER_PROJECT) set(FMT_MASTER_PROJECT OFF) # NOTE: source vs current_source detection is unreliable # this heuristic is more generally applicable esp w.r.t FetchContent if (NOT DEFINED PROJECT_NAME) set(FMT_MASTER_PROJECT ON) message(STATUS "CMake version: ${CMAKE_VERSION}") endif () 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() # DEPRECATED! Should be merged into add_module_library. function(enable_module target) if (MSVC) if(NOT CMAKE_GENERATOR STREQUAL "Ninja") set(BMI_DIR "${CMAKE_CURRENT_BINARY_DIR}") file(TO_NATIVE_PATH "${BMI_DIR}/${target}.ifc" BMI) target_compile_options(${target} PRIVATE /interface /ifcOutput ${BMI} INTERFACE /reference fmt=${BMI}) set_target_properties(${target} PROPERTIES ADDITIONAL_CLEAN_FILES ${BMI}) set_source_files_properties(${BMI} PROPERTIES GENERATED ON) endif() endif () endfunction() set(FMT_USE_CMAKE_MODULES FALSE) if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.28 AND CMAKE_GENERATOR STREQUAL "Ninja") set(FMT_USE_CMAKE_MODULES TRUE) endif () # Adds a library compiled with C++20 module support. # `enabled` is a CMake variables that specifies if modules are enabled. # If modules are disabled `add_module_library` falls back to creating a # non-modular library. # # Usage: # add_module_library( [sources...] FALLBACK [sources...] [IF enabled]) function(add_module_library name) cmake_parse_arguments(AML "" "IF" "FALLBACK" ${ARGN}) set(sources ${AML_UNPARSED_ARGUMENTS}) add_library(${name}) set_target_properties(${name} PROPERTIES LINKER_LANGUAGE CXX) if (NOT ${${AML_IF}}) # Create a non-modular library. target_sources(${name} PRIVATE ${AML_FALLBACK}) set_target_properties(${name} PROPERTIES CXX_SCAN_FOR_MODULES OFF) return() endif () # Modules require C++20. target_compile_features(${name} PUBLIC cxx_std_20) if (CMAKE_COMPILER_IS_GNUCXX) target_compile_options(${name} PUBLIC -fmodules-ts) endif () if (FMT_USE_CMAKE_MODULES) target_sources(${name} PUBLIC FILE_SET fmt TYPE CXX_MODULES FILES ${sources}) else() # `std` is affected by CMake options and may be higher than C++20. get_target_property(std ${name} CXX_STANDARD) if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(pcms) foreach (src ${sources}) get_filename_component(pcm ${src} NAME_WE) set(pcm ${pcm}.pcm) # Propagate -fmodule-file=*.pcm to targets that link with this library. target_compile_options( ${name} PUBLIC -fmodule-file=${CMAKE_CURRENT_BINARY_DIR}/${pcm}) # Use an absolute path to prevent target_link_libraries prepending -l # to it. set(pcms ${pcms} ${CMAKE_CURRENT_BINARY_DIR}/${pcm}) add_custom_command( OUTPUT ${pcm} COMMAND ${CMAKE_CXX_COMPILER} -std=c++${std} -x c++-module --precompile -c -o ${pcm} ${CMAKE_CURRENT_SOURCE_DIR}/${src} "-I$,;-I>" # Required by the -I generator expression above. COMMAND_EXPAND_LISTS DEPENDS ${src}) endforeach () # Add .pcm files as sources to make sure they are built before the library. set(sources) foreach (pcm ${pcms}) get_filename_component(pcm_we ${pcm} NAME_WE) set(obj ${pcm_we}.o) # Use an absolute path to prevent target_link_libraries prepending -l. set(sources ${sources} ${pcm} ${CMAKE_CURRENT_BINARY_DIR}/${obj}) add_custom_command( OUTPUT ${obj} COMMAND ${CMAKE_CXX_COMPILER} $ -c -o ${obj} ${pcm} DEPENDS ${pcm}) endforeach () endif () target_sources(${name} PRIVATE ${sources}) endif() endfunction() include(CMakeParseArguments) # Sets a cache variable with a docstring joined from multiple arguments: # set( ... CACHE ...) # This allows splitting a long docstring for readability. function(set_verbose) # cmake_parse_arguments is broken in CMake 3.4 (cannot parse CACHE) so use # list instead. list(GET ARGN 0 var) list(REMOVE_AT ARGN 0) list(GET ARGN 0 val) list(REMOVE_AT ARGN 0) list(REMOVE_AT ARGN 0) list(GET ARGN 0 type) list(REMOVE_AT ARGN 0) join(doc ${ARGN}) set(${var} ${val} CACHE ${type} ${doc}) endfunction() # Set the default CMAKE_BUILD_TYPE to Release. # This should be done before the project command since the latter can set # CMAKE_BUILD_TYPE itself (it does so for nmake). if (FMT_MASTER_PROJECT AND NOT CMAKE_BUILD_TYPE) set_verbose(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or " "CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.") endif () project(FMT CXX) include(GNUInstallDirs) set_verbose(FMT_INC_DIR ${CMAKE_INSTALL_INCLUDEDIR} CACHE STRING "Installation directory for include files, a relative path that " "will be joined with ${CMAKE_INSTALL_PREFIX} or an absolute path.") option(FMT_PEDANTIC "Enable extra warnings and expensive tests." OFF) option(FMT_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." ${FMT_MASTER_PROJECT}) option(FMT_INSTALL "Generate the install target." ${FMT_MASTER_PROJECT}) option(FMT_TEST "Generate the test target." ${FMT_MASTER_PROJECT}) option(FMT_FUZZ "Generate the fuzz target." OFF) option(FMT_CUDA_TEST "Generate the cuda-test target." OFF) option(FMT_OS "Include OS-specific APIs." ON) option(FMT_MODULE "Build a module instead of a traditional library." OFF) option(FMT_SYSTEM_HEADERS "Expose headers with marking them as system." OFF) option(FMT_UNICODE "Enable Unicode support." ON) if (FMT_TEST AND FMT_MODULE) # The tests require {fmt} to be compiled as traditional library message(STATUS "Testing is incompatible with build mode 'module'.") endif () set(FMT_SYSTEM_HEADERS_ATTRIBUTE "") if (FMT_SYSTEM_HEADERS) set(FMT_SYSTEM_HEADERS_ATTRIBUTE SYSTEM) endif () if (CMAKE_SYSTEM_NAME STREQUAL "MSDOS") set(FMT_TEST OFF) message(STATUS "MSDOS is incompatible with gtest") endif () # Get version from base.h file(READ include/fmt/base.h base_h) if (NOT base_h MATCHES "FMT_VERSION ([0-9]+)([0-9][0-9])([0-9][0-9])") message(FATAL_ERROR "Cannot get FMT_VERSION from base.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 "{fmt} version: ${FMT_VERSION}") message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") if (NOT CMAKE_RUNTIME_OUTPUT_DIRECTORY) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin) endif () list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/support/cmake") include(CheckCXXCompilerFlag) include(JoinPaths) if (FMT_MASTER_PROJECT AND NOT DEFINED CMAKE_CXX_VISIBILITY_PRESET) set_verbose(CMAKE_CXX_VISIBILITY_PRESET hidden CACHE STRING "Preset for the export of private symbols") set_property(CACHE CMAKE_CXX_VISIBILITY_PRESET PROPERTY STRINGS hidden default) endif () if (FMT_MASTER_PROJECT AND NOT DEFINED CMAKE_VISIBILITY_INLINES_HIDDEN) set_verbose(CMAKE_VISIBILITY_INLINES_HIDDEN ON CACHE BOOL "Whether to add a compile flag to hide symbols of inline functions") endif () 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 -Wctor-dtor-privacy -Wdisabled-optimization -Winvalid-pch -Woverloaded-virtual -Wconversion -Wundef -Wno-ctor-dtor-privacy -Wno-format-nonliteral) if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6) set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -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 -Wshadow) endif () if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0) set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wshift-overflow=2 -Wduplicated-cond) # Workaround for GCC regression # [12/13/14/15 regression] New (since gcc 12) false positive null-dereference in vector.resize # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108860 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.0) set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wnull-dereference) endif () endif () set(WERROR_FLAG -Werror) endif () if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -pedantic -Wconversion -Wundef -Wdeprecated -Wweak-vtables -Wshadow -Wno-gnu-zero-variadic-macro-arguments) 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 (FMT_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. join(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 () 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. set(FMT_HEADERS) add_headers(FMT_HEADERS args.h base.h chrono.h color.h compile.h core.h format.h format-inl.h os.h ostream.h printf.h ranges.h std.h xchar.h) set(FMT_SOURCES src/format.cc) add_module_library(fmt src/fmt.cc FALLBACK ${FMT_SOURCES} ${FMT_HEADERS} README.md ChangeLog.md IF FMT_MODULE) add_library(fmt::fmt ALIAS fmt) if (FMT_MODULE) enable_module(fmt) elseif (FMT_OS) target_sources(fmt PRIVATE src/os.cc) else() target_compile_definitions(fmt PRIVATE FMT_OS=0) endif () if (FMT_WERROR) target_compile_options(fmt PRIVATE ${WERROR_FLAG}) endif () if (FMT_PEDANTIC) target_compile_options(fmt PRIVATE ${PEDANTIC_COMPILE_FLAGS}) endif () if (cxx_std_11 IN_LIST CMAKE_CXX_COMPILE_FEATURES) target_compile_features(fmt PUBLIC cxx_std_11) else () message(WARNING "Feature cxx_std_11 is unknown for the CXX compiler") endif () target_include_directories(fmt ${FMT_SYSTEM_HEADERS_ATTRIBUTE} BEFORE PUBLIC $ $) set(FMT_DEBUG_POSTFIX d CACHE STRING "Debug library postfix.") set_target_properties(fmt PROPERTIES VERSION ${FMT_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR} PUBLIC_HEADER "${FMT_HEADERS}" DEBUG_POSTFIX "${FMT_DEBUG_POSTFIX}" # Workaround for Visual Studio 2017: # Ensure the .pdb is created with the same name and in the same directory # as the .lib. Newer VS versions already do this by default, but there is no # harm in setting it for those too. Ignored by other generators. COMPILE_PDB_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" COMPILE_PDB_NAME "fmt" COMPILE_PDB_NAME_DEBUG "fmt${FMT_DEBUG_POSTFIX}") # Set FMT_LIB_NAME for pkg-config fmt.pc. We cannot use the OUTPUT_NAME target # property because it's not set by default. set(FMT_LIB_NAME fmt) if (CMAKE_BUILD_TYPE STREQUAL "Debug") set(FMT_LIB_NAME ${FMT_LIB_NAME}${FMT_DEBUG_POSTFIX}) endif () if (BUILD_SHARED_LIBS) target_compile_definitions(fmt PRIVATE FMT_LIB_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) if (NOT MSVC) # Unicode is always supported on compilers other than MSVC. elseif (FMT_UNICODE) # Unicode support requires compiling with /utf-8. target_compile_options(fmt PUBLIC $<$,$>:/utf-8>) target_compile_options(fmt-header-only INTERFACE $<$,$>:/utf-8>) else () target_compile_definitions(fmt PUBLIC FMT_UNICODE=0) endif () target_compile_definitions(fmt-header-only INTERFACE FMT_HEADER_ONLY=1) target_compile_features(fmt-header-only INTERFACE cxx_std_11) target_include_directories(fmt-header-only ${FMT_SYSTEM_HEADERS_ATTRIBUTE} BEFORE INTERFACE $ $) # Install targets. if (FMT_INSTALL) include(CMakePackageConfigHelpers) set_verbose(FMT_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/fmt CACHE STRING "Installation directory for cmake files, a relative path that " "will be joined with ${CMAKE_INSTALL_PREFIX} or an absolute " "path.") set(version_config ${PROJECT_BINARY_DIR}/fmt-config-version.cmake) set(project_config ${PROJECT_BINARY_DIR}/fmt-config.cmake) set(pkgconfig ${PROJECT_BINARY_DIR}/fmt.pc) set(targets_export_name fmt-targets) set_verbose(FMT_LIB_DIR ${CMAKE_INSTALL_LIBDIR} CACHE STRING "Installation directory for libraries, a relative path that " "will be joined to ${CMAKE_INSTALL_PREFIX} or an absolute path.") set_verbose(FMT_PKGCONFIG_DIR ${CMAKE_INSTALL_LIBDIR}/pkgconfig CACHE STRING "Installation directory for pkgconfig (.pc) files, a relative " "path that will be joined with ${CMAKE_INSTALL_PREFIX} or an " "absolute path.") # Generate the version, config and target files into the build directory. write_basic_package_version_file( ${version_config} VERSION ${FMT_VERSION} COMPATIBILITY AnyNewerVersion) join_paths(libdir_for_pc_file "\${exec_prefix}" "${FMT_LIB_DIR}") join_paths(includedir_for_pc_file "\${prefix}" "${FMT_INC_DIR}") configure_file( "${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}) set(INSTALL_TARGETS fmt fmt-header-only) set(INSTALL_FILE_SET) if (FMT_USE_CMAKE_MODULES) set(INSTALL_FILE_SET FILE_SET fmt DESTINATION "${FMT_INC_DIR}/fmt") endif() # Install the library and headers. install(TARGETS ${INSTALL_TARGETS} COMPONENT fmt_core EXPORT ${targets_export_name} LIBRARY DESTINATION ${FMT_LIB_DIR} ARCHIVE DESTINATION ${FMT_LIB_DIR} PUBLIC_HEADER DESTINATION "${FMT_INC_DIR}/fmt" RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ${INSTALL_FILE_SET}) # 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} COMPONENT fmt_core) install(EXPORT ${targets_export_name} DESTINATION ${FMT_CMAKE_DIR} NAMESPACE fmt:: COMPONENT fmt_core) install(FILES "${pkgconfig}" DESTINATION "${FMT_PKGCONFIG_DIR}" COMPONENT fmt_core) endif () function(add_doc_target) find_program(DOXYGEN doxygen PATHS "$ENV{ProgramFiles}/doxygen/bin" "$ENV{ProgramFiles\(x86\)}/doxygen/bin") if (NOT DOXYGEN) message(STATUS "Target 'doc' disabled because doxygen not found") return () endif () find_program(MKDOCS mkdocs) if (NOT MKDOCS) message(STATUS "Target 'doc' disabled because mkdocs not found") return () endif () set(sources ) foreach (source api.md index.md syntax.md get-started.md fmt.css fmt.js) set(sources ${sources} doc/${source}) endforeach() add_custom_target( doc COMMAND ${CMAKE_COMMAND} -E env PYTHONPATH=${CMAKE_CURRENT_SOURCE_DIR}/support/python ${MKDOCS} build -f ${CMAKE_CURRENT_SOURCE_DIR}/support/mkdocs.yml # MkDocs requires the site dir to be outside of the doc dir. --site-dir ${CMAKE_CURRENT_BINARY_DIR}/doc-html --no-directory-urls SOURCES ${sources}) include(GNUInstallDirs) install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/doc-html/ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/doc/fmt COMPONENT fmt_doc OPTIONAL) endfunction() if (FMT_DOC) add_doc_target() endif () if (FMT_TEST) enable_testing() add_subdirectory(test) endif () # Control fuzzing independent of the unit tests. if (FMT_FUZZ) add_subdirectory(test/fuzzing) # The FMT_FUZZ macro is used to prevent resource exhaustion in fuzzing # mode and make fuzzing practically possible. It is similar to # FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION but uses a different name to # avoid interfering with fuzzing of projects that use {fmt}. # See also https://llvm.org/docs/LibFuzzer.html#fuzzer-friendly-build-mode. target_compile_definitions(fmt PUBLIC FMT_FUZZ) endif () set(gitignore ${PROJECT_SOURCE_DIR}/.gitignore) if (FMT_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 /build/doxyxml .vagrant) 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.md) include(CPack) endif () soci-4.1.4/3rdparty/fmt/.gitignore0000664000175000017500000000040415100423533016715 0ustar zeitlinzeitlin*.a *.so* *.xcodeproj *~ .vscode/ .cache/ .vs/ /CMakeScripts /Testing /_CPack_Packages /install_manifest.txt CMakeCache.txt CMakeUserPresets.json CMakeFiles CPack*.cmake CTestTestfile.cmake FMT.build Makefile bin/ build/ cmake_install.cmake fmt-*.cmake fmt.pc soci-4.1.4/3rdparty/fmt/CONTRIBUTING.md0000664000175000017500000000130615100423533017160 0ustar zeitlinzeitlinContributing to {fmt} ===================== By submitting a pull request or a patch, you represent that you have the right to license your contribution to the {fmt} project owners and the community, agree that your contributions are licensed under the {fmt} license, and agree to future changes to the licensing. All C++ code must adhere to [Google C++ Style Guide]( https://google.github.io/styleguide/cppguide.html) with the following exceptions: * Exceptions are permitted * snake_case should be used instead of UpperCamelCase for function and type names All documentation must adhere to the [Google Developer Documentation Style Guide](https://developers.google.com/style). Thanks for contributing! soci-4.1.4/3rdparty/fmt/.clang-format0000664000175000017500000000064515100423533017307 0ustar zeitlinzeitlin# Run manually to reformat a file: # clang-format -i --style=file Language: Cpp BasedOnStyle: Google IndentPPDirectives: AfterHash IndentCaseLabels: false AlwaysBreakTemplateDeclarations: false DerivePointerAlignment: false AllowShortCaseLabelsOnASingleLine: true QualifierAlignment: Left AlignConsecutiveShortCaseStatements: Enabled: true AcrossEmptyLines: true AcrossComments: true AlignCaseColons: falsesoci-4.1.4/3rdparty/fmt/README.md0000664000175000017500000004634115100423533016216 0ustar zeitlinzeitlin{fmt} [![image](https://github.com/fmtlib/fmt/workflows/linux/badge.svg)](https://github.com/fmtlib/fmt/actions?query=workflow%3Alinux) [![image](https://github.com/fmtlib/fmt/workflows/macos/badge.svg)](https://github.com/fmtlib/fmt/actions?query=workflow%3Amacos) [![image](https://github.com/fmtlib/fmt/workflows/windows/badge.svg)](https://github.com/fmtlib/fmt/actions?query=workflow%3Awindows) [![fmt is continuously fuzzed at oss-fuzz](https://oss-fuzz-build-logs.storage.googleapis.com/badges/fmt.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?\%0Acolspec=ID%20Type%20Component%20Status%20Proj%20Reported%20Owner%20\%0ASummary&q=proj%3Dfmt&can=1) [![OpenSSF Best Practices](https://www.bestpractices.dev/projects/8880/badge)](https://www.bestpractices.dev/projects/8880) [![image](https://api.securityscorecards.dev/projects/github.com/fmtlib/fmt/badge)](https://securityscorecards.dev/viewer/?uri=github.com/fmtlib/fmt) [![Ask questions at StackOverflow with the tag fmt](https://img.shields.io/badge/stackoverflow-fmt-blue.svg)](https://stackoverflow.com/questions/tagged/fmt) **{fmt}** is an open-source formatting library providing a fast and safe alternative to C stdio and C++ iostreams. If you like this project, please consider donating to one of the funds that help victims of the war in Ukraine: . [Documentation](https://fmt.dev) [Cheat Sheets](https://hackingcpp.com/cpp/libs/fmt.html) Q&A: ask questions on [StackOverflow with the tag fmt](https://stackoverflow.com/questions/tagged/fmt). Try {fmt} in [Compiler Explorer](https://godbolt.org/z/8Mx1EW73v). # Features - Simple [format API](https://fmt.dev/latest/api/) with positional arguments for localization - Implementation of [C++20 std::format](https://en.cppreference.com/w/cpp/utility/format) and [C++23 std::print](https://en.cppreference.com/w/cpp/io/print) - [Format string syntax](https://fmt.dev/latest/syntax/) similar to Python\'s [format](https://docs.python.org/3/library/stdtypes.html#str.format) - Fast IEEE 754 floating-point formatter with correct rounding, shortness and round-trip guarantees using the [Dragonbox](https://github.com/jk-jeon/dragonbox) algorithm - Portable Unicode support - Safe [printf implementation](https://fmt.dev/latest/api/#printf-formatting) including the POSIX extension for positional arguments - Extensibility: [support for user-defined types](https://fmt.dev/latest/api/#formatting-user-defined-types) - High performance: faster than common standard library implementations of `(s)printf`, iostreams, `to_string` and `to_chars`, see [Speed tests](#speed-tests) and [Converting a hundred million integers to strings per second](http://www.zverovich.net/2020/06/13/fast-int-to-string-revisited.html) - Small code size both in terms of source code with the minimum configuration consisting of just three files, `base.h`, `format.h` and `format-inl.h`, and compiled code; see [Compile time and code bloat](#compile-time-and-code-bloat) - Reliability: the library has an extensive set of [tests](https://github.com/fmtlib/fmt/tree/master/test) and is [continuously fuzzed](https://bugs.chromium.org/p/oss-fuzz/issues/list?colspec=ID%20Type%20Component%20Status%20Proj%20Reported%20Owner%20Summary&q=proj%3Dfmt&can=1) - Safety: the library is fully type-safe, errors in format strings can be reported at compile time, automatic memory management prevents buffer overflow errors - Ease of use: small self-contained code base, no external dependencies, permissive MIT [license](https://github.com/fmtlib/fmt/blob/master/LICENSE) - [Portability](https://fmt.dev/latest/#portability) with consistent output across platforms and support for older compilers - Clean warning-free codebase even on high warning levels such as `-Wall -Wextra -pedantic` - Locale independence by default - Optional header-only configuration enabled with the `FMT_HEADER_ONLY` macro See the [documentation](https://fmt.dev) for more details. # Examples **Print to stdout** ([run](https://godbolt.org/z/Tevcjh)) ``` c++ #include int main() { fmt::print("Hello, world!\n"); } ``` **Format a string** ([run](https://godbolt.org/z/oK8h33)) ``` c++ std::string s = fmt::format("The answer is {}.", 42); // s == "The answer is 42." ``` **Format a string using positional arguments** ([run](https://godbolt.org/z/Yn7Txe)) ``` c++ std::string s = fmt::format("I'd rather be {1} than {0}.", "right", "happy"); // s == "I'd rather be happy than right." ``` **Print dates and times** ([run](https://godbolt.org/z/c31ExdY3W)) ``` c++ #include int main() { auto now = std::chrono::system_clock::now(); fmt::print("Date and time: {}\n", now); fmt::print("Time: {:%H:%M}\n", now); } ``` Output: Date and time: 2023-12-26 19:10:31.557195597 Time: 19:10 **Print a container** ([run](https://godbolt.org/z/MxM1YqjE7)) ``` c++ #include #include int main() { std::vector v = {1, 2, 3}; fmt::print("{}\n", v); } ``` Output: [1, 2, 3] **Check a format string at compile time** ``` c++ std::string s = fmt::format("{:d}", "I am not a number"); ``` This gives a compile-time error in C++20 because `d` is an invalid format specifier for a string. **Write a file from a single thread** ``` c++ #include int main() { auto out = fmt::output_file("guide.txt"); out.print("Don't {}", "Panic"); } ``` This can be [5 to 9 times faster than fprintf](http://www.zverovich.net/2020/08/04/optimal-file-buffer-size.html). **Print with colors and text styles** ``` c++ #include int main() { fmt::print(fg(fmt::color::crimson) | fmt::emphasis::bold, "Hello, {}!\n", "world"); fmt::print(fg(fmt::color::floral_white) | bg(fmt::color::slate_gray) | fmt::emphasis::underline, "Olá, {}!\n", "Mundo"); fmt::print(fg(fmt::color::steel_blue) | fmt::emphasis::italic, "你好{}ï¼�\n", "世界"); } ``` Output on a modern terminal with Unicode support: ![image](https://github.com/fmtlib/fmt/assets/%0A576385/2a93c904-d6fa-4aa6-b453-2618e1c327d7) # Benchmarks ## Speed tests | Library | Method | Run Time, s | |-------------------|---------------|-------------| | libc | printf | 0.91 | | libc++ | std::ostream | 2.49 | | {fmt} 9.1 | fmt::print | 0.74 | | Boost Format 1.80 | boost::format | 6.26 | | Folly Format | folly::format | 1.87 | {fmt} is the fastest of the benchmarked methods, \~20% faster than `printf`. The above results were generated by building `tinyformat_test.cpp` on macOS 12.6.1 with `clang++ -O3 -DNDEBUG -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](https://github.com/fmtlib/format-benchmark/blob/master/src/tinyformat-test.cc). {fmt} is up to 20-30x faster than `std::ostringstream` and `sprintf` on IEEE754 `float` and `double` formatting ([dtoa-benchmark](https://github.com/fmtlib/dtoa-benchmark)) and faster than [double-conversion](https://github.com/google/double-conversion) and [ryu](https://github.com/ulfjack/ryu): [![image](https://user-images.githubusercontent.com/576385/95684665-11719600-0ba8-11eb-8e5b-972ff4e49428.png)](https://fmt.dev/unknown_mac64_clang12.0.html) ## Compile time and code bloat The script [bloat-test.py][test] from [format-benchmark][bench] 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 clang version 15.0.0 (clang-1500.1.0.2.5), macOS Sonoma, best of three) is shown in the following tables. [test]: https://github.com/fmtlib/format-benchmark/blob/master/bloat-test.py [bench]: https://github.com/fmtlib/format-benchmark **Optimized build (-O3)** | Method | Compile Time, s | Executable size, KiB | Stripped size, KiB | |---------------|-----------------|----------------------|--------------------| | printf | 1.6 | 54 | 50 | | IOStreams | 25.9 | 98 | 84 | | fmt 83652df | 4.8 | 54 | 50 | | tinyformat | 29.1 | 161 | 136 | | Boost Format | 55.0 | 530 | 317 | {fmt} is fast to compile and is comparable to `printf` in terms of per-call binary size (within a rounding error on this system). **Non-optimized build** | Method | Compile Time, s | Executable size, KiB | Stripped size, KiB | |---------------|-----------------|----------------------|--------------------| | printf | 1.4 | 54 | 50 | | IOStreams | 23.4 | 92 | 68 | | {fmt} 83652df | 4.4 | 89 | 85 | | tinyformat | 24.5 | 204 | 161 | | Boost Format | 36.4 | 831 | 462 | `libc`, `lib(std)c++`, and `libfmt` are all linked as shared libraries to compare formatting function overhead only. Boost Format is a header-only library so it doesn\'t provide any linkage options. ## Running the tests Please refer to [Building the library](https://fmt.dev/latest/get-started/#building-from-source) for instructions on how to build the library and run the unit tests. Benchmarks reside in a separate repository, [format-benchmarks](https://github.com/fmtlib/format-benchmark), 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 # Migrating code [clang-tidy](https://clang.llvm.org/extra/clang-tidy/) v18 provides the [modernize-use-std-print](https://clang.llvm.org/extra/clang-tidy/checks/modernize/use-std-print.html) check that is capable of converting occurrences of `printf` and `fprintf` to `fmt::print` if configured to do so. (By default it converts to `std::print`.) # Notable projects using this library - [0 A.D.](https://play0ad.com/): a free, open-source, cross-platform real-time strategy game - [AMPL/MP](https://github.com/ampl/mp): an open-source library for mathematical programming - [Apple's FoundationDB](https://github.com/apple/foundationdb): an open-source, distributed, transactional key-value store - [Aseprite](https://github.com/aseprite/aseprite): animated sprite editor & pixel art tool - [AvioBook](https://www.aviobook.aero/en): a comprehensive aircraft operations suite - [Blizzard Battle.net](https://battle.net/): an online gaming platform - [Celestia](https://celestia.space/): real-time 3D visualization of space - [Ceph](https://ceph.com/): a scalable distributed storage system - [ccache](https://ccache.dev/): a compiler cache - [ClickHouse](https://github.com/ClickHouse/ClickHouse): an analytical database management system - [ContextVision](https://www.contextvision.com/): medical imaging software - [Contour](https://github.com/contour-terminal/contour/): a modern terminal emulator - [CUAUV](https://cuauv.org/): Cornell University\'s autonomous underwater vehicle - [Drake](https://drake.mit.edu/): a planning, control, and analysis toolbox for nonlinear dynamical systems (MIT) - [Envoy](https://github.com/envoyproxy/envoy): C++ L7 proxy and communication bus (Lyft) - [FiveM](https://fivem.net/): a modification framework for GTA V - [fmtlog](https://github.com/MengRao/fmtlog): a performant fmtlib-style logging library with latency in nanoseconds - [Folly](https://github.com/facebook/folly): Facebook open-source library - [GemRB](https://gemrb.org/): a portable open-source implementation of Bioware's Infinity Engine - [Grand Mountain Adventure](https://store.steampowered.com/app/1247360/Grand_Mountain_Adventure/): a beautiful open-world ski & snowboarding game - [HarpyWar/pvpgn](https://github.com/pvpgn/pvpgn-server): Player vs Player Gaming Network with tweaks - [KBEngine](https://github.com/kbengine/kbengine): an open-source MMOG server engine - [Keypirinha](https://keypirinha.com/): a semantic launcher for Windows - [Kodi](https://kodi.tv/) (formerly xbmc): home theater software - [Knuth](https://kth.cash/): high-performance Bitcoin full-node - [libunicode](https://github.com/contour-terminal/libunicode/): a modern C++17 Unicode library - [MariaDB](https://mariadb.org/): relational database management system - [Microsoft Verona](https://github.com/microsoft/verona): research programming language for concurrent ownership - [MongoDB](https://mongodb.com/): distributed document database - [MongoDB Smasher](https://github.com/duckie/mongo_smasher): a small tool to generate randomized datasets - [OpenSpace](https://openspaceproject.com/): an open-source astrovisualization framework - [PenUltima Online (POL)](https://www.polserver.com/): an MMO server, compatible with most Ultima Online clients - [PyTorch](https://github.com/pytorch/pytorch): an open-source machine learning library - [quasardb](https://www.quasardb.net/): a distributed, high-performance, associative database - [Quill](https://github.com/odygrd/quill): asynchronous low-latency logging library - [QKW](https://github.com/ravijanjam/qkw): generalizing aliasing to simplify navigation, and execute complex multi-line terminal command sequences - [redis-cerberus](https://github.com/HunanTV/redis-cerberus): a Redis cluster proxy - [redpanda](https://vectorized.io/redpanda): a 10x faster Kafka® replacement for mission-critical systems written in C++ - [rpclib](http://rpclib.net/): a modern C++ msgpack-RPC server and client library - [Salesforce Analytics Cloud](https://www.salesforce.com/analytics-cloud/overview/): business intelligence software - [Scylla](https://www.scylladb.com/): a Cassandra-compatible NoSQL data store that can handle 1 million transactions per second on a single server - [Seastar](http://www.seastar-project.org/): an advanced, open-source C++ framework for high-performance server applications on modern hardware - [spdlog](https://github.com/gabime/spdlog): super fast C++ logging library - [Stellar](https://www.stellar.org/): financial platform - [Touch Surgery](https://www.touchsurgery.com/): surgery simulator - [TrinityCore](https://github.com/TrinityCore/TrinityCore): open-source MMORPG framework - [ðŸ�™ userver framework](https://userver.tech/): open-source asynchronous framework with a rich set of abstractions and database drivers - [Windows Terminal](https://github.com/microsoft/terminal): the new Windows terminal [More\...](https://github.com/search?q=fmtlib&type=Code) If you are aware of other projects using this library, please let me know by [email](mailto:victor.zverovich@gmail.com) or by submitting an [issue](https://github.com/fmtlib/fmt/issues). # 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, \...))](https://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html) in GCC. There is a POSIX extension that adds positional arguments required for [i18n](https://en.wikipedia.org/wiki/Internationalization_and_localization) to `printf` but it is not a part of C99 and may not be available on some platforms. ## iostreams The main issue with iostreams is best illustrated with an example: ``` c++ std::cout << std::setprecision(2) << std::fixed << 1.23456 << "\n"; ``` which is a lot of typing compared to printf: ``` 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 that 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](#benchmarks)). ## FastFormat This is an interesting library that 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, on STLSoft, which might be too restrictive for use in some projects. ## Boost Spirit.Karma This is not 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_to` with format string compilation on Karma\'s own benchmark, see [Converting a hundred million integers to strings per second](http://www.zverovich.net/2020/06/13/fast-int-to-string-revisited.html). # License {fmt} is distributed under the MIT [license](https://github.com/fmtlib/fmt/blob/master/LICENSE). # Documentation License The [Format String Syntax](https://fmt.dev/latest/syntax/) section in the documentation is based on the one from Python [string module documentation](https://docs.python.org/3/library/string.html#module-string). For this reason, the documentation is distributed under the Python Software Foundation license available in [doc/python-license.txt](https://raw.github.com/fmtlib/fmt/master/doc/python-license.txt). It only applies if you distribute the documentation of {fmt}. # Maintainers The {fmt} library is maintained by Victor Zverovich ([vitaut](https://github.com/vitaut)) with contributions from many other people. See [Contributors](https://github.com/fmtlib/fmt/graphs/contributors) and [Releases](https://github.com/fmtlib/fmt/releases) for some of the names. Let us know if your contribution is not listed or mentioned incorrectly and we\'ll make it right. # Security Policy To report a security issue, please disclose it at [security advisory](https://github.com/fmtlib/fmt/security/advisories/new). This project is maintained by a team of volunteers on a reasonable-effort basis. As such, please give us at least *90* days to work on a fix before public exposure. soci-4.1.4/3rdparty/fmt/support/0000775000175000017500000000000015100423533016443 5ustar zeitlinzeitlinsoci-4.1.4/3rdparty/fmt/support/C++.sublime-syntax0000664000175000017500000021520415100423533021665 0ustar zeitlinzeitlin%YAML 1.2 --- # http://www.sublimetext.com/docs/3/syntax.html name: C++ (fmt) comment: I don't think anyone uses .hp. .cp tends to be paired with .h. (I could be wrong. :) -- chris file_extensions: - cpp - cc - cp - cxx - c++ - C - h - hh - hpp - hxx - h++ - inl - ipp first_line_match: '-\*- C\+\+ -\*-' scope: source.c++ variables: identifier: \b[[:alpha:]_][[:alnum:]_]*\b # upper and lowercase macro_identifier: \b[[:upper:]_][[:upper:][:digit:]_]{2,}\b # only uppercase, at least 3 chars path_lookahead: '(?:::\s*)?(?:{{identifier}}\s*::\s*)*(?:template\s+)?{{identifier}}' operator_method_name: '\boperator\s*(?:[-+*/%^&|~!=<>]|[-+*/%^&|=!<>]=|<<=?|>>=?|&&|\|\||\+\+|--|,|->\*?|\(\)|\[\]|""\s*{{identifier}})' casts: 'const_cast|dynamic_cast|reinterpret_cast|static_cast' operator_keywords: 'and|and_eq|bitand|bitor|compl|not|not_eq|or|or_eq|xor|xor_eq|noexcept' control_keywords: 'break|case|catch|continue|default|do|else|for|goto|if|_Pragma|return|switch|throw|try|while' memory_operators: 'new|delete' basic_types: 'asm|__asm__|auto|bool|_Bool|char|_Complex|double|float|_Imaginary|int|long|short|signed|unsigned|void' before_tag: 'struct|union|enum\s+class|enum\s+struct|enum|class' declspec: '__declspec\(\s*\w+(?:\([^)]+\))?\s*\)' storage_classes: 'static|export|extern|friend|explicit|virtual|register|thread_local' type_qualifier: 'const|constexpr|mutable|typename|volatile' compiler_directive: 'inline|restrict|__restrict__|__restrict' visibility_modifiers: 'private|protected|public' other_keywords: 'typedef|nullptr|{{visibility_modifiers}}|static_assert|sizeof|using|typeid|alignof|alignas|namespace|template' modifiers: '{{storage_classes}}|{{type_qualifier}}|{{compiler_directive}}' non_angle_brackets: '(?=<<|<=)' regular: '[^(){}&;*^%=<>-]*' paren_open: (?:\( paren_close: '\))?' generic_open: (?:< generic_close: '>)?' balance_parentheses: '{{regular}}{{paren_open}}{{regular}}{{paren_close}}{{regular}}' generic_lookahead: <{{regular}}{{generic_open}}{{regular}}{{generic_open}}{{regular}}{{generic_close}}\s*{{generic_close}}{{balance_parentheses}}> data_structures_forward_decl_lookahead: '(\s+{{macro_identifier}})*\s*(:\s*({{path_lookahead}}|{{visibility_modifiers}}|,|\s|<[^;]*>)+)?;' non_func_keywords: 'if|for|switch|while|decltype|sizeof|__declspec|__attribute__|typeid|alignof|alignas|static_assert' format_spec: |- (?x: (?:.? [<>=^])? # fill align [ +-]? # sign \#? # alternate form # technically, octal and hexadecimal integers are also supported as 'width', but rarely used \d* # width ,? # thousands separator (?:\.\d+)? # precision [bcdeEfFgGnosxX%]? # type ) contexts: main: - include: preprocessor-global - include: global ############################################################################# # Reusable contexts # # The follow contexts are currently constructed to be reused in the # Objetive-C++ syntax. They are specifically constructed to not push into # sub-contexts, which ensures that Objective-C++ code isn't accidentally # lexed as plain C++. # # The "unique-*" contexts are additions that C++ makes over C, and thus can # be directly reused in Objective-C++ along with contexts from Objective-C # and C. ############################################################################# unique-late-expressions: # This is highlighted after all of the other control keywords # to allow operator overloading to be lexed properly - match: \boperator\b scope: keyword.control.c++ unique-modifiers: - match: \b({{modifiers}})\b scope: storage.modifier.c++ unique-variables: - match: \bthis\b scope: variable.language.c++ # common C++ instance var naming idiom -- fMemberName - match: '\b(f|m)[[:upper:]]\w*\b' scope: variable.other.readwrite.member.c++ # common C++ instance var naming idiom -- m_member_name - match: '\bm_[[:alnum:]_]+\b' scope: variable.other.readwrite.member.c++ unique-constants: - match: \bnullptr\b scope: constant.language.c++ unique-keywords: - match: \busing\b scope: keyword.control.c++ - match: \bbreak\b scope: keyword.control.flow.break.c++ - match: \bcontinue\b scope: keyword.control.flow.continue.c++ - match: \bgoto\b scope: keyword.control.flow.goto.c++ - match: \breturn\b scope: keyword.control.flow.return.c++ - match: \bthrow\b scope: keyword.control.flow.throw.c++ - match: \b({{control_keywords}})\b scope: keyword.control.c++ - match: '\bdelete\b(\s*\[\])?|\bnew\b(?!])' scope: keyword.control.c++ - match: \b({{operator_keywords}})\b scope: keyword.operator.word.c++ unique-types: - match: \b(char16_t|char32_t|wchar_t|nullptr_t)\b scope: storage.type.c++ - match: \bclass\b scope: storage.type.c++ unique-strings: - match: '((?:L|u8|u|U)?R)("([^\(\)\\ ]{0,16})\()' captures: 1: storage.type.string.c++ 2: punctuation.definition.string.begin.c++ push: - meta_scope: string.quoted.double.c++ - match: '\)\3"' scope: punctuation.definition.string.end.c++ pop: true - match: '\{\{|\}\}' scope: constant.character.escape.c++ - include: formatting-syntax unique-numbers: - match: |- (?x) (?: # floats (?: (?:\b\d(?:[\d']*\d)?\.\d(?:[\d']*\d)?|\B\.\d(?:[\d']*\d)?)(?:[Ee][+-]?\d(?:[\d']*\d)?)?(?:[fFlL]|(?:i[fl]?|h|min|[mun]?s|_\w*))?\b | (?:\b\d(?:[\d']*\d)?\.)(?:\B|(?:[fFlL]|(?:i[fl]?|h|min|[mun]?s|_\w*))\b|(?:[Ee][+-]?\d(?:[\d']*\d)?)(?:[fFlL]|(?:i[fl]?|h|min|[mun]?s|_\w*))?\b) | \b\d(?:[\d']*\d)?(?:[Ee][+-]?\d(?:[\d']*\d)?)(?:[fFlL]|(?:i[fl]?|h|min|[mun]?s|_\w*))?\b ) | # ints \b(?: (?: # dec [1-9](?:[\d']*\d)? | # oct 0(?:[0-7']*[0-7])? | # hex 0[Xx][\da-fA-F](?:[\da-fA-F']*[\da-fA-F])? | # bin 0[Bb][01](?:[01']*[01])? ) # int suffixes (?:(?:l{1,2}|L{1,2})[uU]?|[uU](?:l{0,2}|L{0,2})|(?:i[fl]?|h|min|[mun]?s|_\w*))?)\b ) (?!\.) # Number must not be followed by a decimal point scope: constant.numeric.c++ identifiers: - match: '{{identifier}}\s*(::)\s*' captures: 1: punctuation.accessor.c++ - match: '(?:(::)\s*)?{{identifier}}' captures: 1: punctuation.accessor.c++ function-specifiers: - match: \b(const|final|noexcept|override)\b scope: storage.modifier.c++ ############################################################################# # The following are C++-specific contexts that should not be reused. This is # because they push into subcontexts and use variables that are C++-specific. ############################################################################# ## Common context layout global: - match: '(?=\btemplate\b)' push: - include: template - match: (?=\S) set: global-modifier - include: namespace - include: keywords-angle-brackets - match: '(?={{path_lookahead}}\s*<)' push: global-modifier # Take care of comments just before a function definition. - match: /\* scope: punctuation.definition.comment.c push: - - match: \s*(?=\w) set: global-modifier - match: "" pop: true - - meta_scope: comment.block.c - match: \*/ scope: punctuation.definition.comment.c pop: true - include: early-expressions - match: ^\s*\b(extern)(?=\s+"C(\+\+)?") scope: storage.modifier.c++ push: - include: comments - include: strings - match: '\{' scope: punctuation.section.block.begin.c++ set: - meta_scope: meta.extern-c.c++ - match: '^\s*(#\s*ifdef)\s*__cplusplus\s*' scope: meta.preprocessor.c++ captures: 1: keyword.control.import.c++ set: - match: '\}' scope: punctuation.section.block.end.c++ pop: true - include: preprocessor-global - include: global - match: '\}' scope: punctuation.section.block.end.c++ pop: true - include: preprocessor-global - include: global - match: (?=\S) set: global-modifier - match: ^\s*(?=\w) push: global-modifier - include: late-expressions statements: - include: preprocessor-statements - include: scope:source.c#label - include: expressions expressions: - include: early-expressions - include: late-expressions early-expressions: - include: early-expressions-before-generic-type - include: generic-type - include: early-expressions-after-generic-type early-expressions-before-generic-type: - include: preprocessor-expressions - include: comments - include: case-default - include: typedef - include: keywords-angle-brackets - include: keywords-parens - include: keywords - include: numbers # Prevent a '<' from getting scoped as the start of another template # parameter list, if in reality a less-than-or-equals sign is meant. - match: <= scope: keyword.operator.comparison.c early-expressions-after-generic-type: - include: members-arrow - include: operators - include: members-dot - include: strings - include: parens - include: brackets - include: block - include: variables - include: constants - match: ',' scope: punctuation.separator.c++ - match: '\)|\}' scope: invalid.illegal.stray-bracket-end.c++ expressions-minus-generic-type: - include: early-expressions-before-generic-type - include: angle-brackets - include: early-expressions-after-generic-type - include: late-expressions expressions-minus-generic-type-function-call: - include: early-expressions-before-generic-type - include: angle-brackets - include: early-expressions-after-generic-type - include: late-expressions-before-function-call - include: identifiers - match: ';' scope: punctuation.terminator.c++ late-expressions: - include: late-expressions-before-function-call - include: function-call - include: identifiers - match: ';' scope: punctuation.terminator.c++ late-expressions-before-function-call: - include: unique-late-expressions - include: modifiers-parens - include: modifiers - include: types expressions-minus-function-call: - include: early-expressions - include: late-expressions-before-function-call - include: identifiers - match: ';' scope: punctuation.terminator.c++ comments: - include: scope:source.c#comments operators: - include: scope:source.c#operators modifiers: - include: unique-modifiers - include: scope:source.c#modifiers variables: - include: unique-variables - include: scope:source.c#variables constants: - include: unique-constants - include: scope:source.c#constants keywords: - include: unique-keywords - include: scope:source.c#keywords types: - include: unique-types - include: types-parens - include: scope:source.c#types strings: - include: unique-strings - match: '(L|u8|u|U)?(")' captures: 1: storage.type.string.c++ 2: punctuation.definition.string.begin.c++ push: - meta_scope: string.quoted.double.c++ - match: '"' scope: punctuation.definition.string.end.c++ pop: true - include: scope:source.c#string_escaped_char - match: |- (?x)% (\d+\$)? # field (argument #) [#0\- +']* # flags [,;:_]? # separator character (AltiVec) ((-?\d+)|\*(-?\d+\$)?)? # minimum field width (\.((-?\d+)|\*(-?\d+\$)?)?)? # precision (hh|h|ll|l|j|t|z|q|L|vh|vl|v|hv|hl)? # length modifier (\[[^\]]+\]|[am]s|[diouxXDOUeEfFgGaACcSspn%]) # conversion type scope: constant.other.placeholder.c++ - match: '\{\{|\}\}' scope: constant.character.escape.c++ - include: formatting-syntax - include: scope:source.c#strings formatting-syntax: # https://docs.python.org/3.6/library/string.html#formatstrings - match: |- # simple form (?x) (\{) (?: [\w.\[\]]+)? # field_name ( ! [ars])? # conversion ( : (?:{{format_spec}}| # format_spec OR [^}%]*%.[^}]*) # any format-like string )? (\}) scope: constant.other.placeholder.c++ captures: 1: punctuation.definition.placeholder.begin.c++ 2: storage.modifier.c++onversion.c++ 3: constant.other.format-spec.c++ 4: punctuation.definition.placeholder.end.c++ - match: \{(?=[^\}"']+\{[^"']*\}) # complex (nested) form scope: punctuation.definition.placeholder.begin.c++ push: - meta_scope: constant.other.placeholder.c++ - match: \} scope: punctuation.definition.placeholder.end.c++ pop: true - match: '[\w.\[\]]+' - match: '![ars]' scope: storage.modifier.conversion.c++ - match: ':' push: - meta_scope: meta.format-spec.c++ constant.other.format-spec.c++ - match: (?=\}) pop: true - include: formatting-syntax numbers: - include: unique-numbers - include: scope:source.c#numbers ## C++-specific contexts case-default: - match: '\b(default|case)\b' scope: keyword.control.c++ push: - match: (?=[);,]) pop: true - match: ':' scope: punctuation.separator.c++ pop: true - include: expressions modifiers-parens: - match: '\b(alignas)\b\s*(\()' captures: 1: storage.modifier.c++ 2: meta.group.c++ punctuation.section.group.begin.c++ push: - meta_content_scope: meta.group.c++ - match: '\)' scope: meta.group.c++ punctuation.section.group.end.c++ pop: true - include: expressions - match: \b(__attribute__)\s*(\(\() captures: 1: storage.modifier.c++ 2: meta.group.c++ punctuation.section.group.begin.c++ push : - meta_scope: meta.attribute.c++ - meta_content_scope: meta.group.c++ - include: parens - include: strings - match: \)\) scope: meta.group.c++ punctuation.section.group.end.c++ pop: true - match: \b(__declspec)(\() captures: 1: storage.modifier.c++ 2: meta.group.c++ punctuation.section.group.begin.c++ push: - meta_content_scope: meta.group.c++ - match: '\)' scope: meta.group.c++ punctuation.section.group.end.c++ pop: true - match: '\b(align|allocate|code_seg|deprecated|property|uuid)\b\s*(\()' captures: 1: storage.modifier.c++ 2: meta.group.c++ punctuation.section.group.begin.c++ push: - meta_content_scope: meta.group.c++ - match: '\)' scope: meta.group.c++ punctuation.section.group.end.c++ pop: true - include: numbers - include: strings - match: \b(get|put)\b scope: variable.parameter.c++ - match: ',' scope: punctuation.separator.c++ - match: '=' scope: keyword.operator.assignment.c++ - match: '\b(appdomain|deprecated|dllimport|dllexport|jintrinsic|naked|noalias|noinline|noreturn|nothrow|novtable|process|restrict|safebuffers|selectany|thread)\b' scope: constant.other.c++ types-parens: - match: '\b(decltype)\b\s*(\()' captures: 1: storage.type.c++ 2: meta.group.c++ punctuation.section.group.begin.c++ push: - meta_content_scope: meta.group.c++ - match: '\)' scope: meta.group.c++ punctuation.section.group.end.c++ pop: true - include: expressions keywords-angle-brackets: - match: \b({{casts}})\b\s* scope: keyword.operator.word.cast.c++ push: - match: '>' scope: punctuation.section.generic.end.c++ pop: true - match: '<' scope: punctuation.section.generic.begin.c++ push: - match: '(?=>)' pop: true - include: expressions-minus-generic-type-function-call keywords-parens: - match: '\b(alignof|typeid|static_assert|sizeof)\b\s*(\()' captures: 1: keyword.operator.word.c++ 2: meta.group.c++ punctuation.section.group.begin.c++ push: - meta_content_scope: meta.group.c++ - match: '\)' scope: meta.group.c++ punctuation.section.group.end.c++ pop: true - include: expressions namespace: - match: '\b(using)\s+(namespace)\s+(?={{path_lookahead}})' captures: 1: keyword.control.c++ 2: keyword.control.c++ push: - include: identifiers - match: '' pop: true - match: '\b(namespace)\s+(?=({{path_lookahead}})?(?!\s*[;,]))' scope: meta.namespace.c++ captures: 1: keyword.control.c++ push: - meta_content_scope: meta.namespace.c++ entity.name.namespace.c++ - include: identifiers - match: '' set: - meta_scope: meta.namespace.c++ - include: comments - match: '=' scope: keyword.operator.alias.c++ - match: '(?=;)' pop: true - match: '\}' scope: meta.block.c++ punctuation.section.block.end.c++ pop: true - match: '\{' scope: punctuation.section.block.begin.c++ push: - meta_scope: meta.block.c++ - match: '(?=\})' pop: true - include: preprocessor-global - include: global - include: expressions template-common: # Exit the template scope if we hit some basic invalid characters. This # helps when a user is in the middle of typing their template types and # prevents re-highlighting the whole file until the next > is found. - match: (?=[{};]) pop: true - include: expressions template: - match: \btemplate\b scope: storage.type.template.c++ push: - meta_scope: meta.template.c++ # Explicitly include comments here at the top, in order to NOT match the # \S lookahead in the case of comments. - include: comments - match: < scope: punctuation.section.generic.begin.c++ set: - meta_content_scope: meta.template.c++ - match: '>' scope: meta.template.c++ punctuation.section.generic.end.c++ pop: true - match: \.{3} scope: keyword.operator.variadic.c++ - match: \b(typename|{{before_tag}})\b scope: storage.type.c++ - include: template # include template here for nested templates - include: template-common - match: (?=\S) set: - meta_content_scope: meta.template.c++ - match: \b({{before_tag}})\b scope: storage.type.c++ - include: template-common generic-type: - match: '(?=(?!template){{path_lookahead}}\s*{{generic_lookahead}}\s*\()' push: - meta_scope: meta.function-call.c++ - match: \btemplate\b scope: storage.type.template.c++ - match: '(?:(::)\s*)?{{identifier}}\s*(::)\s*' captures: 1: punctuation.accessor.double-colon.c++ 2: punctuation.accessor.double-colon.c++ - match: (?:(::)\s*)?({{identifier}})\s*(<) captures: 1: punctuation.accessor.double-colon.c++ 2: variable.function.c++ 3: punctuation.section.generic.begin.c++ push: - match: '>' scope: punctuation.section.generic.end.c++ pop: true - include: expressions-minus-generic-type-function-call - match: (?:(::)\s*)?({{identifier}})\s*(\() captures: 1: punctuation.accessor.double-colon.c++ 2: variable.function.c++ 3: punctuation.section.group.begin.c++ set: - meta_scope: meta.function-call.c++ - meta_content_scope: meta.group.c++ - match: '\)' scope: meta.group.c++ punctuation.section.group.end.c++ pop: true - include: expressions - include: angle-brackets - match: '\(' scope: meta.group.c++ punctuation.section.group.begin.c++ set: - meta_scope: meta.function-call.c++ - meta_content_scope: meta.group.c++ - match: '\)' scope: meta.group.c++ punctuation.section.group.end.c++ pop: true - include: expressions - match: '(?=(?!template){{path_lookahead}}\s*{{generic_lookahead}})' push: - include: identifiers - match: '<' scope: punctuation.section.generic.begin.c++ set: - match: '>' scope: punctuation.section.generic.end.c++ pop: true - include: expressions-minus-generic-type-function-call angle-brackets: - match: '<(?!<)' scope: punctuation.section.generic.begin.c++ push: - match: '>' scope: punctuation.section.generic.end.c++ pop: true - include: expressions-minus-generic-type-function-call block: - match: '\{' scope: punctuation.section.block.begin.c++ push: - meta_scope: meta.block.c++ - match: (?=^\s*#\s*(elif|else|endif)\b) pop: true - match: '\}' scope: punctuation.section.block.end.c++ pop: true - include: statements function-call: - match: (?={{path_lookahead}}\s*\() push: - meta_scope: meta.function-call.c++ - include: scope:source.c#c99 - match: '(?:(::)\s*)?{{identifier}}\s*(::)\s*' scope: variable.function.c++ captures: 1: punctuation.accessor.c++ 2: punctuation.accessor.c++ - match: '(?:(::)\s*)?{{identifier}}' scope: variable.function.c++ captures: 1: punctuation.accessor.c++ - match: '\(' scope: meta.group.c++ punctuation.section.group.begin.c++ set: - meta_content_scope: meta.function-call.c++ meta.group.c++ - match: '\)' scope: meta.function-call.c++ meta.group.c++ punctuation.section.group.end.c++ pop: true - include: expressions members-inside-function-call: - meta_content_scope: meta.method-call.c++ meta.group.c++ - match: \) scope: meta.method-call.c++ meta.group.c++ punctuation.section.group.end.c++ pop: true - include: expressions members-after-accessor-junction: # After we've seen an accessor (dot or arrow), this context decides what # kind of entity we're accessing. - include: comments - match: \btemplate\b scope: meta.method-call.c++ storage.type.template.c++ # Guaranteed to be a template member function call after we match this set: - meta_content_scope: meta.method-call.c++ - include: comments - match: '{{identifier}}' scope: variable.function.member.c++ set: - meta_content_scope: meta.method-call.c++ - match: \( scope: meta.group.c++ punctuation.section.group.begin.c++ set: members-inside-function-call - include: comments - include: angle-brackets - match: (?=\S) # safety pop pop: true - match: (?=\S) # safety pop pop: true # Operator overloading - match: '({{operator_method_name}})\s*(\()' captures: 0: meta.method-call.c++ 1: variable.function.member.c++ 2: meta.group.c++ punctuation.section.group.begin.c++ set: members-inside-function-call # Non-templated member function call - match: (~?{{identifier}})\s*(\() captures: 0: meta.method-call.c++ 1: variable.function.member.c++ 2: meta.group.c++ punctuation.section.group.begin.c++ set: members-inside-function-call # Templated member function call - match: (~?{{identifier}})\s*(?={{generic_lookahead}}) captures: 1: variable.function.member.c++ set: - meta_scope: meta.method-call.c++ - match: < scope: punctuation.section.generic.begin.c++ set: - meta_content_scope: meta.method-call.c++ - match: '>' scope: punctuation.section.generic.end.c++ set: - meta_content_scope: meta.method-call.c++ - include: comments - match: \( scope: punctuation.section.group.begin.c++ set: members-inside-function-call - match: (?=\S) # safety pop pop: true - include: expressions # Explicit base-class access - match: ({{identifier}})\s*(::) captures: 1: variable.other.base-class.c++ 2: punctuation.accessor.double-colon.c++ set: members-after-accessor-junction # reset # Just a regular member variable - match: '{{identifier}}' scope: variable.other.readwrite.member.c++ pop: true members-dot: - include: scope:source.c#access-illegal # No lookahead required because members-dot goes after operators in the # early-expressions-after-generic-type context. This means triple dots # (i.e. "..." or "variadic") is attempted first. - match: \. scope: punctuation.accessor.dot.c++ push: members-after-accessor-junction members-arrow: # This needs to be before operators in the # early-expressions-after-generic-type context because otherwise the "->" # from the C language will match. - match: -> scope: punctuation.accessor.arrow.c++ push: members-after-accessor-junction typedef: - match: \btypedef\b scope: storage.type.c++ push: - match: ({{identifier}})?\s*(?=;) captures: 1: entity.name.type.typedef.c++ pop: true - match: \b(struct)\s+({{identifier}})\b captures: 1: storage.type.c++ - include: expressions-minus-generic-type parens: - match: \( scope: punctuation.section.group.begin.c++ push: - meta_scope: meta.group.c++ - match: \) scope: punctuation.section.group.end.c++ pop: true - include: expressions brackets: - match: \[ scope: punctuation.section.brackets.begin.c++ push: - meta_scope: meta.brackets.c++ - match: \] scope: punctuation.section.brackets.end.c++ pop: true - include: expressions function-trailing-return-type: - match: '{{non_angle_brackets}}' pop: true - include: angle-brackets - include: types - include: modifiers-parens - include: modifiers - include: identifiers - match: \*|& scope: keyword.operator.c++ - include: function-trailing-return-type-parens - match: '(?=\S)' pop: true function-trailing-return-type-parens: - match: \( scope: punctuation.section.group.begin.c++ push: - meta_scope: meta.group.c++ - match: \) scope: punctuation.section.group.end.c++ pop: true - include: function-trailing-return-type ## Detection of function and data structure definitions at the global level global-modifier: - include: comments - include: modifiers-parens - include: modifiers # Constructors and destructors don't have a type - match: '(?={{path_lookahead}}\s*::\s*{{identifier}}\s*(\(|$))' set: - meta_content_scope: meta.function.c++ entity.name.function.constructor.c++ - include: identifiers - match: '(?=[^\w\s])' set: function-definition-params - match: '(?={{path_lookahead}}\s*::\s*~{{identifier}}\s*(\(|$))' set: - meta_content_scope: meta.function.c++ entity.name.function.destructor.c++ - include: identifiers - match: '~{{identifier}}' - match: '(?=[^\w\s])' set: function-definition-params # If we see a path ending in :: before a newline, we don't know if it is # a constructor or destructor, or a long return type, so we are just going # to treat it like a regular function. Most likely it is a constructor, # since it doesn't seem most developers would create such a long typename. - match: '(?={{path_lookahead}}\s*::\s*$)' set: - meta_content_scope: meta.function.c++ entity.name.function.c++ - include: identifiers - match: '~{{identifier}}' - match: '(?=[^\w\s])' set: function-definition-params - include: unique-strings - match: '(?=\S)' set: global-type global-type: - include: comments - match: \*|& scope: keyword.operator.c++ - match: '(?=\b({{control_keywords}}|{{operator_keywords}}|{{casts}}|{{memory_operators}}|{{other_keywords}}|operator)\b)' pop: true - match: '(?=\s)' set: global-maybe-function # If a class/struct/enum followed by a name that is not a macro or declspec # then this is likely a return type of a function. This is uncommon. - match: |- (?x: ({{before_tag}}) \s+ (?= (?![[:upper:][:digit:]_]+\b|__declspec|{{before_tag}}) {{path_lookahead}} (\s+{{identifier}}\s*\(|\s*[*&]) ) ) captures: 1: storage.type.c++ set: - include: identifiers - match: '' set: global-maybe-function # The previous match handles return types of struct/enum/etc from a func, # there this one exits the context to allow matching an actual struct/class - match: '(?=\b({{before_tag}})\b)' set: data-structures - match: '(?=\b({{casts}})\b\s*<)' pop: true - match: '{{non_angle_brackets}}' pop: true - include: angle-brackets - include: types # Allow a macro call - match: '({{identifier}})\s*(\()(?=[^\)]+\))' captures: 1: variable.function.c++ 2: meta.group.c++ punctuation.section.group.begin.c++ push: - meta_scope: meta.function-call.c++ - meta_content_scope: meta.group.c++ - match: '\)' scope: meta.group.c++ punctuation.section.group.end.c++ pop: true - include: expressions - match: '(?={{path_lookahead}}\s*\()' set: - include: function-call - match: '' pop: true - include: variables - include: constants - include: identifiers - match: (?=\W) pop: true global-maybe-function: - include: comments # Consume pointer info, macros and any type info that was offset by macros - match: \*|& scope: keyword.operator.c++ - match: '(?=\b({{control_keywords}}|{{operator_keywords}}|{{casts}}|{{memory_operators}}|{{other_keywords}})\b)' pop: true - match: '\b({{type_qualifier}})\b' scope: storage.modifier.c++ - match: '{{non_angle_brackets}}' pop: true - include: angle-brackets - include: types - include: modifiers-parens - include: modifiers # All uppercase identifier just before a newline is most likely a macro - match: '[[:upper:][:digit:]_]+\s*$' # Operator overloading - match: '(?=({{path_lookahead}}\s*(?:{{generic_lookahead}})?::\s*)?{{operator_method_name}}\s*(\(|$))' set: - meta_content_scope: meta.function.c++ entity.name.function.c++ - include: identifiers - match: '(?=\s*(\(|$))' set: function-definition-params # Identifier that is not the function name - likely a macro or type - match: '(?={{path_lookahead}}([ \t]+|[*&])(?!\s*(<|::|\(|$)))' push: - include: identifiers - match: '' pop: true # Real function definition - match: '(?={{path_lookahead}}({{generic_lookahead}}({{path_lookahead}})?)\s*(\(|$))' set: [function-definition-params, global-function-identifier-generic] - match: '(?={{path_lookahead}}\s*(\(|$))' set: [function-definition-params, global-function-identifier] - match: '(?={{path_lookahead}}\s*::\s*$)' set: [function-definition-params, global-function-identifier] - match: '(?=\S)' pop: true global-function-identifier-generic: - include: angle-brackets - match: '::' scope: punctuation.accessor.c++ - match: '(?={{identifier}}<.*>\s*\()' push: - meta_content_scope: entity.name.function.c++ - include: identifiers - match: '(?=<)' pop: true - match: '(?={{identifier}}\s*\()' push: - meta_content_scope: entity.name.function.c++ - include: identifiers - match: '' pop: true - match: '(?=\()' pop: true global-function-identifier: - meta_content_scope: entity.name.function.c++ - include: identifiers - match: '(?=\S)' pop: true function-definition-params: - meta_content_scope: meta.function.c++ - include: comments - match: '(?=\()' set: - match: \( scope: meta.function.parameters.c++ meta.group.c++ punctuation.section.group.begin.c++ set: - meta_content_scope: meta.function.parameters.c++ meta.group.c++ - match : \) scope: punctuation.section.group.end.c++ set: function-definition-continue - match: '\bvoid\b' scope: storage.type.c++ - match: '{{identifier}}(?=\s*(\[|,|\)|=))' scope: variable.parameter.c++ - match: '=' scope: keyword.operator.assignment.c++ push: - match: '(?=,|\))' pop: true - include: expressions-minus-generic-type - include: scope:source.c#preprocessor-line-continuation - include: expressions-minus-generic-type - include: scope:source.c#preprocessor-line-continuation - match: (?=\S) pop: true function-definition-continue: - meta_content_scope: meta.function.c++ - include: comments - match: '(?=;)' pop: true - match: '->' scope: punctuation.separator.c++ set: function-definition-trailing-return - include: function-specifiers - match: '=' scope: keyword.operator.assignment.c++ - match: '&' scope: keyword.operator.c++ - match: \b0\b scope: constant.numeric.c++ - match: \b(default|delete)\b scope: storage.modifier.c++ - match: '(?=\{)' set: function-definition-body - match: '(?=\S)' pop: true function-definition-trailing-return: - include: comments - match: '(?=;)' pop: true - match: '(?=\{)' set: function-definition-body - include: function-specifiers - include: function-trailing-return-type function-definition-body: - meta_content_scope: meta.function.c++ meta.block.c++ - match: '\{' scope: punctuation.section.block.begin.c++ set: - meta_content_scope: meta.function.c++ meta.block.c++ - match: '\}' scope: meta.function.c++ meta.block.c++ punctuation.section.block.end.c++ pop: true - match: (?=^\s*#\s*(elif|else|endif)\b) pop: true - match: '(?=({{before_tag}})([^(;]+$|.*\{))' push: data-structures - include: statements ## Data structures including classes, structs, unions and enums data-structures: - match: '\bclass\b' scope: storage.type.c++ set: data-structures-class-definition # Detect variable type definitions using struct/enum/union followed by a tag - match: '\b({{before_tag}})(?=\s+{{path_lookahead}}\s+{{path_lookahead}}\s*[=;\[])' scope: storage.type.c++ - match: '\bstruct\b' scope: storage.type.c++ set: data-structures-struct-definition - match: '\benum(\s+(class|struct))?\b' scope: storage.type.c++ set: data-structures-enum-definition - match: '\bunion\b' scope: storage.type.c++ set: data-structures-union-definition - match: '(?=\S)' pop: true preprocessor-workaround-eat-macro-before-identifier: # Handle macros so they aren't matched as the class name - match: ({{macro_identifier}})(?=\s+~?{{identifier}}) captures: 1: meta.assumed-macro.c data-structures-class-definition: - meta_scope: meta.class.c++ - include: data-structures-definition-common-begin - match: '{{identifier}}(?={{data_structures_forward_decl_lookahead}})' scope: entity.name.class.forward-decl.c++ set: data-structures-class-definition-after-identifier - match: '{{identifier}}' scope: entity.name.class.c++ set: data-structures-class-definition-after-identifier - match: '(?=[:{])' set: data-structures-class-definition-after-identifier - match: '(?=;)' pop: true data-structures-class-definition-after-identifier: - meta_content_scope: meta.class.c++ - include: data-structures-definition-common-begin # No matching of identifiers since they should all be macros at this point - include: data-structures-definition-common-end - match: '\{' scope: meta.block.c++ punctuation.section.block.begin.c++ set: - meta_content_scope: meta.class.c++ meta.block.c++ - match: '\}' scope: meta.class.c++ meta.block.c++ punctuation.section.block.end.c++ pop: true - include: data-structures-body data-structures-struct-definition: - meta_scope: meta.struct.c++ - include: data-structures-definition-common-begin - match: '{{identifier}}(?={{data_structures_forward_decl_lookahead}})' scope: entity.name.struct.forward-decl.c++ set: data-structures-struct-definition-after-identifier - match: '{{identifier}}' scope: entity.name.struct.c++ set: data-structures-struct-definition-after-identifier - match: '(?=[:{])' set: data-structures-struct-definition-after-identifier - match: '(?=;)' pop: true data-structures-struct-definition-after-identifier: - meta_content_scope: meta.struct.c++ - include: data-structures-definition-common-begin # No matching of identifiers since they should all be macros at this point - include: data-structures-definition-common-end - match: '\{' scope: meta.block.c++ punctuation.section.block.begin.c++ set: - meta_content_scope: meta.struct.c++ meta.block.c++ - match: '\}' scope: meta.struct.c++ meta.block.c++ punctuation.section.block.end.c++ pop: true - include: data-structures-body data-structures-enum-definition: - meta_scope: meta.enum.c++ - include: data-structures-definition-common-begin - match: '{{identifier}}(?={{data_structures_forward_decl_lookahead}})' scope: entity.name.enum.forward-decl.c++ set: data-structures-enum-definition-after-identifier - match: '{{identifier}}' scope: entity.name.enum.c++ set: data-structures-enum-definition-after-identifier - match: '(?=[:{])' set: data-structures-enum-definition-after-identifier - match: '(?=;)' pop: true data-structures-enum-definition-after-identifier: - meta_content_scope: meta.enum.c++ - include: data-structures-definition-common-begin # No matching of identifiers since they should all be macros at this point - include: data-structures-definition-common-end - match: '\{' scope: meta.block.c++ punctuation.section.block.begin.c++ set: - meta_content_scope: meta.enum.c++ meta.block.c++ # Enums don't support methods so we have a simplified body - match: '\}' scope: meta.enum.c++ meta.block.c++ punctuation.section.block.end.c++ pop: true - include: statements data-structures-union-definition: - meta_scope: meta.union.c++ - include: data-structures-definition-common-begin - match: '{{identifier}}(?={{data_structures_forward_decl_lookahead}})' scope: entity.name.union.forward-decl.c++ set: data-structures-union-definition-after-identifier - match: '{{identifier}}' scope: entity.name.union.c++ set: data-structures-union-definition-after-identifier - match: '(?=[{])' set: data-structures-union-definition-after-identifier - match: '(?=;)' pop: true data-structures-union-definition-after-identifier: - meta_content_scope: meta.union.c++ - include: data-structures-definition-common-begin # No matching of identifiers since they should all be macros at this point # Unions don't support base classes - include: angle-brackets - match: '\{' scope: meta.block.c++ punctuation.section.block.begin.c++ set: - meta_content_scope: meta.union.c++ meta.block.c++ - match: '\}' scope: meta.union.c++ meta.block.c++ punctuation.section.block.end.c++ pop: true - include: data-structures-body - match: '(?=;)' pop: true data-structures-definition-common-begin: - include: comments - match: '(?=\b(?:{{before_tag}}|{{control_keywords}})\b)' pop: true - include: preprocessor-other - include: modifiers-parens - include: modifiers - include: preprocessor-workaround-eat-macro-before-identifier data-structures-definition-common-end: - include: angle-brackets - match: \bfinal\b scope: storage.modifier.c++ - match: ':' scope: punctuation.separator.c++ push: - include: comments - include: preprocessor-other - include: modifiers-parens - include: modifiers - match: '\b(virtual|{{visibility_modifiers}})\b' scope: storage.modifier.c++ - match: (?={{path_lookahead}}) push: - meta_scope: entity.other.inherited-class.c++ - include: identifiers - match: '' pop: true - include: angle-brackets - match: ',' scope: punctuation.separator.c++ - match: (?=\{|;) pop: true - match: '(?=;)' pop: true data-structures-body: - include: preprocessor-data-structures - match: '(?=\btemplate\b)' push: - include: template - match: (?=\S) set: data-structures-modifier - include: typedef - match: \b({{visibility_modifiers}})\s*(:)(?!:) captures: 1: storage.modifier.c++ 2: punctuation.section.class.c++ - match: '^\s*(?=(?:~?\w+|::))' push: data-structures-modifier - include: expressions-minus-generic-type data-structures-modifier: - match: '\bfriend\b' scope: storage.modifier.c++ push: - match: (?=;) pop: true - match: '\{' scope: punctuation.section.block.begin.c++ set: - meta_scope: meta.block.c++ - match: '\}' scope: punctuation.section.block.end.c++ pop: true - include: statements - match: '\b({{before_tag}})\b' scope: storage.type.c++ - include: expressions-minus-function-call - include: comments - include: modifiers-parens - include: modifiers - match: '\bstatic_assert(?=\s*\()' scope: meta.static-assert.c++ keyword.operator.word.c++ push: - match: '\(' scope: meta.group.c++ punctuation.section.group.begin.c++ set: - meta_content_scope: meta.function-call.c++ meta.group.c++ - match: '\)' scope: meta.function-call.c++ meta.group.c++ punctuation.section.group.end.c++ pop: true - include: expressions # Destructor - match: '(?:{{identifier}}\s*(::)\s*)?~{{identifier}}(?=\s*(\(|$))' scope: meta.method.destructor.c++ entity.name.function.destructor.c++ captures: 1: punctuation.accessor.c++ set: method-definition-params # It's a macro, not a constructor if there is no type in the first param - match: '({{identifier}})\s*(\()(?=\s*(?!void){{identifier}}\s*[),])' captures: 1: variable.function.c++ 2: meta.group.c++ punctuation.section.group.begin.c++ push: - meta_scope: meta.function-call.c++ - meta_content_scope: meta.group.c++ - match: '\)' scope: meta.group.c++ punctuation.section.group.end.c++ pop: true - include: expressions # Constructor - include: preprocessor-workaround-eat-macro-before-identifier - match: '((?!{{before_tag}}|template){{identifier}})(?=\s*\()' scope: meta.method.constructor.c++ entity.name.function.constructor.c++ set: method-definition-params # Long form constructor - match: '({{identifier}}\s*(::)\s*{{identifier}})(?=\s*\()' captures: 1: meta.method.constructor.c++ entity.name.function.constructor.c++ 2: punctuation.accessor.c++ push: method-definition-params - match: '(?=\S)' set: data-structures-type data-structures-type: - include: comments - match: \*|& scope: keyword.operator.c++ # Cast methods - match: '(operator)\s+({{identifier}})(?=\s*(\(|$))' captures: 1: keyword.control.c++ 2: meta.method.c++ entity.name.function.c++ set: method-definition-params - match: '(?=\b({{control_keywords}}|{{operator_keywords}}|{{casts}}|{{memory_operators}}|{{other_keywords}}|operator)\b)' pop: true - match: '(?=\s)' set: data-structures-maybe-method # If a class/struct/enum followed by a name that is not a macro or declspec # then this is likely a return type of a function. This is uncommon. - match: |- (?x: ({{before_tag}}) \s+ (?= (?![[:upper:][:digit:]_]+\b|__declspec|{{before_tag}}) {{path_lookahead}} (\s+{{identifier}}\s*\(|\s*[*&]) ) ) captures: 1: storage.type.c++ set: - include: identifiers - match: '' set: data-structures-maybe-method # The previous match handles return types of struct/enum/etc from a func, # there this one exits the context to allow matching an actual struct/class - match: '(?=\b({{before_tag}})\b)' set: data-structures - match: '(?=\b({{casts}})\b\s*<)' pop: true - match: '{{non_angle_brackets}}' pop: true - include: angle-brackets - include: types - include: variables - include: constants - include: identifiers - match: (?=[&*]) set: data-structures-maybe-method - match: (?=\W) pop: true data-structures-maybe-method: - include: comments # Consume pointer info, macros and any type info that was offset by macros - match: \*|& scope: keyword.operator.c++ - match: '(?=\b({{control_keywords}}|{{operator_keywords}}|{{casts}}|{{memory_operators}}|{{other_keywords}})\b)' pop: true - match: '\b({{type_qualifier}})\b' scope: storage.modifier.c++ - match: '{{non_angle_brackets}}' pop: true - include: angle-brackets - include: types - include: modifiers-parens - include: modifiers # Operator overloading - match: '{{operator_method_name}}(?=\s*(\(|$))' scope: meta.method.c++ entity.name.function.c++ set: method-definition-params # Identifier that is not the function name - likely a macro or type - match: '(?={{path_lookahead}}([ \t]+|[*&])(?!\s*(<|::|\()))' push: - include: identifiers - match: '' pop: true # Real function definition - match: '(?={{path_lookahead}}({{generic_lookahead}})\s*(\())' set: [method-definition-params, data-structures-function-identifier-generic] - match: '(?={{path_lookahead}}\s*(\())' set: [method-definition-params, data-structures-function-identifier] - match: '(?={{path_lookahead}}\s*::\s*$)' set: [method-definition-params, data-structures-function-identifier] - match: '(?=\S)' pop: true data-structures-function-identifier-generic: - include: angle-brackets - match: '(?={{identifier}})' push: - meta_content_scope: entity.name.function.c++ - include: identifiers - match: '(?=<)' pop: true - match: '(?=\()' pop: true data-structures-function-identifier: - meta_content_scope: entity.name.function.c++ - include: identifiers - match: '(?=\S)' pop: true method-definition-params: - meta_content_scope: meta.method.c++ - include: comments - match: '(?=\()' set: - match: \( scope: meta.method.parameters.c++ meta.group.c++ punctuation.section.group.begin.c++ set: - meta_content_scope: meta.method.parameters.c++ meta.group.c++ - match : \) scope: punctuation.section.group.end.c++ set: method-definition-continue - match: '\bvoid\b' scope: storage.type.c++ - match: '{{identifier}}(?=\s*(\[|,|\)|=))' scope: variable.parameter.c++ - match: '=' scope: keyword.operator.assignment.c++ push: - match: '(?=,|\))' pop: true - include: expressions-minus-generic-type - include: expressions-minus-generic-type - match: '(?=\S)' pop: true method-definition-continue: - meta_content_scope: meta.method.c++ - include: comments - match: '(?=;)' pop: true - match: '->' scope: punctuation.separator.c++ set: method-definition-trailing-return - include: function-specifiers - match: '=' scope: keyword.operator.assignment.c++ - match: '&' scope: keyword.operator.c++ - match: \b0\b scope: constant.numeric.c++ - match: \b(default|delete)\b scope: storage.modifier.c++ - match: '(?=:)' set: - match: ':' scope: punctuation.separator.initializer-list.c++ set: - meta_scope: meta.method.constructor.initializer-list.c++ - match: '{{identifier}}' scope: variable.other.readwrite.member.c++ push: - match: \( scope: meta.group.c++ punctuation.section.group.begin.c++ set: - meta_content_scope: meta.group.c++ - match: \) scope: meta.group.c++ punctuation.section.group.end.c++ pop: true - include: expressions - match: \{ scope: meta.group.c++ punctuation.section.group.begin.c++ set: - meta_content_scope: meta.group.c++ - match: \} scope: meta.group.c++ punctuation.section.group.end.c++ pop: true - include: expressions - include: comments - match: (?=\{|;) set: method-definition-continue - include: expressions - match: '(?=\{)' set: method-definition-body - match: '(?=\S)' pop: true method-definition-trailing-return: - include: comments - match: '(?=;)' pop: true - match: '(?=\{)' set: method-definition-body - include: function-specifiers - include: function-trailing-return-type method-definition-body: - meta_content_scope: meta.method.c++ meta.block.c++ - match: '\{' scope: punctuation.section.block.begin.c++ set: - meta_content_scope: meta.method.c++ meta.block.c++ - match: '\}' scope: meta.method.c++ meta.block.c++ punctuation.section.block.end.c++ pop: true - match: (?=^\s*#\s*(elif|else|endif)\b) pop: true - match: '(?=({{before_tag}})([^(;]+$|.*\{))' push: data-structures - include: statements ## Preprocessor for data-structures preprocessor-data-structures: - include: preprocessor-rule-enabled-data-structures - include: preprocessor-rule-disabled-data-structures - include: preprocessor-practical-workarounds preprocessor-rule-disabled-data-structures: - match: ^\s*((#if)\s+(0))\b captures: 1: meta.preprocessor.c++ 2: keyword.control.import.c++ 3: constant.numeric.preprocessor.c++ push: - match: ^\s*(#\s*endif)\b captures: 1: meta.preprocessor.c++ keyword.control.import.c++ pop: true - match: ^\s*(#\s*else)\b captures: 1: meta.preprocessor.c++ keyword.control.import.else.c++ push: - match: (?=^\s*#\s*endif\b) pop: true - include: negated-block - include: data-structures-body - match: "" push: - meta_scope: comment.block.preprocessor.if-branch.c++ - match: (?=^\s*#\s*(else|endif)\b) pop: true - include: scope:source.c#preprocessor-disabled preprocessor-rule-enabled-data-structures: - match: ^\s*((#if)\s+(0*1))\b captures: 1: meta.preprocessor.c++ 2: keyword.control.import.c++ 3: constant.numeric.preprocessor.c++ push: - match: ^\s*(#\s*endif)\b captures: 1: meta.preprocessor.c++ keyword.control.import.c++ pop: true - match: ^\s*(#\s*else)\b captures: 1: meta.preprocessor.c++ keyword.control.import.else.c++ push: - meta_content_scope: comment.block.preprocessor.else-branch.c++ - match: (?=^\s*#\s*endif\b) pop: true - include: scope:source.c#preprocessor-disabled - match: "" push: - match: (?=^\s*#\s*(else|endif)\b) pop: true - include: negated-block - include: data-structures-body ## Preprocessor for global preprocessor-global: - include: preprocessor-rule-enabled-global - include: preprocessor-rule-disabled-global - include: preprocessor-rule-other-global preprocessor-statements: - include: preprocessor-rule-enabled-statements - include: preprocessor-rule-disabled-statements - include: preprocessor-rule-other-statements preprocessor-expressions: - include: scope:source.c#incomplete-inc - include: preprocessor-macro-define - include: scope:source.c#pragma-mark - include: preprocessor-other preprocessor-rule-disabled-global: - match: ^\s*((#if)\s+(0))\b captures: 1: meta.preprocessor.c++ 2: keyword.control.import.c++ 3: constant.numeric.preprocessor.c++ push: - match: ^\s*(#\s*endif)\b captures: 1: meta.preprocessor.c++ keyword.control.import.c++ pop: true - match: ^\s*(#\s*else)\b captures: 1: meta.preprocessor.c++ keyword.control.import.else.c++ push: - match: (?=^\s*#\s*endif\b) pop: true - include: preprocessor-global - include: negated-block - include: global - match: "" push: - meta_scope: comment.block.preprocessor.if-branch.c++ - match: (?=^\s*#\s*(else|endif)\b) pop: true - include: scope:source.c#preprocessor-disabled preprocessor-rule-enabled-global: - match: ^\s*((#if)\s+(0*1))\b captures: 1: meta.preprocessor.c++ 2: keyword.control.import.c++ 3: constant.numeric.preprocessor.c++ push: - match: ^\s*(#\s*endif)\b captures: 1: meta.preprocessor.c++ keyword.control.import.c++ pop: true - match: ^\s*(#\s*else)\b captures: 1: meta.preprocessor.c++ keyword.control.import.else.c++ push: - meta_content_scope: comment.block.preprocessor.else-branch.c++ - match: (?=^\s*#\s*endif\b) pop: true - include: scope:source.c#preprocessor-disabled - match: "" push: - match: (?=^\s*#\s*(else|endif)\b) pop: true - include: preprocessor-global - include: negated-block - include: global preprocessor-rule-other-global: - match: ^\s*(#\s*(?:if|ifdef|ifndef))\b captures: 1: keyword.control.import.c++ push: - meta_scope: meta.preprocessor.c++ - include: scope:source.c#preprocessor-line-continuation - include: scope:source.c#preprocessor-comments - match: \bdefined\b scope: keyword.control.c++ # Enter a new scope where all elif/else branches have their # contexts popped by a subsequent elif/else/endif. This ensures that # preprocessor branches don't push multiple meta.block scopes on # the stack, thus messing up the "global" context's detection of # functions. - match: $\n set: preprocessor-if-branch-global # These gymnastics here ensure that we are properly handling scope even # when the preprocessor is used to create different scope beginnings, such # as a different if/while condition preprocessor-if-branch-global: - match: ^\s*(#\s*endif)\b captures: 1: meta.preprocessor.c++ keyword.control.import.c++ pop: true - match: (?=^\s*#\s*(elif|else)\b) push: preprocessor-elif-else-branch-global - match: \{ scope: punctuation.section.block.begin.c++ set: preprocessor-block-if-branch-global - include: preprocessor-global - include: negated-block - include: global preprocessor-block-if-branch-global: - meta_scope: meta.block.c++ - match: ^\s*(#\s*endif)\b captures: 1: meta.preprocessor.c++ keyword.control.import.c++ set: preprocessor-block-finish-global - match: (?=^\s*#\s*(elif|else)\b) push: preprocessor-elif-else-branch-global - match: \} scope: punctuation.section.block.end.c++ set: preprocessor-if-branch-global - include: statements preprocessor-block-finish-global: - meta_scope: meta.block.c++ - match: ^\s*(#\s*(?:if|ifdef|ifndef))\b captures: 1: meta.preprocessor.c++ keyword.control.import.c++ set: preprocessor-block-finish-if-branch-global - match: \} scope: punctuation.section.block.end.c++ pop: true - include: statements preprocessor-block-finish-if-branch-global: - match: ^\s*(#\s*endif)\b captures: 1: keyword.control.import.c++ pop: true - match: \} scope: punctuation.section.block.end.c++ set: preprocessor-if-branch-global - include: statements preprocessor-elif-else-branch-global: - match: (?=^\s*#\s*(endif)\b) pop: true - include: preprocessor-global - include: negated-block - include: global ## Preprocessor for statements preprocessor-rule-disabled-statements: - match: ^\s*((#if)\s+(0))\b captures: 1: meta.preprocessor.c++ 2: keyword.control.import.c++ 3: constant.numeric.preprocessor.c++ push: - match: ^\s*(#\s*endif)\b captures: 1: meta.preprocessor.c++ keyword.control.import.c++ pop: true - match: ^\s*(#\s*else)\b captures: 1: meta.preprocessor.c++ keyword.control.import.else.c++ push: - match: (?=^\s*#\s*endif\b) pop: true - include: negated-block - include: statements - match: "" push: - meta_scope: comment.block.preprocessor.if-branch.c++ - match: (?=^\s*#\s*(else|endif)\b) pop: true - include: scope:source.c#preprocessor-disabled preprocessor-rule-enabled-statements: - match: ^\s*((#if)\s+(0*1))\b captures: 1: meta.preprocessor.c++ 2: keyword.control.import.c++ 3: constant.numeric.preprocessor.c++ push: - match: ^\s*(#\s*endif)\b captures: 1: meta.preprocessor.c++ keyword.control.import.c++ pop: true - match: ^\s*(#\s*else)\b captures: 1: meta.preprocessor.c++ keyword.control.import.else.c++ push: - meta_content_scope: comment.block.preprocessor.else-branch.c++ - match: (?=^\s*#\s*endif\b) pop: true - include: scope:source.c#preprocessor-disabled - match: "" push: - match: (?=^\s*#\s*(else|endif)\b) pop: true - include: negated-block - include: statements preprocessor-rule-other-statements: - match: ^\s*(#\s*(?:if|ifdef|ifndef))\b captures: 1: keyword.control.import.c++ push: - meta_scope: meta.preprocessor.c++ - include: scope:source.c#preprocessor-line-continuation - include: scope:source.c#preprocessor-comments - match: \bdefined\b scope: keyword.control.c++ # Enter a new scope where all elif/else branches have their # contexts popped by a subsequent elif/else/endif. This ensures that # preprocessor branches don't push multiple meta.block scopes on # the stack, thus messing up the "global" context's detection of # functions. - match: $\n set: preprocessor-if-branch-statements # These gymnastics here ensure that we are properly handling scope even # when the preprocessor is used to create different scope beginnings, such # as a different if/while condition preprocessor-if-branch-statements: - match: ^\s*(#\s*endif)\b captures: 1: meta.preprocessor.c++ keyword.control.import.c++ pop: true - match: (?=^\s*#\s*(elif|else)\b) push: preprocessor-elif-else-branch-statements - match: \{ scope: punctuation.section.block.begin.c++ set: preprocessor-block-if-branch-statements - match: (?=(?!{{non_func_keywords}}){{path_lookahead}}\s*\() set: preprocessor-if-branch-function-call - include: negated-block - include: statements preprocessor-if-branch-function-call: - meta_content_scope: meta.function-call.c++ - include: scope:source.c#c99 - match: '(?:(::)\s*)?{{identifier}}\s*(::)\s*' scope: variable.function.c++ captures: 1: punctuation.accessor.c++ 2: punctuation.accessor.c++ - match: '(?:(::)\s*)?{{identifier}}' scope: variable.function.c++ captures: 1: punctuation.accessor.c++ - match: '\(' scope: meta.group.c++ punctuation.section.group.begin.c++ set: preprocessor-if-branch-function-call-arguments preprocessor-if-branch-function-call-arguments: - meta_content_scope: meta.function-call.c++ meta.group.c++ - match : \) scope: meta.function-call.c++ meta.group.c++ punctuation.section.group.end.c++ set: preprocessor-if-branch-statements - match: ^\s*(#\s*(?:elif|else))\b captures: 1: meta.preprocessor.c++ keyword.control.import.c++ set: preprocessor-if-branch-statements - match: ^\s*(#\s*endif)\b captures: 1: meta.preprocessor.c++ keyword.control.import.c++ set: preprocessor-if-branch-function-call-arguments-finish - include: expressions preprocessor-if-branch-function-call-arguments-finish: - meta_content_scope: meta.function-call.c++ meta.group.c++ - match: \) scope: meta.function-call.c++ meta.group.c++ punctuation.section.group.end.c++ pop: true - include: expressions preprocessor-block-if-branch-statements: - meta_scope: meta.block.c++ - match: ^\s*(#\s*endif)\b captures: 1: meta.preprocessor.c++ keyword.control.import.c++ set: preprocessor-block-finish-statements - match: (?=^\s*#\s*(elif|else)\b) push: preprocessor-elif-else-branch-statements - match: \} scope: punctuation.section.block.end.c++ set: preprocessor-if-branch-statements - include: statements preprocessor-block-finish-statements: - meta_scope: meta.block.c++ - match: ^\s*(#\s*(?:if|ifdef|ifndef))\b captures: 1: meta.preprocessor.c++ keyword.control.import.c++ set: preprocessor-block-finish-if-branch-statements - match: \} scope: punctuation.section.block.end.c++ pop: true - include: statements preprocessor-block-finish-if-branch-statements: - match: ^\s*(#\s*endif)\b captures: 1: keyword.control.import.c++ pop: true - match: \} scope: meta.block.c++ punctuation.section.block.end.c++ set: preprocessor-if-branch-statements - include: statements preprocessor-elif-else-branch-statements: - match: (?=^\s*#\s*endif\b) pop: true - include: negated-block - include: statements ## Preprocessor other negated-block: - match: '\}' scope: punctuation.section.block.end.c++ push: - match: '\{' scope: punctuation.section.block.begin.c++ pop: true - match: (?=^\s*#\s*(elif|else|endif)\b) pop: true - include: statements preprocessor-macro-define: - match: ^\s*(\#\s*define)\b captures: 1: meta.preprocessor.macro.c++ keyword.control.import.define.c++ push: - meta_content_scope: meta.preprocessor.macro.c++ - include: scope:source.c#preprocessor-line-continuation - include: scope:source.c#preprocessor-line-ending - include: scope:source.c#preprocessor-comments - match: '({{identifier}})(?=\()' scope: entity.name.function.preprocessor.c++ set: - match: '\(' scope: punctuation.section.group.begin.c++ set: preprocessor-macro-params - match: '{{identifier}}' scope: entity.name.constant.preprocessor.c++ set: preprocessor-macro-definition preprocessor-macro-params: - meta_scope: meta.preprocessor.macro.parameters.c++ meta.group.c++ - match: '{{identifier}}' scope: variable.parameter.c++ - match: \) scope: punctuation.section.group.end.c++ set: preprocessor-macro-definition - match: ',' scope: punctuation.separator.c++ push: - match: '{{identifier}}' scope: variable.parameter.c++ pop: true - include: scope:source.c#preprocessor-line-continuation - include: scope:source.c#preprocessor-comments - match: '\.\.\.' scope: keyword.operator.variadic.c++ - match: '(?=\))' pop: true - match: (/\*).*(\*/) scope: comment.block.c++ captures: 1: punctuation.definition.comment.c++ 2: punctuation.definition.comment.c++ - match: '\S+' scope: invalid.illegal.unexpected-character.c++ - include: scope:source.c#preprocessor-line-continuation - include: scope:source.c#preprocessor-comments - match: '\.\.\.' scope: keyword.operator.variadic.c++ - match: (/\*).*(\*/) scope: comment.block.c++ captures: 1: punctuation.definition.comment.c++ 2: punctuation.definition.comment.c++ - match: $\n scope: invalid.illegal.unexpected-end-of-line.c++ preprocessor-macro-definition: - meta_content_scope: meta.preprocessor.macro.c++ - include: scope:source.c#preprocessor-line-continuation - include: scope:source.c#preprocessor-line-ending - include: scope:source.c#preprocessor-comments # Don't define blocks in define statements - match: '\{' scope: punctuation.section.block.begin.c++ - match: '\}' scope: punctuation.section.block.end.c++ - include: expressions preprocessor-practical-workarounds: - include: preprocessor-convention-ignore-uppercase-ident-lines - include: scope:source.c#preprocessor-convention-ignore-uppercase-calls-without-semicolon preprocessor-convention-ignore-uppercase-ident-lines: - match: ^(\s*{{macro_identifier}})+\s*$ scope: meta.assumed-macro.c++ push: # It's possible that we are dealing with a function return type on its own line, and the # name of the function is on the subsequent line. - match: '(?={{path_lookahead}}({{generic_lookahead}}({{path_lookahead}})?)\s*\()' set: [function-definition-params, global-function-identifier-generic] - match: '(?={{path_lookahead}}\s*\()' set: [function-definition-params, global-function-identifier] - match: ^ pop: true preprocessor-other: - match: ^\s*(#\s*(?:if|ifdef|ifndef|elif|else|line|pragma|undef))\b captures: 1: keyword.control.import.c++ push: - meta_scope: meta.preprocessor.c++ - include: scope:source.c#preprocessor-line-continuation - include: scope:source.c#preprocessor-line-ending - include: scope:source.c#preprocessor-comments - match: \bdefined\b scope: keyword.control.c++ - match: ^\s*(#\s*endif)\b captures: 1: meta.preprocessor.c++ keyword.control.import.c++ - match: ^\s*(#\s*(?:error|warning))\b captures: 1: keyword.control.import.error.c++ push: - meta_scope: meta.preprocessor.diagnostic.c++ - include: scope:source.c#preprocessor-line-continuation - include: scope:source.c#preprocessor-line-ending - include: scope:source.c#preprocessor-comments - include: strings - match: '\S+' scope: string.unquoted.c++ - match: ^\s*(#\s*(?:include|include_next|import))\b captures: 1: keyword.control.import.include.c++ push: - meta_scope: meta.preprocessor.include.c++ - include: scope:source.c#preprocessor-line-continuation - include: scope:source.c#preprocessor-line-ending - include: scope:source.c#preprocessor-comments - match: '"' scope: punctuation.definition.string.begin.c++ push: - meta_scope: string.quoted.double.include.c++ - match: '"' scope: punctuation.definition.string.end.c++ pop: true - match: < scope: punctuation.definition.string.begin.c++ push: - meta_scope: string.quoted.other.lt-gt.include.c++ - match: '>' scope: punctuation.definition.string.end.c++ pop: true - include: preprocessor-practical-workarounds soci-4.1.4/3rdparty/fmt/support/python/0000775000175000017500000000000015100423533017764 5ustar zeitlinzeitlinsoci-4.1.4/3rdparty/fmt/support/python/mkdocstrings_handlers/0000775000175000017500000000000015100423533024353 5ustar zeitlinzeitlinsoci-4.1.4/3rdparty/fmt/support/python/mkdocstrings_handlers/cxx/0000775000175000017500000000000015100423533025155 5ustar zeitlinzeitlinsoci-4.1.4/3rdparty/fmt/support/python/mkdocstrings_handlers/cxx/templates/0000775000175000017500000000000015100423533027153 5ustar zeitlinzeitlinsoci-4.1.4/3rdparty/fmt/support/python/mkdocstrings_handlers/cxx/templates/README0000664000175000017500000000010015100423533030022 0ustar zeitlinzeitlinmkdocsstrings requires a handler to have a templates directory. soci-4.1.4/3rdparty/fmt/support/python/mkdocstrings_handlers/cxx/__init__.py0000664000175000017500000002747315100423533027303 0ustar zeitlinzeitlin# A basic mkdocstrings handler for {fmt}. # Copyright (c) 2012 - present, Victor Zverovich # https://github.com/fmtlib/fmt/blob/master/LICENSE import os import xml.etree.ElementTree as ElementTree from pathlib import Path from subprocess import PIPE, STDOUT, CalledProcessError, Popen from typing import Any, List, Mapping, Optional from mkdocstrings.handlers.base import BaseHandler class Definition: """A definition extracted by Doxygen.""" def __init__(self, name: str, kind: Optional[str] = None, node: Optional[ElementTree.Element] = None, is_member: bool = False): self.name = name self.kind = kind if kind is not None else node.get('kind') self.desc = None self.id = name if not is_member else None self.members = None self.params = None self.template_params = None self.trailing_return_type = None self.type = None # A map from Doxygen to HTML tags. tag_map = { 'bold': 'b', 'emphasis': 'em', 'computeroutput': 'code', 'para': 'p', 'programlisting': 'pre', 'verbatim': 'pre' } # A map from Doxygen tags to text. tag_text_map = { 'codeline': '', 'highlight': '', 'sp': ' ' } def escape_html(s: str) -> str: return s.replace("<", "<") def doxyxml2html(nodes: List[ElementTree.Element]): out = '' for n in nodes: tag = tag_map.get(n.tag) if not tag: out += tag_text_map[n.tag] out += '<' + tag + '>' if tag else '' out += '' if tag == 'pre' else '' if n.text: out += escape_html(n.text) out += doxyxml2html(list(n)) out += '' if tag == 'pre' else '' out += '' if tag else '' if n.tail: out += n.tail return out def convert_template_params(node: ElementTree.Element) -> Optional[List[Definition]]: template_param_list = node.find('templateparamlist') if template_param_list is None: return None params = [] for param_node in template_param_list.findall('param'): name = param_node.find('declname') param = Definition(name.text if name is not None else '', 'param') param.type = param_node.find('type').text params.append(param) return params def get_description(node: ElementTree.Element) -> List[ElementTree.Element]: return node.findall('briefdescription/para') + \ node.findall('detaileddescription/para') def normalize_type(type_: str) -> str: type_ = type_.replace('< ', '<').replace(' >', '>') return type_.replace(' &', '&').replace(' *', '*') def convert_type(type_: ElementTree.Element) -> Optional[str]: if type_ is None: return None result = type_.text if type_.text else '' for ref in type_: result += ref.text if ref.tail: result += ref.tail result += type_.tail.strip() return normalize_type(result) def convert_params(func: ElementTree.Element) -> List[Definition]: params = [] for p in func.findall('param'): d = Definition(p.find('declname').text, 'param') d.type = convert_type(p.find('type')) params.append(d) return params def convert_return_type(d: Definition, node: ElementTree.Element) -> None: d.trailing_return_type = None if d.type == 'auto' or d.type == 'constexpr auto': parts = node.find('argsstring').text.split(' -> ') if len(parts) > 1: d.trailing_return_type = normalize_type(parts[1]) def render_param(param: Definition) -> str: return param.type + (f' {param.name}' if len(param.name) > 0 else '') def render_decl(d: Definition) -> str: text = '' if d.id is not None: text += f'\n' text += '
'

    text += '
' if d.template_params is not None: text += 'template <' text += ', '.join([render_param(p) for p in d.template_params]) text += '>\n' text += '
' text += '
' end = ';' if d.kind == 'function' or d.kind == 'variable': text += d.type + ' ' if len(d.type) > 0 else '' elif d.kind == 'typedef': text += 'using ' elif d.kind == 'define': end = '' else: text += d.kind + ' ' text += d.name if d.params is not None: params = ', '.join([ (p.type + ' ' if p.type else '') + p.name for p in d.params]) text += '(' + escape_html(params) + ')' if d.trailing_return_type: text += ' -⁠> ' + escape_html(d.trailing_return_type) elif d.kind == 'typedef': text += ' = ' + escape_html(d.type) text += end text += '
' text += '
\n' if d.id is not None: text += f'
\n' return text class CxxHandler(BaseHandler): def __init__(self, **kwargs: Any) -> None: super().__init__(handler='cxx', **kwargs) headers = [ 'args.h', 'base.h', 'chrono.h', 'color.h', 'compile.h', 'format.h', 'os.h', 'ostream.h', 'printf.h', 'ranges.h', 'std.h', 'xchar.h' ] # Run doxygen. cmd = ['doxygen', '-'] support_dir = Path(__file__).parents[3] top_dir = os.path.dirname(support_dir) include_dir = os.path.join(top_dir, 'include', 'fmt') self._ns2doxyxml = {} build_dir = os.path.join(top_dir, 'build') os.makedirs(build_dir, exist_ok=True) self._doxyxml_dir = os.path.join(build_dir, 'doxyxml') p = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=STDOUT) _, _ = p.communicate(input=r''' PROJECT_NAME = fmt GENERATE_XML = YES GENERATE_LATEX = NO GENERATE_HTML = NO INPUT = {0} XML_OUTPUT = {1} QUIET = YES AUTOLINK_SUPPORT = NO MACRO_EXPANSION = YES PREDEFINED = _WIN32=1 \ __linux__=1 \ FMT_ENABLE_IF(...)= \ FMT_USE_USER_LITERALS=1 \ FMT_USE_ALIAS_TEMPLATES=1 \ FMT_USE_NONTYPE_TEMPLATE_ARGS=1 \ FMT_API= \ "FMT_BEGIN_NAMESPACE=namespace fmt {{" \ "FMT_END_NAMESPACE=}}" \ "FMT_DOC=1" '''.format( ' '.join([os.path.join(include_dir, h) for h in headers]), self._doxyxml_dir).encode('utf-8')) if p.returncode != 0: raise CalledProcessError(p.returncode, cmd) # Merge all file-level XMLs into one to simplify search. self._file_doxyxml = None for h in headers: filename = h.replace(".h", "_8h.xml") with open(os.path.join(self._doxyxml_dir, filename)) as f: doxyxml = ElementTree.parse(f) if self._file_doxyxml is None: self._file_doxyxml = doxyxml continue root = self._file_doxyxml.getroot() for node in doxyxml.getroot(): root.append(node) def collect_compound(self, identifier: str, cls: List[ElementTree.Element]) -> Definition: """Collect a compound definition such as a struct.""" path = os.path.join(self._doxyxml_dir, cls[0].get('refid') + '.xml') with open(path) as f: xml = ElementTree.parse(f) node = xml.find('compounddef') d = Definition(identifier, node=node) d.template_params = convert_template_params(node) d.desc = get_description(node) d.members = [] for m in \ node.findall('sectiondef[@kind="public-attrib"]/memberdef') + \ node.findall('sectiondef[@kind="public-func"]/memberdef'): name = m.find('name').text # Doxygen incorrectly classifies members of private unnamed unions as # public members of the containing class. if name.endswith('_'): continue desc = get_description(m) if len(desc) == 0: continue kind = m.get('kind') member = Definition(name if name else '', kind=kind, is_member=True) type_text = m.find('type').text member.type = type_text if type_text else '' if kind == 'function': member.params = convert_params(m) convert_return_type(member, m) member.template_params = None member.desc = desc d.members.append(member) return d def collect(self, identifier: str, _config: Mapping[str, Any]) -> Definition: qual_name = 'fmt::' + identifier param_str = None paren = qual_name.find('(') if paren > 0: qual_name, param_str = qual_name[:paren], qual_name[paren + 1:-1] colons = qual_name.rfind('::') namespace, name = qual_name[:colons], qual_name[colons + 2:] # Load XML. doxyxml = self._ns2doxyxml.get(namespace) if doxyxml is None: path = f'namespace{namespace.replace("::", "_1_1")}.xml' with open(os.path.join(self._doxyxml_dir, path)) as f: doxyxml = ElementTree.parse(f) self._ns2doxyxml[namespace] = doxyxml nodes = doxyxml.findall( f"compounddef/sectiondef/memberdef/name[.='{name}']/..") if len(nodes) == 0: nodes = self._file_doxyxml.findall( f"compounddef/sectiondef/memberdef/name[.='{name}']/..") candidates = [] for node in nodes: # Process a function or a typedef. params = None d = Definition(name, node=node) if d.kind == 'function': params = convert_params(node) node_param_str = ', '.join([p.type for p in params]) if param_str and param_str != node_param_str: candidates.append(f'{name}({node_param_str})') continue elif d.kind == 'define': params = [] for p in node.findall('param'): param = Definition(p.find('defname').text, kind='param') param.type = None params.append(param) d.type = convert_type(node.find('type')) d.template_params = convert_template_params(node) d.params = params convert_return_type(d, node) d.desc = get_description(node) return d cls = doxyxml.findall(f"compounddef/innerclass[.='{qual_name}']") if not cls: raise Exception(f'Cannot find {identifier}. Candidates: {candidates}') return self.collect_compound(identifier, cls) def render(self, d: Definition, config: dict) -> str: if d.id is not None: self.do_heading('', 0, id=d.id) text = '
\n' text += render_decl(d) text += '
\n' text += doxyxml2html(d.desc) if d.members is not None: for m in d.members: text += self.render(m, config) text += '
\n' text += '
\n' return text def get_handler(theme: str, custom_templates: Optional[str] = None, **_config: Any) -> CxxHandler: """Return an instance of `CxxHandler`. Arguments: theme: The theme to use when rendering contents. custom_templates: Directory containing custom templates. **_config: Configuration passed to the handler. """ return CxxHandler(theme=theme, custom_templates=custom_templates) soci-4.1.4/3rdparty/fmt/support/Vagrantfile0000664000175000017500000000110715100423533020627 0ustar zeitlinzeitlin# -*- mode: ruby -*- # vi: set ft=ruby : # A vagrant config for testing against gcc-4.8. Vagrant.configure("2") do |config| config.vm.box = "bento/ubuntu-22.04-arm64" config.vm.provider "vmware_desktop" do |vb| vb.memory = "4096" end config.vm.provision "shell", inline: <<-SHELL apt-get update apt-get install -y g++ make wget git wget -q https://github.com/Kitware/CMake/releases/download/v3.26.0/cmake-3.26.0-Linux-x86_64.tar.gz tar xzf cmake-3.26.0-Linux-x86_64.tar.gz ln -s `pwd`/cmake-3.26.0-Linux-x86_64/bin/cmake /usr/local/bin SHELL end soci-4.1.4/3rdparty/fmt/support/build.gradle0000664000175000017500000000761115100423533020727 0ustar zeitlinzeitlinimport java.nio.file.Paths // General gradle arguments for root project buildscript { repositories { google() jcenter() } dependencies { // // https://developer.android.com/studio/releases/gradle-plugin#updating-gradle // // Notice that 4.0.0 here is the version of [Android Gradle Plugin] // According to URL above you will need Gradle 6.1 or higher // classpath "com.android.tools.build:gradle:4.1.1" } } repositories { google() jcenter() } // Project's root where CMakeLists.txt exists: rootDir/support/.cxx -> rootDir def rootDir = Paths.get(project.buildDir.getParent()).getParent() println("rootDir: ${rootDir}") // Output: Shared library (.so) for Android apply plugin: "com.android.library" android { compileSdkVersion 25 // Android 7.0 // Target ABI // - This option controls target platform of module // - The platform might be limited by compiler's support // some can work with Clang(default), but some can work only with GCC... // if bad, both toolchains might not support it splits { abi { enable true // Specify platforms for Application reset() include "arm64-v8a", "armeabi-v7a", "x86_64" } } ndkVersion "21.3.6528147" // ANDROID_NDK_HOME is deprecated. Be explicit defaultConfig { minSdkVersion 21 // Android 5.0+ targetSdkVersion 25 // Follow Compile SDK versionCode 34 // Follow release count versionName "7.1.2" // Follow Official version externalNativeBuild { cmake { arguments "-DANDROID_STL=c++_shared" // Specify Android STL arguments "-DBUILD_SHARED_LIBS=true" // Build shared object arguments "-DFMT_TEST=false" // Skip test arguments "-DFMT_DOC=false" // Skip document cppFlags "-std=c++17" targets "fmt" } } println(externalNativeBuild.cmake.cppFlags) println(externalNativeBuild.cmake.arguments) } // External Native build // - Use existing CMakeList.txt // - Give path to CMake. This gradle file should be // neighbor of the top level cmake externalNativeBuild { cmake { version "3.10.0+" path "${rootDir}/CMakeLists.txt" // buildStagingDirectory "./build" // Custom path for cmake output } } sourceSets{ // Android Manifest for Gradle main { manifest.srcFile "AndroidManifest.xml" } } // https://developer.android.com/studio/build/native-dependencies#build_system_configuration buildFeatures { prefab true prefabPublishing true } prefab { fmt { headers "${rootDir}/include" } } } assemble.doLast { // Instead of `ninja install`, Gradle will deploy the files. // We are doing this since FMT is dependent to the ANDROID_STL after build copy { from "build/intermediates/cmake" into "${rootDir}/libs" } // Copy debug binaries copy { from "${rootDir}/libs/debug/obj" into "${rootDir}/libs/debug" } // Copy Release binaries copy { from "${rootDir}/libs/release/obj" into "${rootDir}/libs/release" } // Remove empty directory delete "${rootDir}/libs/debug/obj" delete "${rootDir}/libs/release/obj" // Copy AAR files. Notice that the aar is named after the folder of this script. copy { from "build/outputs/aar/support-release.aar" into "${rootDir}/libs" rename "support-release.aar", "fmt-release.aar" } copy { from "build/outputs/aar/support-debug.aar" into "${rootDir}/libs" rename "support-debug.aar", "fmt-debug.aar" } } soci-4.1.4/3rdparty/fmt/support/cmake/0000775000175000017500000000000015100423533017523 5ustar zeitlinzeitlinsoci-4.1.4/3rdparty/fmt/support/cmake/FindSetEnv.cmake0000664000175000017500000000045315100423533022534 0ustar zeitlinzeitlin# A CMake script to find SetEnv.cmd. find_program(WINSDK_SETENV NAMES SetEnv.cmd PATHS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]/bin") if (WINSDK_SETENV AND PRINT_PATH) execute_process(COMMAND ${CMAKE_COMMAND} -E echo "${WINSDK_SETENV}") endif () soci-4.1.4/3rdparty/fmt/support/cmake/fmt-config.cmake.in0000664000175000017500000000022315100423533023160 0ustar zeitlinzeitlin@PACKAGE_INIT@ if (NOT TARGET fmt::fmt) include(${CMAKE_CURRENT_LIST_DIR}/@targets_export_name@.cmake) endif () check_required_components(fmt) soci-4.1.4/3rdparty/fmt/support/cmake/JoinPaths.cmake0000664000175000017500000000167715100423533022437 0ustar zeitlinzeitlin# This module provides function for joining paths # known from from most languages # # Original license: # SPDX-License-Identifier: (MIT OR CC0-1.0) # Explicit permission given to distribute this module under # the terms of the project as described in /LICENSE.rst. # Copyright 2020 Jan Tojnar # https://github.com/jtojnar/cmake-snips # # Modelled after Python’s os.path.join # https://docs.python.org/3.7/library/os.path.html#os.path.join # Windows not supported function(join_paths joined_path first_path_segment) set(temp_path "${first_path_segment}") foreach(current_segment IN LISTS ARGN) if(NOT ("${current_segment}" STREQUAL "")) if(IS_ABSOLUTE "${current_segment}") set(temp_path "${current_segment}") else() set(temp_path "${temp_path}/${current_segment}") endif() endif() endforeach() set(${joined_path} "${temp_path}" PARENT_SCOPE) endfunction() soci-4.1.4/3rdparty/fmt/support/cmake/fmt.pc.in0000664000175000017500000000041015100423533021235 0ustar zeitlinzeitlinprefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=@CMAKE_INSTALL_PREFIX@ libdir=@libdir_for_pc_file@ includedir=@includedir_for_pc_file@ Name: fmt Description: A modern formatting library Version: @FMT_VERSION@ Libs: -L${libdir} -l@FMT_LIB_NAME@ Cflags: -I${includedir} soci-4.1.4/3rdparty/fmt/support/check-commits0000775000175000017500000000255515100423533021126 0ustar zeitlinzeitlin#!/usr/bin/env python3 """Compile source on a range of commits Usage: check-commits """ import docopt, os, sys, tempfile from subprocess import check_call, check_output, run args = docopt.docopt(__doc__) start = args.get('') source = args.get('') cwd = os.getcwd() with tempfile.TemporaryDirectory() as work_dir: check_call(['git', 'clone', 'https://github.com/fmtlib/fmt.git'], cwd=work_dir) repo_dir = os.path.join(work_dir, 'fmt') commits = check_output( ['git', 'rev-list', f'{start}..HEAD', '--abbrev-commit', '--', 'include', 'src'], text=True, cwd=repo_dir).rstrip().split('\n') commits.reverse() print('Time\tCommit') for commit in commits: check_call(['git', '-c', 'advice.detachedHead=false', 'checkout', commit], cwd=repo_dir) returncode = run( ['c++', '-std=c++11', '-O3', '-DNDEBUG', '-I', 'include', 'src/format.cc', os.path.join(cwd, source)], cwd=repo_dir).returncode if returncode != 0: continue times = [] for i in range(5): output = check_output([os.path.join(repo_dir, 'a.out')], text=True) times.append(float(output)) message = check_output(['git', 'log', '-1', '--pretty=format:%s', commit], cwd=repo_dir, text=True) print(f'{min(times)}\t{commit} {message[:40]}') sys.stdout.flush() soci-4.1.4/3rdparty/fmt/support/Android.mk0000664000175000017500000000045315100423533020356 0ustar zeitlinzeitlinLOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := fmt_static LOCAL_MODULE_FILENAME := libfmt LOCAL_SRC_FILES := ../src/format.cc LOCAL_C_INCLUDES := $(LOCAL_PATH) LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH) LOCAL_CFLAGS += -std=c++11 -fexceptions include $(BUILD_STATIC_LIBRARY) soci-4.1.4/3rdparty/fmt/support/mkdocs.yml0000664000175000017500000000174515100423533020455 0ustar zeitlinzeitlinsite_name: '{fmt}' docs_dir: ../doc repo_url: https://github.com/fmtlib/fmt theme: name: material features: - navigation.tabs - navigation.top - toc.integrate extra_javascript: - https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.2/highlight.min.js - fmt.js extra_css: - https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.2/styles/default.min.css - fmt.css markdown_extensions: - pymdownx.highlight: # Use JavaScript syntax highlighter instead of Pygments because it # automatically applies to code blocks extracted through Doxygen. use_pygments: false anchor_linenums: true line_spans: __span pygments_lang_class: true - pymdownx.inlinehilite - pymdownx.snippets plugins: - search - mkdocstrings: default_handler: cxx nav: - Home: index.md - Get Started: get-started.md - API: api.md - Syntax: syntax.md exclude_docs: ChangeLog-old.md extra: version: provider: mike generator: false soci-4.1.4/3rdparty/fmt/support/release.py0000775000175000017500000001342415100423533020444 0ustar zeitlinzeitlin#!/usr/bin/env python3 """Make a release. Usage: release.py [] For the release command $FMT_TOKEN should contain a GitHub personal access token obtained from https://github.com/settings/tokens. """ from __future__ import print_function import datetime, docopt, errno, fileinput, json, os import re, shutil, sys from subprocess import check_call import urllib.request class Git: def __init__(self, dir): self.dir = dir def call(self, method, args, **kwargs): return check_call(['git', method] + list(args), **kwargs) def add(self, *args): return self.call('add', args, cwd=self.dir) def checkout(self, *args): return self.call('checkout', args, cwd=self.dir) def clean(self, *args): return self.call('clean', args, cwd=self.dir) def clone(self, *args): return self.call('clone', list(args) + [self.dir]) def commit(self, *args): return self.call('commit', args, cwd=self.dir) def pull(self, *args): return self.call('pull', args, cwd=self.dir) def push(self, *args): return self.call('push', args, cwd=self.dir) def reset(self, *args): return self.call('reset', args, cwd=self.dir) def update(self, *args): clone = not os.path.exists(self.dir) if clone: self.clone(*args) return clone def clean_checkout(repo, branch): repo.clean('-f', '-d') repo.reset('--hard') repo.checkout(branch) class Runner: def __init__(self, cwd): self.cwd = cwd def __call__(self, *args, **kwargs): kwargs['cwd'] = kwargs.get('cwd', self.cwd) check_call(args, **kwargs) def create_build_env(): """Create a build environment.""" class Env: pass env = Env() env.fmt_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) env.build_dir = 'build' env.fmt_repo = Git(os.path.join(env.build_dir, 'fmt')) return env if __name__ == '__main__': args = docopt.docopt(__doc__) env = create_build_env() fmt_repo = env.fmt_repo branch = args.get('') if branch is None: branch = 'master' if not fmt_repo.update('-b', branch, 'git@github.com:fmtlib/fmt'): clean_checkout(fmt_repo, branch) # Update the date in the changelog and extract the version and the first # section content. changelog = 'ChangeLog.md' changelog_path = os.path.join(fmt_repo.dir, changelog) is_first_section = True first_section = [] for i, line in enumerate(fileinput.input(changelog_path, inplace=True)): if i == 0: version = re.match(r'# (.*) - TBD', line).group(1) line = '# {} - {}\n'.format( version, datetime.date.today().isoformat()) elif not is_first_section: pass elif line.startswith('#'): is_first_section = False else: first_section.append(line) sys.stdout.write(line) if first_section[0] == '\n': first_section.pop(0) ns_version = None base_h_path = os.path.join(fmt_repo.dir, 'include', 'fmt', 'base.h') for line in fileinput.input(base_h_path): m = re.match(r'\s*inline namespace v(.*) .*', line) if m: ns_version = m.group(1) break major_version = version.split('.')[0] if not ns_version or ns_version != major_version: raise Exception(f'Version mismatch {ns_version} != {major_version}') # Workaround GitHub-flavored Markdown treating newlines as
. changes = '' code_block = False stripped = False for line in first_section: if re.match(r'^\s*```', line): code_block = not code_block changes += line stripped = False continue if code_block: changes += line continue if line == '\n' or re.match(r'^\s*\|.*', line): if stripped: changes += '\n' stripped = False changes += line continue if stripped: line = ' ' + line.lstrip() changes += line.rstrip() stripped = True fmt_repo.checkout('-B', 'release') fmt_repo.add(changelog) fmt_repo.commit('-m', 'Update version') # Build the docs and package. run = Runner(fmt_repo.dir) run('cmake', '.') run('make', 'doc', 'package_source') # Create a release on GitHub. fmt_repo.push('origin', 'release') auth_headers = {'Authorization': 'token ' + os.getenv('FMT_TOKEN')} req = urllib.request.Request( 'https://api.github.com/repos/fmtlib/fmt/releases', data=json.dumps({'tag_name': version, 'target_commitish': 'release', 'body': changes, 'draft': True}).encode('utf-8'), headers=auth_headers, method='POST') with urllib.request.urlopen(req) as response: if response.status != 201: raise Exception(f'Failed to create a release ' + '{response.status} {response.reason}') response_data = json.loads(response.read().decode('utf-8')) id = response_data['id'] # Upload the package. uploads_url = 'https://uploads.github.com/repos/fmtlib/fmt/releases' package = 'fmt-{}.zip'.format(version) req = urllib.request.Request( f'{uploads_url}/{id}/assets?name={package}', headers={'Content-Type': 'application/zip'} | auth_headers, data=open('build/fmt/' + package, 'rb').read(), method='POST') with urllib.request.urlopen(req) as response: if response.status != 201: raise Exception(f'Failed to upload an asset ' '{response.status} {response.reason}') short_version = '.'.join(version.split('.')[:-1]) check_call(['./mkdocs', 'deploy', short_version]) soci-4.1.4/3rdparty/fmt/support/README0000664000175000017500000000012515100423533017321 0ustar zeitlinzeitlinThis directory contains build support files such as * CMake modules * Build scripts soci-4.1.4/3rdparty/fmt/support/printable.py0000775000175000017500000001373515100423533021011 0ustar zeitlinzeitlin#!/usr/bin/env python3 # This script is based on # https://github.com/rust-lang/rust/blob/master/library/core/src/unicode/printable.py # distributed under https://github.com/rust-lang/rust/blob/master/LICENSE-MIT. # This script uses the following Unicode tables: # - UnicodeData.txt from collections import namedtuple import csv import os import subprocess NUM_CODEPOINTS=0x110000 def to_ranges(iter): current = None for i in iter: if current is None or i != current[1] or i in (0x10000, 0x20000): if current is not None: yield tuple(current) current = [i, i + 1] else: current[1] += 1 if current is not None: yield tuple(current) def get_escaped(codepoints): for c in codepoints: if (c.class_ or "Cn") in "Cc Cf Cs Co Cn Zl Zp Zs".split() and c.value != ord(' '): yield c.value def get_file(f): try: return open(os.path.basename(f)) except FileNotFoundError: subprocess.run(["curl", "-O", f], check=True) return open(os.path.basename(f)) Codepoint = namedtuple('Codepoint', 'value class_') def get_codepoints(f): r = csv.reader(f, delimiter=";") prev_codepoint = 0 class_first = None for row in r: codepoint = int(row[0], 16) name = row[1] class_ = row[2] if class_first is not None: if not name.endswith("Last>"): raise ValueError("Missing Last after First") for c in range(prev_codepoint + 1, codepoint): yield Codepoint(c, class_first) class_first = None if name.endswith("First>"): class_first = class_ yield Codepoint(codepoint, class_) prev_codepoint = codepoint if class_first is not None: raise ValueError("Missing Last after First") for c in range(prev_codepoint + 1, NUM_CODEPOINTS): yield Codepoint(c, None) def compress_singletons(singletons): uppers = [] # (upper, # items in lowers) lowers = [] for i in singletons: upper = i >> 8 lower = i & 0xff if len(uppers) == 0 or uppers[-1][0] != upper: uppers.append((upper, 1)) else: upper, count = uppers[-1] uppers[-1] = upper, count + 1 lowers.append(lower) return uppers, lowers def compress_normal(normal): # lengths 0x00..0x7f are encoded as 00, 01, ..., 7e, 7f # lengths 0x80..0x7fff are encoded as 80 80, 80 81, ..., ff fe, ff ff compressed = [] # [truelen, (truelenaux), falselen, (falselenaux)] prev_start = 0 for start, count in normal: truelen = start - prev_start falselen = count prev_start = start + count assert truelen < 0x8000 and falselen < 0x8000 entry = [] if truelen > 0x7f: entry.append(0x80 | (truelen >> 8)) entry.append(truelen & 0xff) else: entry.append(truelen & 0x7f) if falselen > 0x7f: entry.append(0x80 | (falselen >> 8)) entry.append(falselen & 0xff) else: entry.append(falselen & 0x7f) compressed.append(entry) return compressed def print_singletons(uppers, lowers, uppersname, lowersname): print(" static constexpr singleton {}[] = {{".format(uppersname)) for u, c in uppers: print(" {{{:#04x}, {}}},".format(u, c)) print(" };") print(" static constexpr unsigned char {}[] = {{".format(lowersname)) for i in range(0, len(lowers), 8): print(" {}".format(" ".join("{:#04x},".format(l) for l in lowers[i:i+8]))) print(" };") def print_normal(normal, normalname): print(" static constexpr unsigned char {}[] = {{".format(normalname)) for v in normal: print(" {}".format(" ".join("{:#04x},".format(i) for i in v))) print(" };") def main(): file = get_file("https://www.unicode.org/Public/UNIDATA/UnicodeData.txt") codepoints = get_codepoints(file) CUTOFF=0x10000 singletons0 = [] singletons1 = [] normal0 = [] normal1 = [] extra = [] for a, b in to_ranges(get_escaped(codepoints)): if a > 2 * CUTOFF: extra.append((a, b - a)) elif a == b - 1: if a & CUTOFF: singletons1.append(a & ~CUTOFF) else: singletons0.append(a) elif a == b - 2: if a & CUTOFF: singletons1.append(a & ~CUTOFF) singletons1.append((a + 1) & ~CUTOFF) else: singletons0.append(a) singletons0.append(a + 1) else: if a >= 2 * CUTOFF: extra.append((a, b - a)) elif a & CUTOFF: normal1.append((a & ~CUTOFF, b - a)) else: normal0.append((a, b - a)) singletons0u, singletons0l = compress_singletons(singletons0) singletons1u, singletons1l = compress_singletons(singletons1) normal0 = compress_normal(normal0) normal1 = compress_normal(normal1) print("""\ FMT_FUNC auto is_printable(uint32_t cp) -> bool {\ """) print_singletons(singletons0u, singletons0l, 'singletons0', 'singletons0_lower') print_singletons(singletons1u, singletons1l, 'singletons1', 'singletons1_lower') print_normal(normal0, 'normal0') print_normal(normal1, 'normal1') print("""\ auto lower = static_cast(cp); if (cp < 0x10000) { return is_printable(lower, singletons0, sizeof(singletons0) / sizeof(*singletons0), singletons0_lower, normal0, sizeof(normal0)); } if (cp < 0x20000) { return is_printable(lower, singletons1, sizeof(singletons1) / sizeof(*singletons1), singletons1_lower, normal1, sizeof(normal1)); }\ """) for a, b in extra: print(" if (0x{:x} <= cp && cp < 0x{:x}) return false;".format(a, a + b)) print("""\ return cp < 0x{:x}; }}\ """.format(NUM_CODEPOINTS)) if __name__ == '__main__': main() soci-4.1.4/3rdparty/fmt/support/docopt.py0000664000175000017500000004651015100423533020313 0ustar zeitlinzeitlin"""Pythonic command-line interface parser that will make you smile. * http://docopt.org * Repository and issue-tracker: https://github.com/docopt/docopt * Licensed under terms of MIT license (see LICENSE-MIT) * Copyright (c) 2013 Vladimir Keleshev, vladimir@keleshev.com """ import sys import re __all__ = ['docopt'] __version__ = '0.6.1' class DocoptLanguageError(Exception): """Error in construction of usage-message by developer.""" class DocoptExit(SystemExit): """Exit in case user invoked program with incorrect arguments.""" usage = '' def __init__(self, message=''): SystemExit.__init__(self, (message + '\n' + self.usage).strip()) class Pattern(object): def __eq__(self, other): return repr(self) == repr(other) def __hash__(self): return hash(repr(self)) def fix(self): self.fix_identities() self.fix_repeating_arguments() return self def fix_identities(self, uniq=None): """Make pattern-tree tips point to same object if they are equal.""" if not hasattr(self, 'children'): return self uniq = list(set(self.flat())) if uniq is None else uniq for i, child in enumerate(self.children): if not hasattr(child, 'children'): assert child in uniq self.children[i] = uniq[uniq.index(child)] else: child.fix_identities(uniq) def fix_repeating_arguments(self): """Fix elements that should accumulate/increment values.""" either = [list(child.children) for child in transform(self).children] for case in either: for e in [child for child in case if case.count(child) > 1]: if type(e) is Argument or type(e) is Option and e.argcount: if e.value is None: e.value = [] elif type(e.value) is not list: e.value = e.value.split() if type(e) is Command or type(e) is Option and e.argcount == 0: e.value = 0 return self def transform(pattern): """Expand pattern into an (almost) equivalent one, but with single Either. Example: ((-a | -b) (-c | -d)) => (-a -c | -a -d | -b -c | -b -d) Quirks: [-a] => (-a), (-a...) => (-a -a) """ result = [] groups = [[pattern]] while groups: children = groups.pop(0) parents = [Required, Optional, OptionsShortcut, Either, OneOrMore] if any(t in map(type, children) for t in parents): child = [c for c in children if type(c) in parents][0] children.remove(child) if type(child) is Either: for c in child.children: groups.append([c] + children) elif type(child) is OneOrMore: groups.append(child.children * 2 + children) else: groups.append(child.children + children) else: result.append(children) return Either(*[Required(*e) for e in result]) class LeafPattern(Pattern): """Leaf/terminal node of a pattern tree.""" def __init__(self, name, value=None): self.name, self.value = name, value def __repr__(self): return '%s(%r, %r)' % (self.__class__.__name__, self.name, self.value) def flat(self, *types): return [self] if not types or type(self) in types else [] def match(self, left, collected=None): collected = [] if collected is None else collected pos, match = self.single_match(left) if match is None: return False, left, collected left_ = left[:pos] + left[pos + 1:] same_name = [a for a in collected if a.name == self.name] if type(self.value) in (int, list): if type(self.value) is int: increment = 1 else: increment = ([match.value] if type(match.value) is str else match.value) if not same_name: match.value = increment return True, left_, collected + [match] same_name[0].value += increment return True, left_, collected return True, left_, collected + [match] class BranchPattern(Pattern): """Branch/inner node of a pattern tree.""" def __init__(self, *children): self.children = list(children) def __repr__(self): return '%s(%s)' % (self.__class__.__name__, ', '.join(repr(a) for a in self.children)) def flat(self, *types): if type(self) in types: return [self] return sum([child.flat(*types) for child in self.children], []) class Argument(LeafPattern): def single_match(self, left): for n, pattern in enumerate(left): if type(pattern) is Argument: return n, Argument(self.name, pattern.value) return None, None @classmethod def parse(class_, source): name = re.findall('(<\S*?>)', source)[0] value = re.findall('\[default: (.*)\]', source, flags=re.I) return class_(name, value[0] if value else None) class Command(Argument): def __init__(self, name, value=False): self.name, self.value = name, value def single_match(self, left): for n, pattern in enumerate(left): if type(pattern) is Argument: if pattern.value == self.name: return n, Command(self.name, True) else: break return None, None class Option(LeafPattern): def __init__(self, short=None, long=None, argcount=0, value=False): assert argcount in (0, 1) self.short, self.long, self.argcount = short, long, argcount self.value = None if value is False and argcount else value @classmethod def parse(class_, option_description): short, long, argcount, value = None, None, 0, False options, _, description = option_description.strip().partition(' ') options = options.replace(',', ' ').replace('=', ' ') for s in options.split(): if s.startswith('--'): long = s elif s.startswith('-'): short = s else: argcount = 1 if argcount: matched = re.findall('\[default: (.*)\]', description, flags=re.I) value = matched[0] if matched else None return class_(short, long, argcount, value) def single_match(self, left): for n, pattern in enumerate(left): if self.name == pattern.name: return n, pattern return None, None @property def name(self): return self.long or self.short def __repr__(self): return 'Option(%r, %r, %r, %r)' % (self.short, self.long, self.argcount, self.value) class Required(BranchPattern): def match(self, left, collected=None): collected = [] if collected is None else collected l = left c = collected for pattern in self.children: matched, l, c = pattern.match(l, c) if not matched: return False, left, collected return True, l, c class Optional(BranchPattern): def match(self, left, collected=None): collected = [] if collected is None else collected for pattern in self.children: m, left, collected = pattern.match(left, collected) return True, left, collected class OptionsShortcut(Optional): """Marker/placeholder for [options] shortcut.""" class OneOrMore(BranchPattern): def match(self, left, collected=None): assert len(self.children) == 1 collected = [] if collected is None else collected l = left c = collected l_ = None matched = True times = 0 while matched: # could it be that something didn't match but changed l or c? matched, l, c = self.children[0].match(l, c) times += 1 if matched else 0 if l_ == l: break l_ = l if times >= 1: return True, l, c return False, left, collected class Either(BranchPattern): def match(self, left, collected=None): collected = [] if collected is None else collected outcomes = [] for pattern in self.children: matched, _, _ = outcome = pattern.match(left, collected) if matched: outcomes.append(outcome) if outcomes: return min(outcomes, key=lambda outcome: len(outcome[1])) return False, left, collected class Tokens(list): def __init__(self, source, error=DocoptExit): self += source.split() if hasattr(source, 'split') else source self.error = error @staticmethod def from_pattern(source): source = re.sub(r'([\[\]\(\)\|]|\.\.\.)', r' \1 ', source) source = [s for s in re.split('\s+|(\S*<.*?>)', source) if s] return Tokens(source, error=DocoptLanguageError) def move(self): return self.pop(0) if len(self) else None def current(self): return self[0] if len(self) else None def parse_long(tokens, options): """long ::= '--' chars [ ( ' ' | '=' ) chars ] ;""" long, eq, value = tokens.move().partition('=') assert long.startswith('--') value = None if eq == value == '' else value similar = [o for o in options if o.long == long] if tokens.error is DocoptExit and similar == []: # if no exact match similar = [o for o in options if o.long and o.long.startswith(long)] if len(similar) > 1: # might be simply specified ambiguously 2+ times? raise tokens.error('%s is not a unique prefix: %s?' % (long, ', '.join(o.long for o in similar))) elif len(similar) < 1: argcount = 1 if eq == '=' else 0 o = Option(None, long, argcount) options.append(o) if tokens.error is DocoptExit: o = Option(None, long, argcount, value if argcount else True) else: o = Option(similar[0].short, similar[0].long, similar[0].argcount, similar[0].value) if o.argcount == 0: if value is not None: raise tokens.error('%s must not have an argument' % o.long) else: if value is None: if tokens.current() in [None, '--']: raise tokens.error('%s requires argument' % o.long) value = tokens.move() if tokens.error is DocoptExit: o.value = value if value is not None else True return [o] def parse_shorts(tokens, options): """shorts ::= '-' ( chars )* [ [ ' ' ] chars ] ;""" token = tokens.move() assert token.startswith('-') and not token.startswith('--') left = token.lstrip('-') parsed = [] while left != '': short, left = '-' + left[0], left[1:] similar = [o for o in options if o.short == short] if len(similar) > 1: raise tokens.error('%s is specified ambiguously %d times' % (short, len(similar))) elif len(similar) < 1: o = Option(short, None, 0) options.append(o) if tokens.error is DocoptExit: o = Option(short, None, 0, True) else: # why copying is necessary here? o = Option(short, similar[0].long, similar[0].argcount, similar[0].value) value = None if o.argcount != 0: if left == '': if tokens.current() in [None, '--']: raise tokens.error('%s requires argument' % short) value = tokens.move() else: value = left left = '' if tokens.error is DocoptExit: o.value = value if value is not None else True parsed.append(o) return parsed def parse_pattern(source, options): tokens = Tokens.from_pattern(source) result = parse_expr(tokens, options) if tokens.current() is not None: raise tokens.error('unexpected ending: %r' % ' '.join(tokens)) return Required(*result) def parse_expr(tokens, options): """expr ::= seq ( '|' seq )* ;""" seq = parse_seq(tokens, options) if tokens.current() != '|': return seq result = [Required(*seq)] if len(seq) > 1 else seq while tokens.current() == '|': tokens.move() seq = parse_seq(tokens, options) result += [Required(*seq)] if len(seq) > 1 else seq return [Either(*result)] if len(result) > 1 else result def parse_seq(tokens, options): """seq ::= ( atom [ '...' ] )* ;""" result = [] while tokens.current() not in [None, ']', ')', '|']: atom = parse_atom(tokens, options) if tokens.current() == '...': atom = [OneOrMore(*atom)] tokens.move() result += atom return result def parse_atom(tokens, options): """atom ::= '(' expr ')' | '[' expr ']' | 'options' | long | shorts | argument | command ; """ token = tokens.current() result = [] if token in '([': tokens.move() matching, pattern = {'(': [')', Required], '[': [']', Optional]}[token] result = pattern(*parse_expr(tokens, options)) if tokens.move() != matching: raise tokens.error("unmatched '%s'" % token) return [result] elif token == 'options': tokens.move() return [OptionsShortcut()] elif token.startswith('--') and token != '--': return parse_long(tokens, options) elif token.startswith('-') and token not in ('-', '--'): return parse_shorts(tokens, options) elif token.startswith('<') and token.endswith('>') or token.isupper(): return [Argument(tokens.move())] else: return [Command(tokens.move())] def parse_argv(tokens, options, options_first=False): """Parse command-line argument vector. If options_first: argv ::= [ long | shorts ]* [ argument ]* [ '--' [ argument ]* ] ; else: argv ::= [ long | shorts | argument ]* [ '--' [ argument ]* ] ; """ parsed = [] while tokens.current() is not None: if tokens.current() == '--': return parsed + [Argument(None, v) for v in tokens] elif tokens.current().startswith('--'): parsed += parse_long(tokens, options) elif tokens.current().startswith('-') and tokens.current() != '-': parsed += parse_shorts(tokens, options) elif options_first: return parsed + [Argument(None, v) for v in tokens] else: parsed.append(Argument(None, tokens.move())) return parsed def parse_defaults(doc): defaults = [] for s in parse_section('options:', doc): # FIXME corner case "bla: options: --foo" _, _, s = s.partition(':') # get rid of "options:" split = re.split('\n[ \t]*(-\S+?)', '\n' + s)[1:] split = [s1 + s2 for s1, s2 in zip(split[::2], split[1::2])] options = [Option.parse(s) for s in split if s.startswith('-')] defaults += options return defaults def parse_section(name, source): pattern = re.compile('^([^\n]*' + name + '[^\n]*\n?(?:[ \t].*?(?:\n|$))*)', re.IGNORECASE | re.MULTILINE) return [s.strip() for s in pattern.findall(source)] def formal_usage(section): _, _, section = section.partition(':') # drop "usage:" pu = section.split() return '( ' + ' '.join(') | (' if s == pu[0] else s for s in pu[1:]) + ' )' def extras(help, version, options, doc): if help and any((o.name in ('-h', '--help')) and o.value for o in options): print(doc.strip("\n")) sys.exit() if version and any(o.name == '--version' and o.value for o in options): print(version) sys.exit() class Dict(dict): def __repr__(self): return '{%s}' % ',\n '.join('%r: %r' % i for i in sorted(self.items())) def docopt(doc, argv=None, help=True, version=None, options_first=False): """Parse `argv` based on command-line interface described in `doc`. `docopt` creates your command-line interface based on its description that you pass as `doc`. Such description can contain --options, , commands, which could be [optional], (required), (mutually | exclusive) or repeated... Parameters ---------- doc : str Description of your command-line interface. argv : list of str, optional Argument vector to be parsed. sys.argv[1:] is used if not provided. help : bool (default: True) Set to False to disable automatic help on -h or --help options. version : any object If passed, the object will be printed if --version is in `argv`. options_first : bool (default: False) Set to True to require options precede positional arguments, i.e. to forbid options and positional arguments intermix. Returns ------- args : dict A dictionary, where keys are names of command-line elements such as e.g. "--verbose" and "", and values are the parsed values of those elements. Example ------- >>> from docopt import docopt >>> doc = ''' ... Usage: ... my_program tcp [--timeout=] ... my_program serial [--baud=] [--timeout=] ... my_program (-h | --help | --version) ... ... Options: ... -h, --help Show this screen and exit. ... --baud= Baudrate [default: 9600] ... ''' >>> argv = ['tcp', '127.0.0.1', '80', '--timeout', '30'] >>> docopt(doc, argv) {'--baud': '9600', '--help': False, '--timeout': '30', '--version': False, '': '127.0.0.1', '': '80', 'serial': False, 'tcp': True} See also -------- * For video introduction see http://docopt.org * Full documentation is available in README.rst as well as online at https://github.com/docopt/docopt#readme """ argv = sys.argv[1:] if argv is None else argv usage_sections = parse_section('usage:', doc) if len(usage_sections) == 0: raise DocoptLanguageError('"usage:" (case-insensitive) not found.') if len(usage_sections) > 1: raise DocoptLanguageError('More than one "usage:" (case-insensitive).') DocoptExit.usage = usage_sections[0] options = parse_defaults(doc) pattern = parse_pattern(formal_usage(DocoptExit.usage), options) # [default] syntax for argument is disabled #for a in pattern.flat(Argument): # same_name = [d for d in arguments if d.name == a.name] # if same_name: # a.value = same_name[0].value argv = parse_argv(Tokens(argv), list(options), options_first) pattern_options = set(pattern.flat(Option)) for options_shortcut in pattern.flat(OptionsShortcut): doc_options = parse_defaults(doc) options_shortcut.children = list(set(doc_options) - pattern_options) #if any_options: # options_shortcut.children += [Option(o.short, o.long, o.argcount) # for o in argv if type(o) is Option] extras(help, version, argv, doc) matched, left, collected = pattern.fix().match(argv) if matched and left == []: # better error message if left? return Dict((a.name, a.value) for a in (pattern.flat() + collected)) raise DocoptExit() soci-4.1.4/3rdparty/fmt/support/mkdocs0000775000175000017500000000532215100423533017653 0ustar zeitlinzeitlin#!/usr/bin/env python3 # A script to invoke mkdocs with the correct environment. # Additionally supports deploying via mike: # ./mkdocs deploy [mike-deploy-options] # For example: # ./mkdocs deploy # This will checkout the website to fmt/build/fmt.dev and deploy documentation # there. import errno, os, shutil, sys from subprocess import call support_dir = os.path.dirname(os.path.normpath(__file__)) build_dir = os.path.join(os.path.dirname(support_dir), 'build') # Set PYTHONPATH for the mkdocstrings handler. env = os.environ.copy() path = env.get('PYTHONPATH') env['PYTHONPATH'] = \ (path + ':' if path else '') + os.path.join(support_dir, 'python') redirect_page = \ ''' Redirecting Redirecting to api... ''' config_path = os.path.join(support_dir, 'mkdocs.yml') args = sys.argv[1:] if len(args) > 0: command = args[0] if command == 'deploy' or command == 'set-default': git_url = 'https://github.com/' if 'CI' in os.environ else 'git@github.com:' site_repo = git_url + 'fmtlib/fmt.dev.git' site_dir = os.path.join(build_dir, 'fmt.dev') try: shutil.rmtree(site_dir) except OSError as e: if e.errno == errno.ENOENT: pass ret = call(['git', 'clone', '--depth=1', site_repo, site_dir]) if ret != 0: sys.exit(ret) # Copy the config to the build dir because the site is built relative to it. config_build_path = os.path.join(build_dir, 'mkdocs.yml') shutil.copyfile(config_path, config_build_path) version = args[1] ret = call(['mike'] + args + ['--config-file', config_build_path, '--branch', 'master'], cwd=site_dir, env=env) if ret != 0 or version == 'dev': sys.exit(ret) current_doc_path = os.path.join(site_dir, version) # mike stages files added by deploy for deletion for unclear reason, # undo it. ret = call(['git', 'reset', '--hard'], cwd=site_dir) if False: os.makedirs(current_doc_path, exist_ok=True) redirect_page_path = os.path.join(current_doc_path, 'api.html') with open(redirect_page_path, "w") as file: file.write(redirect_page) ret = call(['git', 'add', redirect_page_path], cwd=site_dir) if ret != 0: sys.exit(ret) ret = call(['git', 'commit', '--amend', '--no-edit'], cwd=site_dir) sys.exit(ret) elif not command.startswith('-'): args += ['-f', config_path] sys.exit(call(['mkdocs'] + args, env=env)) soci-4.1.4/3rdparty/fmt/support/AndroidManifest.xml0000664000175000017500000000003715100423533022234 0ustar zeitlinzeitlin soci-4.1.4/3rdparty/fmt/ChangeLog.md0000664000175000017500000035344015100423533017111 0ustar zeitlinzeitlin# 12.1.0 - 2025-10-29 - Optimized `buffer::append`, resulting in up to ~16% improvement on spdlog benchmarks (https://github.com/fmtlib/fmt/pull/4541). Thanks @fyrsta7. - Worked around an ABI incompatibility in `std::locale_ref` between clang and gcc (https://github.com/fmtlib/fmt/issues/4573). - Made `std::variant` and `std::expected` formatters work with `format_as` (https://github.com/fmtlib/fmt/issues/4574, https://github.com/fmtlib/fmt/pull/4575). Thanks @phprus. - Made `fmt::join` work with C++ modules (https://github.com/fmtlib/fmt/issues/4379, https://github.com/fmtlib/fmt/pull/4577). Thanks @Arghnews. - Exported `fmt::is_compiled_string` and `operator""_cf` from the module (https://github.com/fmtlib/fmt/pull/4544). Thanks @CrackedMatter. - Fixed a compatibility issue with C++ modules in clang (https://github.com/fmtlib/fmt/pull/4548). Thanks @tsarn. - Added support for cv-qualified types to the `std::optional` formatter (https://github.com/fmtlib/fmt/issues/4561, https://github.com/fmtlib/fmt/pull/4562). Thanks @OleksandrKvl. - Added demangling support (used in exception and `std::type_info` formatters) for libc++ and clang-cl (https://github.com/fmtlib/fmt/issues/4542, https://github.com/fmtlib/fmt/pull/4560, https://github.com/fmtlib/fmt/issues/4568, https://github.com/fmtlib/fmt/pull/4571). Thanks @FatihBAKIR and @rohitsutreja. - Switched to global `malloc`/`free` to enable allocator customization (https://github.com/fmtlib/fmt/issues/4569, https://github.com/fmtlib/fmt/pull/4570). Thanks @rohitsutreja. - Made the `FMT_USE_CONSTEVAL` macro configurable by users (https://github.com/fmtlib/fmt/pull/4546). Thanks @SnapperTT. - Fixed compilation with locales disabled in the header-only mode (https://github.com/fmtlib/fmt/issues/4550). - Fixed compilation with clang 21 and `-std=c++20` (https://github.com/fmtlib/fmt/issues/4552). - Fixed a dynamic linking issue with clang-cl (https://github.com/fmtlib/fmt/issues/4576, https://github.com/fmtlib/fmt/pull/4584). Thanks @FatihBAKIR. - Fixed a warning suppression leakage on gcc (https://github.com/fmtlib/fmt/pull/4588). Thanks @ZedThree. - Made more internal color APIs `constexpr` (https://github.com/fmtlib/fmt/pull/4581). Thanks @ishani. - Fixed compatibility with clang as a host compiler for NVCC (https://github.com/fmtlib/fmt/pull/4564). Thanks @valgur. - Fixed various warnings and lint issues (https://github.com/fmtlib/fmt/issues/4565, https://github.com/fmtlib/fmt/pull/4572, https://github.com/fmtlib/fmt/pull/4557). Thanks @LiangHuDream and @teruyamato0731. - Improved documentation (https://github.com/fmtlib/fmt/issues/4549, https://github.com/fmtlib/fmt/pull/4551, https://github.com/fmtlib/fmt/issues/4566, https://github.com/fmtlib/fmt/pull/4567, https://github.com/fmtlib/fmt/pull/4578,). Thanks @teruyamato0731, @petersteneteg and @zimmerman-dev. # 12.0.0 - 2025-09-17 - Optimized the default floating point formatting (https://github.com/fmtlib/fmt/issues/3675, https://github.com/fmtlib/fmt/issues/4516). In particular, formatting a `double` with format string compilation into a stack allocated buffer is more than 60% faster in version 12.0 compared to 11.2 according to [dtoa-benchmark](https://github.com/fmtlib/dtoa-benchmark): ``` Function Time (ns) Speedup fmt11 34.471 1.00x fmt12 21.000 1.64x ``` - Added `constexpr` support to `fmt::format`. For example: ```c++ #include using namespace fmt::literals; std::string s = fmt::format(""_cf, 42); ``` now works at compile time provided that `std::string` supports `constexpr` (https://github.com/fmtlib/fmt/issues/3403, https://github.com/fmtlib/fmt/pull/4456). Thanks @msvetkin. - Added `FMT_STATIC_FORMAT` that allows formatting into a string of the exact required size at compile time. For example: ```c++ #include constexpr auto s = FMT_STATIC_FORMAT("{}", 42); ``` compiles to just ```s __ZL1s: .asciiz "42" ``` It can be accessed as a C string with `s.c_str()` or as a string view with `s.str()`. - Improved C++20 module support (https://github.com/fmtlib/fmt/pull/4451, https://github.com/fmtlib/fmt/pull/4459, https://github.com/fmtlib/fmt/pull/4476, https://github.com/fmtlib/fmt/pull/4488, https://github.com/fmtlib/fmt/issues/4491, https://github.com/fmtlib/fmt/pull/4495). Thanks @arBmind, @tkhyn, @Mishura4, @anonymouspc and @autoantwort. - Switched to using estimated display width in precision. For example: ```c++ fmt::print("|{:.4}|\n|1234|\n", "���"); ``` prints ![](https://github.com/user-attachments/assets/6c4446b3-13eb-43b9-b74a-b4543540ad6a) because `�` has an estimated width of 2 (https://github.com/fmtlib/fmt/issues/4272, https://github.com/fmtlib/fmt/pull/4443, https://github.com/fmtlib/fmt/pull/4475). Thanks @nikhilreddydev and @localspook. - Fix interaction between debug presentation, precision, and width for strings (https://github.com/fmtlib/fmt/pull/4478). Thanks @localspook. - Implemented allocator propagation on `basic_memory_buffer` move (https://github.com/fmtlib/fmt/issues/4487, https://github.com/fmtlib/fmt/pull/4490). Thanks @toprakmurat. - Fixed an ambiguity between `std::reference_wrapper` and `format_as` formatters (https://github.com/fmtlib/fmt/issues/4424, https://github.com/fmtlib/fmt/pull/4434). Thanks @jeremy-rifkin. - Removed the following deprecated APIs: - `has_formatter`: use `is_formattable` instead, - `basic_format_args::parse_context_type`, `basic_format_args::formatter_type` and similar aliases in context types, - wide stream overload of `fmt::printf`, - wide stream overloads of `fmt::print` that take text styles, - `is_*char` traits, - `fmt::localtime`. - Deprecated wide overloads of `fmt::fprintf` and `fmt::sprintf`. - Improved diagnostics for the incorrect usage of `fmt::ptr` (https://github.com/fmtlib/fmt/pull/4453). Thanks @TobiSchluter. - Made handling of ANSI escape sequences more efficient (https://github.com/fmtlib/fmt/pull/4511, https://github.com/fmtlib/fmt/pull/4528). Thanks @localspook and @Anas-Hamdane. - Fixed a buffer overflow on all emphasis flags set (https://github.com/fmtlib/fmt/pull/4498). Thanks @dominicpoeschko. - Fixed an integer overflow for precision close to the max `int` value. - Fixed compatibility with WASI (https://github.com/fmtlib/fmt/issues/4496, https://github.com/fmtlib/fmt/pull/4497). Thanks @whitequark. - Fixed `back_insert_iterator` detection, preventing a fallback on slower path that handles arbitrary iterators (https://github.com/fmtlib/fmt/issues/4454). - Fixed handling of invalid glibc `FILE` buffers (https://github.com/fmtlib/fmt/issues/4469). - Added `wchar_t` support to the `std::byte` formatter (https://github.com/fmtlib/fmt/issues/4479, https://github.com/fmtlib/fmt/pull/4480). Thanks @phprus. - Changed component prefix from `fmt-` to `fmt_` for compatibility with NSIS/CPack on Windows, e.g. `fmt-doc` changed to `fmt_doc` (https://github.com/fmtlib/fmt/issues/4441, https://github.com/fmtlib/fmt/pull/4442). Thanks @n-stein. - Added the `FMT_CUSTOM_ASSERT_FAIL` macro to simplify providing a custom `fmt::assert_fail` implementation (https://github.com/fmtlib/fmt/pull/4505). Thanks @HazardyKnusperkeks. - Switched to `FMT_THROW` on reporting format errors so that it can be overriden by users when exceptions are disabled (https://github.com/fmtlib/fmt/pull/4521). Thanks @HazardyKnusperkeks. - Improved master project detection and disabled install targets when using {fmt} as a subproject by default (https://github.com/fmtlib/fmt/pull/4536). Thanks @crueter. - Made various code improvements (https://github.com/fmtlib/fmt/pull/4445, https://github.com/fmtlib/fmt/pull/4448, https://github.com/fmtlib/fmt/pull/4473, https://github.com/fmtlib/fmt/pull/4522). Thanks @localspook, @tchaikov and @way4sahil. - Added Conan instructions to the docs (https://github.com/fmtlib/fmt/pull/4537). Thanks @uilianries. - Removed Bazel files to avoid issues with downstream packaging (https://github.com/fmtlib/fmt/pull/4530). Thanks @mering. - Added more entries for generated files to `.gitignore` (https://github.com/fmtlib/fmt/pull/4355, https://github.com/fmtlib/fmt/pull/4512). Thanks @dinomight and @localspook. - Fixed various warnings and compilation issues (https://github.com/fmtlib/fmt/pull/4447, https://github.com/fmtlib/fmt/issues/4470, https://github.com/fmtlib/fmt/pull/4474, https://github.com/fmtlib/fmt/pull/4477, https://github.com/fmtlib/fmt/pull/4471, https://github.com/fmtlib/fmt/pull/4483, https://github.com/fmtlib/fmt/pull/4515, https://github.com/fmtlib/fmt/issues/4533, https://github.com/fmtlib/fmt/pull/4534). Thanks @dodomorandi, @localspook, @remyjette, @Tomek-Stolarczyk, @Mishura4, @mattiasljungstrom and @FatihBAKIR. # 11.2.0 - 2025-05-03 - Added the `s` specifier for `std::error_code`. It allows formatting an error message as a string. For example: ```c++ #include int main() { auto ec = std::make_error_code(std::errc::no_such_file_or_directory); fmt::print("{:s}\n", ec); } ``` prints ``` No such file or directory ``` (The actual message is platform-specific.) - Fixed formatting of `std::chrono::local_time` and `tm` (https://github.com/fmtlib/fmt/issues/3815, https://github.com/fmtlib/fmt/issues/4350). For example ([godbolt](https://www.godbolt.org/z/8o4b1PPn5)): ```c++ #include int main() { std::chrono::zoned_time zt( std::chrono::current_zone(), std::chrono::system_clock::now()); fmt::print("{}", zt.get_local_time()); } ``` is now formatted consistenly across platforms. - Added diagnostics for cases when timezone information is not available. For example: ```c++ fmt::print("{:Z}", std::chrono::local_seconds()); ``` now gives a compile-time error. - Deprecated `fmt::localtime` in favor of `std::localtime`. - Fixed compilation with GCC 15 and C++20 modules enabled (https://github.com/fmtlib/fmt/pull/4347). Thanks @tkhyn. - Fixed handling of named arguments in format specs (https://github.com/fmtlib/fmt/issues/4360, https://github.com/fmtlib/fmt/pull/4361). Thanks @dinomight. - Added error reporting for duplicate named arguments (https://github.com/fmtlib/fmt/issues/4282, https://github.com/fmtlib/fmt/pull/4367). Thanks @dinomight. - Fixed formatting of `long` with `FMT_BUILTIN_TYPES=0` (https://github.com/fmtlib/fmt/issues/4375, https://github.com/fmtlib/fmt/issues/4394). - Optimized `text_style` using bit packing (https://github.com/fmtlib/fmt/pull/4363). Thanks @localspook. - Added support for incomplete types (https://github.com/fmtlib/fmt/issues/3180, https://github.com/fmtlib/fmt/pull/4383). Thanks @localspook. - Fixed a flush issue in `fmt::print` when using libstdc++ (https://github.com/fmtlib/fmt/issues/4398). - Fixed `fmt::println` usage with `FMT_ENFORCE_COMPILE_STRING` and legacy compile-time checks (https://github.com/fmtlib/fmt/pull/4407). Thanks @madmaxoft. - Removed legacy header `fmt/core.h` from docs (https://github.com/fmtlib/fmt/pull/4421, https://github.com/fmtlib/fmt/pull/4422). Thanks @krzysztofkortas. - Worked around limitations of `__builtin_strlen` during constant evaluation (https://github.com/fmtlib/fmt/issues/4423, https://github.com/fmtlib/fmt/pull/4429). Thanks @BRevzin. - Worked around a bug in MSVC v141 (https://github.com/fmtlib/fmt/issues/4412, https://github.com/fmtlib/fmt/pull/4413). Thanks @hirohira9119. - Removed the `fmt_detail` namespace (https://github.com/fmtlib/fmt/issues/4324). - Removed specializations of `std::is_floating_point` in tests (https://github.com/fmtlib/fmt/issues/4417). - Fixed a CMake error when setting `CMAKE_MODULE_PATH` in the pedantic mode (https://github.com/fmtlib/fmt/pull/4426). Thanks @rlalik. - Updated the Bazel config (https://github.com/fmtlib/fmt/pull/4400). Thanks @Vertexwahn. # 11.1.4 - 2025-02-26 - Fixed ABI compatibility with earlier 11.x versions on Windows (https://github.com/fmtlib/fmt/issues/4359). - Improved the logic of switching between fixed and exponential format for `float` (https://github.com/fmtlib/fmt/issues/3649). - Moved `is_compiled_string` to the public API (https://github.com/fmtlib/fmt/issues/4335, https://github.com/fmtlib/fmt/issues/4342). Thanks @SwooshyCueb. - Simplified implementation of `operator""_cf` (https://github.com/fmtlib/fmt/pull/4349). Thanks @localspook. - Fixed `__builtin_strlen` detection (https://github.com/fmtlib/fmt/pull/4329). Thanks @localspook. - Fixed handling of BMI paths with the Ninja generator (https://github.com/fmtlib/fmt/pull/4344). Thanks @tkhyn. - Fixed gcc 8.3 compile errors (https://github.com/fmtlib/fmt/issues/4331, https://github.com/fmtlib/fmt/pull/4336). Thanks @sergiud. - Fixed a bogus MSVC warning (https://github.com/fmtlib/fmt/pull/4356). Thanks @dinomight. # 11.1.3 - 2025-01-25 - Fixed compilation on GCC 9.4 (https://github.com/fmtlib/fmt/issues/4313). - Worked around an internal compiler error when using C++20 modules with GCC 14.2 and earlier (https://github.com/fmtlib/fmt/issues/4295). - Worked around a bug in GCC 6 (https://github.com/fmtlib/fmt/issues/4318). - Fixed an issue caused by instantiating `formatter` (https://github.com/fmtlib/fmt/issues/4303, https://github.com/fmtlib/fmt/pull/4325). Thanks @timsong-cpp. - Fixed formatting into `std::ostreambuf_iterator` when using format string compilation (https://github.com/fmtlib/fmt/issues/4309, https://github.com/fmtlib/fmt/pull/4312). Thanks @phprus. - Restored a constraint on the map formatter so that it correctly reports as unformattable when the element is (https://github.com/fmtlib/fmt/pull/4326). Thanks @timsong-cpp. - Reduced the size of format specs (https://github.com/fmtlib/fmt/issues/4298). - Readded `args()` to `fmt::format_context` (https://github.com/fmtlib/fmt/issues/4307, https://github.com/fmtlib/fmt/pull/4310). Thanks @Erroneous1. - Fixed a bogus MSVC warning (https://github.com/fmtlib/fmt/issues/4314, https://github.com/fmtlib/fmt/pull/4322). Thanks @ZehMatt. - Fixed a pedantic mode error in the CMake config (https://github.com/fmtlib/fmt/pull/4327). Thanks @rlalik. # 11.1.2 - 2025-01-12 - Fixed ABI compatibility with earlier 11.x versions (https://github.com/fmtlib/fmt/issues/4292). - Added `wchar_t` support to the `std::bitset` formatter (https://github.com/fmtlib/fmt/issues/4285, https://github.com/fmtlib/fmt/pull/4286, https://github.com/fmtlib/fmt/issues/4289, https://github.com/fmtlib/fmt/pull/4290). Thanks @phprus. - Prefixed CMake components with `fmt-` to simplify usage of {fmt} via `add_subdirectory` (https://github.com/fmtlib/fmt/issues/4283). - Updated docs for meson (https://github.com/fmtlib/fmt/pull/4291). Thanks @trim21. - Fixed a compilation error in chrono on nvcc (https://github.com/fmtlib/fmt/issues/4297, https://github.com/fmtlib/fmt/pull/4301). Thanks @breyerml. - Fixed various warnings (https://github.com/fmtlib/fmt/pull/4288, https://github.com/fmtlib/fmt/pull/4299). Thanks @GamesTrap and @edo9300. # 11.1.1 - 2024-12-27 - Fixed ABI compatibility with earlier 11.x versions (https://github.com/fmtlib/fmt/issues/4278). - Defined CMake components (`core` and `doc`) to allow docs to be installed separately (https://github.com/fmtlib/fmt/pull/4276). Thanks @carlsmedstad. # 11.1.0 - 2024-12-25 - Improved C++20 module support (https://github.com/fmtlib/fmt/issues/4081, https://github.com/fmtlib/fmt/pull/4083, https://github.com/fmtlib/fmt/pull/4084, https://github.com/fmtlib/fmt/pull/4152, https://github.com/fmtlib/fmt/issues/4153, https://github.com/fmtlib/fmt/pull/4169, https://github.com/fmtlib/fmt/issues/4190, https://github.com/fmtlib/fmt/issues/4234, https://github.com/fmtlib/fmt/pull/4239). Thanks @kamrann and @Arghnews. - Reduced debug (unoptimized) binary code size and the number of template instantiations when passing formatting arguments. For example, unoptimized binary code size for `fmt::print("{}", 42)` was reduced by ~40% on GCC and ~60% on clang (x86-64). GCC: - Before: 161 instructions of which 105 are in reusable functions ([godbolt](https://www.godbolt.org/z/s9bGoo4ze)). - After: 116 instructions of which 60 are in reusable functions ([godbolt](https://www.godbolt.org/z/r7GGGxMs6)). Clang: - Before: 310 instructions of which 251 are in reusable functions ([godbolt](https://www.godbolt.org/z/Ts88b7M9o)). - After: 194 instructions of which 135 are in reusable functions ([godbolt](https://www.godbolt.org/z/vcrjP8ceW)). - Added an experimental `fmt::writer` API that can be used for writing to different destinations such as files or strings (https://github.com/fmtlib/fmt/issues/2354). For example ([godbolt](https://www.godbolt.org/z/rWoKfbP7e)): ```c++ #include void write_text(fmt::writer w) { w.print("The answer is {}.", 42); } int main() { // Write to FILE. write_text(stdout); // Write to fmt::ostream. auto f = fmt::output_file("myfile"); write_text(f); // Write to std::string. auto sb = fmt::string_buffer(); write_text(sb); std::string s = sb.str(); } ``` - Added width and alignment support to the formatter of `std::error_code`. - Made `std::expected` formattable (https://github.com/fmtlib/fmt/issues/4145, https://github.com/fmtlib/fmt/pull/4148). For example ([godbolt](https://www.godbolt.org/z/hrj5c6G86)): ```c++ fmt::print("{}", std::expected()); ``` prints ``` expected() ``` Thanks @phprus. - Made `fmt::is_formattable` SFINAE-friendly (https://github.com/fmtlib/fmt/issues/4147). - Added support for `_BitInt` formatting when using clang (https://github.com/fmtlib/fmt/issues/4007, https://github.com/fmtlib/fmt/pull/4072, https://github.com/fmtlib/fmt/issues/4140, https://github.com/fmtlib/fmt/issues/4173, https://github.com/fmtlib/fmt/pull/4176). For example ([godbolt](https://www.godbolt.org/z/KWjbWec5z)): ```c++ using int42 = _BitInt(42); fmt::print("{}", int42(100)); ``` Thanks @Arghnews. - Added the `n` specifier for tuples and pairs (https://github.com/fmtlib/fmt/pull/4107). Thanks @someonewithpc. - Added support for tuple-like types to `fmt::join` (https://github.com/fmtlib/fmt/issues/4226, https://github.com/fmtlib/fmt/pull/4230). Thanks @phprus. - Made more types formattable at compile time (https://github.com/fmtlib/fmt/pull/4127). Thanks @AnthonyVH. - Implemented a more efficient compile-time `fmt::formatted_size` (https://github.com/fmtlib/fmt/issues/4102, https://github.com/fmtlib/fmt/pull/4103). Thanks @phprus. - Fixed compile-time formatting of some string types (https://github.com/fmtlib/fmt/pull/4065). Thanks @torshepherd. - Made compiled version of `fmt::format_to` work with `std::back_insert_iterator>` (https://github.com/fmtlib/fmt/issues/4206, https://github.com/fmtlib/fmt/pull/4211). Thanks @phprus. - Added a formatter for `std::reference_wrapper` (https://github.com/fmtlib/fmt/pull/4163, https://github.com/fmtlib/fmt/pull/4164). Thanks @yfeldblum and @phprus. - Added experimental padding support (glibc `strftime` extension) to `%m`, `%j` and `%Y` (https://github.com/fmtlib/fmt/pull/4161). Thanks @KKhanhH. - Made microseconds formatted as `us` instead of `µs` if the Unicode support is disabled (https://github.com/fmtlib/fmt/issues/4088). - Fixed an unreleased regression in transcoding of surrogate pairs (https://github.com/fmtlib/fmt/issues/4094, https://github.com/fmtlib/fmt/pull/4095). Thanks @phprus. - Made `fmt::appender` satisfy `std::output_iterator` concept (https://github.com/fmtlib/fmt/issues/4092, https://github.com/fmtlib/fmt/pull/4093). Thanks @phprus. - Made `std::iterator_traits` standard-conforming (https://github.com/fmtlib/fmt/pull/4185). Thanks @CaseyCarter. - Made it easier to reuse `fmt::formatter` for types with an implicit conversion to `std::string_view` (https://github.com/fmtlib/fmt/issues/4036, https://github.com/fmtlib/fmt/pull/4055). Thanks @Arghnews. - Made it possible to disable `` use via `FMT_CPP_LIB_FILESYSTEM` for compatibility with some video game console SDKs, e.g. Nintendo Switch SDK (https://github.com/fmtlib/fmt/issues/4257, https://github.com/fmtlib/fmt/pull/4258, https://github.com/fmtlib/fmt/pull/4259). Thanks @W4RH4WK and @phprus. - Fixed compatibility with platforms that use 80-bit `long double` (https://github.com/fmtlib/fmt/issues/4245, https://github.com/fmtlib/fmt/pull/4246). Thanks @jsirpoma. - Added support for UTF-32 code units greater than `0xFFFF` in fill (https://github.com/fmtlib/fmt/issues/4201). - Fixed handling of legacy encodings on Windows with GCC (https://github.com/fmtlib/fmt/issues/4162). - Made `fmt::to_string` take `fmt::basic_memory_buffer` by const reference (https://github.com/fmtlib/fmt/issues/4261, https://github.com/fmtlib/fmt/pull/4262). Thanks @sascha-devel. - Added `fmt::dynamic_format_arg_store::size` (https://github.com/fmtlib/fmt/pull/4270). Thanks @hannes-harnisch. - Removed the ability to control locale usage via an undocumented `FMT_STATIC_THOUSANDS_SEPARATOR` in favor of `FMT_USE_LOCALE`. - Renamed `FMT_EXCEPTIONS` to `FMT_USE_EXCEPTIONS` for consistency with other similar macros. - Improved include directory ordering to reduce the chance of including incorrect headers when using multiple versions of {fmt} (https://github.com/fmtlib/fmt/pull/4116). Thanks @cdzhan. - Made it possible to compile a subset of {fmt} without the C++ runtime. - Improved documentation and README (https://github.com/fmtlib/fmt/pull/4066, https://github.com/fmtlib/fmt/issues/4117, https://github.com/fmtlib/fmt/issues/4203, https://github.com/fmtlib/fmt/pull/4235). Thanks @zyctree and @nikola-sh. - Improved the documentation generator (https://github.com/fmtlib/fmt/pull/4110, https://github.com/fmtlib/fmt/pull/4115). Thanks @rturrado. - Improved CI (https://github.com/fmtlib/fmt/pull/4155, https://github.com/fmtlib/fmt/pull/4151). Thanks @phprus. - Fixed various warnings and compilation issues (https://github.com/fmtlib/fmt/issues/2708, https://github.com/fmtlib/fmt/issues/4091, https://github.com/fmtlib/fmt/issues/4109, https://github.com/fmtlib/fmt/issues/4113, https://github.com/fmtlib/fmt/issues/4125, https://github.com/fmtlib/fmt/issues/4129, https://github.com/fmtlib/fmt/pull/4130, https://github.com/fmtlib/fmt/pull/4131, https://github.com/fmtlib/fmt/pull/4132, https://github.com/fmtlib/fmt/issues/4133, https://github.com/fmtlib/fmt/issues/4144, https://github.com/fmtlib/fmt/issues/4150, https://github.com/fmtlib/fmt/issues/4158, https://github.com/fmtlib/fmt/pull/4159, https://github.com/fmtlib/fmt/issues/4160, https://github.com/fmtlib/fmt/pull/4170, https://github.com/fmtlib/fmt/issues/4177, https://github.com/fmtlib/fmt/pull/4187, https://github.com/fmtlib/fmt/pull/4188, https://github.com/fmtlib/fmt/pull/4194, https://github.com/fmtlib/fmt/pull/4200, https://github.com/fmtlib/fmt/issues/4205, https://github.com/fmtlib/fmt/issues/4207, https://github.com/fmtlib/fmt/pull/4208, https://github.com/fmtlib/fmt/pull/4210, https://github.com/fmtlib/fmt/issues/4220, https://github.com/fmtlib/fmt/issues/4231, https://github.com/fmtlib/fmt/issues/4232, https://github.com/fmtlib/fmt/pull/4233, https://github.com/fmtlib/fmt/pull/4236, https://github.com/fmtlib/fmt/pull/4267, https://github.com/fmtlib/fmt/pull/4271). Thanks @torsten48, @Arghnews, @tinfoilboy, @aminya, @Ottani, @zeroomega, @c4v4, @kongy, @vinayyadav3016, @sergio-nsk, @phprus and @YexuanXiao. # 11.0.2 - 2024-07-20 - Fixed compatibility with non-POSIX systems (https://github.com/fmtlib/fmt/issues/4054, https://github.com/fmtlib/fmt/issues/4060). - Fixed performance regressions when using `std::back_insert_iterator` with `fmt::format_to` (https://github.com/fmtlib/fmt/issues/4070). - Fixed handling of `std::generator` and move-only iterators (https://github.com/fmtlib/fmt/issues/4053, https://github.com/fmtlib/fmt/pull/4057). Thanks @Arghnews. - Made `formatter::parse` work with types convertible to `std::string_view` (https://github.com/fmtlib/fmt/issues/4036, https://github.com/fmtlib/fmt/pull/4055). Thanks @Arghnews. - Made `volatile void*` formattable (https://github.com/fmtlib/fmt/issues/4049, https://github.com/fmtlib/fmt/pull/4056). Thanks @Arghnews. - Made `Glib::ustring` not be confused with `std::string` (https://github.com/fmtlib/fmt/issues/4052). - Made `fmt::context` iterator compatible with STL algorithms that rely on iterator category (https://github.com/fmtlib/fmt/issues/4079). # 11.0.1 - 2024-07-05 - Fixed version number in the inline namespace (https://github.com/fmtlib/fmt/issues/4047). - Fixed disabling Unicode support via CMake (https://github.com/fmtlib/fmt/issues/4051). - Fixed deprecated `visit_format_arg` (https://github.com/fmtlib/fmt/pull/4043). Thanks @nebkat. - Fixed handling of a sign and improved the `std::complex` formater (https://github.com/fmtlib/fmt/pull/4034, https://github.com/fmtlib/fmt/pull/4050). Thanks @tesch1 and @phprus. - Fixed ADL issues in `fmt::printf` when using C++20 (https://github.com/fmtlib/fmt/pull/4042). Thanks @toge. - Removed a redundant check in the formatter for `std::expected` (https://github.com/fmtlib/fmt/pull/4040). Thanks @phprus. # 11.0.0 - 2024-07-01 - Added `fmt/base.h` which provides a subset of the API with minimal include dependencies and enough functionality to replace all uses of the `printf` family of functions. This brings the compile time of code using {fmt} much closer to the equivalent `printf` code as shown on the following benchmark that compiles 100 source files: | Method | Compile Time (s) | |--------------|------------------| | printf | 1.6 | | IOStreams | 25.9 | | fmt 10.x | 19.0 | | fmt 11.0 | 4.8 | | tinyformat | 29.1 | | Boost Format | 55.0 | This gives almost 4x improvement in build speed compared to version 10. Note that the benchmark is purely formatting code and includes. In real projects the difference from `printf` will be smaller partly because common standard headers will be included in almost any translation unit (TU) anyway. In particular, in every case except `printf` above ~1s is spent in total on including `` in all TUs. - Optimized includes in other headers such as `fmt/format.h` which is now roughly equivalent to the old `fmt/core.h` in terms of build speed. - Migrated the documentation at https://fmt.dev/ from Sphinx to MkDocs. - Improved C++20 module support (https://github.com/fmtlib/fmt/issues/3990, https://github.com/fmtlib/fmt/pull/3991, https://github.com/fmtlib/fmt/issues/3993, https://github.com/fmtlib/fmt/pull/3994, https://github.com/fmtlib/fmt/pull/3997, https://github.com/fmtlib/fmt/pull/3998, https://github.com/fmtlib/fmt/pull/4004, https://github.com/fmtlib/fmt/pull/4005, https://github.com/fmtlib/fmt/pull/4006, https://github.com/fmtlib/fmt/pull/4013, https://github.com/fmtlib/fmt/pull/4027, https://github.com/fmtlib/fmt/pull/4029). In particular, native CMake support for modules is now used if available. Thanks @yujincheng08 and @matt77hias. - Added an option to replace standard includes with `import std` enabled via the `FMT_IMPORT_STD` macro (https://github.com/fmtlib/fmt/issues/3921, https://github.com/fmtlib/fmt/pull/3928). Thanks @matt77hias. - Exported `fmt::range_format`, `fmt::range_format_kind` and `fmt::compiled_string` from the `fmt` module (https://github.com/fmtlib/fmt/pull/3970, https://github.com/fmtlib/fmt/pull/3999). Thanks @matt77hias and @yujincheng08. - Improved integration with stdio in `fmt::print`, enabling direct writes into a C stream buffer in common cases. This may give significant performance improvements ranging from tens of percent to [2x]( https://stackoverflow.com/a/78457454/471164) and eliminates dynamic memory allocations on the buffer level. It is currently enabled for built-in and string types with wider availability coming up in future releases. For example, it gives ~24% improvement on a [simple benchmark]( https://isocpp.org/files/papers/P3107R5.html#perf) compiled with Apple clang version 15.0.0 (clang-1500.1.0.2.5) and run on macOS 14.2.1: ``` ------------------------------------------------------- Benchmark Time CPU Iterations ------------------------------------------------------- printf 81.8 ns 81.5 ns 8496899 fmt::print (10.x) 63.8 ns 61.9 ns 11524151 fmt::print (11.0) 51.3 ns 51.0 ns 13846580 ``` - Improved safety of `fmt::format_to` when writing to an array (https://github.com/fmtlib/fmt/pull/3805). For example ([godbolt](https://www.godbolt.org/z/cYrn8dWY8)): ```c++ auto volkswagen = char[4]; auto result = fmt::format_to(volkswagen, "elephant"); ``` no longer results in a buffer overflow. Instead the output will be truncated and you can get the end iterator and whether truncation occurred from the `result` object. Thanks @ThePhD. - Enabled Unicode support by default in MSVC, bringing it on par with other compilers and making it unnecessary for users to enable it explicitly. Most of {fmt} is encoding-agnostic but this prevents mojibake in places where encoding matters such as path formatting and terminal output. You can control the Unicode support via the CMake `FMT_UNICODE` option. Note that some {fmt} packages such as the one in vcpkg have already been compiled with Unicode enabled. - Added a formatter for `std::expected` (https://github.com/fmtlib/fmt/pull/3834). Thanks @dominicpoeschko. - Added a formatter for `std::complex` (https://github.com/fmtlib/fmt/issues/1467, https://github.com/fmtlib/fmt/issues/3886, https://github.com/fmtlib/fmt/pull/3892, https://github.com/fmtlib/fmt/pull/3900). Thanks @phprus. - Added a formatter for `std::type_info` (https://github.com/fmtlib/fmt/pull/3978). Thanks @matt77hias. - Specialized `formatter` for `std::basic_string` types with custom traits and allocators (https://github.com/fmtlib/fmt/issues/3938, https://github.com/fmtlib/fmt/pull/3943). Thanks @dieram3. - Added formatters for `std::chrono::day`, `std::chrono::month`, `std::chrono::year` and `std::chrono::year_month_day` (https://github.com/fmtlib/fmt/issues/3758, https://github.com/fmtlib/fmt/issues/3772, https://github.com/fmtlib/fmt/pull/3906, https://github.com/fmtlib/fmt/pull/3913). For example: ```c++ #include #include int main() { fmt::print(fg(fmt::color::green), "{}\n", std::chrono::day(7)); } ``` prints a green day: image Thanks @zivshek. - Fixed handling of precision in `%S` (https://github.com/fmtlib/fmt/issues/3794, https://github.com/fmtlib/fmt/pull/3814). Thanks @js324. - Added support for the `-` specifier (glibc `strftime` extension) to day of the month (`%d`) and week of the year (`%W`, `%U`, `%V`) specifiers (https://github.com/fmtlib/fmt/pull/3976). Thanks @ZaheenJ. - Fixed the scope of the `-` extension in chrono formatting so that it doesn't apply to subsequent specifiers (https://github.com/fmtlib/fmt/issues/3811, https://github.com/fmtlib/fmt/pull/3812). Thanks @phprus. - Improved handling of `time_point::min()` (https://github.com/fmtlib/fmt/issues/3282). - Added support for character range formatting (https://github.com/fmtlib/fmt/issues/3857, https://github.com/fmtlib/fmt/pull/3863). Thanks @js324. - Added `string` and `debug_string` range formatters (https://github.com/fmtlib/fmt/pull/3973, https://github.com/fmtlib/fmt/pull/4024). Thanks @matt77hias. - Enabled ADL for `begin` and `end` in `fmt::join` (https://github.com/fmtlib/fmt/issues/3813, https://github.com/fmtlib/fmt/pull/3824). Thanks @bbolli. - Made contiguous iterator optimizations apply to `std::basic_string` iterators (https://github.com/fmtlib/fmt/pull/3798). Thanks @phprus. - Added support for ranges with mutable `begin` and `end` (https://github.com/fmtlib/fmt/issues/3752, https://github.com/fmtlib/fmt/pull/3800, https://github.com/fmtlib/fmt/pull/3955). Thanks @tcbrindle and @Arghnews. - Added support for move-only iterators to `fmt::join` (https://github.com/fmtlib/fmt/issues/3802, https://github.com/fmtlib/fmt/pull/3946). Thanks @Arghnews. - Moved range and iterator overloads of `fmt::join` to `fmt/ranges.h`, next to other overloads. - Fixed handling of types with `begin` returning `void` such as Eigen matrices (https://github.com/fmtlib/fmt/issues/3839, https://github.com/fmtlib/fmt/pull/3964). Thanks @Arghnews. - Added an `fmt::formattable` concept (https://github.com/fmtlib/fmt/pull/3974). Thanks @matt77hias. - Added support for `__float128` (https://github.com/fmtlib/fmt/issues/3494). - Fixed rounding issues when formatting `long double` with fixed precision (https://github.com/fmtlib/fmt/issues/3539). - Made `fmt::isnan` not trigger floating-point exception for NaN values (https://github.com/fmtlib/fmt/issues/3948, https://github.com/fmtlib/fmt/pull/3951). Thanks @alexdewar. - Removed dependency on `` for `std::allocator_traits` when possible (https://github.com/fmtlib/fmt/pull/3804). Thanks @phprus. - Enabled compile-time checks in formatting functions that take text colors and styles. - Deprecated wide stream overloads of `fmt::print` that take text styles. - Made format string compilation work with clang 12 and later despite only partial non-type template parameter support (https://github.com/fmtlib/fmt/issues/4000, https://github.com/fmtlib/fmt/pull/4001). Thanks @yujincheng08. - Made `fmt::iterator_buffer`'s move constructor `noexcept` (https://github.com/fmtlib/fmt/pull/3808). Thanks @waywardmonkeys. - Started enforcing that `formatter::format` is const for compatibility with `std::format` (https://github.com/fmtlib/fmt/issues/3447). - Added `fmt::basic_format_arg::visit` and deprecated `fmt::visit_format_arg`. - Made `fmt::basic_string_view` not constructible from `nullptr` for consistency with `std::string_view` in C++23 (https://github.com/fmtlib/fmt/pull/3846). Thanks @dalle. - Fixed `fmt::group_digits` for negative integers (https://github.com/fmtlib/fmt/issues/3891, https://github.com/fmtlib/fmt/pull/3901). Thanks @phprus. - Fixed handling of negative ids in `fmt::basic_format_args::get` (https://github.com/fmtlib/fmt/pull/3945). Thanks @marlenecota. - Fixed handling of a buffer boundary on flush (https://github.com/fmtlib/fmt/issues/4229). - Improved named argument validation (https://github.com/fmtlib/fmt/issues/3817). - Disabled copy construction/assignment for `fmt::format_arg_store` and fixed moved construction (https://github.com/fmtlib/fmt/pull/3833). Thanks @ivafanas. - Worked around a locale issue in RHEL/devtoolset (https://github.com/fmtlib/fmt/issues/3858, https://github.com/fmtlib/fmt/pull/3859). Thanks @g199209. - Added RTTI detection for MSVC (https://github.com/fmtlib/fmt/pull/3821, https://github.com/fmtlib/fmt/pull/3963). Thanks @edo9300. - Migrated the documentation from Sphinx to MkDocs. - Improved documentation and README (https://github.com/fmtlib/fmt/issues/3775, https://github.com/fmtlib/fmt/pull/3784, https://github.com/fmtlib/fmt/issues/3788, https://github.com/fmtlib/fmt/pull/3789, https://github.com/fmtlib/fmt/pull/3793, https://github.com/fmtlib/fmt/issues/3818, https://github.com/fmtlib/fmt/pull/3820, https://github.com/fmtlib/fmt/pull/3822, https://github.com/fmtlib/fmt/pull/3843, https://github.com/fmtlib/fmt/pull/3890, https://github.com/fmtlib/fmt/issues/3894, https://github.com/fmtlib/fmt/pull/3895, https://github.com/fmtlib/fmt/pull/3905, https://github.com/fmtlib/fmt/issues/3942, https://github.com/fmtlib/fmt/pull/4008). Thanks @zencatalyst, WolleTD, @tupaschoal, @Dobiasd, @frank-weinberg, @bbolli, @phprus, @waywardmonkeys, @js324 and @tchaikov. - Improved CI and tests (https://github.com/fmtlib/fmt/issues/3878, https://github.com/fmtlib/fmt/pull/3883, https://github.com/fmtlib/fmt/issues/3897, https://github.com/fmtlib/fmt/pull/3979, https://github.com/fmtlib/fmt/pull/3980, https://github.com/fmtlib/fmt/pull/3988, https://github.com/fmtlib/fmt/pull/4010, https://github.com/fmtlib/fmt/pull/4012, https://github.com/fmtlib/fmt/pull/4038). Thanks @vgorrX, @waywardmonkeys, @tchaikov and @phprus. - Fixed buffer overflow when using format string compilation with debug format and `std::back_insert_iterator` (https://github.com/fmtlib/fmt/issues/3795, https://github.com/fmtlib/fmt/pull/3797). Thanks @phprus. - Improved Bazel support (https://github.com/fmtlib/fmt/pull/3792, https://github.com/fmtlib/fmt/pull/3801, https://github.com/fmtlib/fmt/pull/3962, https://github.com/fmtlib/fmt/pull/3965). Thanks @Vertexwahn. - Improved/fixed the CMake config (https://github.com/fmtlib/fmt/issues/3777, https://github.com/fmtlib/fmt/pull/3783, https://github.com/fmtlib/fmt/issues/3847, https://github.com/fmtlib/fmt/pull/3907). Thanks @phprus and @xTachyon. - Fixed various warnings and compilation issues (https://github.com/fmtlib/fmt/issues/3685, https://github.com/fmtlib/fmt/issues/3769, https://github.com/fmtlib/fmt/issues/3796, https://github.com/fmtlib/fmt/issues/3803, https://github.com/fmtlib/fmt/pull/3806, https://github.com/fmtlib/fmt/pull/3807, https://github.com/fmtlib/fmt/issues/3809, https://github.com/fmtlib/fmt/pull/3810, https://github.com/fmtlib/fmt/issues/3830, https://github.com/fmtlib/fmt/pull/3832, https://github.com/fmtlib/fmt/issues/3835, https://github.com/fmtlib/fmt/pull/3844, https://github.com/fmtlib/fmt/issues/3854, https://github.com/fmtlib/fmt/pull/3856, https://github.com/fmtlib/fmt/pull/3865, https://github.com/fmtlib/fmt/pull/3866, https://github.com/fmtlib/fmt/pull/3880, https://github.com/fmtlib/fmt/issues/3881, https://github.com/fmtlib/fmt/issues/3884, https://github.com/fmtlib/fmt/issues/3898, https://github.com/fmtlib/fmt/pull/3899, https://github.com/fmtlib/fmt/pull/3909, https://github.com/fmtlib/fmt/pull/3917, https://github.com/fmtlib/fmt/pull/3923, https://github.com/fmtlib/fmt/pull/3924, https://github.com/fmtlib/fmt/issues/3925, https://github.com/fmtlib/fmt/pull/3930, https://github.com/fmtlib/fmt/pull/3931, https://github.com/fmtlib/fmt/pull/3933, https://github.com/fmtlib/fmt/issues/3935, https://github.com/fmtlib/fmt/pull/3937, https://github.com/fmtlib/fmt/pull/3967, https://github.com/fmtlib/fmt/pull/3968, https://github.com/fmtlib/fmt/pull/3972, https://github.com/fmtlib/fmt/pull/3983, https://github.com/fmtlib/fmt/issues/3992, https://github.com/fmtlib/fmt/pull/3995, https://github.com/fmtlib/fmt/pull/4009, https://github.com/fmtlib/fmt/pull/4023). Thanks @hmbj, @phprus, @res2k, @Baardi, @matt77hias, @waywardmonkeys, @hmbj, @yakra, @prlw1, @Arghnews, @mtillmann0, @ShifftC, @eepp, @jimmy-park and @ChristianGebhardt. # 10.2.1 - 2024-01-04 - Fixed ABI compatibility with earlier 10.x versions (https://github.com/fmtlib/fmt/issues/3785, https://github.com/fmtlib/fmt/pull/3786). Thanks @saraedum. # 10.2.0 - 2024-01-01 - Added support for the `%j` specifier (the number of days) for `std::chrono::duration` (https://github.com/fmtlib/fmt/issues/3643, https://github.com/fmtlib/fmt/pull/3732). Thanks @intelfx. - Added support for the chrono suffix for days and changed the suffix for minutes from "m" to the correct "min" (https://github.com/fmtlib/fmt/issues/3662, https://github.com/fmtlib/fmt/pull/3664). For example ([godbolt](https://godbolt.org/z/9KhMnq9ba)): ```c++ #include int main() { fmt::print("{}\n", std::chrono::days(42)); // prints "42d" } ``` Thanks @Richardk2n. - Fixed an overflow in `std::chrono::time_point` formatting with large dates (https://github.com/fmtlib/fmt/issues/3725, https://github.com/fmtlib/fmt/pull/3727). Thanks @cschreib. - Added a formatter for `std::source_location` (https://github.com/fmtlib/fmt/pull/3730). For example ([godbolt](https://godbolt.org/z/YajfKjhhr)): ```c++ #include #include int main() { fmt::print("{}\n", std::source_location::current()); } ``` prints ``` /app/example.cpp:5:51: int main() ``` Thanks @felix642. - Added a formatter for `std::bitset` (https://github.com/fmtlib/fmt/pull/3660). For example ([godbolt](https://godbolt.org/z/bdEaGeYxe)): ```c++ #include #include int main() { fmt::print("{}\n", std::bitset<6>(42)); // prints "101010" } ``` Thanks @muggenhor. - Added an experimental `nested_formatter` that provides an easy way of applying a formatter to one or more subobjects while automatically handling width, fill and alignment. For example: ```c++ #include struct point { double x, y; }; template <> struct fmt::formatter : nested_formatter { auto format(point p, format_context& ctx) const { return write_padded(ctx, [=](auto out) { return format_to(out, "({}, {})", nested(p.x), nested(p.y)); }); } }; int main() { fmt::print("[{:>20.2f}]", point{1, 2}); } ``` prints ``` [ (1.00, 2.00)] ``` - Added the generic representation (`g`) to `std::filesystem::path` (https://github.com/fmtlib/fmt/issues/3715, https://github.com/fmtlib/fmt/pull/3729). For example: ```c++ #include #include int main() { fmt::print("{:g}\n", std::filesystem::path("C:\\foo")); } ``` prints `"C:/foo"` on Windows. Thanks @js324. - Made `format_as` work with references (https://github.com/fmtlib/fmt/pull/3739). Thanks @tchaikov. - Fixed formatting of invalid UTF-8 with precision (https://github.com/fmtlib/fmt/issues/3284). - Fixed an inconsistency between `fmt::to_string` and `fmt::format` (https://github.com/fmtlib/fmt/issues/3684). - Disallowed unsafe uses of `fmt::styled` (https://github.com/fmtlib/fmt/issues/3625): ```c++ auto s = fmt::styled(std::string("dangle"), fmt::emphasis::bold); fmt::print("{}\n", s); // compile error ``` Pass `fmt::styled(...)` as a parameter instead. - Added a null check when formatting a C string with the `s` specifier (https://github.com/fmtlib/fmt/issues/3706). - Disallowed the `c` specifier for `bool` (https://github.com/fmtlib/fmt/issues/3726, https://github.com/fmtlib/fmt/pull/3734). Thanks @js324. - Made the default formatting unlocalized in `fmt::ostream_formatter` for consistency with the rest of the library (https://github.com/fmtlib/fmt/issues/3460). - Fixed localized formatting in bases other than decimal (https://github.com/fmtlib/fmt/issues/3693, https://github.com/fmtlib/fmt/pull/3750). Thanks @js324. - Fixed a performance regression in experimental `fmt::ostream::print` (https://github.com/fmtlib/fmt/issues/3674). - Added synchronization with the underlying output stream when writing to the Windows console (https://github.com/fmtlib/fmt/pull/3668, https://github.com/fmtlib/fmt/issues/3688, https://github.com/fmtlib/fmt/pull/3689). Thanks @Roman-Koshelev and @dimztimz. - Changed to only export `format_error` when {fmt} is built as a shared library (https://github.com/fmtlib/fmt/issues/3626, https://github.com/fmtlib/fmt/pull/3627). Thanks @phprus. - Made `fmt::streamed` `constexpr`. (https://github.com/fmtlib/fmt/pull/3650). Thanks @muggenhor. - Made `fmt::format_int` `constexpr` (https://github.com/fmtlib/fmt/issues/4031, https://github.com/fmtlib/fmt/pull/4032). Thanks @dixlorenz. - Enabled `consteval` on older versions of MSVC (https://github.com/fmtlib/fmt/pull/3757). Thanks @phprus. - Added an option to build without `wchar_t` support on Windows (https://github.com/fmtlib/fmt/issues/3631, https://github.com/fmtlib/fmt/pull/3636). Thanks @glebm. - Improved build and CI configuration (https://github.com/fmtlib/fmt/pull/3679, https://github.com/fmtlib/fmt/issues/3701, https://github.com/fmtlib/fmt/pull/3702, https://github.com/fmtlib/fmt/pull/3749). Thanks @jcar87, @pklima and @tchaikov. - Fixed various warnings, compilation and test issues (https://github.com/fmtlib/fmt/issues/3607, https://github.com/fmtlib/fmt/pull/3610, https://github.com/fmtlib/fmt/pull/3624, https://github.com/fmtlib/fmt/pull/3630, https://github.com/fmtlib/fmt/pull/3634, https://github.com/fmtlib/fmt/pull/3638, https://github.com/fmtlib/fmt/issues/3645, https://github.com/fmtlib/fmt/issues/3646, https://github.com/fmtlib/fmt/pull/3647, https://github.com/fmtlib/fmt/pull/3652, https://github.com/fmtlib/fmt/issues/3654, https://github.com/fmtlib/fmt/pull/3663, https://github.com/fmtlib/fmt/issues/3670, https://github.com/fmtlib/fmt/pull/3680, https://github.com/fmtlib/fmt/issues/3694, https://github.com/fmtlib/fmt/pull/3695, https://github.com/fmtlib/fmt/pull/3699, https://github.com/fmtlib/fmt/issues/3705, https://github.com/fmtlib/fmt/issues/3710, https://github.com/fmtlib/fmt/issues/3712, https://github.com/fmtlib/fmt/pull/3713, https://github.com/fmtlib/fmt/issues/3714, https://github.com/fmtlib/fmt/pull/3716, https://github.com/fmtlib/fmt/pull/3723, https://github.com/fmtlib/fmt/issues/3738, https://github.com/fmtlib/fmt/issues/3740, https://github.com/fmtlib/fmt/pull/3741, https://github.com/fmtlib/fmt/pull/3743, https://github.com/fmtlib/fmt/issues/3745, https://github.com/fmtlib/fmt/pull/3747, https://github.com/fmtlib/fmt/pull/3748, https://github.com/fmtlib/fmt/pull/3751, https://github.com/fmtlib/fmt/pull/3754, https://github.com/fmtlib/fmt/pull/3755, https://github.com/fmtlib/fmt/issues/3760, https://github.com/fmtlib/fmt/pull/3762, https://github.com/fmtlib/fmt/issues/3763, https://github.com/fmtlib/fmt/pull/3764, https://github.com/fmtlib/fmt/issues/3774, https://github.com/fmtlib/fmt/pull/3779). Thanks @danakj, @vinayyadav3016, @cyyever, @phprus, @qimiko, @saschasc, @gsjaardema, @lazka, @Zhaojun-Liu, @carlsmedstad, @hotwatermorning, @cptFracassa, @kuguma, @PeterJohnson, @H1X4Dev, @asantoni, @eltociear, @msimberg, @tchaikov, @waywardmonkeys. - Improved documentation and README (https://github.com/fmtlib/fmt/issues/2086, https://github.com/fmtlib/fmt/issues/3637, https://github.com/fmtlib/fmt/pull/3642, https://github.com/fmtlib/fmt/pull/3653, https://github.com/fmtlib/fmt/pull/3655, https://github.com/fmtlib/fmt/pull/3661, https://github.com/fmtlib/fmt/issues/3673, https://github.com/fmtlib/fmt/pull/3677, https://github.com/fmtlib/fmt/pull/3737, https://github.com/fmtlib/fmt/issues/3742, https://github.com/fmtlib/fmt/pull/3744). Thanks @idzm, @perlun, @joycebrum, @fennewald, @reinhardt1053, @GeorgeLS. - Updated CI dependencies (https://github.com/fmtlib/fmt/pull/3615, https://github.com/fmtlib/fmt/pull/3622, https://github.com/fmtlib/fmt/pull/3623, https://github.com/fmtlib/fmt/pull/3666, https://github.com/fmtlib/fmt/pull/3696, https://github.com/fmtlib/fmt/pull/3697, https://github.com/fmtlib/fmt/pull/3759, https://github.com/fmtlib/fmt/pull/3782). # 10.1.1 - 2023-08-28 - Added formatters for `std::atomic` and `atomic_flag` (https://github.com/fmtlib/fmt/pull/3574, https://github.com/fmtlib/fmt/pull/3594). Thanks @wangzw and @AlexGuteniev. - Fixed an error about partial specialization of `formatter` after instantiation when compiled with gcc and C++20 (https://github.com/fmtlib/fmt/issues/3584). - Fixed compilation as a C++20 module with gcc and clang (https://github.com/fmtlib/fmt/issues/3587, https://github.com/fmtlib/fmt/pull/3597, https://github.com/fmtlib/fmt/pull/3605). Thanks @MathewBensonCode. - Made `fmt::to_string` work with types that have `format_as` overloads (https://github.com/fmtlib/fmt/pull/3575). Thanks @phprus. - Made `formatted_size` work with integral format specifiers at compile time (https://github.com/fmtlib/fmt/pull/3591). Thanks @elbeno. - Fixed a warning about the `no_unique_address` attribute on clang-cl (https://github.com/fmtlib/fmt/pull/3599). Thanks @lukester1975. - Improved compatibility with the legacy GBK encoding (https://github.com/fmtlib/fmt/issues/3598, https://github.com/fmtlib/fmt/pull/3599). Thanks @YuHuanTin. - Added OpenSSF Scorecard analysis (https://github.com/fmtlib/fmt/issues/3530, https://github.com/fmtlib/fmt/pull/3571). Thanks @joycebrum. - Updated CI dependencies (https://github.com/fmtlib/fmt/pull/3591, https://github.com/fmtlib/fmt/pull/3592, https://github.com/fmtlib/fmt/pull/3593, https://github.com/fmtlib/fmt/pull/3602). # 10.1.0 - 2023-08-12 - Optimized format string compilation resulting in up to 40% speed up in compiled `format_to` and \~4x speed up in compiled `format_to_n` on a concatenation benchmark (https://github.com/fmtlib/fmt/issues/3133, https://github.com/fmtlib/fmt/issues/3484). {fmt} 10.0: --------------------------------------------------------- Benchmark Time CPU Iterations --------------------------------------------------------- BM_format_to 78.9 ns 78.9 ns 8881746 BM_format_to_n 568 ns 568 ns 1232089 {fmt} 10.1: --------------------------------------------------------- Benchmark Time CPU Iterations --------------------------------------------------------- BM_format_to 54.9 ns 54.9 ns 12727944 BM_format_to_n 133 ns 133 ns 5257795 - Optimized storage of an empty allocator in `basic_memory_buffer` (https://github.com/fmtlib/fmt/pull/3485). Thanks @Minty-Meeo. - Added formatters for proxy references to elements of `std::vector` and `std::bitset` (https://github.com/fmtlib/fmt/issues/3567, https://github.com/fmtlib/fmt/pull/3570). For example ([godbolt](https://godbolt.org/z/zYb79Pvn8)): ```c++ #include #include int main() { auto v = std::vector{true}; fmt::print("{}", v[0]); } ``` Thanks @phprus and @felix642. - Fixed an ambiguous formatter specialization for containers that look like container adaptors such as `boost::flat_set` (https://github.com/fmtlib/fmt/issues/3556, https://github.com/fmtlib/fmt/pull/3561). Thanks @5chmidti. - Fixed compilation when formatting durations not convertible from `std::chrono::seconds` (https://github.com/fmtlib/fmt/pull/3430). Thanks @patlkli. - Made the `formatter` specialization for `char*` const-correct (https://github.com/fmtlib/fmt/pull/3432). Thanks @timsong-cpp. - Made `{}` and `{:}` handled consistently during compile-time checks (https://github.com/fmtlib/fmt/issues/3526). - Disallowed passing temporaries to `make_format_args` to improve API safety by preventing dangling references. - Improved the compile-time error for unformattable types (https://github.com/fmtlib/fmt/pull/3478). Thanks @BRevzin. - Improved the floating-point formatter (https://github.com/fmtlib/fmt/pull/3448, https://github.com/fmtlib/fmt/pull/3450). Thanks @florimond-collette. - Fixed handling of precision for `long double` larger than 64 bits. (https://github.com/fmtlib/fmt/issues/3539, https://github.com/fmtlib/fmt/issues/3564). - Made floating-point and chrono tests less platform-dependent (https://github.com/fmtlib/fmt/issues/3337, https://github.com/fmtlib/fmt/issues/3433, https://github.com/fmtlib/fmt/pull/3434). Thanks @phprus. - Removed the remnants of the Grisu floating-point formatter that has been replaced by Dragonbox in earlier versions. - Added `throw_format_error` to the public API (https://github.com/fmtlib/fmt/pull/3551). Thanks @mjerabek. - Made `FMT_THROW` assert even if assertions are disabled when compiling with exceptions disabled (https://github.com/fmtlib/fmt/issues/3418, https://github.com/fmtlib/fmt/pull/3439). Thanks @BRevzin. - Made `format_as` and `std::filesystem::path` formatter work with exotic code unit types. (https://github.com/fmtlib/fmt/pull/3457, https://github.com/fmtlib/fmt/pull/3476). Thanks @gix and @hmbj. - Added support for the `?` format specifier to `std::filesystem::path` and made the default unescaped for consistency with strings. - Deprecated the wide stream overload of `printf`. - Removed unused `basic_printf_parse_context`. - Improved RTTI detection used when formatting exceptions (https://github.com/fmtlib/fmt/pull/3468). Thanks @danakj. - Improved compatibility with VxWorks7 (https://github.com/fmtlib/fmt/pull/3467). Thanks @wenshan1. - Improved documentation (https://github.com/fmtlib/fmt/issues/3174, https://github.com/fmtlib/fmt/issues/3423, https://github.com/fmtlib/fmt/pull/3454, https://github.com/fmtlib/fmt/issues/3458, https://github.com/fmtlib/fmt/pull/3461, https://github.com/fmtlib/fmt/issues/3487, https://github.com/fmtlib/fmt/pull/3515). Thanks @zencatalyst, @rlalik and @mikecrowe. - Improved build and CI configurations (https://github.com/fmtlib/fmt/issues/3449, https://github.com/fmtlib/fmt/pull/3451, https://github.com/fmtlib/fmt/pull/3452, https://github.com/fmtlib/fmt/pull/3453, https://github.com/fmtlib/fmt/pull/3459, https://github.com/fmtlib/fmt/issues/3481, https://github.com/fmtlib/fmt/pull/3486, https://github.com/fmtlib/fmt/issues/3489, https://github.com/fmtlib/fmt/pull/3496, https://github.com/fmtlib/fmt/issues/3517, https://github.com/fmtlib/fmt/pull/3523, https://github.com/fmtlib/fmt/pull/3563). Thanks @joycebrum, @glebm, @phprus, @petrmanek, @setoye and @abouvier. - Fixed various warnings and compilation issues (https://github.com/fmtlib/fmt/issues/3408, https://github.com/fmtlib/fmt/issues/3424, https://github.com/fmtlib/fmt/issues/3444, https://github.com/fmtlib/fmt/pull/3446, https://github.com/fmtlib/fmt/pull/3475, https://github.com/fmtlib/fmt/pull/3482, https://github.com/fmtlib/fmt/issues/3492, https://github.com/fmtlib/fmt/pull/3493, https://github.com/fmtlib/fmt/pull/3508, https://github.com/fmtlib/fmt/issues/3509, https://github.com/fmtlib/fmt/issues/3533, https://github.com/fmtlib/fmt/pull/3542, https://github.com/fmtlib/fmt/issues/3543, https://github.com/fmtlib/fmt/issues/3540, https://github.com/fmtlib/fmt/pull/3544, https://github.com/fmtlib/fmt/issues/3548, https://github.com/fmtlib/fmt/pull/3549, https://github.com/fmtlib/fmt/pull/3550, https://github.com/fmtlib/fmt/pull/3552). Thanks @adesitter, @hmbj, @Minty-Meeo, @phprus, @TobiSchluter, @kieranclancy, @alexeedm, @jurihock, @Ozomahtli and @razaqq. # 10.0.0 - 2023-05-09 - Replaced Grisu with a new floating-point formatting algorithm for given precision (https://github.com/fmtlib/fmt/issues/3262, https://github.com/fmtlib/fmt/issues/2750, https://github.com/fmtlib/fmt/pull/3269, https://github.com/fmtlib/fmt/pull/3276). The new algorithm is based on Dragonbox already used for the shortest representation and gives substantial performance improvement: ![](https://user-images.githubusercontent.com/33922675/211956670-84891a09-6867-47d9-82fc-3230da7abe0f.png) - Red: new algorithm - Green: new algorithm with `FMT_USE_FULL_CACHE_DRAGONBOX` defined to 1 - Blue: old algorithm Thanks @jk-jeon. - Replaced `snprintf`-based hex float formatter with an internal implementation (https://github.com/fmtlib/fmt/pull/3179, https://github.com/fmtlib/fmt/pull/3203). This removes the last usage of `s(n)printf` in {fmt}. Thanks @phprus. - Fixed alignment of floating-point numbers with localization (https://github.com/fmtlib/fmt/issues/3263, https://github.com/fmtlib/fmt/pull/3272). Thanks @ShawnZhong. - Made handling of `#` consistent with `std::format`. - Improved C++20 module support (https://github.com/fmtlib/fmt/pull/3134, https://github.com/fmtlib/fmt/pull/3254, https://github.com/fmtlib/fmt/pull/3386, https://github.com/fmtlib/fmt/pull/3387, https://github.com/fmtlib/fmt/pull/3388, https://github.com/fmtlib/fmt/pull/3392, https://github.com/fmtlib/fmt/pull/3397, https://github.com/fmtlib/fmt/pull/3399, https://github.com/fmtlib/fmt/pull/3400). Thanks @laitingsheng, @Orvid and @DanielaE. - Switched to the [modules CMake library](https://github.com/vitaut/modules) which allows building {fmt} as a C++20 module with clang: CXX=clang++ cmake -DFMT_MODULE=ON . make - Made `format_as` work with any user-defined type and not just enums. For example ([godbolt](https://godbolt.org/z/b7rqhq5Kh)): ```c++ #include struct floaty_mc_floatface { double value; }; auto format_as(floaty_mc_floatface f) { return f.value; } int main() { fmt::print("{:8}\n", floaty_mc_floatface{0.42}); // prints " 0.42" } ``` - Removed deprecated implicit conversions for enums and conversions to primitive types for compatibility with `std::format` and to prevent potential ODR violations. Use `format_as` instead. - Added support for fill, align and width to the time point formatter (https://github.com/fmtlib/fmt/issues/3237, https://github.com/fmtlib/fmt/pull/3260, https://github.com/fmtlib/fmt/pull/3275). For example ([godbolt](https://godbolt.org/z/rKP6MGz6c)): ```c++ #include int main() { // prints " 2023" fmt::print("{:>8%Y}\n", std::chrono::system_clock::now()); } ``` Thanks @ShawnZhong. - Implemented formatting of subseconds (https://github.com/fmtlib/fmt/issues/2207, https://github.com/fmtlib/fmt/issues/3117, https://github.com/fmtlib/fmt/pull/3115, https://github.com/fmtlib/fmt/pull/3143, https://github.com/fmtlib/fmt/pull/3144, https://github.com/fmtlib/fmt/pull/3349). For example ([godbolt](https://godbolt.org/z/45738oGEo)): ```c++ #include int main() { // prints 01.234567 fmt::print("{:%S}\n", std::chrono::microseconds(1234567)); } ``` Thanks @patrickroocks @phprus and @BRevzin. - Added precision support to `%S` (https://github.com/fmtlib/fmt/pull/3148). Thanks @SappyJoy - Added support for `std::utc_time` (https://github.com/fmtlib/fmt/issues/3098, https://github.com/fmtlib/fmt/pull/3110). Thanks @patrickroocks. - Switched formatting of `std::chrono::system_clock` from local time to UTC for compatibility with the standard (https://github.com/fmtlib/fmt/issues/3199, https://github.com/fmtlib/fmt/pull/3230). Thanks @ned14. - Added support for `%Ez` and `%Oz` to chrono formatters. (https://github.com/fmtlib/fmt/issues/3220, https://github.com/fmtlib/fmt/pull/3222). Thanks @phprus. - Improved validation of format specifiers for `std::chrono::duration` (https://github.com/fmtlib/fmt/issues/3219, https://github.com/fmtlib/fmt/pull/3232). Thanks @ShawnZhong. - Fixed formatting of time points before the epoch (https://github.com/fmtlib/fmt/issues/3117, https://github.com/fmtlib/fmt/pull/3261). For example ([godbolt](https://godbolt.org/z/f7bcznb3W)): ```c++ #include int main() { auto t = std::chrono::system_clock::from_time_t(0) - std::chrono::milliseconds(250); fmt::print("{:%S}\n", t); // prints 59.750000000 } ``` Thanks @ShawnZhong. - Experimental: implemented glibc extension for padding seconds, minutes and hours (https://github.com/fmtlib/fmt/issues/2959, https://github.com/fmtlib/fmt/pull/3271). Thanks @ShawnZhong. - Added a formatter for `std::exception` (https://github.com/fmtlib/fmt/issues/2977, https://github.com/fmtlib/fmt/issues/3012, https://github.com/fmtlib/fmt/pull/3062, https://github.com/fmtlib/fmt/pull/3076, https://github.com/fmtlib/fmt/pull/3119). For example ([godbolt](https://godbolt.org/z/8xoWGs9e4)): ```c++ #include #include int main() { try { std::vector().at(0); } catch(const std::exception& e) { fmt::print("{}", e); } } ``` prints: vector::_M_range_check: __n (which is 0) >= this->size() (which is 0) on libstdc++. Thanks @zach2good and @phprus. - Moved `std::error_code` formatter from `fmt/os.h` to `fmt/std.h`. (https://github.com/fmtlib/fmt/pull/3125). Thanks @phprus. - Added formatters for standard container adapters: `std::priority_queue`, `std::queue` and `std::stack` (https://github.com/fmtlib/fmt/issues/3215, https://github.com/fmtlib/fmt/pull/3279). For example ([godbolt](https://godbolt.org/z/74h1xY9qK)): ```c++ #include #include #include int main() { auto s = std::stack>(); for (auto b: {true, false, true}) s.push(b); fmt::print("{}\n", s); // prints [true, false, true] } ``` Thanks @ShawnZhong. - Added a formatter for `std::optional` to `fmt/std.h` (https://github.com/fmtlib/fmt/issues/1367, https://github.com/fmtlib/fmt/pull/3303). Thanks @tom-huntington. - Fixed formatting of valueless by exception variants (https://github.com/fmtlib/fmt/pull/3347). Thanks @TheOmegaCarrot. - Made `fmt::ptr` accept `unique_ptr` with a custom deleter (https://github.com/fmtlib/fmt/pull/3177). Thanks @hmbj. - Fixed formatting of noncopyable ranges and nested ranges of chars (https://github.com/fmtlib/fmt/pull/3158 https://github.com/fmtlib/fmt/issues/3286, https://github.com/fmtlib/fmt/pull/3290). Thanks @BRevzin. - Fixed issues with formatting of paths and ranges of paths (https://github.com/fmtlib/fmt/issues/3319, https://github.com/fmtlib/fmt/pull/3321 https://github.com/fmtlib/fmt/issues/3322). Thanks @phprus. - Improved handling of invalid Unicode in paths. - Enabled compile-time checks on Apple clang 14 and later (https://github.com/fmtlib/fmt/pull/3331). Thanks @cloyce. - Improved compile-time checks of named arguments (https://github.com/fmtlib/fmt/issues/3105, https://github.com/fmtlib/fmt/pull/3214). Thanks @rbrich. - Fixed formatting when both alignment and `0` are given (https://github.com/fmtlib/fmt/issues/3236, https://github.com/fmtlib/fmt/pull/3248). Thanks @ShawnZhong. - Improved Unicode support in the experimental file API on Windows (https://github.com/fmtlib/fmt/issues/3234, https://github.com/fmtlib/fmt/pull/3293). Thanks @Fros1er. - Unified UTF transcoding (https://github.com/fmtlib/fmt/pull/3416). Thanks @phprus. - Added support for UTF-8 digit separators via an experimental locale facet (https://github.com/fmtlib/fmt/issues/1861). For example ([godbolt](https://godbolt.org/z/f7bcznb3W)): ```c++ auto loc = std::locale( std::locale(), new fmt::format_facet("’")); auto s = fmt::format(loc, "{:L}", 1000); ``` where `’` is U+2019 used as a digit separator in the de_CH locale. - Added an overload of `formatted_size` that takes a locale (https://github.com/fmtlib/fmt/issues/3084, https://github.com/fmtlib/fmt/pull/3087). Thanks @gerboengels. - Removed the deprecated `FMT_DEPRECATED_OSTREAM`. - Fixed a UB when using a null `std::string_view` with `fmt::to_string` or format string compilation (https://github.com/fmtlib/fmt/issues/3241, https://github.com/fmtlib/fmt/pull/3244). Thanks @phprus. - Added `starts_with` to the fallback `string_view` implementation (https://github.com/fmtlib/fmt/pull/3080). Thanks @phprus. - Added `fmt::basic_format_string::get()` for compatibility with `basic_format_string` (https://github.com/fmtlib/fmt/pull/3111). Thanks @huangqinjin. - Added `println` for compatibility with C++23 (https://github.com/fmtlib/fmt/pull/3267). Thanks @ShawnZhong. - Renamed the `FMT_EXPORT` macro for shared library usage to `FMT_LIB_EXPORT`. - Improved documentation (https://github.com/fmtlib/fmt/issues/3108, https://github.com/fmtlib/fmt/issues/3169, https://github.com/fmtlib/fmt/pull/3243). https://github.com/fmtlib/fmt/pull/3404, https://github.com/fmtlib/fmt/pull/4002). Thanks @Cleroth, @Vertexwahn and @yujincheng08. - Improved build configuration and tests (https://github.com/fmtlib/fmt/pull/3118, https://github.com/fmtlib/fmt/pull/3120, https://github.com/fmtlib/fmt/pull/3188, https://github.com/fmtlib/fmt/issues/3189, https://github.com/fmtlib/fmt/pull/3198, https://github.com/fmtlib/fmt/pull/3205, https://github.com/fmtlib/fmt/pull/3207, https://github.com/fmtlib/fmt/pull/3210, https://github.com/fmtlib/fmt/pull/3240, https://github.com/fmtlib/fmt/pull/3256, https://github.com/fmtlib/fmt/pull/3264, https://github.com/fmtlib/fmt/issues/3299, https://github.com/fmtlib/fmt/pull/3302, https://github.com/fmtlib/fmt/pull/3312, https://github.com/fmtlib/fmt/issues/3317, https://github.com/fmtlib/fmt/pull/3328, https://github.com/fmtlib/fmt/pull/3333, https://github.com/fmtlib/fmt/pull/3369, https://github.com/fmtlib/fmt/issues/3373, https://github.com/fmtlib/fmt/pull/3395, https://github.com/fmtlib/fmt/pull/3406, https://github.com/fmtlib/fmt/pull/3411). Thanks @dimztimz, @phprus, @DavidKorczynski, @ChrisThrasher, @FrancoisCarouge, @kennyweiss, @luzpaz, @codeinred, @Mixaill, @joycebrum, @kevinhwang and @Vertexwahn. - Fixed a regression in handling empty format specifiers after a colon (`{:}`) (https://github.com/fmtlib/fmt/pull/3086). Thanks @oxidase. - Worked around a broken implementation of `std::is_constant_evaluated` in some versions of libstdc++ on clang (https://github.com/fmtlib/fmt/issues/3247, https://github.com/fmtlib/fmt/pull/3281). Thanks @phprus. - Fixed formatting of volatile variables (https://github.com/fmtlib/fmt/pull/3068). - Fixed various warnings and compilation issues (https://github.com/fmtlib/fmt/pull/3057, https://github.com/fmtlib/fmt/pull/3066, https://github.com/fmtlib/fmt/pull/3072, https://github.com/fmtlib/fmt/pull/3082, https://github.com/fmtlib/fmt/pull/3091, https://github.com/fmtlib/fmt/issues/3092, https://github.com/fmtlib/fmt/pull/3093, https://github.com/fmtlib/fmt/pull/3095, https://github.com/fmtlib/fmt/issues/3096, https://github.com/fmtlib/fmt/pull/3097, https://github.com/fmtlib/fmt/issues/3128, https://github.com/fmtlib/fmt/pull/3129, https://github.com/fmtlib/fmt/pull/3137, https://github.com/fmtlib/fmt/pull/3139, https://github.com/fmtlib/fmt/issues/3140, https://github.com/fmtlib/fmt/pull/3142, https://github.com/fmtlib/fmt/issues/3149, https://github.com/fmtlib/fmt/pull/3150, https://github.com/fmtlib/fmt/issues/3154, https://github.com/fmtlib/fmt/issues/3163, https://github.com/fmtlib/fmt/issues/3178, https://github.com/fmtlib/fmt/pull/3184, https://github.com/fmtlib/fmt/pull/3196, https://github.com/fmtlib/fmt/issues/3204, https://github.com/fmtlib/fmt/pull/3206, https://github.com/fmtlib/fmt/pull/3208, https://github.com/fmtlib/fmt/issues/3213, https://github.com/fmtlib/fmt/pull/3216, https://github.com/fmtlib/fmt/issues/3224, https://github.com/fmtlib/fmt/issues/3226, https://github.com/fmtlib/fmt/issues/3228, https://github.com/fmtlib/fmt/pull/3229, https://github.com/fmtlib/fmt/pull/3259, https://github.com/fmtlib/fmt/issues/3274, https://github.com/fmtlib/fmt/issues/3287, https://github.com/fmtlib/fmt/pull/3288, https://github.com/fmtlib/fmt/issues/3292, https://github.com/fmtlib/fmt/pull/3295, https://github.com/fmtlib/fmt/pull/3296, https://github.com/fmtlib/fmt/issues/3298, https://github.com/fmtlib/fmt/issues/3325, https://github.com/fmtlib/fmt/pull/3326, https://github.com/fmtlib/fmt/issues/3334, https://github.com/fmtlib/fmt/issues/3342, https://github.com/fmtlib/fmt/pull/3343, https://github.com/fmtlib/fmt/issues/3351, https://github.com/fmtlib/fmt/pull/3352, https://github.com/fmtlib/fmt/pull/3362, https://github.com/fmtlib/fmt/issues/3365, https://github.com/fmtlib/fmt/pull/3366, https://github.com/fmtlib/fmt/pull/3374, https://github.com/fmtlib/fmt/issues/3377, https://github.com/fmtlib/fmt/pull/3378, https://github.com/fmtlib/fmt/issues/3381, https://github.com/fmtlib/fmt/pull/3398, https://github.com/fmtlib/fmt/pull/3413, https://github.com/fmtlib/fmt/issues/3415). Thanks @phprus, @gsjaardema, @NewbieOrange, @EngineLessCC, @asmaloney, @HazardyKnusperkeks, @sergiud, @Youw, @thesmurph, @czudziakm, @Roman-Koshelev, @chronoxor, @ShawnZhong, @russelltg, @glebm, @tmartin-gh, @Zhaojun-Liu, @louiswins and @mogemimi. # 9.1.0 - 2022-08-27 - `fmt::formatted_size` now works at compile time (https://github.com/fmtlib/fmt/pull/3026). For example ([godbolt](https://godbolt.org/z/1MW5rMdf8)): ```c++ #include int main() { using namespace fmt::literals; constexpr size_t n = fmt::formatted_size("{}"_cf, 42); fmt::print("{}\n", n); // prints 2 } ``` Thanks @marksantaniello. - Fixed handling of invalid UTF-8 (https://github.com/fmtlib/fmt/pull/3038, https://github.com/fmtlib/fmt/pull/3044, https://github.com/fmtlib/fmt/pull/3056). Thanks @phprus and @skeeto. - Improved Unicode support in `ostream` overloads of `print` (https://github.com/fmtlib/fmt/pull/2994, https://github.com/fmtlib/fmt/pull/3001, https://github.com/fmtlib/fmt/pull/3025). Thanks @dimztimz. - Fixed handling of the sign specifier in localized formatting on systems with 32-bit `wchar_t` (https://github.com/fmtlib/fmt/issues/3041). - Added support for wide streams to `fmt::streamed` (https://github.com/fmtlib/fmt/pull/2994). Thanks @phprus. - Added the `n` specifier that disables the output of delimiters when formatting ranges (https://github.com/fmtlib/fmt/pull/2981, https://github.com/fmtlib/fmt/pull/2983). For example ([godbolt](https://godbolt.org/z/roKqGdj8c)): ```c++ #include #include int main() { auto v = std::vector{1, 2, 3}; fmt::print("{:n}\n", v); // prints 1, 2, 3 } ``` Thanks @BRevzin. - Worked around problematic `std::string_view` constructors introduced in C++23 (https://github.com/fmtlib/fmt/issues/3030, https://github.com/fmtlib/fmt/issues/3050). Thanks @strega-nil-ms. - Improve handling (exclusion) of recursive ranges (https://github.com/fmtlib/fmt/issues/2968, https://github.com/fmtlib/fmt/pull/2974). Thanks @Dani-Hub. - Improved error reporting in format string compilation (https://github.com/fmtlib/fmt/issues/3055). - Improved the implementation of [Dragonbox](https://github.com/jk-jeon/dragonbox), the algorithm used for the default floating-point formatting (https://github.com/fmtlib/fmt/pull/2984). Thanks @jk-jeon. - Fixed issues with floating-point formatting on exotic platforms. - Improved the implementation of chrono formatting (https://github.com/fmtlib/fmt/pull/3010). Thanks @phprus. - Improved documentation (https://github.com/fmtlib/fmt/pull/2966, https://github.com/fmtlib/fmt/pull/3009, https://github.com/fmtlib/fmt/issues/3020, https://github.com/fmtlib/fmt/pull/3037). Thanks @mwinterb, @jcelerier and @remiburtin. - Improved build configuration (https://github.com/fmtlib/fmt/pull/2991, https://github.com/fmtlib/fmt/pull/2995, https://github.com/fmtlib/fmt/issues/3004, https://github.com/fmtlib/fmt/pull/3007, https://github.com/fmtlib/fmt/pull/3040). Thanks @dimztimz and @hwhsu1231. - Fixed various warnings and compilation issues (https://github.com/fmtlib/fmt/issues/2969, https://github.com/fmtlib/fmt/pull/2971, https://github.com/fmtlib/fmt/issues/2975, https://github.com/fmtlib/fmt/pull/2982, https://github.com/fmtlib/fmt/pull/2985, https://github.com/fmtlib/fmt/issues/2988, https://github.com/fmtlib/fmt/issues/2989, https://github.com/fmtlib/fmt/issues/3000, https://github.com/fmtlib/fmt/issues/3006, https://github.com/fmtlib/fmt/issues/3014, https://github.com/fmtlib/fmt/issues/3015, https://github.com/fmtlib/fmt/pull/3021, https://github.com/fmtlib/fmt/issues/3023, https://github.com/fmtlib/fmt/pull/3024, https://github.com/fmtlib/fmt/pull/3029, https://github.com/fmtlib/fmt/pull/3043, https://github.com/fmtlib/fmt/issues/3052, https://github.com/fmtlib/fmt/pull/3053, https://github.com/fmtlib/fmt/pull/3054). Thanks @h-friederich, @dimztimz, @olupton, @bernhardmgruber and @phprus. # 9.0.0 - 2022-07-04 - Switched to the internal floating point formatter for all decimal presentation formats. In particular this results in consistent rounding on all platforms and removing the `s[n]printf` fallback for decimal FP formatting. - Compile-time floating point formatting no longer requires the header-only mode. For example ([godbolt](https://godbolt.org/z/G37PTeG3b)): ```c++ #include #include consteval auto compile_time_dtoa(double value) -> std::array { auto result = std::array(); fmt::format_to(result.data(), FMT_COMPILE("{}"), value); return result; } constexpr auto answer = compile_time_dtoa(0.42); ``` works with the default settings. - Improved the implementation of [Dragonbox](https://github.com/jk-jeon/dragonbox), the algorithm used for the default floating-point formatting (https://github.com/fmtlib/fmt/pull/2713, https://github.com/fmtlib/fmt/pull/2750). Thanks @jk-jeon. - Made `fmt::to_string` work with `__float128`. This uses the internal FP formatter and works even on system without `__float128` support in `[s]printf`. - Disabled automatic `std::ostream` insertion operator (`operator<<`) discovery when `fmt/ostream.h` is included to prevent ODR violations. You can get the old behavior by defining `FMT_DEPRECATED_OSTREAM` but this will be removed in the next major release. Use `fmt::streamed` or `fmt::ostream_formatter` to enable formatting via `std::ostream` instead. - Added `fmt::ostream_formatter` that can be used to write `formatter` specializations that perform formatting via `std::ostream`. For example ([godbolt](https://godbolt.org/z/5sEc5qMsf)): ```c++ #include struct date { int year, month, day; friend std::ostream& operator<<(std::ostream& os, const date& d) { return os << d.year << '-' << d.month << '-' << d.day; } }; template <> struct fmt::formatter : ostream_formatter {}; std::string s = fmt::format("The date is {}", date{2012, 12, 9}); // s == "The date is 2012-12-9" ``` - Added the `fmt::streamed` function that takes an object and formats it via `std::ostream`. For example ([godbolt](https://godbolt.org/z/5G3346G1f)): ```c++ #include #include int main() { fmt::print("Current thread id: {}\n", fmt::streamed(std::this_thread::get_id())); } ``` Note that `fmt/std.h` provides a `formatter` specialization for `std::thread::id` so you don\'t need to format it via `std::ostream`. - Deprecated implicit conversions of unscoped enums to integers for consistency with scoped enums. - Added an argument-dependent lookup based `format_as` extension API to simplify formatting of enums. - Added experimental `std::variant` formatting support (https://github.com/fmtlib/fmt/pull/2941). For example ([godbolt](https://godbolt.org/z/KG9z6cq68)): ```c++ #include #include int main() { auto v = std::variant(42); fmt::print("{}\n", v); } ``` prints: variant(42) Thanks @jehelset. - Added experimental `std::filesystem::path` formatting support (https://github.com/fmtlib/fmt/issues/2865, https://github.com/fmtlib/fmt/pull/2902, https://github.com/fmtlib/fmt/issues/2917, https://github.com/fmtlib/fmt/pull/2918). For example ([godbolt](https://godbolt.org/z/o44dMexEb)): ```c++ #include #include int main() { fmt::print("There is no place like {}.", std::filesystem::path("/home")); } ``` prints: There is no place like "/home". Thanks @phprus. - Added a `std::thread::id` formatter to `fmt/std.h`. For example ([godbolt](https://godbolt.org/z/j1azbYf3E)): ```c++ #include #include int main() { fmt::print("Current thread id: {}\n", std::this_thread::get_id()); } ``` - Added `fmt::styled` that applies a text style to an individual argument (https://github.com/fmtlib/fmt/pull/2793). For example ([godbolt](https://godbolt.org/z/vWGW7v5M6)): ```c++ #include #include int main() { auto now = std::chrono::system_clock::now(); fmt::print( "[{}] {}: {}\n", fmt::styled(now, fmt::emphasis::bold), fmt::styled("error", fg(fmt::color::red)), "something went wrong"); } ``` prints ![](https://user-images.githubusercontent.com/576385/175071215-12809244-dab0-4005-96d8-7cd911c964d5.png) Thanks @rbrugo. - Made `fmt::print` overload for text styles correctly handle UTF-8 (https://github.com/fmtlib/fmt/issues/2681, https://github.com/fmtlib/fmt/pull/2701). Thanks @AlexGuteniev. - Fixed Unicode handling when writing to an ostream. - Added support for nested specifiers to range formatting (https://github.com/fmtlib/fmt/pull/2673). For example ([godbolt](https://godbolt.org/z/xd3Gj38cf)): ```c++ #include #include int main() { fmt::print("{::#x}\n", std::vector{10, 20, 30}); } ``` prints `[0xa, 0x14, 0x1e]`. Thanks @BRevzin. - Implemented escaping of wide strings in ranges (https://github.com/fmtlib/fmt/pull/2904). Thanks @phprus. - Added support for ranges with `begin` / `end` found via the argument-dependent lookup (https://github.com/fmtlib/fmt/pull/2807). Thanks @rbrugo. - Fixed formatting of certain kinds of ranges of ranges (https://github.com/fmtlib/fmt/pull/2787). Thanks @BRevzin. - Fixed handling of maps with element types other than `std::pair` (https://github.com/fmtlib/fmt/pull/2944). Thanks @BrukerJWD. - Made tuple formatter enabled only if elements are formattable (https://github.com/fmtlib/fmt/issues/2939, https://github.com/fmtlib/fmt/pull/2940). Thanks @jehelset. - Made `fmt::join` compatible with format string compilation (https://github.com/fmtlib/fmt/issues/2719, https://github.com/fmtlib/fmt/pull/2720). Thanks @phprus. - Made compile-time checks work with named arguments of custom types and `std::ostream` `print` overloads (https://github.com/fmtlib/fmt/issues/2816, https://github.com/fmtlib/fmt/issues/2817, https://github.com/fmtlib/fmt/pull/2819). Thanks @timsong-cpp. - Removed `make_args_checked` because it is no longer needed for compile-time checks (https://github.com/fmtlib/fmt/pull/2760). Thanks @phprus. - Removed the following deprecated APIs: `_format`, `arg_join`, the `format_to` overload that takes a memory buffer, `[v]fprintf` that takes an `ostream`. - Removed the deprecated implicit conversion of `[const] signed char*` and `[const] unsigned char*` to C strings. - Removed the deprecated `fmt/locale.h`. - Replaced the deprecated `fileno()` with `descriptor()` in `buffered_file`. - Moved `to_string_view` to the `detail` namespace since it\'s an implementation detail. - Made access mode of a created file consistent with `fopen` by setting `S_IWGRP` and `S_IWOTH` (https://github.com/fmtlib/fmt/pull/2733). Thanks @arogge. - Removed a redundant buffer resize when formatting to `std::ostream` (https://github.com/fmtlib/fmt/issues/2842, https://github.com/fmtlib/fmt/pull/2843). Thanks @jcelerier. - Made precision computation for strings consistent with width (https://github.com/fmtlib/fmt/issues/2888). - Fixed handling of locale separators in floating point formatting (https://github.com/fmtlib/fmt/issues/2830). - Made sign specifiers work with `__int128_t` (https://github.com/fmtlib/fmt/issues/2773). - Improved support for systems such as CHERI with extra data stored in pointers (https://github.com/fmtlib/fmt/pull/2932). Thanks @davidchisnall. - Improved documentation (https://github.com/fmtlib/fmt/pull/2706, https://github.com/fmtlib/fmt/pull/2712, https://github.com/fmtlib/fmt/pull/2789, https://github.com/fmtlib/fmt/pull/2803, https://github.com/fmtlib/fmt/pull/2805, https://github.com/fmtlib/fmt/pull/2815, https://github.com/fmtlib/fmt/pull/2924). Thanks @BRevzin, @Pokechu22, @setoye, @rtobar, @rbrugo, @anoonD and @leha-bot. - Improved build configuration (https://github.com/fmtlib/fmt/pull/2766, https://github.com/fmtlib/fmt/pull/2772, https://github.com/fmtlib/fmt/pull/2836, https://github.com/fmtlib/fmt/pull/2852, https://github.com/fmtlib/fmt/pull/2907, https://github.com/fmtlib/fmt/pull/2913, https://github.com/fmtlib/fmt/pull/2914). Thanks @kambala-decapitator, @mattiasljungstrom, @kieselnb, @nathannaveen and @Vertexwahn. - Fixed various warnings and compilation issues (https://github.com/fmtlib/fmt/issues/2408, https://github.com/fmtlib/fmt/issues/2507, https://github.com/fmtlib/fmt/issues/2697, https://github.com/fmtlib/fmt/issues/2715, https://github.com/fmtlib/fmt/issues/2717, https://github.com/fmtlib/fmt/pull/2722, https://github.com/fmtlib/fmt/pull/2724, https://github.com/fmtlib/fmt/pull/2725, https://github.com/fmtlib/fmt/issues/2726, https://github.com/fmtlib/fmt/pull/2728, https://github.com/fmtlib/fmt/pull/2732, https://github.com/fmtlib/fmt/issues/2738, https://github.com/fmtlib/fmt/pull/2742, https://github.com/fmtlib/fmt/issues/2744, https://github.com/fmtlib/fmt/issues/2745, https://github.com/fmtlib/fmt/issues/2746, https://github.com/fmtlib/fmt/issues/2754, https://github.com/fmtlib/fmt/pull/2755, https://github.com/fmtlib/fmt/issues/2757, https://github.com/fmtlib/fmt/pull/2758, https://github.com/fmtlib/fmt/issues/2761, https://github.com/fmtlib/fmt/pull/2762, https://github.com/fmtlib/fmt/issues/2763, https://github.com/fmtlib/fmt/pull/2765, https://github.com/fmtlib/fmt/issues/2769, https://github.com/fmtlib/fmt/pull/2770, https://github.com/fmtlib/fmt/issues/2771, https://github.com/fmtlib/fmt/issues/2777, https://github.com/fmtlib/fmt/pull/2779, https://github.com/fmtlib/fmt/pull/2782, https://github.com/fmtlib/fmt/pull/2783, https://github.com/fmtlib/fmt/issues/2794, https://github.com/fmtlib/fmt/issues/2796, https://github.com/fmtlib/fmt/pull/2797, https://github.com/fmtlib/fmt/pull/2801, https://github.com/fmtlib/fmt/pull/2802, https://github.com/fmtlib/fmt/issues/2808, https://github.com/fmtlib/fmt/issues/2818, https://github.com/fmtlib/fmt/pull/2819, https://github.com/fmtlib/fmt/issues/2829, https://github.com/fmtlib/fmt/issues/2835, https://github.com/fmtlib/fmt/issues/2848, https://github.com/fmtlib/fmt/issues/2860, https://github.com/fmtlib/fmt/pull/2861, https://github.com/fmtlib/fmt/pull/2882, https://github.com/fmtlib/fmt/issues/2886, https://github.com/fmtlib/fmt/issues/2891, https://github.com/fmtlib/fmt/pull/2892, https://github.com/fmtlib/fmt/issues/2895, https://github.com/fmtlib/fmt/issues/2896, https://github.com/fmtlib/fmt/pull/2903, https://github.com/fmtlib/fmt/issues/2906, https://github.com/fmtlib/fmt/issues/2908, https://github.com/fmtlib/fmt/pull/2909, https://github.com/fmtlib/fmt/issues/2920, https://github.com/fmtlib/fmt/pull/2922, https://github.com/fmtlib/fmt/pull/2927, https://github.com/fmtlib/fmt/pull/2929, https://github.com/fmtlib/fmt/issues/2936, https://github.com/fmtlib/fmt/pull/2937, https://github.com/fmtlib/fmt/pull/2938, https://github.com/fmtlib/fmt/pull/2951, https://github.com/fmtlib/fmt/issues/2954, https://github.com/fmtlib/fmt/pull/2957, https://github.com/fmtlib/fmt/issues/2958, https://github.com/fmtlib/fmt/pull/2960). Thanks @matrackif @Tobi823, @ivan-volnov, @VasiliPupkin256, @federico-busato, @barcharcraz, @jk-jeon, @HazardyKnusperkeks, @dalboris, @seanm, @gsjaardema, @timsong-cpp, @seanm, @frithrah, @chronoxor, @Agga, @madmaxoft, @JurajX, @phprus and @Dani-Hub. # 8.1.1 - 2022-01-06 - Restored ABI compatibility with version 8.0.x (https://github.com/fmtlib/fmt/issues/2695, https://github.com/fmtlib/fmt/pull/2696). Thanks @saraedum. - Fixed chrono formatting on big endian systems (https://github.com/fmtlib/fmt/issues/2698, https://github.com/fmtlib/fmt/pull/2699). Thanks @phprus and @xvitaly. - Fixed a linkage error with mingw (https://github.com/fmtlib/fmt/issues/2691, https://github.com/fmtlib/fmt/pull/2692). Thanks @rbberger. # 8.1.0 - 2022-01-02 - Optimized chrono formatting (https://github.com/fmtlib/fmt/pull/2500, https://github.com/fmtlib/fmt/pull/2537, https://github.com/fmtlib/fmt/issues/2541, https://github.com/fmtlib/fmt/pull/2544, https://github.com/fmtlib/fmt/pull/2550, https://github.com/fmtlib/fmt/pull/2551, https://github.com/fmtlib/fmt/pull/2576, https://github.com/fmtlib/fmt/issues/2577, https://github.com/fmtlib/fmt/pull/2586, https://github.com/fmtlib/fmt/pull/2591, https://github.com/fmtlib/fmt/pull/2594, https://github.com/fmtlib/fmt/pull/2602, https://github.com/fmtlib/fmt/pull/2617, https://github.com/fmtlib/fmt/issues/2628, https://github.com/fmtlib/fmt/pull/2633, https://github.com/fmtlib/fmt/issues/2670, https://github.com/fmtlib/fmt/pull/2671). Processing of some specifiers such as `%z` and `%Y` is now up to 10-20 times faster, for example on GCC 11 with libstdc++: ---------------------------------------------------------------------------- Benchmark Before After ---------------------------------------------------------------------------- FMTFormatter_z 261 ns 26.3 ns FMTFormatterCompile_z 246 ns 11.6 ns FMTFormatter_Y 263 ns 26.1 ns FMTFormatterCompile_Y 244 ns 10.5 ns ---------------------------------------------------------------------------- Thanks @phprus and @toughengineer. - Implemented subsecond formatting for chrono durations (https://github.com/fmtlib/fmt/pull/2623). For example ([godbolt](https://godbolt.org/z/es7vWTETe)): ```c++ #include int main() { fmt::print("{:%S}", std::chrono::milliseconds(1234)); } ``` prints \"01.234\". Thanks @matrackif. - Fixed handling of precision 0 when formatting chrono durations (https://github.com/fmtlib/fmt/issues/2587, https://github.com/fmtlib/fmt/pull/2588). Thanks @lukester1975. - Fixed an overflow on invalid inputs in the `tm` formatter (https://github.com/fmtlib/fmt/pull/2564). Thanks @phprus. - Added `fmt::group_digits` that formats integers with a non-localized digit separator (comma) for groups of three digits. For example ([godbolt](https://godbolt.org/z/TxGxG9Poq)): ```c++ #include int main() { fmt::print("{} dollars", fmt::group_digits(1000000)); } ``` prints \"1,000,000 dollars\". - Added support for faint, conceal, reverse and blink text styles (https://github.com/fmtlib/fmt/pull/2394): Thanks @benit8 and @data-man. - Added experimental support for compile-time floating point formatting (https://github.com/fmtlib/fmt/pull/2426, https://github.com/fmtlib/fmt/pull/2470). It is currently limited to the header-only mode. Thanks @alexezeder. - Added UDL-based named argument support to compile-time format string checks (https://github.com/fmtlib/fmt/issues/2640, https://github.com/fmtlib/fmt/pull/2649). For example ([godbolt](https://godbolt.org/z/ohGbbvonv)): ```c++ #include int main() { using namespace fmt::literals; fmt::print("{answer:s}", "answer"_a=42); } ``` gives a compile-time error on compilers with C++20 `consteval` and non-type template parameter support (gcc 10+) because `s` is not a valid format specifier for an integer. Thanks @alexezeder. - Implemented escaping of string range elements. For example ([godbolt](https://godbolt.org/z/rKvM1vKf3)): ```c++ #include #include int main() { fmt::print("{}", std::vector{"\naan"}); } ``` is now printed as: ["\naan"] instead of: [" aan"] - Added an experimental `?` specifier for escaping strings. (https://github.com/fmtlib/fmt/pull/2674). Thanks @BRevzin. - Switched to JSON-like representation of maps and sets for consistency with Python\'s `str.format`. For example ([godbolt](https://godbolt.org/z/seKjoY9W5)): ```c++ #include #include int main() { fmt::print("{}", std::map{{"answer", 42}}); } ``` is now printed as: {"answer": 42} - Extended `fmt::join` to support C++20-only ranges (https://github.com/fmtlib/fmt/pull/2549). Thanks @BRevzin. - Optimized handling of non-const-iterable ranges and implemented initial support for non-const-formattable types. - Disabled implicit conversions of scoped enums to integers that was accidentally introduced in earlier versions (https://github.com/fmtlib/fmt/pull/1841). - Deprecated implicit conversion of `[const] signed char*` and `[const] unsigned char*` to C strings. - Deprecated `_format`, a legacy UDL-based format API (https://github.com/fmtlib/fmt/pull/2646). Thanks @alexezeder. - Marked `format`, `formatted_size` and `to_string` as `[[nodiscard]]` (https://github.com/fmtlib/fmt/pull/2612). @0x8000-0000. - Added missing diagnostic when trying to format function and member pointers as well as objects convertible to pointers which is explicitly disallowed (https://github.com/fmtlib/fmt/issues/2598, https://github.com/fmtlib/fmt/pull/2609, https://github.com/fmtlib/fmt/pull/2610). Thanks @AlexGuteniev. - Optimized writing to a contiguous buffer with `format_to_n` (https://github.com/fmtlib/fmt/pull/2489). Thanks @Roman-Koshelev. - Optimized writing to non-`char` buffers (https://github.com/fmtlib/fmt/pull/2477). Thanks @Roman-Koshelev. - Decimal point is now localized when using the `L` specifier. - Improved floating point formatter implementation (https://github.com/fmtlib/fmt/pull/2498, https://github.com/fmtlib/fmt/pull/2499). Thanks @Roman-Koshelev. - Fixed handling of very large precision in fixed format (https://github.com/fmtlib/fmt/pull/2616). - Made a table of cached powers used in FP formatting static (https://github.com/fmtlib/fmt/pull/2509). Thanks @jk-jeon. - Resolved a lookup ambiguity with C++20 format-related functions due to ADL (https://github.com/fmtlib/fmt/issues/2639, https://github.com/fmtlib/fmt/pull/2641). Thanks @mkurdej. - Removed unnecessary inline namespace qualification (https://github.com/fmtlib/fmt/issues/2642, https://github.com/fmtlib/fmt/pull/2643). Thanks @mkurdej. - Implemented argument forwarding in `format_to_n` (https://github.com/fmtlib/fmt/issues/2462, https://github.com/fmtlib/fmt/pull/2463). Thanks @owent. - Fixed handling of implicit conversions in `fmt::to_string` and format string compilation (https://github.com/fmtlib/fmt/issues/2565). - Changed the default access mode of files created by `fmt::output_file` to `-rw-r--r--` for consistency with `fopen` (https://github.com/fmtlib/fmt/issues/2530). - Make `fmt::ostream::flush` public (https://github.com/fmtlib/fmt/issues/2435). - Improved C++14/17 attribute detection (https://github.com/fmtlib/fmt/pull/2615). Thanks @AlexGuteniev. - Improved `consteval` detection for MSVC (https://github.com/fmtlib/fmt/pull/2559). Thanks @DanielaE. - Improved documentation (https://github.com/fmtlib/fmt/issues/2406, https://github.com/fmtlib/fmt/pull/2446, https://github.com/fmtlib/fmt/issues/2493, https://github.com/fmtlib/fmt/issues/2513, https://github.com/fmtlib/fmt/pull/2515, https://github.com/fmtlib/fmt/issues/2522, https://github.com/fmtlib/fmt/pull/2562, https://github.com/fmtlib/fmt/pull/2575, https://github.com/fmtlib/fmt/pull/2606, https://github.com/fmtlib/fmt/pull/2620, https://github.com/fmtlib/fmt/issues/2676). Thanks @sobolevn, @UnePierre, @zhsj, @phprus, @ericcurtin and @Lounarok. - Improved fuzzers and added a fuzzer for chrono timepoint formatting (https://github.com/fmtlib/fmt/pull/2461, https://github.com/fmtlib/fmt/pull/2469). @pauldreik, - Added the `FMT_SYSTEM_HEADERS` CMake option setting which marks {fmt}\'s headers as system. It can be used to suppress warnings (https://github.com/fmtlib/fmt/issues/2644, https://github.com/fmtlib/fmt/pull/2651). Thanks @alexezeder. - Added the Bazel build system support (https://github.com/fmtlib/fmt/pull/2505, https://github.com/fmtlib/fmt/pull/2516). Thanks @Vertexwahn. - Improved build configuration and tests (https://github.com/fmtlib/fmt/issues/2437, https://github.com/fmtlib/fmt/pull/2558, https://github.com/fmtlib/fmt/pull/2648, https://github.com/fmtlib/fmt/pull/2650, https://github.com/fmtlib/fmt/pull/2663, https://github.com/fmtlib/fmt/pull/2677). Thanks @DanielaE, @alexezeder and @phprus. - Fixed various warnings and compilation issues (https://github.com/fmtlib/fmt/pull/2353, https://github.com/fmtlib/fmt/pull/2356, https://github.com/fmtlib/fmt/pull/2399, https://github.com/fmtlib/fmt/issues/2408, https://github.com/fmtlib/fmt/pull/2414, https://github.com/fmtlib/fmt/pull/2427, https://github.com/fmtlib/fmt/pull/2432, https://github.com/fmtlib/fmt/pull/2442, https://github.com/fmtlib/fmt/pull/2434, https://github.com/fmtlib/fmt/issues/2439, https://github.com/fmtlib/fmt/pull/2447, https://github.com/fmtlib/fmt/pull/2450, https://github.com/fmtlib/fmt/issues/2455, https://github.com/fmtlib/fmt/issues/2465, https://github.com/fmtlib/fmt/issues/2472, https://github.com/fmtlib/fmt/issues/2474, https://github.com/fmtlib/fmt/pull/2476, https://github.com/fmtlib/fmt/issues/2478, https://github.com/fmtlib/fmt/issues/2479, https://github.com/fmtlib/fmt/issues/2481, https://github.com/fmtlib/fmt/pull/2482, https://github.com/fmtlib/fmt/pull/2483, https://github.com/fmtlib/fmt/issues/2490, https://github.com/fmtlib/fmt/pull/2491, https://github.com/fmtlib/fmt/pull/2510, https://github.com/fmtlib/fmt/pull/2518, https://github.com/fmtlib/fmt/issues/2528, https://github.com/fmtlib/fmt/pull/2529, https://github.com/fmtlib/fmt/pull/2539, https://github.com/fmtlib/fmt/issues/2540, https://github.com/fmtlib/fmt/pull/2545, https://github.com/fmtlib/fmt/pull/2555, https://github.com/fmtlib/fmt/issues/2557, https://github.com/fmtlib/fmt/issues/2570, https://github.com/fmtlib/fmt/pull/2573, https://github.com/fmtlib/fmt/pull/2582, https://github.com/fmtlib/fmt/issues/2605, https://github.com/fmtlib/fmt/pull/2611, https://github.com/fmtlib/fmt/pull/2647, https://github.com/fmtlib/fmt/issues/2627, https://github.com/fmtlib/fmt/pull/2630, https://github.com/fmtlib/fmt/issues/2635, https://github.com/fmtlib/fmt/issues/2638, https://github.com/fmtlib/fmt/issues/2653, https://github.com/fmtlib/fmt/issues/2654, https://github.com/fmtlib/fmt/issues/2661, https://github.com/fmtlib/fmt/pull/2664, https://github.com/fmtlib/fmt/pull/2684). Thanks @DanielaE, @mwinterb, @cdacamar, @TrebledJ, @bodomartin, @cquammen, @white238, @mmarkeloff, @palacaze, @jcelerier, @mborn-adi, @BrukerJWD, @spyridon97, @phprus, @oliverlee, @joshessman-llnl, @akohlmey, @timkalu, @olupton, @Acretock, @alexezeder, @andrewcorrigan, @lucpelletier and @HazardyKnusperkeks. # 8.0.1 - 2021-07-02 - Fixed the version number in the inline namespace (https://github.com/fmtlib/fmt/issues/2374). - Added a missing presentation type check for `std::string` (https://github.com/fmtlib/fmt/issues/2402). - Fixed a linkage error when mixing code built with clang and gcc (https://github.com/fmtlib/fmt/issues/2377). - Fixed documentation issues (https://github.com/fmtlib/fmt/pull/2396, https://github.com/fmtlib/fmt/issues/2403, https://github.com/fmtlib/fmt/issues/2406). Thanks @mkurdej. - Removed dead code in FP formatter ( https://github.com/fmtlib/fmt/pull/2398). Thanks @javierhonduco. - Fixed various warnings and compilation issues (https://github.com/fmtlib/fmt/issues/2351, https://github.com/fmtlib/fmt/issues/2359, https://github.com/fmtlib/fmt/pull/2365, https://github.com/fmtlib/fmt/issues/2368, https://github.com/fmtlib/fmt/pull/2370, https://github.com/fmtlib/fmt/pull/2376, https://github.com/fmtlib/fmt/pull/2381, https://github.com/fmtlib/fmt/pull/2382, https://github.com/fmtlib/fmt/issues/2386, https://github.com/fmtlib/fmt/pull/2389, https://github.com/fmtlib/fmt/pull/2395, https://github.com/fmtlib/fmt/pull/2397, https://github.com/fmtlib/fmt/issues/2400, https://github.com/fmtlib/fmt/issues/2401, https://github.com/fmtlib/fmt/pull/2407). Thanks @zx2c4, @AidanSun05, @mattiasljungstrom, @joemmett, @erengy, @patlkli, @gsjaardema and @phprus. # 8.0.0 - 2021-06-21 - Enabled compile-time format string checks by default. For example ([godbolt](https://godbolt.org/z/sMxcohGjz)): ```c++ #include int main() { fmt::print("{:d}", "I am not a number"); } ``` gives a compile-time error on compilers with C++20 `consteval` support (gcc 10+, clang 11+) because `d` is not a valid format specifier for a string. To pass a runtime string wrap it in `fmt::runtime`: ```c++ fmt::print(fmt::runtime("{:d}"), "I am not a number"); ``` - Added compile-time formatting (https://github.com/fmtlib/fmt/pull/2019, https://github.com/fmtlib/fmt/pull/2044, https://github.com/fmtlib/fmt/pull/2056, https://github.com/fmtlib/fmt/pull/2072, https://github.com/fmtlib/fmt/pull/2075, https://github.com/fmtlib/fmt/issues/2078, https://github.com/fmtlib/fmt/pull/2129, https://github.com/fmtlib/fmt/pull/2326). For example ([godbolt](https://godbolt.org/z/Mxx9d89jM)): ```c++ #include consteval auto compile_time_itoa(int value) -> std::array { auto result = std::array(); fmt::format_to(result.data(), FMT_COMPILE("{}"), value); return result; } constexpr auto answer = compile_time_itoa(42); ``` Most of the formatting functionality is available at compile time with a notable exception of floating-point numbers and pointers. Thanks @alexezeder. - Optimized handling of format specifiers during format string compilation. For example, hexadecimal formatting (`"{:x}"`) is now 3-7x faster than before when using `format_to` with format string compilation and a stack-allocated buffer (https://github.com/fmtlib/fmt/issues/1944). Before (7.1.3): ---------------------------------------------------------------------------- Benchmark Time CPU Iterations ---------------------------------------------------------------------------- FMTCompileOld/0 15.5 ns 15.5 ns 43302898 FMTCompileOld/42 16.6 ns 16.6 ns 43278267 FMTCompileOld/273123 18.7 ns 18.6 ns 37035861 FMTCompileOld/9223372036854775807 19.4 ns 19.4 ns 35243000 ---------------------------------------------------------------------------- After (8.x): ---------------------------------------------------------------------------- Benchmark Time CPU Iterations ---------------------------------------------------------------------------- FMTCompileNew/0 1.99 ns 1.99 ns 360523686 FMTCompileNew/42 2.33 ns 2.33 ns 279865664 FMTCompileNew/273123 3.72 ns 3.71 ns 190230315 FMTCompileNew/9223372036854775807 5.28 ns 5.26 ns 130711631 ---------------------------------------------------------------------------- It is even faster than `std::to_chars` from libc++ compiled with clang on macOS: ---------------------------------------------------------------------------- Benchmark Time CPU Iterations ---------------------------------------------------------------------------- ToChars/0 4.42 ns 4.41 ns 160196630 ToChars/42 5.00 ns 4.98 ns 140735201 ToChars/273123 7.26 ns 7.24 ns 95784130 ToChars/9223372036854775807 8.77 ns 8.75 ns 75872534 ---------------------------------------------------------------------------- In other cases, especially involving `std::string` construction, the speed up is usually lower because handling format specifiers takes a smaller fraction of the total time. - Added the `_cf` user-defined literal to represent a compiled format string. It can be used instead of the `FMT_COMPILE` macro (https://github.com/fmtlib/fmt/pull/2043, https://github.com/fmtlib/fmt/pull/2242): ```c++ #include using namespace fmt::literals; auto s = fmt::format(FMT_COMPILE("{}"), 42); // � not modern auto s = fmt::format("{}"_cf, 42); // 🙂 modern as hell ``` It requires compiler support for class types in non-type template parameters (a C++20 feature) which is available in GCC 9.3+. Thanks @alexezeder. - Format string compilation now requires `format` functions of `formatter` specializations for user-defined types to be `const`: ```c++ template <> struct fmt::formatter: formatter { template auto format(my_type obj, FormatContext& ctx) const { // Note const here. // ... } }; ``` - Added UDL-based named argument support to format string compilation (https://github.com/fmtlib/fmt/pull/2243, https://github.com/fmtlib/fmt/pull/2281). For example: ```c++ #include using namespace fmt::literals; auto s = fmt::format(FMT_COMPILE("{answer}"), "answer"_a = 42); ``` Here the argument named \"answer\" is resolved at compile time with no runtime overhead. Thanks @alexezeder. - Added format string compilation support to `fmt::print` (https://github.com/fmtlib/fmt/issues/2280, https://github.com/fmtlib/fmt/pull/2304). Thanks @alexezeder. - Added initial support for compiling {fmt} as a C++20 module (https://github.com/fmtlib/fmt/pull/2235, https://github.com/fmtlib/fmt/pull/2240, https://github.com/fmtlib/fmt/pull/2260, https://github.com/fmtlib/fmt/pull/2282, https://github.com/fmtlib/fmt/pull/2283, https://github.com/fmtlib/fmt/pull/2288, https://github.com/fmtlib/fmt/pull/2298, https://github.com/fmtlib/fmt/pull/2306, https://github.com/fmtlib/fmt/pull/2307, https://github.com/fmtlib/fmt/pull/2309, https://github.com/fmtlib/fmt/pull/2318, https://github.com/fmtlib/fmt/pull/2324, https://github.com/fmtlib/fmt/pull/2332, https://github.com/fmtlib/fmt/pull/2340). Thanks @DanielaE. - Made symbols private by default reducing shared library size (https://github.com/fmtlib/fmt/pull/2301). For example there was a \~15% reported reduction on one platform. Thanks @sergiud. - Optimized includes making the result of preprocessing `fmt/format.h` \~20% smaller with libstdc++/C++20 and slightly improving build times (https://github.com/fmtlib/fmt/issues/1998). - Added support of ranges with non-const `begin` / `end` (https://github.com/fmtlib/fmt/pull/1953). Thanks @kitegi. - Added support of `std::byte` and other formattable types to `fmt::join` (https://github.com/fmtlib/fmt/issues/1981, https://github.com/fmtlib/fmt/issues/2040, https://github.com/fmtlib/fmt/pull/2050, https://github.com/fmtlib/fmt/issues/2262). For example: ```c++ #include #include #include int main() { auto bytes = std::vector{std::byte(4), std::byte(2)}; fmt::print("{}", fmt::join(bytes, "")); } ``` prints \"42\". Thanks @kamibo. - Implemented the default format for `std::chrono::system_clock` (https://github.com/fmtlib/fmt/issues/2319, https://github.com/fmtlib/fmt/pull/2345). For example: ```c++ #include int main() { fmt::print("{}", std::chrono::system_clock::now()); } ``` prints \"2021-06-18 15:22:00\" (the output depends on the current date and time). Thanks @sunmy2019. - Made more chrono specifiers locale independent by default. Use the `'L'` specifier to get localized formatting. For example: ```c++ #include int main() { std::locale::global(std::locale("ru_RU.UTF-8")); auto monday = std::chrono::weekday(1); fmt::print("{}\n", monday); // prints "Mon" fmt::print("{:L}\n", monday); // prints "пн" } ``` - Improved locale handling in chrono formatting (https://github.com/fmtlib/fmt/issues/2337, https://github.com/fmtlib/fmt/pull/2349, https://github.com/fmtlib/fmt/pull/2350). Thanks @phprus. - Deprecated `fmt/locale.h` moving the formatting functions that take a locale to `fmt/format.h` (`char`) and `fmt/xchar` (other overloads). This doesn\'t introduce a dependency on `` so there is virtually no compile time effect. - Deprecated an undocumented `format_to` overload that takes `basic_memory_buffer`. - Made parameter order in `vformat_to` consistent with `format_to` (https://github.com/fmtlib/fmt/issues/2327). - Added support for time points with arbitrary durations (https://github.com/fmtlib/fmt/issues/2208). For example: ```c++ #include int main() { using tp = std::chrono::time_point< std::chrono::system_clock, std::chrono::seconds>; fmt::print("{:%S}", tp(std::chrono::seconds(42))); } ``` prints \"42\". - Formatting floating-point numbers no longer produces trailing zeros by default for consistency with `std::format`. For example: ```c++ #include int main() { fmt::print("{0:.3}", 1.1); } ``` prints \"1.1\". Use the `'#'` specifier to keep trailing zeros. - Dropped a limit on the number of elements in a range and replaced `{}` with `[]` as range delimiters for consistency with Python\'s `str.format`. - The `'L'` specifier for locale-specific numeric formatting can now be combined with presentation specifiers as in `std::format`. For example: ```c++ #include #include int main() { std::locale::global(std::locale("fr_FR.UTF-8")); fmt::print("{0:.2Lf}", 0.42); } ``` prints \"0,42\". The deprecated `'n'` specifier has been removed. - Made the `0` specifier ignored for infinity and NaN (https://github.com/fmtlib/fmt/issues/2305, https://github.com/fmtlib/fmt/pull/2310). Thanks @Liedtke. - Made the hexfloat formatting use the right alignment by default (https://github.com/fmtlib/fmt/issues/2308, https://github.com/fmtlib/fmt/pull/2317). Thanks @Liedtke. - Removed the deprecated numeric alignment (`'='`). Use the `'0'` specifier instead. - Removed the deprecated `fmt/posix.h` header that has been replaced with `fmt/os.h`. - Removed the deprecated `format_to_n_context`, `format_to_n_args` and `make_format_to_n_args`. They have been replaced with `format_context`, `` format_args` and ``make_format_args\`\` respectively. - Moved `wchar_t`-specific functions and types to `fmt/xchar.h`. You can define `FMT_DEPRECATED_INCLUDE_XCHAR` to automatically include `fmt/xchar.h` from `fmt/format.h` but this will be disabled in the next major release. - Fixed handling of the `'+'` specifier in localized formatting (https://github.com/fmtlib/fmt/issues/2133). - Added support for the `'s'` format specifier that gives textual representation of `bool` (https://github.com/fmtlib/fmt/issues/2094, https://github.com/fmtlib/fmt/pull/2109). For example: ```c++ #include int main() { fmt::print("{:s}", true); } ``` prints \"true\". Thanks @powercoderlol. - Made `fmt::ptr` work with function pointers (https://github.com/fmtlib/fmt/pull/2131). For example: ```c++ #include int main() { fmt::print("My main: {}\n", fmt::ptr(main)); } ``` Thanks @mikecrowe. - The undocumented support for specializing `formatter` for pointer types has been removed. - Fixed `fmt::formatted_size` with format string compilation (https://github.com/fmtlib/fmt/pull/2141, https://github.com/fmtlib/fmt/pull/2161). Thanks @alexezeder. - Fixed handling of empty format strings during format string compilation (https://github.com/fmtlib/fmt/issues/2042): ```c++ auto s = fmt::format(FMT_COMPILE("")); ``` Thanks @alexezeder. - Fixed handling of enums in `fmt::to_string` (https://github.com/fmtlib/fmt/issues/2036). - Improved width computation (https://github.com/fmtlib/fmt/issues/2033, https://github.com/fmtlib/fmt/issues/2091). For example: ```c++ #include int main() { fmt::print("{:-<10}{}\n", "你好", "世界"); fmt::print("{:-<10}{}\n", "hello", "world"); } ``` prints ![](https://user-images.githubusercontent.com/576385/119840373-cea3ca80-beb9-11eb-91e0-54266c48e181.png) on a modern terminal. - The experimental fast output stream (`fmt::ostream`) is now truncated by default for consistency with `fopen` (https://github.com/fmtlib/fmt/issues/2018). For example: ```c++ #include int main() { fmt::ostream out1 = fmt::output_file("guide"); out1.print("Zaphod"); out1.close(); fmt::ostream out2 = fmt::output_file("guide"); out2.print("Ford"); } ``` writes \"Ford\" to the file \"guide\". To preserve the old file content if any pass `fmt::file::WRONLY | fmt::file::CREATE` flags to `fmt::output_file`. - Fixed moving of `fmt::ostream` that holds buffered data (https://github.com/fmtlib/fmt/issues/2197, https://github.com/fmtlib/fmt/pull/2198). Thanks @vtta. - Replaced the `fmt::system_error` exception with a function of the same name that constructs `std::system_error` (https://github.com/fmtlib/fmt/issues/2266). - Replaced the `fmt::windows_error` exception with a function of the same name that constructs `std::system_error` with the category returned by `fmt::system_category()` (https://github.com/fmtlib/fmt/issues/2274, https://github.com/fmtlib/fmt/pull/2275). The latter is similar to `std::system_category` but correctly handles UTF-8. Thanks @phprus. - Replaced `fmt::error_code` with `std::error_code` and made it formattable (https://github.com/fmtlib/fmt/issues/2269, https://github.com/fmtlib/fmt/pull/2270, https://github.com/fmtlib/fmt/pull/2273). Thanks @phprus. - Added speech synthesis support (https://github.com/fmtlib/fmt/pull/2206). - Made `format_to` work with a memory buffer that has a custom allocator (https://github.com/fmtlib/fmt/pull/2300). Thanks @voxmea. - Added `Allocator::max_size` support to `basic_memory_buffer`. (https://github.com/fmtlib/fmt/pull/1960). Thanks @phprus. - Added wide string support to `fmt::join` (https://github.com/fmtlib/fmt/pull/2236). Thanks @crbrz. - Made iterators passed to `formatter` specializations via a format context satisfy C++20 `std::output_iterator` requirements (https://github.com/fmtlib/fmt/issues/2156, https://github.com/fmtlib/fmt/pull/2158, https://github.com/fmtlib/fmt/issues/2195, https://github.com/fmtlib/fmt/pull/2204). Thanks @randomnetcat. - Optimized the `printf` implementation (https://github.com/fmtlib/fmt/pull/1982, https://github.com/fmtlib/fmt/pull/1984, https://github.com/fmtlib/fmt/pull/2016, https://github.com/fmtlib/fmt/pull/2164). Thanks @rimathia and @moiwi. - Improved detection of `constexpr` `char_traits` (https://github.com/fmtlib/fmt/pull/2246, https://github.com/fmtlib/fmt/pull/2257). Thanks @phprus. - Fixed writing to `stdout` when it is redirected to `NUL` on Windows (https://github.com/fmtlib/fmt/issues/2080). - Fixed exception propagation from iterators (https://github.com/fmtlib/fmt/issues/2097). - Improved `strftime` error handling (https://github.com/fmtlib/fmt/issues/2238, https://github.com/fmtlib/fmt/pull/2244). Thanks @yumeyao. - Stopped using deprecated GCC UDL template extension. - Added `fmt/args.h` to the install target (https://github.com/fmtlib/fmt/issues/2096). - Error messages are now passed to assert when exceptions are disabled (https://github.com/fmtlib/fmt/pull/2145). Thanks @NobodyXu. - Added the `FMT_MASTER_PROJECT` CMake option to control build and install targets when {fmt} is included via `add_subdirectory` (https://github.com/fmtlib/fmt/issues/2098, https://github.com/fmtlib/fmt/pull/2100). Thanks @randomizedthinking. - Improved build configuration (https://github.com/fmtlib/fmt/pull/2026, https://github.com/fmtlib/fmt/pull/2122). Thanks @luncliff and @ibaned. - Fixed various warnings and compilation issues (https://github.com/fmtlib/fmt/issues/1947, https://github.com/fmtlib/fmt/pull/1959, https://github.com/fmtlib/fmt/pull/1963, https://github.com/fmtlib/fmt/pull/1965, https://github.com/fmtlib/fmt/issues/1966, https://github.com/fmtlib/fmt/pull/1974, https://github.com/fmtlib/fmt/pull/1975, https://github.com/fmtlib/fmt/pull/1990, https://github.com/fmtlib/fmt/issues/2000, https://github.com/fmtlib/fmt/pull/2001, https://github.com/fmtlib/fmt/issues/2002, https://github.com/fmtlib/fmt/issues/2004, https://github.com/fmtlib/fmt/pull/2006, https://github.com/fmtlib/fmt/pull/2009, https://github.com/fmtlib/fmt/pull/2010, https://github.com/fmtlib/fmt/issues/2038, https://github.com/fmtlib/fmt/issues/2039, https://github.com/fmtlib/fmt/issues/2047, https://github.com/fmtlib/fmt/pull/2053, https://github.com/fmtlib/fmt/issues/2059, https://github.com/fmtlib/fmt/pull/2065, https://github.com/fmtlib/fmt/pull/2067, https://github.com/fmtlib/fmt/pull/2068, https://github.com/fmtlib/fmt/pull/2073, https://github.com/fmtlib/fmt/issues/2103, https://github.com/fmtlib/fmt/issues/2105, https://github.com/fmtlib/fmt/pull/2106, https://github.com/fmtlib/fmt/pull/2107, https://github.com/fmtlib/fmt/issues/2116, https://github.com/fmtlib/fmt/pull/2117, https://github.com/fmtlib/fmt/issues/2118, https://github.com/fmtlib/fmt/pull/2119, https://github.com/fmtlib/fmt/issues/2127, https://github.com/fmtlib/fmt/pull/2128, https://github.com/fmtlib/fmt/issues/2140, https://github.com/fmtlib/fmt/issues/2142, https://github.com/fmtlib/fmt/pull/2143, https://github.com/fmtlib/fmt/pull/2144, https://github.com/fmtlib/fmt/issues/2147, https://github.com/fmtlib/fmt/issues/2148, https://github.com/fmtlib/fmt/issues/2149, https://github.com/fmtlib/fmt/pull/2152, https://github.com/fmtlib/fmt/pull/2160, https://github.com/fmtlib/fmt/issues/2170, https://github.com/fmtlib/fmt/issues/2175, https://github.com/fmtlib/fmt/issues/2176, https://github.com/fmtlib/fmt/pull/2177, https://github.com/fmtlib/fmt/issues/2178, https://github.com/fmtlib/fmt/pull/2179, https://github.com/fmtlib/fmt/issues/2180, https://github.com/fmtlib/fmt/issues/2181, https://github.com/fmtlib/fmt/pull/2183, https://github.com/fmtlib/fmt/issues/2184, https://github.com/fmtlib/fmt/issues/2185, https://github.com/fmtlib/fmt/pull/2186, https://github.com/fmtlib/fmt/pull/2187, https://github.com/fmtlib/fmt/pull/2190, https://github.com/fmtlib/fmt/pull/2192, https://github.com/fmtlib/fmt/pull/2194, https://github.com/fmtlib/fmt/pull/2205, https://github.com/fmtlib/fmt/issues/2210, https://github.com/fmtlib/fmt/pull/2211, https://github.com/fmtlib/fmt/pull/2215, https://github.com/fmtlib/fmt/pull/2216, https://github.com/fmtlib/fmt/pull/2218, https://github.com/fmtlib/fmt/pull/2220, https://github.com/fmtlib/fmt/issues/2228, https://github.com/fmtlib/fmt/pull/2229, https://github.com/fmtlib/fmt/pull/2230, https://github.com/fmtlib/fmt/issues/2233, https://github.com/fmtlib/fmt/pull/2239, https://github.com/fmtlib/fmt/issues/2248, https://github.com/fmtlib/fmt/issues/2252, https://github.com/fmtlib/fmt/pull/2253, https://github.com/fmtlib/fmt/pull/2255, https://github.com/fmtlib/fmt/issues/2261, https://github.com/fmtlib/fmt/issues/2278, https://github.com/fmtlib/fmt/issues/2284, https://github.com/fmtlib/fmt/pull/2287, https://github.com/fmtlib/fmt/pull/2289, https://github.com/fmtlib/fmt/pull/2290, https://github.com/fmtlib/fmt/pull/2293, https://github.com/fmtlib/fmt/issues/2295, https://github.com/fmtlib/fmt/pull/2296, https://github.com/fmtlib/fmt/pull/2297, https://github.com/fmtlib/fmt/issues/2311, https://github.com/fmtlib/fmt/pull/2313, https://github.com/fmtlib/fmt/pull/2315, https://github.com/fmtlib/fmt/issues/2320, https://github.com/fmtlib/fmt/pull/2321, https://github.com/fmtlib/fmt/pull/2323, https://github.com/fmtlib/fmt/issues/2328, https://github.com/fmtlib/fmt/pull/2329, https://github.com/fmtlib/fmt/pull/2333, https://github.com/fmtlib/fmt/pull/2338, https://github.com/fmtlib/fmt/pull/2341). Thanks @darklukee, @fagg, @killerbot242, @jgopel, @yeswalrus, @Finkman, @HazardyKnusperkeks, @dkavolis, @concatime, @chronoxor, @summivox, @yNeo, @Apache-HB, @alexezeder, @toojays, @Brainy0207, @vadz, @imsherlock, @phprus, @white238, @yafshar, @BillyDonahue, @jstaahl, @denchat, @DanielaE, @ilyakurdyukov, @ilmai, @JessyDL, @sergiud, @mwinterb, @sven-herrmann, @jmelas, @twoixter, @crbrz and @upsj. - Improved documentation (https://github.com/fmtlib/fmt/issues/1986, https://github.com/fmtlib/fmt/pull/2051, https://github.com/fmtlib/fmt/issues/2057, https://github.com/fmtlib/fmt/pull/2081, https://github.com/fmtlib/fmt/issues/2084, https://github.com/fmtlib/fmt/pull/2312). Thanks @imba-tjd, @0x416c69 and @mordante. - Continuous integration and test improvements (https://github.com/fmtlib/fmt/issues/1969, https://github.com/fmtlib/fmt/pull/1991, https://github.com/fmtlib/fmt/pull/2020, https://github.com/fmtlib/fmt/pull/2110, https://github.com/fmtlib/fmt/pull/2114, https://github.com/fmtlib/fmt/issues/2196, https://github.com/fmtlib/fmt/pull/2217, https://github.com/fmtlib/fmt/pull/2247, https://github.com/fmtlib/fmt/pull/2256, https://github.com/fmtlib/fmt/pull/2336, https://github.com/fmtlib/fmt/pull/2346). Thanks @jgopel, @alexezeder and @DanielaE. The change log for versions 0.8.0 - 7.1.3 is available [here]( doc/ChangeLog-old.md). soci-4.1.4/3rdparty/fmt/test/0000775000175000017500000000000015100423533015706 5ustar zeitlinzeitlinsoci-4.1.4/3rdparty/fmt/test/compile-test.cc0000664000175000017500000003762315100423533020635 0ustar zeitlinzeitlin// Formatting library for C++ - formatting library tests // // Copyright (c) 2012 - present, Victor Zverovich // All rights reserved. // // For the license information refer to format.h. #include "fmt/compile.h" #include #include #include #include #include "fmt/chrono.h" #include "fmt/ranges.h" #include "gmock/gmock.h" #include "gtest-extra.h" TEST(compile_test, compile_fallback) { // FMT_COMPILE should fallback on runtime formatting when `if constexpr` is // not available. EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), 42)); } struct type_with_get { template friend void get(type_with_get); }; FMT_BEGIN_NAMESPACE template <> struct formatter : formatter { template auto format(type_with_get, FormatContext& ctx) const -> decltype(ctx.out()) { return formatter::format(42, ctx); } }; FMT_END_NAMESPACE TEST(compile_test, compile_type_with_get) { EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), type_with_get())); } #if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) struct test_formattable {}; FMT_BEGIN_NAMESPACE template <> struct formatter : formatter { char word_spec = 'f'; constexpr auto parse(format_parse_context& ctx) { auto it = ctx.begin(), end = ctx.end(); if (it == end || *it == '}') return it; if (it != end && (*it == 'f' || *it == 'b')) word_spec = *it++; if (it != end && *it != '}') throw format_error("invalid format"); return it; } template constexpr auto format(test_formattable, FormatContext& ctx) const -> decltype(ctx.out()) { return formatter::format(word_spec == 'f' ? "foo" : "bar", ctx); } }; FMT_END_NAMESPACE TEST(compile_test, format_default) { EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), 42)); EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), 42u)); EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), 42ll)); EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), 42ull)); EXPECT_EQ("true", fmt::format(FMT_COMPILE("{}"), true)); EXPECT_EQ("x", fmt::format(FMT_COMPILE("{}"), 'x')); EXPECT_EQ("4.2", fmt::format(FMT_COMPILE("{}"), 4.2)); EXPECT_EQ("foo", fmt::format(FMT_COMPILE("{}"), "foo")); EXPECT_EQ("foo", fmt::format(FMT_COMPILE("{}"), std::string("foo"))); EXPECT_EQ("foo", fmt::format(FMT_COMPILE("{}"), test_formattable())); auto t = std::chrono::system_clock::now(); EXPECT_EQ(fmt::format("{}", t), fmt::format(FMT_COMPILE("{}"), t)); # ifdef __cpp_lib_byte EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), std::byte{42})); # endif } TEST(compile_test, format_escape) { EXPECT_EQ("\"string\"", fmt::format(FMT_COMPILE("{:?}"), "string")); EXPECT_EQ("prefix \"string\"", fmt::format(FMT_COMPILE("prefix {:?}"), "string")); EXPECT_EQ("\"string\" suffix", fmt::format(FMT_COMPILE("{:?} suffix"), "string")); EXPECT_EQ("\"abc\"", fmt::format(FMT_COMPILE("{0:<5?}"), "abc")); EXPECT_EQ("\"abc\" ", fmt::format(FMT_COMPILE("{0:<7?}"), "abc")); } TEST(compile_test, format_wide_string) { EXPECT_EQ(L"42", fmt::format(FMT_COMPILE(L"{}"), 42)); } TEST(compile_test, format_specs) { EXPECT_EQ("42", fmt::format(FMT_COMPILE("{:x}"), 0x42)); EXPECT_EQ("1.2 ms ", fmt::format(FMT_COMPILE("{:7.1%Q %q}"), std::chrono::duration(1.234))); } TEST(compile_test, dynamic_format_specs) { EXPECT_EQ("foo ", fmt::format(FMT_COMPILE("{:{}}"), "foo", 5)); EXPECT_EQ(" 3.14", fmt::format(FMT_COMPILE("{:{}.{}f}"), 3.141592, 6, 2)); EXPECT_EQ( "=1.234ms=", fmt::format(FMT_COMPILE("{:=^{}.{}}"), std::chrono::duration(1.234), 9, 3)); } TEST(compile_test, manual_ordering) { EXPECT_EQ("42", fmt::format(FMT_COMPILE("{0}"), 42)); EXPECT_EQ(" -42", fmt::format(FMT_COMPILE("{0:4}"), -42)); EXPECT_EQ("41 43", fmt::format(FMT_COMPILE("{0} {1}"), 41, 43)); EXPECT_EQ("41 43", fmt::format(FMT_COMPILE("{1} {0}"), 43, 41)); EXPECT_EQ("41 43", fmt::format(FMT_COMPILE("{0} {2}"), 41, 42, 43)); EXPECT_EQ(" 41 43", fmt::format(FMT_COMPILE("{1:{2}} {0:4}"), 43, 41, 4)); EXPECT_EQ("42 1.2 ms ", fmt::format(FMT_COMPILE("{0} {1:7.1%Q %q}"), 42, std::chrono::duration(1.234))); EXPECT_EQ( "true 42 42 foo 0x1234 foo", fmt::format(FMT_COMPILE("{0} {1} {2} {3} {4} {5}"), true, 42, 42.0f, "foo", reinterpret_cast(0x1234), test_formattable())); EXPECT_EQ(L"42", fmt::format(FMT_COMPILE(L"{0}"), 42)); } TEST(compile_test, named) { auto runtime_named_field_compiled = fmt::detail::compile(FMT_COMPILE("{arg}")); static_assert(std::is_same_v>); EXPECT_EQ("42", fmt::format(FMT_COMPILE("{}"), fmt::arg("arg", 42))); EXPECT_EQ("41 43", fmt::format(FMT_COMPILE("{} {}"), fmt::arg("arg", 41), fmt::arg("arg", 43))); EXPECT_EQ("foobar", fmt::format(FMT_COMPILE("{a0}{a1}"), fmt::arg("a0", "foo"), fmt::arg("a1", "bar"))); EXPECT_EQ("foobar", fmt::format(FMT_COMPILE("{}{a1}"), fmt::arg("a0", "foo"), fmt::arg("a1", "bar"))); EXPECT_EQ("foofoo", fmt::format(FMT_COMPILE("{a0}{}"), fmt::arg("a0", "foo"), fmt::arg("a1", "bar"))); EXPECT_EQ("foobar", fmt::format(FMT_COMPILE("{0}{a1}"), fmt::arg("a0", "foo"), fmt::arg("a1", "bar"))); EXPECT_EQ("foobar", fmt::format(FMT_COMPILE("{a0}{1}"), fmt::arg("a0", "foo"), fmt::arg("a1", "bar"))); EXPECT_EQ("foobar", fmt::format(FMT_COMPILE("{}{a1}"), "foo", fmt::arg("a1", "bar"))); EXPECT_EQ("foobar", fmt::format(FMT_COMPILE("{a0}{a1}"), fmt::arg("a1", "bar"), fmt::arg("a2", "baz"), fmt::arg("a0", "foo"))); EXPECT_EQ(" bar foo ", fmt::format(FMT_COMPILE(" {foo} {bar} "), fmt::arg("foo", "bar"), fmt::arg("bar", "foo"))); EXPECT_THROW(fmt::format(FMT_COMPILE("{invalid}"), fmt::arg("valid", 42)), fmt::format_error); # if FMT_USE_NONTYPE_TEMPLATE_ARGS using namespace fmt::literals; auto statically_named_field_compiled = fmt::detail::compile(FMT_COMPILE("{arg}")); static_assert(std::is_same_v>); EXPECT_EQ("41 43", fmt::format(FMT_COMPILE("{a0} {a1}"), "a0"_a = 41, "a1"_a = 43)); EXPECT_EQ("41 43", fmt::format(FMT_COMPILE("{a1} {a0}"), "a0"_a = 43, "a1"_a = 41)); # endif } TEST(compile_test, join) { unsigned char data[] = {0x1, 0x2, 0xaf}; EXPECT_EQ("0102af", fmt::format(FMT_COMPILE("{:02x}"), fmt::join(data, ""))); } TEST(compile_test, format_to) { char buf[8]; auto end = fmt::format_to(buf, FMT_COMPILE("{}"), 42); *end = '\0'; EXPECT_STREQ("42", buf); end = fmt::format_to(buf, FMT_COMPILE("{:x}"), 42); *end = '\0'; EXPECT_STREQ("2a", buf); } TEST(compile_test, format_to_n) { constexpr auto buffer_size = 8; char buffer[buffer_size]; auto res = fmt::format_to_n(buffer, buffer_size, FMT_COMPILE("{}"), 42); *res.out = '\0'; EXPECT_STREQ("42", buffer); res = fmt::format_to_n(buffer, buffer_size, FMT_COMPILE("{:x}"), 42); *res.out = '\0'; EXPECT_STREQ("2a", buffer); } TEST(compile_test, output_iterators) { std::list out; fmt::format_to(std::back_inserter(out), FMT_COMPILE("{}"), 42); EXPECT_EQ("42", std::string(out.begin(), out.end())); std::stringstream s; fmt::format_to(std::ostream_iterator(s), FMT_COMPILE("{}"), 42); EXPECT_EQ("42", s.str()); std::stringstream s2; fmt::format_to(std::ostreambuf_iterator(s2), FMT_COMPILE("{}.{:06d}"), 42, 43); EXPECT_EQ("42.000043", s2.str()); } # if FMT_USE_CONSTEVAL && (!FMT_MSC_VERSION || FMT_MSC_VERSION >= 1940) TEST(compile_test, constexpr_formatted_size) { FMT_CONSTEXPR20 size_t size = fmt::formatted_size(FMT_COMPILE("{}"), 42); EXPECT_EQ(size, 2); FMT_CONSTEXPR20 size_t hex_size = fmt::formatted_size(FMT_COMPILE("{:x}"), 15); EXPECT_EQ(hex_size, 1); FMT_CONSTEXPR20 size_t binary_size = fmt::formatted_size(FMT_COMPILE("{:b}"), 15); EXPECT_EQ(binary_size, 4); FMT_CONSTEXPR20 size_t padded_size = fmt::formatted_size(FMT_COMPILE("{:*^6}"), 42); EXPECT_EQ(padded_size, 6); FMT_CONSTEXPR20 size_t float_size = fmt::formatted_size(FMT_COMPILE("{:.3}"), 12.345); EXPECT_EQ(float_size, 4); FMT_CONSTEXPR20 size_t str_size = fmt::formatted_size(FMT_COMPILE("{:s}"), "abc"); EXPECT_EQ(str_size, 3); } TEST(compile_test, static_format) { constexpr auto result = FMT_STATIC_FORMAT("{}", 42); EXPECT_STREQ(result.c_str(), "42"); EXPECT_EQ(result.str(), "42"); } # endif TEST(compile_test, text_and_arg) { EXPECT_EQ(">>>42<<<", fmt::format(FMT_COMPILE(">>>{}<<<"), 42)); EXPECT_EQ("42!", fmt::format(FMT_COMPILE("{}!"), 42)); } TEST(compile_test, unknown_format_fallback) { EXPECT_EQ(" 42 ", fmt::format(FMT_COMPILE("{name:^4}"), fmt::arg("name", 42))); std::vector v1; fmt::format_to(std::back_inserter(v1), FMT_COMPILE("{}"), 42); EXPECT_EQ("42", fmt::string_view(v1.data(), v1.size())); std::vector v2; fmt::format_to(std::back_inserter(v2), FMT_COMPILE("{name:^4}"), fmt::arg("name", 42)); EXPECT_EQ(" 42 ", fmt::string_view(v2.data(), v2.size())); char buffer[4]; auto result = fmt::format_to_n(buffer, 4, FMT_COMPILE("{name:^5}"), fmt::arg("name", 42)); EXPECT_EQ(5u, result.size); EXPECT_EQ(buffer + 4, result.out); EXPECT_EQ(" 42 ", fmt::string_view(buffer, 4)); } TEST(compile_test, empty) { EXPECT_EQ("", fmt::format(FMT_COMPILE(""))); } struct to_stringable { friend fmt::string_view to_string_view(to_stringable) { return {}; } }; FMT_BEGIN_NAMESPACE template <> struct formatter { auto parse(format_parse_context& ctx) const -> decltype(ctx.begin()) { return ctx.begin(); } template auto format(const to_stringable&, FormatContext& ctx) -> decltype(ctx.out()) { return ctx.out(); } }; FMT_END_NAMESPACE TEST(compile_test, to_string_and_formatter) { fmt::format(FMT_COMPILE("{}"), to_stringable()); } struct std_context_test {}; FMT_BEGIN_NAMESPACE template <> struct formatter : formatter { auto format(std_context_test, format_context& ctx) const -> decltype(ctx.out()) { return ctx.out(); } }; FMT_END_NAMESPACE TEST(compile_test, print) { EXPECT_WRITE(stdout, fmt::print(FMT_COMPILE("Don't {}!"), "panic"), "Don't panic!"); EXPECT_WRITE(stderr, fmt::print(stderr, FMT_COMPILE("Don't {}!"), "panic"), "Don't panic!"); fmt::print(FMT_COMPILE("{}"), std_context_test()); } #endif #if FMT_USE_NONTYPE_TEMPLATE_ARGS TEST(compile_test, compile_format_string_literal) { using namespace fmt::literals; EXPECT_EQ("", fmt::format(""_cf)); EXPECT_EQ("42", fmt::format("{}"_cf, 42)); EXPECT_EQ(L"42", fmt::format(L"{}"_cf, 42)); } #endif #if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) template auto check_is_compiled_string(const S&) -> bool { return fmt::is_compiled_string::value; } TEST(compile_test, is_compiled_string) { EXPECT_TRUE(check_is_compiled_string(FMT_COMPILE("asdf"))); EXPECT_TRUE(check_is_compiled_string(FMT_COMPILE("{}"))); } #endif // MSVS 2019 19.29.30145.0 - OK // MSVS 2022 19.32.31332.0, 19.37.32826.1 - compile-test.cc(362,3): fatal error // C1001: Internal compiler error. // (compiler file // 'D:\a\_work\1\s\src\vctools\Compiler\CxxFE\sl\p1\c\constexpr\constexpr.cpp', // line 8635) #if FMT_USE_CONSTEVAL && \ (!FMT_MSC_VERSION || \ (FMT_MSC_VERSION >= 1928 && FMT_MSC_VERSION < 1930)) && \ defined(__cpp_lib_is_constant_evaluated) template struct test_string { template constexpr auto operator==(const T& rhs) const -> bool { return fmt::basic_string_view(rhs).compare(buffer) == 0; } Char buffer[max_string_length]{}; }; template consteval auto test_format(auto format, const Args&... args) { test_string string{}; fmt::format_to(string.buffer, format, args...); return string; } TEST(compile_time_formatting_test, bool) { EXPECT_EQ("true", test_format<5>(FMT_COMPILE("{}"), true)); EXPECT_EQ("false", test_format<6>(FMT_COMPILE("{}"), false)); EXPECT_EQ("true ", test_format<6>(FMT_COMPILE("{:5}"), true)); EXPECT_EQ("1", test_format<2>(FMT_COMPILE("{:d}"), true)); } TEST(compile_time_formatting_test, integer) { EXPECT_EQ("42", test_format<3>(FMT_COMPILE("{}"), 42)); EXPECT_EQ("420", test_format<4>(FMT_COMPILE("{}"), 420)); EXPECT_EQ("42 42", test_format<6>(FMT_COMPILE("{} {}"), 42, 42)); EXPECT_EQ("42 42", test_format<6>(FMT_COMPILE("{} {}"), uint32_t{42}, uint64_t{42})); EXPECT_EQ("+42", test_format<4>(FMT_COMPILE("{:+}"), 42)); EXPECT_EQ("42", test_format<3>(FMT_COMPILE("{:-}"), 42)); EXPECT_EQ(" 42", test_format<4>(FMT_COMPILE("{: }"), 42)); EXPECT_EQ("-0042", test_format<6>(FMT_COMPILE("{:05}"), -42)); EXPECT_EQ("101010", test_format<7>(FMT_COMPILE("{:b}"), 42)); EXPECT_EQ("0b101010", test_format<9>(FMT_COMPILE("{:#b}"), 42)); EXPECT_EQ("0B101010", test_format<9>(FMT_COMPILE("{:#B}"), 42)); EXPECT_EQ("042", test_format<4>(FMT_COMPILE("{:#o}"), 042)); EXPECT_EQ("0x4a", test_format<5>(FMT_COMPILE("{:#x}"), 0x4a)); EXPECT_EQ("0X4A", test_format<5>(FMT_COMPILE("{:#X}"), 0x4a)); EXPECT_EQ(" 42", test_format<6>(FMT_COMPILE("{:5}"), 42)); EXPECT_EQ(" 42", test_format<6>(FMT_COMPILE("{:5}"), 42l)); EXPECT_EQ(" 42", test_format<6>(FMT_COMPILE("{:5}"), 42ll)); EXPECT_EQ(" 42", test_format<6>(FMT_COMPILE("{:5}"), 42ull)); EXPECT_EQ("42 ", test_format<5>(FMT_COMPILE("{:<4}"), 42)); EXPECT_EQ(" 42", test_format<5>(FMT_COMPILE("{:>4}"), 42)); EXPECT_EQ(" 42 ", test_format<5>(FMT_COMPILE("{:^4}"), 42)); EXPECT_EQ("**-42", test_format<6>(FMT_COMPILE("{:*>5}"), -42)); } TEST(compile_time_formatting_test, char) { EXPECT_EQ("c", test_format<2>(FMT_COMPILE("{}"), 'c')); EXPECT_EQ("c ", test_format<4>(FMT_COMPILE("{:3}"), 'c')); EXPECT_EQ("99", test_format<3>(FMT_COMPILE("{:d}"), 'c')); } TEST(compile_time_formatting_test, string) { EXPECT_EQ("42", test_format<3>(FMT_COMPILE("{}"), "42")); EXPECT_EQ("The answer is 42", test_format<17>(FMT_COMPILE("{} is {}"), "The answer", "42")); EXPECT_EQ("abc**", test_format<6>(FMT_COMPILE("{:*<5}"), "abc")); EXPECT_EQ("**🤡**", test_format<9>(FMT_COMPILE("{:*^6}"), "🤡")); } TEST(compile_time_formatting_test, combination) { EXPECT_EQ("420, true, answer", test_format<18>(FMT_COMPILE("{}, {}, {}"), 420, true, "answer")); EXPECT_EQ(" -42", test_format<5>(FMT_COMPILE("{:{}}"), -42, 4)); } TEST(compile_time_formatting_test, custom_type) { EXPECT_EQ("foo", test_format<4>(FMT_COMPILE("{}"), test_formattable())); EXPECT_EQ("bar", test_format<4>(FMT_COMPILE("{:b}"), test_formattable())); } TEST(compile_time_formatting_test, multibyte_fill) { EXPECT_EQ("жж42", test_format<8>(FMT_COMPILE("{:ж>4}"), 42)); } #endif #if FMT_USE_CONSTEXPR_STRING TEST(compile_test, constexpr_string_format) { constexpr auto result = []() { return fmt::format(FMT_COMPILE("{}"), 42) == "42"; }(); EXPECT_TRUE(result); // Test with a larger string to avoid small string optimization. constexpr auto big = []() { return fmt::format(FMT_COMPILE("{:100}"), ' ') == std::string(100, ' '); }(); EXPECT_TRUE(big); } #endif // FMT_USE_CONSTEXPR_STRING soci-4.1.4/3rdparty/fmt/test/detect-stdfs.cc0000664000175000017500000000113715100423533020610 0ustar zeitlinzeitlin// Formatting library for C++ - tests of formatters for standard library types // // Copyright (c) 2012 - present, Victor Zverovich // All rights reserved. // // For the license information refer to format.h. #include // _GLIBCXX_RELEASE & _LIBCPP_VERSION #if defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE == 8 # error libfound "stdc++fs" #elif !defined(__apple_build_version__) && defined(_LIBCPP_VERSION) && \ _LIBCPP_VERSION >= 7000 && _LIBCPP_VERSION < 9000 # error libfound "c++fs" #else // none if std::filesystem does not require additional libraries # error libfound "" #endif soci-4.1.4/3rdparty/fmt/test/mock-allocator.h0000664000175000017500000000430015100423533020763 0ustar zeitlinzeitlin// Formatting library for C++ - mock allocator // // Copyright (c) 2012 - present, Victor Zverovich // All rights reserved. // // For the license information refer to format.h. #ifndef FMT_MOCK_ALLOCATOR_H_ #define FMT_MOCK_ALLOCATOR_H_ #include // assert #include // size_t #include // std::allocator_traits #include "gmock/gmock.h" template class mock_allocator { public: using value_type = T; using size_type = size_t; using pointer = T*; using const_pointer = const T*; using reference = T&; using const_reference = const T&; using difference_type = ptrdiff_t; template struct rebind { using other = mock_allocator; }; mock_allocator() {} mock_allocator(const mock_allocator&) {} MOCK_METHOD(T*, allocate, (size_t)); MOCK_METHOD(void, deallocate, (T*, size_t)); }; template class allocator_ref { private: Allocator* alloc_; void move(allocator_ref& other) { alloc_ = other.alloc_; other.alloc_ = nullptr; } public: using value_type = typename Allocator::value_type; using propagate_on_container_move_assignment = fmt::bool_constant; explicit allocator_ref(Allocator* alloc = nullptr) : alloc_(alloc) {} allocator_ref(const allocator_ref& other) : alloc_(other.alloc_) {} allocator_ref(allocator_ref&& other) { move(other); } allocator_ref& operator=(allocator_ref&& other) { assert(this != &other); move(other); return *this; } allocator_ref& operator=(const allocator_ref& other) { alloc_ = other.alloc_; return *this; } public: auto get() const -> Allocator* { return alloc_; } auto allocate(size_t n) -> value_type* { return std::allocator_traits::allocate(*alloc_, n); } void deallocate(value_type* p, size_t n) { alloc_->deallocate(p, n); } friend auto operator==(allocator_ref a, allocator_ref b) noexcept -> bool { if (a.alloc_ == b.alloc_) return true; return a.alloc_ && b.alloc_ && *a.alloc_ == *b.alloc_; } friend auto operator!=(allocator_ref a, allocator_ref b) noexcept -> bool { return !(a == b); } }; #endif // FMT_MOCK_ALLOCATOR_H_ soci-4.1.4/3rdparty/fmt/test/args-test.cc0000664000175000017500000001257615100423533020141 0ustar zeitlinzeitlin// Formatting library for C++ - dynamic argument store tests // // Copyright (c) 2012 - present, Victor Zverovich // All rights reserved. // // For the license information refer to format.h. #include "fmt/args.h" #include #include "gtest/gtest.h" TEST(args_test, basic) { fmt::dynamic_format_arg_store store; store.push_back(42); store.push_back("abc1"); store.push_back(1.5f); EXPECT_EQ("42 and abc1 and 1.5", fmt::vformat("{} and {} and {}", store)); } TEST(args_test, strings_and_refs) { // Unfortunately the tests are compiled with old ABI so strings use COW. fmt::dynamic_format_arg_store store; char str[] = "1234567890"; store.push_back(str); store.push_back(std::cref(str)); store.push_back(fmt::string_view{str}); str[0] = 'X'; auto result = fmt::vformat("{} and {} and {}", store); EXPECT_EQ("1234567890 and X234567890 and X234567890", result); } struct custom_type { int i = 0; }; FMT_BEGIN_NAMESPACE template <> struct formatter { auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) { return ctx.begin(); } template auto format(const custom_type& p, FormatContext& ctx) const -> decltype(ctx.out()) { return fmt::format_to(ctx.out(), "cust={}", p.i); } }; FMT_END_NAMESPACE TEST(args_test, custom_format) { fmt::dynamic_format_arg_store store; auto c = custom_type(); store.push_back(c); ++c.i; store.push_back(c); ++c.i; store.push_back(std::cref(c)); ++c.i; auto result = fmt::vformat("{} and {} and {}", store); EXPECT_EQ("cust=0 and cust=1 and cust=3", result); } struct to_stringable { friend auto to_string_view(to_stringable) -> fmt::string_view { return {}; } }; FMT_BEGIN_NAMESPACE template <> struct formatter { auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) { return ctx.begin(); } auto format(to_stringable, format_context& ctx) const -> decltype(ctx.out()) { return ctx.out(); } }; FMT_END_NAMESPACE TEST(args_test, to_string_and_formatter) { fmt::dynamic_format_arg_store store; auto s = to_stringable(); store.push_back(s); store.push_back(std::cref(s)); fmt::vformat("", store); } TEST(args_test, named_int) { fmt::dynamic_format_arg_store store; store.push_back(fmt::arg("a1", 42)); EXPECT_EQ("42", fmt::vformat("{a1}", store)); } TEST(args_test, named_strings) { fmt::dynamic_format_arg_store store; char str[] = "1234567890"; store.push_back(fmt::arg("a1", str)); store.push_back(fmt::arg("a2", std::cref(str))); str[0] = 'X'; EXPECT_EQ("1234567890 and X234567890", fmt::vformat("{a1} and {a2}", store)); } TEST(args_test, named_arg_by_ref) { fmt::dynamic_format_arg_store store; char band[] = "Rolling Stones"; store.push_back(fmt::arg("band", std::cref(band))); band[9] = 'c'; // Changing band affects the output. EXPECT_EQ(fmt::vformat("{band}", store), "Rolling Scones"); } TEST(args_test, named_custom_format) { fmt::dynamic_format_arg_store store; auto c = custom_type(); store.push_back(fmt::arg("c1", c)); ++c.i; store.push_back(fmt::arg("c2", c)); ++c.i; store.push_back(fmt::arg("c_ref", std::cref(c))); ++c.i; auto result = fmt::vformat("{c1} and {c2} and {c_ref}", store); EXPECT_EQ("cust=0 and cust=1 and cust=3", result); } TEST(args_test, clear) { fmt::dynamic_format_arg_store store; store.push_back(42); auto result = fmt::vformat("{}", store); EXPECT_EQ("42", result); store.push_back(43); result = fmt::vformat("{} and {}", store); EXPECT_EQ("42 and 43", result); store.clear(); store.push_back(44); result = fmt::vformat("{}", store); EXPECT_EQ("44", result); } TEST(args_test, reserve) { fmt::dynamic_format_arg_store store; store.reserve(2, 1); store.push_back(1.5f); store.push_back(fmt::arg("a", 42)); auto result = fmt::vformat("{} and {a}", store); EXPECT_EQ("1.5 and 42", result); } struct copy_throwable { copy_throwable() {} copy_throwable(const copy_throwable&) { throw "deal with it"; } }; FMT_BEGIN_NAMESPACE template <> struct formatter { auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) { return ctx.begin(); } auto format(copy_throwable, format_context& ctx) const -> decltype(ctx.out()) { return ctx.out(); } }; FMT_END_NAMESPACE TEST(args_test, throw_on_copy) { fmt::dynamic_format_arg_store store; store.push_back(std::string("foo")); try { store.push_back(copy_throwable()); } catch (...) { } EXPECT_EQ(fmt::vformat("{}", store), "foo"); } TEST(args_test, move_constructor) { using store_type = fmt::dynamic_format_arg_store; auto store = std::unique_ptr(new store_type()); store->push_back(42); store->push_back(std::string("foo")); store->push_back(fmt::arg("a1", "foo")); auto moved_store = std::move(*store); store.reset(); EXPECT_EQ(fmt::vformat("{} {} {a1}", moved_store), "42 foo foo"); } TEST(args_test, size) { fmt::dynamic_format_arg_store store; EXPECT_EQ(store.size(), 0); store.push_back(42); EXPECT_EQ(store.size(), 1); store.push_back("Molybdenum"); EXPECT_EQ(store.size(), 2); store.clear(); EXPECT_EQ(store.size(), 0); } soci-4.1.4/3rdparty/fmt/test/add-subdirectory-test/0000775000175000017500000000000015100423533022127 5ustar zeitlinzeitlinsoci-4.1.4/3rdparty/fmt/test/add-subdirectory-test/CMakeLists.txt0000664000175000017500000000112315100423533024664 0ustar zeitlinzeitlincmake_minimum_required(VERSION 3.8...3.25) project(fmt-test CXX) add_subdirectory(../.. fmt) add_executable(library-test main.cc) target_include_directories(library-test PUBLIC SYSTEM .) target_compile_options(library-test PRIVATE ${PEDANTIC_COMPILE_FLAGS}) target_link_libraries(library-test fmt::fmt) if (TARGET fmt::fmt-header-only) add_executable(header-only-test main.cc) target_include_directories(header-only-test PUBLIC SYSTEM .) target_compile_options(header-only-test PRIVATE ${PEDANTIC_COMPILE_FLAGS}) target_link_libraries(header-only-test fmt::fmt-header-only) endif () soci-4.1.4/3rdparty/fmt/test/add-subdirectory-test/main.cc0000664000175000017500000000020015100423533023352 0ustar zeitlinzeitlin#include "fmt/base.h" int main(int argc, char** argv) { for (int i = 0; i < argc; ++i) fmt::print("{}: {}\n", i, argv[i]); } soci-4.1.4/3rdparty/fmt/test/CMakeLists.txt0000664000175000017500000002167415100423533020460 0ustar zeitlinzeitlinadd_subdirectory(gtest) include(CheckSymbolExists) set(TEST_MAIN_SRC test-main.cc gtest-extra.cc gtest-extra.h util.cc) add_library(test-main STATIC ${TEST_MAIN_SRC}) target_include_directories(test-main PUBLIC $) target_link_libraries(test-main gtest fmt) # Adds a test. # Usage: add_fmt_test(name srcs...) function(add_fmt_test name) cmake_parse_arguments(ADD_FMT_TEST "HEADER_ONLY;MODULE" "" "" ${ARGN}) set(sources ${name}.cc ${ADD_FMT_TEST_UNPARSED_ARGUMENTS}) if (ADD_FMT_TEST_HEADER_ONLY) set(sources ${sources} ${TEST_MAIN_SRC} ../src/os.cc) set(libs gtest fmt-header-only) if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wno-weak-vtables) endif () elseif (ADD_FMT_TEST_MODULE) set(libs test-main test-module) set_source_files_properties(${name}.cc PROPERTIES OBJECT_DEPENDS test-module) else () set(libs test-main fmt) endif () add_executable(${name} ${sources}) target_link_libraries(${name} ${libs}) if (ADD_FMT_TEST_HEADER_ONLY AND NOT FMT_UNICODE) target_compile_definitions(${name} PUBLIC FMT_UNICODE=0) endif () # Define if certain C++ features can be used. if (FMT_PEDANTIC) target_compile_options(${name} PRIVATE ${PEDANTIC_COMPILE_FLAGS}) endif () if (FMT_WERROR) target_compile_options(${name} PRIVATE ${WERROR_FLAG}) endif () add_test(NAME ${name} COMMAND ${name}) endfunction() if (FMT_MODULE) return () endif () add_fmt_test(args-test) add_fmt_test(base-test) add_fmt_test(assert-test) add_fmt_test(chrono-test) add_fmt_test(color-test) add_fmt_test(gtest-extra-test) add_fmt_test(format-test mock-allocator.h) if (MSVC) target_compile_options(format-test PRIVATE /bigobj) endif () if (NOT (MSVC AND BUILD_SHARED_LIBS)) add_fmt_test(format-impl-test HEADER_ONLY header-only-test.cc) endif () add_fmt_test(ostream-test) add_fmt_test(compile-test) add_fmt_test(compile-fp-test) if (MSVC) # Without this option, MSVC returns 199711L for the __cplusplus macro. target_compile_options(compile-fp-test PRIVATE /Zc:__cplusplus) endif() add_fmt_test(printf-test) add_fmt_test(ranges-test ranges-odr-test.cc) add_fmt_test(no-builtin-types-test HEADER_ONLY) add_fmt_test(scan-test HEADER_ONLY) check_symbol_exists(strptime "time.h" HAVE_STRPTIME) if (HAVE_STRPTIME) target_compile_definitions(scan-test PRIVATE FMT_HAVE_STRPTIME) endif () add_fmt_test(std-test) try_compile(compile_result_unused ${CMAKE_CURRENT_BINARY_DIR} SOURCES ${CMAKE_CURRENT_LIST_DIR}/detect-stdfs.cc OUTPUT_VARIABLE RAWOUTPUT) string(REGEX REPLACE ".*libfound \"([^\"]*)\".*" "\\1" STDLIBFS "${RAWOUTPUT}") if (STDLIBFS) target_link_libraries(std-test ${STDLIBFS}) endif () add_fmt_test(unicode-test HEADER_ONLY) if (MSVC) target_compile_options(unicode-test PRIVATE /utf-8) endif () add_fmt_test(xchar-test) add_fmt_test(enforce-checks-test) target_compile_definitions(enforce-checks-test PRIVATE -DFMT_ENFORCE_COMPILE_STRING) add_executable(perf-sanity perf-sanity.cc) target_link_libraries(perf-sanity fmt::fmt) if (FMT_MODULE) # The tests need {fmt} to be compiled as traditional library # because of visibility of implementation details. # If module support is present the module tests require a # test-only module to be built from {fmt} add_library(test-module OBJECT ${CMAKE_SOURCE_DIR}/src/fmt.cc) target_compile_features(test-module PUBLIC cxx_std_11) target_include_directories(test-module PUBLIC $) enable_module(test-module) add_fmt_test(module-test MODULE test-main.cc) if (MSVC) target_compile_options(test-module PRIVATE /utf-8 /Zc:__cplusplus /Zc:externConstexpr /Zc:inline) target_compile_options(module-test PRIVATE /utf-8 /Zc:__cplusplus /Zc:externConstexpr /Zc:inline) endif () endif () if (NOT DEFINED MSVC_STATIC_RUNTIME AND MSVC) foreach (flag_var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) if (${flag_var} MATCHES "^(/|-)(MT|MTd)") set(MSVC_STATIC_RUNTIME ON) break() endif() endforeach() endif() if (NOT MSVC_STATIC_RUNTIME) add_executable(posix-mock-test posix-mock-test.cc ../src/format.cc ${TEST_MAIN_SRC}) target_include_directories( posix-mock-test PRIVATE ${PROJECT_SOURCE_DIR}/include) target_link_libraries(posix-mock-test gtest) if (FMT_PEDANTIC) target_compile_options(posix-mock-test PRIVATE ${PEDANTIC_COMPILE_FLAGS}) endif () if (MSVC) target_compile_options(posix-mock-test PRIVATE /utf-8) endif () add_test(NAME posix-mock-test COMMAND posix-mock-test) add_fmt_test(os-test) endif () message(STATUS "FMT_PEDANTIC: ${FMT_PEDANTIC}") if (FMT_PEDANTIC) # Test that the library can be compiled with exceptions disabled. # -fno-exception is broken in icc: https://github.com/fmtlib/fmt/issues/822. if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "Intel") check_cxx_compiler_flag(-fno-exceptions HAVE_FNO_EXCEPTIONS_FLAG) endif () if (HAVE_FNO_EXCEPTIONS_FLAG) add_library(noexception-test ../src/format.cc noexception-test.cc) target_include_directories( noexception-test PRIVATE ${PROJECT_SOURCE_DIR}/include) target_compile_options(noexception-test PRIVATE -fno-exceptions) target_compile_options(noexception-test PRIVATE ${PEDANTIC_COMPILE_FLAGS}) endif () # Test that the library compiles without locale. add_library(nolocale-test ../src/format.cc) target_include_directories( nolocale-test PRIVATE ${PROJECT_SOURCE_DIR}/include) target_compile_definitions( nolocale-test PRIVATE FMT_STATIC_THOUSANDS_SEPARATOR=1) endif () # These tests are disabled on Windows because they take too long. # They are disabled on GCC < 4.9 because it can not parse UDLs without # a space after `operator""` but that is an incorrect syntax for any more # modern compiler. if (FMT_PEDANTIC AND NOT WIN32 AND NOT ( CMAKE_CXX_COMPILER_ID MATCHES "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9)) # Test if incorrect API usages produce compilation error. add_test(compile-error-test ${CMAKE_CTEST_COMMAND} --build-and-test "${CMAKE_CURRENT_SOURCE_DIR}/compile-error-test" "${CMAKE_CURRENT_BINARY_DIR}/compile-error-test" --build-generator ${CMAKE_GENERATOR} --build-makeprogram ${CMAKE_MAKE_PROGRAM} --build-options "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" "-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}" "-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}" "-DCXX_STANDARD_FLAG=${CXX_STANDARD_FLAG}" "-DFMT_DIR=${CMAKE_SOURCE_DIR}") # Test if the targets are found from the build directory. add_test(find-package-test ${CMAKE_CTEST_COMMAND} -C ${CMAKE_BUILD_TYPE} --build-and-test "${CMAKE_CURRENT_SOURCE_DIR}/find-package-test" "${CMAKE_CURRENT_BINARY_DIR}/find-package-test" --build-generator ${CMAKE_GENERATOR} --build-makeprogram ${CMAKE_MAKE_PROGRAM} --build-options "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" "-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}" "-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}" "-DFMT_DIR=${PROJECT_BINARY_DIR}" "-DPEDANTIC_COMPILE_FLAGS=${PEDANTIC_COMPILE_FLAGS}" "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}") # Test if the targets are found when add_subdirectory is used. add_test(add-subdirectory-test ${CMAKE_CTEST_COMMAND} -C ${CMAKE_BUILD_TYPE} --build-and-test "${CMAKE_CURRENT_SOURCE_DIR}/add-subdirectory-test" "${CMAKE_CURRENT_BINARY_DIR}/add-subdirectory-test" --build-generator ${CMAKE_GENERATOR} --build-makeprogram ${CMAKE_MAKE_PROGRAM} --build-options "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" "-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}" "-DPEDANTIC_COMPILE_FLAGS=${PEDANTIC_COMPILE_FLAGS}" "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}") endif () # This test is disabled on Windows because it is POSIX-specific. if (FMT_PEDANTIC AND NOT WIN32) add_test(static-export-test ${CMAKE_CTEST_COMMAND} -C ${CMAKE_BUILD_TYPE} --build-and-test "${CMAKE_CURRENT_SOURCE_DIR}/static-export-test" "${CMAKE_CURRENT_BINARY_DIR}/static-export-test" --build-generator ${CMAKE_GENERATOR} --build-makeprogram ${CMAKE_MAKE_PROGRAM} --build-options "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" "-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}" "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}") endif () # Activate optional CUDA tests if CUDA is found. For version selection see # https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#cpp14-language-features if (FMT_CUDA_TEST) if (${CMAKE_VERSION} VERSION_LESS 3.15) find_package(CUDA 9.0) else () include(CheckLanguage) check_language(CUDA) if (CMAKE_CUDA_COMPILER) enable_language(CUDA OPTIONAL) set(CUDA_FOUND TRUE) endif () endif () if (CUDA_FOUND) add_subdirectory(cuda-test) add_test(NAME cuda-test COMMAND fmt-in-cuda-test) endif () endif () soci-4.1.4/3rdparty/fmt/test/enforce-checks-test.cc0000664000175000017500000000332215100423533022051 0ustar zeitlinzeitlin// Formatting library for C++ - formatting library tests // // Copyright (c) 2012 - present, Victor Zverovich // All rights reserved. // // For the license information refer to format.h. #include #include #define I 42 // simulate https://en.cppreference.com/w/c/numeric/complex/I #include "fmt/chrono.h" #include "fmt/color.h" #include "fmt/format.h" #include "fmt/ostream.h" #include "fmt/ranges.h" #include "fmt/xchar.h" #undef I // Exercise the API to verify that everything we expect to can compile. void test_format_api() { (void)fmt::format(FMT_STRING("{}"), 42); (void)fmt::format(FMT_STRING(L"{}"), 42); (void)fmt::format(FMT_STRING("noop")); (void)fmt::to_string(42); (void)fmt::to_wstring(42); std::vector out; fmt::format_to(std::back_inserter(out), FMT_STRING("{}"), 42); char buffer[4]; fmt::format_to_n(buffer, 3, FMT_STRING("{}"), 12345); wchar_t wbuffer[4]; fmt::format_to_n(wbuffer, 3, FMT_STRING(L"{}"), 12345); } void test_chrono() { (void)fmt::format(FMT_STRING("{}"), std::chrono::seconds(42)); (void)fmt::format(FMT_STRING(L"{}"), std::chrono::seconds(42)); } void test_text_style() { fmt::print(fg(fmt::rgb(255, 20, 30)), FMT_STRING("{}"), "rgb(255,20,30)"); (void)fmt::format(fg(fmt::rgb(255, 20, 30)), FMT_STRING("{}"), "rgb(255,20,30)"); fmt::text_style ts = fg(fmt::rgb(255, 20, 30)); std::string out; fmt::format_to(std::back_inserter(out), ts, FMT_STRING("rgb(255,20,30){}{}{}"), 1, 2, 3); } void test_range() { std::vector hello = {'h', 'e', 'l', 'l', 'o'}; (void)fmt::format(FMT_STRING("{}"), hello); } int main() { test_format_api(); test_chrono(); test_text_style(); test_range(); } soci-4.1.4/3rdparty/fmt/test/posix-mock.h0000664000175000017500000000302415100423533020147 0ustar zeitlinzeitlin// Formatting library for C++ - mocks of POSIX functions // // Copyright (c) 2012 - present, Victor Zverovich // All rights reserved. // // For the license information refer to format.h. #ifndef FMT_POSIX_TEST_H #define FMT_POSIX_TEST_H #include #include #include #ifdef __APPLE__ # include #endif #ifdef _WIN32 # include #else # include // for FreeBSD version # include // for ssize_t #endif #ifndef _MSC_VER struct stat; #endif namespace test { #ifndef _MSC_VER // Size type for read and write. using size_t = size_t; using ssize_t = ssize_t; int open(const char* path, int oflag, int mode); int fstat(int fd, struct stat* buf); #else using size_t = unsigned; using ssize_t = int; #endif #ifndef _WIN32 long sysconf(int name); #else DWORD GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh); #endif int close(int fildes); int dup(int fildes); int dup2(int fildes, int fildes2); FILE* fdopen(int fildes, const char* mode); ssize_t read(int fildes, void* buf, size_t nbyte); ssize_t write(int fildes, const void* buf, size_t nbyte); #ifndef _WIN32 int pipe(int fildes[2]); #else int pipe(int* pfds, unsigned psize, int textmode); #endif FILE* fopen(const char* filename, const char* mode); int fclose(FILE* stream); int(fileno)(FILE* stream); #if defined(FMT_LOCALE) && !defined(_WIN32) locale_t newlocale(int category_mask, const char* locale, locale_t base); #endif } // namespace test #define FMT_SYSTEM(call) test::call #endif // FMT_POSIX_TEST_H soci-4.1.4/3rdparty/fmt/test/header-only-test.cc0000664000175000017500000000037515100423533021406 0ustar zeitlinzeitlin// Header-only configuration test #include "fmt/base.h" #include "fmt/ostream.h" #include "gtest/gtest.h" #ifndef FMT_HEADER_ONLY # error "Not in the header-only mode." #endif TEST(header_only_test, format) { EXPECT_EQ(fmt::format("foo"), "foo"); } soci-4.1.4/3rdparty/fmt/test/ostream-test.cc0000664000175000017500000002202515100423533020645 0ustar zeitlinzeitlin// Formatting library for C++ - std::ostream support tests // // Copyright (c) 2012 - present, Victor Zverovich // All rights reserved. // // For the license information refer to format.h. #include #include "fmt/format.h" using fmt::runtime; struct test {}; // Test that there is no issues with specializations when fmt/ostream.h is // included after fmt/format.h. namespace fmt { template <> struct formatter : formatter { auto format(const test&, format_context& ctx) const -> decltype(ctx.out()) { return formatter::format(42, ctx); } }; } // namespace fmt #include #include "fmt/compile.h" #include "fmt/ostream.h" #include "fmt/ranges.h" #include "gmock/gmock.h" #include "gtest-extra.h" #include "util.h" auto operator<<(std::ostream& os, const date& d) -> std::ostream& { os << d.year() << '-' << d.month() << '-' << d.day(); return os; } auto operator<<(std::wostream& os, const date& d) -> std::wostream& { os << d.year() << L'-' << d.month() << L'-' << d.day(); return os; } // Make sure that overloaded comma operators do no harm to is_streamable. struct type_with_comma_op {}; template void operator,(type_with_comma_op, const T&); template type_with_comma_op operator<<(T&, const date&); enum streamable_enum {}; auto operator<<(std::ostream& os, streamable_enum) -> std::ostream& { return os << "streamable_enum"; } enum unstreamable_enum {}; auto format_as(unstreamable_enum e) -> int { return e; } struct empty_test {}; auto operator<<(std::ostream& os, empty_test) -> std::ostream& { return os << ""; } namespace fmt { template <> struct formatter : ostream_formatter {}; template <> struct formatter : ostream_formatter {}; template <> struct formatter : ostream_formatter {}; template <> struct formatter : ostream_formatter {}; } // namespace fmt TEST(ostream_test, enum) { EXPECT_EQ("streamable_enum", fmt::format("{}", streamable_enum())); EXPECT_EQ("0", fmt::format("{}", unstreamable_enum())); } TEST(ostream_test, format) { EXPECT_EQ("a string", fmt::format("{0}", test_string("a string"))); EXPECT_EQ("The date is 2012-12-9", fmt::format("The date is {0}", date(2012, 12, 9))); } TEST(ostream_test, format_specs) { using fmt::format_error; EXPECT_EQ("def ", fmt::format("{0:<5}", test_string("def"))); EXPECT_EQ(" def", fmt::format("{0:>5}", test_string("def"))); EXPECT_EQ(" def ", fmt::format("{0:^5}", test_string("def"))); EXPECT_EQ("def**", fmt::format("{0:*<5}", test_string("def"))); EXPECT_THROW_MSG((void)fmt::format(runtime("{0:+}"), test_string()), format_error, "invalid format specifier"); EXPECT_THROW_MSG((void)fmt::format(runtime("{0:-}"), test_string()), format_error, "invalid format specifier"); EXPECT_THROW_MSG((void)fmt::format(runtime("{0: }"), test_string()), format_error, "invalid format specifier"); EXPECT_THROW_MSG((void)fmt::format(runtime("{0:#}"), test_string()), format_error, "invalid format specifier"); EXPECT_THROW_MSG((void)fmt::format(runtime("{0:05}"), test_string()), format_error, "format specifier requires numeric argument"); EXPECT_EQ("test ", fmt::format("{0:13}", test_string("test"))); EXPECT_EQ("test ", fmt::format("{0:{1}}", test_string("test"), 13)); EXPECT_EQ("te", fmt::format("{0:.2}", test_string("test"))); EXPECT_EQ("te", fmt::format("{0:.{1}}", test_string("test"), 2)); } TEST(ostream_test, empty_custom_output) { EXPECT_EQ("", fmt::format("{}", empty_test())); } TEST(ostream_test, print) { { std::ostringstream os; fmt::print(os, "Don't {}!", "panic"); EXPECT_EQ("Don't panic!", os.str()); } { std::ostringstream os; fmt::println(os, "Don't {}!", "panic"); EXPECT_EQ("Don't panic!\n", os.str()); } } TEST(ostream_test, write_to_ostream) { std::ostringstream os; fmt::memory_buffer buffer; const char* foo = "foo"; buffer.append(foo, foo + std::strlen(foo)); fmt::detail::write_buffer(os, buffer); EXPECT_EQ("foo", os.str()); } TEST(ostream_test, write_to_ostream_max_size) { auto max_size = fmt::detail::max_value(); auto max_streamsize = fmt::detail::max_value(); if (max_size <= fmt::detail::to_unsigned(max_streamsize)) return; struct test_buffer final : fmt::detail::buffer { explicit test_buffer(size_t size) : fmt::detail::buffer([](buffer&, size_t) {}, nullptr, size, size) {} } buffer(max_size); struct mock_streambuf : std::streambuf { MOCK_METHOD(std::streamsize, xsputn, (const void*, std::streamsize)); auto xsputn(const char* s, std::streamsize n) -> std::streamsize override { const void* v = s; return xsputn(v, n); } } streambuf; struct test_ostream : std::ostream { explicit test_ostream(mock_streambuf& output_buffer) : std::ostream(&output_buffer) {} } os(streambuf); testing::InSequence sequence; const char* data = nullptr; using ustreamsize = std::make_unsigned::type; ustreamsize size = max_size; do { auto n = std::min(size, fmt::detail::to_unsigned(max_streamsize)); EXPECT_CALL(streambuf, xsputn(data, static_cast(n))) .WillOnce(testing::Return(max_streamsize)); data += n; size -= n; } while (size != 0); fmt::detail::write_buffer(os, buffer); } TEST(ostream_test, join) { int v[3] = {1, 2, 3}; EXPECT_EQ("1, 2, 3", fmt::format("{}", fmt::join(v, v + 3, ", "))); } TEST(ostream_test, join_fallback_formatter) { auto strs = std::vector{test_string("foo"), test_string("bar")}; EXPECT_EQ("foo, bar", fmt::format("{}", fmt::join(strs, ", "))); } #if FMT_USE_CONSTEXPR TEST(ostream_test, constexpr_string) { EXPECT_EQ("42", fmt::format(FMT_STRING("{}"), std::string("42"))); EXPECT_EQ("a string", fmt::format(FMT_STRING("{0}"), test_string("a string"))); } #endif namespace fmt_test { struct abc {}; template auto operator<<(Output& out, abc) -> Output& { return out << "abc"; } } // namespace fmt_test template struct test_template {}; template auto operator<<(std::ostream& os, test_template) -> std::ostream& { return os << 1; } namespace fmt { template struct formatter> : formatter { auto format(test_template, format_context& ctx) const -> decltype(ctx.out()) { return formatter::format(2, ctx); } }; template <> struct formatter : ostream_formatter {}; } // namespace fmt TEST(ostream_test, template) { EXPECT_EQ("2", fmt::format("{}", test_template())); } TEST(ostream_test, format_to_n) { char buffer[4]; buffer[3] = 'x'; auto result = fmt::format_to_n(buffer, 3, "{}", fmt_test::abc()); EXPECT_EQ(3u, result.size); EXPECT_EQ(buffer + 3, result.out); EXPECT_EQ("abcx", fmt::string_view(buffer, 4)); result = fmt::format_to_n(buffer, 3, "x{}y", fmt_test::abc()); EXPECT_EQ(5u, result.size); EXPECT_EQ(buffer + 3, result.out); EXPECT_EQ("xabx", fmt::string_view(buffer, 4)); } struct copyfmt_test {}; std::ostream& operator<<(std::ostream& os, copyfmt_test) { std::ios ios(nullptr); ios.copyfmt(os); return os << "foo"; } namespace fmt { template <> struct formatter : ostream_formatter {}; } // namespace fmt TEST(ostream_test, copyfmt) { EXPECT_EQ("foo", fmt::format("{}", copyfmt_test())); } TEST(ostream_test, to_string) { EXPECT_EQ("abc", fmt::to_string(fmt_test::abc())); } TEST(ostream_test, range) { auto strs = std::vector{test_string("foo"), test_string("bar")}; EXPECT_EQ("[foo, bar]", fmt::format("{}", strs)); } struct abstract { virtual ~abstract() = default; virtual void f() = 0; friend auto operator<<(std::ostream& os, const abstract&) -> std::ostream& { return os; } }; namespace fmt { template <> struct formatter : ostream_formatter {}; } // namespace fmt void format_abstract_compiles(const abstract& a) { fmt::format(FMT_COMPILE("{}"), a); } TEST(ostream_test, is_formattable) { EXPECT_TRUE(fmt::is_formattable()); EXPECT_TRUE(fmt::is_formattable>()); } struct streamable_and_unformattable {}; auto operator<<(std::ostream& os, streamable_and_unformattable) -> std::ostream& { return os << "foo"; } TEST(ostream_test, streamed) { EXPECT_FALSE(fmt::is_formattable()); EXPECT_EQ(fmt::format("{}", fmt::streamed(streamable_and_unformattable())), "foo"); } TEST(ostream_test, closed_ofstream) { std::ofstream ofs; fmt::print(ofs, "discard"); } struct unlocalized {}; auto operator<<(std::ostream& os, unlocalized) -> std::ostream& { return os << 12345; } namespace fmt { template <> struct formatter : ostream_formatter {}; } // namespace fmt TEST(ostream_test, unlocalized) { auto loc = get_locale("en_US.UTF-8"); std::locale::global(loc); EXPECT_EQ(fmt::format(loc, "{}", unlocalized()), "12345"); } soci-4.1.4/3rdparty/fmt/test/no-builtin-types-test.cc0000664000175000017500000000121315100423533022411 0ustar zeitlinzeitlin// Formatting library for C++ - formatting library tests // // Copyright (c) 2012 - present, Victor Zverovich // All rights reserved. // // For the license information refer to format.h. #include "gtest/gtest.h" #if !defined(__GNUC__) || __GNUC__ >= 5 # define FMT_BUILTIN_TYPES 0 # include "fmt/format.h" TEST(no_builtin_types_test, format) { EXPECT_EQ(fmt::format("{}", 42), "42"); EXPECT_EQ(fmt::format("{}", 42L), "42"); } TEST(no_builtin_types_test, double_is_custom_type) { double d = 42; auto args = fmt::make_format_args(d); EXPECT_EQ(fmt::format_args(args).get(0).type(), fmt::detail::type::custom_type); } #endif soci-4.1.4/3rdparty/fmt/test/static-export-test/0000775000175000017500000000000015100423533021471 5ustar zeitlinzeitlinsoci-4.1.4/3rdparty/fmt/test/static-export-test/library.cc0000664000175000017500000000021615100423533023443 0ustar zeitlinzeitlin#include __attribute__((visibility("default"))) std::string foo() { return fmt::format(FMT_COMPILE("foo bar {}"), 4242); } soci-4.1.4/3rdparty/fmt/test/static-export-test/CMakeLists.txt0000664000175000017500000000145515100423533024236 0ustar zeitlinzeitlincmake_minimum_required(VERSION 3.8...3.25) project(fmt-link CXX) set(BUILD_SHARED_LIBS OFF) set(CMAKE_VISIBILITY_INLINES_HIDDEN TRUE) set(CMAKE_CXX_VISIBILITY_PRESET "hidden") # Broken LTO on GCC 4 if (CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5) set(BROKEN_LTO ON) endif () if (NOT BROKEN_LTO AND CMAKE_VERSION VERSION_GREATER "3.8") # CMake 3.9+ include(CheckIPOSupported) check_ipo_supported(RESULT HAVE_IPO) if (HAVE_IPO) set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) endif () endif () add_subdirectory(../.. fmt) set_property(TARGET fmt PROPERTY POSITION_INDEPENDENT_CODE ON) add_library(library-test SHARED library.cc) target_link_libraries(library-test PRIVATE fmt::fmt) add_executable(exe-test main.cc) target_link_libraries(exe-test PRIVATE library-test) soci-4.1.4/3rdparty/fmt/test/static-export-test/main.cc0000664000175000017500000000016215100423533022723 0ustar zeitlinzeitlin#include #include extern std::string foo(); int main() { std::cout << foo() << std::endl; } soci-4.1.4/3rdparty/fmt/test/perf-sanity.cc0000664000175000017500000000137415100423533020463 0ustar zeitlinzeitlin// A quick and dirty performance test. // For actual benchmarks see https://github.com/fmtlib/format-benchmark. #include #include #include #include "fmt/format.h" int main() { const int n = 10000000; auto start = std::chrono::steady_clock::now(); for (int iteration = 0; iteration < n; ++iteration) { auto buf = fmt::memory_buffer(); fmt::format_to(std::back_inserter(buf), "Hello, {}. The answer is {} and {}.", 1, 2345, 6789); } std::atomic_signal_fence(std::memory_order_acq_rel); // Clobber memory. auto end = std::chrono::steady_clock::now(); // Print time in milliseconds. std::chrono::duration duration = end - start; fmt::print("{:.1f}\n", duration.count() * 1000); } soci-4.1.4/3rdparty/fmt/test/compile-error-test/0000775000175000017500000000000015100423533021442 5ustar zeitlinzeitlinsoci-4.1.4/3rdparty/fmt/test/compile-error-test/CMakeLists.txt0000664000175000017500000001532515100423533024210 0ustar zeitlinzeitlin# Test if compile errors are produced where necessary. cmake_minimum_required(VERSION 3.8...3.25) project(compile-error-test CXX) set(fmt_headers " #include #include #include #include ") set(error_test_names "") set(non_error_test_content "") # For error tests (we expect them to produce compilation error): # * adds a name of test into `error_test_names` list # * generates a single source file (with the same name) for each test # For non-error tests (we expect them to compile successfully): # * adds a code segment as separate function to `non_error_test_content` function (expect_compile name code_fragment) cmake_parse_arguments(EXPECT_COMPILE "ERROR" "" "" ${ARGN}) string(MAKE_C_IDENTIFIER "${name}" test_name) if (EXPECT_COMPILE_ERROR) file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/${test_name}.cc" " ${fmt_headers} void ${test_name}() { ${code_fragment} } ") set(error_test_names_copy "${error_test_names}") list(APPEND error_test_names_copy "${test_name}") set(error_test_names "${error_test_names_copy}" PARENT_SCOPE) else() set(non_error_test_content " ${non_error_test_content} void ${test_name}() { ${code_fragment} }" PARENT_SCOPE) endif() endfunction () # Generates a source file for non-error test with `non_error_test_content` and # CMake project file with all error and single non-error test targets. function (run_tests) set(cmake_targets "") foreach(test_name IN LISTS error_test_names) set(cmake_targets " ${cmake_targets} add_library(test-${test_name} ${test_name}.cc) target_link_libraries(test-${test_name} PRIVATE fmt::fmt) ") endforeach() file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/non_error_test.cc" " ${fmt_headers} ${non_error_test_content} ") set(cmake_targets " ${cmake_targets} add_library(non-error-test non_error_test.cc) target_link_libraries(non-error-test PRIVATE fmt::fmt) ") file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/test/CMakeLists.txt" " cmake_minimum_required(VERSION 3.8...3.25) project(tests CXX) add_subdirectory(${FMT_DIR} fmt) ${cmake_targets} ") set(build_directory "${CMAKE_CURRENT_BINARY_DIR}/test/build") file(MAKE_DIRECTORY "${build_directory}") execute_process( COMMAND "${CMAKE_COMMAND}" "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" "-DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS}" "-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}" "-DCMAKE_GENERATOR=${CMAKE_GENERATOR}" "-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}" "-DFMT_DIR=${FMT_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/test" WORKING_DIRECTORY "${build_directory}" RESULT_VARIABLE result_var OUTPUT_VARIABLE output_var ERROR_VARIABLE output_var) if (NOT result_var EQUAL 0) message(FATAL_ERROR "Unable to configure:\n${output_var}") endif() foreach(test_name IN LISTS error_test_names) execute_process( COMMAND "${CMAKE_COMMAND}" --build "${build_directory}" --target "test-${test_name}" WORKING_DIRECTORY "${build_directory}" RESULT_VARIABLE result_var OUTPUT_VARIABLE output_var ERROR_QUIET) if (result_var EQUAL 0) message(SEND_ERROR "No compile error for \"${test_name}\":\n${output_var}") endif () endforeach() execute_process( COMMAND "${CMAKE_COMMAND}" --build "${build_directory}" --target "non-error-test" WORKING_DIRECTORY "${build_directory}" RESULT_VARIABLE result_var OUTPUT_VARIABLE output_var ERROR_VARIABLE output_var) if (NOT result_var EQUAL 0) message(SEND_ERROR "Compile error for combined non-error test:\n${output_var}") endif () endfunction () # Check if the source file skeleton compiles. expect_compile(check "") expect_compile(check-error "compilation_error" ERROR) # Formatting a wide character with a narrow format string is forbidden. expect_compile(wide-character-narrow-format-string "fmt::format(L\"{}\", L'a');") expect_compile(wide-character-narrow-format-string-error "fmt::format(\"{}\", L'a');" ERROR) # Formatting a wide string with a narrow format string is forbidden. expect_compile(wide-string-narrow-format-string "fmt::format(L\"{}\", L\"foo\");") expect_compile(wide-string-narrow-format-string-error "fmt::format(\"{}\", L\"foo\");" ERROR) # Formatting a narrow string with a wide format string is forbidden because # mixing UTF-8 with UTF-16/32 can result in an invalid output. expect_compile(narrow-string-wide-format-string "fmt::format(L\"{}\", L\"foo\");") expect_compile(narrow-string-wide-format-string-error "fmt::format(L\"{}\", \"foo\");" ERROR) expect_compile(cast-to-string " struct S { operator std::string() const { return std::string(); } }; fmt::format(\"{}\", std::string(S())); ") expect_compile(cast-to-string-error " struct S { operator std::string() const { return std::string(); } }; fmt::format(\"{}\", S()); " ERROR) # Formatting a function expect_compile(format-function " void (*f)(); fmt::format(\"{}\", fmt::ptr(f)); ") expect_compile(format-function-error " void (*f)(); fmt::format(\"{}\", f); " ERROR) # Formatting an unformattable argument should always be a compile time error expect_compile(format-lots-of-arguments-with-unformattable " struct E {}; fmt::format(\"\", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, E()); " ERROR) expect_compile(format-lots-of-arguments-with-function " void (*f)(); fmt::format(\"\", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, f); " ERROR) if (CMAKE_CXX_STANDARD GREATER_EQUAL 20) # Compile-time argument type check expect_compile(format-string-number-spec " #ifdef FMT_HAS_CONSTEVAL fmt::format(\"{:d}\", 42); #endif ") expect_compile(format-string-number-spec-error " #ifdef FMT_HAS_CONSTEVAL fmt::format(\"{:d}\", \"I am not a number\"); #else #error #endif " ERROR) expect_compile(print-string-number-spec-error " #ifdef FMT_HAS_CONSTEVAL fmt::print(\"{:d}\", \"I am not a number\"); #else #error #endif " ERROR) expect_compile(print-stream-string-number-spec-error " #ifdef FMT_HAS_CONSTEVAL fmt::print(std::cout, \"{:d}\", \"I am not a number\"); #else #error #endif " ERROR) # Compile-time argument name check expect_compile(format-string-name " #if defined(FMT_HAS_CONSTEVAL) && FMT_USE_NONTYPE_TEMPLATE_ARGS using namespace fmt::literals; fmt::print(\"{foo}\", \"foo\"_a=42); #endif ") expect_compile(format-string-name-error " #if defined(FMT_HAS_CONSTEVAL) && FMT_USE_NONTYPE_TEMPLATE_ARGS using namespace fmt::literals; fmt::print(\"{foo}\", \"bar\"_a=42); #else #error #endif " ERROR) endif () # Run all tests run_tests() soci-4.1.4/3rdparty/fmt/test/scan.h0000664000175000017500000004772715100423533017024 0ustar zeitlinzeitlin// Formatting library for C++ - scanning API proof of concept // // Copyright (c) 2019 - present, Victor Zverovich // All rights reserved. // // For the license information refer to format.h. #include #include #include #include #include "fmt/format-inl.h" FMT_BEGIN_NAMESPACE namespace detail { inline auto is_whitespace(char c) -> bool { return c == ' ' || c == '\n'; } // If c is a hex digit returns its numeric value, otherwise -1. inline auto to_hex_digit(char c) -> int { if (c >= '0' && c <= '9') return c - '0'; if (c >= 'a' && c <= 'f') return c - 'a' + 10; if (c >= 'A' && c <= 'F') return c - 'A' + 10; return -1; } struct maybe_contiguous_range { const char* begin; const char* end; explicit operator bool() const { return begin != nullptr; } }; class scan_buffer { private: const char* ptr_; const char* end_; bool contiguous_; protected: scan_buffer(const char* ptr, const char* end, bool contiguous) : ptr_(ptr), end_(end), contiguous_(contiguous) {} ~scan_buffer() = default; void set(span buf) { ptr_ = buf.data; end_ = buf.data + buf.size; } auto ptr() const -> const char* { return ptr_; } public: scan_buffer(const scan_buffer&) = delete; void operator=(const scan_buffer&) = delete; // Fills the buffer with more input if available. virtual void consume() = 0; class sentinel {}; class iterator { private: const char** ptr_; scan_buffer* buf_; // This could be merged with ptr_. char value_; static auto get_sentinel() -> const char** { static const char* ptr = nullptr; return &ptr; } friend class scan_buffer; friend auto operator==(iterator lhs, sentinel) -> bool { return *lhs.ptr_ == nullptr; } friend auto operator!=(iterator lhs, sentinel) -> bool { return *lhs.ptr_ != nullptr; } iterator(scan_buffer* buf) : buf_(buf) { if (buf->ptr_ == buf->end_) { ptr_ = get_sentinel(); return; } ptr_ = &buf->ptr_; value_ = *buf->ptr_; } friend scan_buffer& get_buffer(iterator it) { return *it.buf_; } public: iterator() : ptr_(get_sentinel()), buf_(nullptr) {} auto operator++() -> iterator& { if (!buf_->try_consume()) ptr_ = get_sentinel(); value_ = *buf_->ptr_; return *this; } auto operator++(int) -> iterator { iterator copy = *this; ++*this; return copy; } auto operator*() const -> char { return value_; } auto base() const -> const char* { return buf_->ptr_; } friend auto to_contiguous(iterator it) -> maybe_contiguous_range; friend auto advance(iterator it, size_t n) -> iterator; }; friend auto to_contiguous(iterator it) -> maybe_contiguous_range { if (it.buf_->is_contiguous()) return {it.buf_->ptr_, it.buf_->end_}; return {nullptr, nullptr}; } friend auto advance(iterator it, size_t n) -> iterator { FMT_ASSERT(it.buf_->is_contiguous(), ""); const char*& ptr = it.buf_->ptr_; ptr += n; it.value_ = *ptr; if (ptr == it.buf_->end_) it.ptr_ = iterator::get_sentinel(); return it; } auto begin() -> iterator { return this; } auto end() -> sentinel { return {}; } auto is_contiguous() const -> bool { return contiguous_; } // Tries consuming a single code unit. Returns true iff there is more input. auto try_consume() -> bool { FMT_ASSERT(ptr_ != end_, ""); ++ptr_; if (ptr_ != end_) return true; consume(); return ptr_ != end_; } }; using scan_iterator = scan_buffer::iterator; using scan_sentinel = scan_buffer::sentinel; class string_scan_buffer final : public scan_buffer { private: void consume() override {} public: explicit string_scan_buffer(string_view s) : scan_buffer(s.begin(), s.end(), true) {} }; class file_scan_buffer final : public scan_buffer { private: template static auto get_file(F* f, int) -> glibc_file { return f; } template static auto get_file(F* f, int) -> apple_file { return f; } static auto get_file(FILE* f, ...) -> fallback_file { return f; } decltype(get_file(static_cast(nullptr), 0)) file_; // Fills the buffer if it is empty. void fill() { span buf = file_.get_read_buffer(); if (buf.size == 0) { int c = file_.get(); // Put the character back since we are only filling the buffer. if (c != EOF) file_.unget(static_cast(c)); buf = file_.get_read_buffer(); } set(buf); } void consume() override { // Consume the current buffer content. size_t n = to_unsigned(ptr() - file_.get_read_buffer().data); for (size_t i = 0; i != n; ++i) file_.get(); fill(); } public: explicit file_scan_buffer(FILE* f) : scan_buffer(nullptr, nullptr, false), file_(f) { flockfile(f); fill(); } ~file_scan_buffer() { FILE* f = file_; funlockfile(f); } }; } // namespace detail template struct scanner { // A deleted default constructor indicates a disabled scanner. scanner() = delete; }; class scan_parse_context { private: string_view format_; public: using iterator = string_view::iterator; FMT_CONSTEXPR explicit scan_parse_context(string_view format) : format_(format) {} FMT_CONSTEXPR auto begin() const -> iterator { return format_.begin(); } FMT_CONSTEXPR auto end() const -> iterator { return format_.end(); } void advance_to(iterator it) { format_.remove_prefix(detail::to_unsigned(it - begin())); } }; namespace detail { enum class scan_type { none_type, int_type, uint_type, long_long_type, ulong_long_type, double_type, float_type, string_type, string_view_type, custom_type }; template struct custom_scan_arg { void* value; void (*scan)(void* arg, scan_parse_context& parse_ctx, Context& ctx); }; } // namespace detail // A scan argument. Context is a template parameter for the compiled API where // output can be unbuffered. template class basic_scan_arg { private: using scan_type = detail::scan_type; scan_type type_; union { int* int_value_; unsigned* uint_value_; long long* long_long_value_; unsigned long long* ulong_long_value_; double* double_value_; float* float_value_; std::string* string_; string_view* string_view_; detail::custom_scan_arg custom_; // TODO: more types }; template static void scan_custom_arg(void* arg, scan_parse_context& parse_ctx, Context& ctx) { auto s = scanner(); parse_ctx.advance_to(s.parse(parse_ctx)); ctx.advance_to(s.scan(*static_cast(arg), ctx)); } public: FMT_CONSTEXPR basic_scan_arg() : type_(scan_type::none_type), int_value_(nullptr) {} FMT_CONSTEXPR basic_scan_arg(int& value) : type_(scan_type::int_type), int_value_(&value) {} FMT_CONSTEXPR basic_scan_arg(unsigned& value) : type_(scan_type::uint_type), uint_value_(&value) {} FMT_CONSTEXPR basic_scan_arg(long long& value) : type_(scan_type::long_long_type), long_long_value_(&value) {} FMT_CONSTEXPR basic_scan_arg(unsigned long long& value) : type_(scan_type::ulong_long_type), ulong_long_value_(&value) {} FMT_CONSTEXPR basic_scan_arg(double& value) : type_(scan_type::double_type), double_value_(&value) {} FMT_CONSTEXPR basic_scan_arg(float& value) : type_(scan_type::float_type), float_value_(&value) {} FMT_CONSTEXPR basic_scan_arg(std::string& value) : type_(scan_type::string_type), string_(&value) {} FMT_CONSTEXPR basic_scan_arg(string_view& value) : type_(scan_type::string_view_type), string_view_(&value) {} template FMT_CONSTEXPR basic_scan_arg(T& value) : type_(scan_type::custom_type) { custom_.value = &value; custom_.scan = scan_custom_arg; } constexpr explicit operator bool() const noexcept { return type_ != scan_type::none_type; } auto type() const -> detail::scan_type { return type_; } template auto visit(Visitor&& vis) -> decltype(vis(monostate())) { switch (type_) { case scan_type::none_type: break; case scan_type::int_type: return vis(*int_value_); case scan_type::uint_type: return vis(*uint_value_); case scan_type::long_long_type: return vis(*long_long_value_); case scan_type::ulong_long_type: return vis(*ulong_long_value_); case scan_type::double_type: return vis(*double_value_); case scan_type::float_type: return vis(*float_value_); case scan_type::string_type: return vis(*string_); case scan_type::string_view_type: return vis(*string_view_); case scan_type::custom_type: break; } return vis(monostate()); } auto scan_custom(const char* parse_begin, scan_parse_context& parse_ctx, Context& ctx) const -> bool { if (type_ != scan_type::custom_type) return false; parse_ctx.advance_to(parse_begin); custom_.scan(custom_.value, parse_ctx, ctx); return true; } }; class scan_context; using scan_arg = basic_scan_arg; struct scan_args { int size; const scan_arg* data; template FMT_CONSTEXPR scan_args(const std::array& store) : size(N), data(store.data()) { static_assert(N < INT_MAX, "too many arguments"); } }; class scan_context { private: detail::scan_buffer& buf_; scan_args args_; public: using iterator = detail::scan_iterator; using sentinel = detail::scan_sentinel; FMT_CONSTEXPR explicit scan_context(detail::scan_buffer& buf, scan_args args) : buf_(buf), args_(args) {} FMT_CONSTEXPR auto arg(int id) const -> scan_arg { return id < args_.size ? args_.data[id] : scan_arg(); } auto begin() const -> iterator { return buf_.begin(); } auto end() const -> sentinel { return {}; } void advance_to(iterator) { buf_.consume(); } }; namespace detail { const char* parse_scan_specs(const char* begin, const char* end, format_specs& specs, scan_type) { while (begin != end) { switch (to_ascii(*begin)) { // TODO: parse more scan format specifiers case 'x': specs.set_type(presentation_type::hex); ++begin; break; case '}': return begin; } } return begin; } template ::value)> auto read(scan_iterator it, T& value) -> scan_iterator { if (it == scan_sentinel()) return it; char c = *it; if (c < '0' || c > '9') report_error("invalid input"); int num_digits = 0; T n = 0, prev = 0; char prev_digit = c; do { prev = n; n = n * 10 + static_cast(c - '0'); prev_digit = c; c = *++it; ++num_digits; if (c < '0' || c > '9') break; } while (it != scan_sentinel()); // Check overflow. if (num_digits <= std::numeric_limits::digits10) { value = n; return it; } unsigned max = to_unsigned((std::numeric_limits::max)()); if (num_digits == std::numeric_limits::digits10 + 1 && prev * 10ull + unsigned(prev_digit - '0') <= max) { value = n; } else { report_error("number is too big"); } return it; } template ::value)> auto read_hex(scan_iterator it, T& value) -> scan_iterator { if (it == scan_sentinel()) return it; int digit = to_hex_digit(*it); if (digit < 0) report_error("invalid input"); int num_digits = 0; T n = 0; do { n = (n << 4) + static_cast(digit); ++num_digits; digit = to_hex_digit(*++it); if (digit < 0) break; } while (it != scan_sentinel()); // Check overflow. if (num_digits <= (std::numeric_limits::digits >> 2)) value = n; else report_error("number is too big"); return it; } template ::value)> auto read(scan_iterator it, T& value, const format_specs& specs) -> scan_iterator { if (specs.type() == presentation_type::hex) return read_hex(it, value); return read(it, value); } template ::value)> auto read(scan_iterator it, T& value, const format_specs& specs = {}) -> scan_iterator { bool negative = it != scan_sentinel() && *it == '-'; if (negative) { ++it; if (it == scan_sentinel()) report_error("invalid input"); } using unsigned_type = typename std::make_unsigned::type; unsigned_type abs_value = 0; it = read(it, abs_value, specs); auto n = static_cast(abs_value); value = negative ? -n : n; return it; } auto read(scan_iterator it, double& value, const format_specs& = {}) -> scan_iterator { if (it == scan_sentinel()) return it; // Simple floating-point parsing bool negative = *it == '-'; if (negative) { ++it; if (it == scan_sentinel()) report_error("invalid input"); } double result = 0.0; // Parse integer part while (it != scan_sentinel() && *it >= '0' && *it <= '9') { result = result * 10.0 + (*it - '0'); ++it; } // Parse decimal part if present if (it != scan_sentinel() && *it == '.') { ++it; double fraction = 0.1; while (it != scan_sentinel() && *it >= '0' && *it <= '9') { result += (*it - '0') * fraction; fraction *= 0.1; ++it; } } value = negative ? -result : result; return it; } auto read(scan_iterator it, float& value, const format_specs& specs = {}) -> scan_iterator { double temp; it = read(it, temp, specs); value = static_cast(temp); return it; } auto read(scan_iterator it, std::string& value, const format_specs& = {}) -> scan_iterator { while (it != scan_sentinel() && *it != ' ') value.push_back(*it++); return it; } auto read(scan_iterator it, string_view& value, const format_specs& = {}) -> scan_iterator { auto range = to_contiguous(it); // This could also be checked at compile time in scan. if (!range) report_error("string_view requires contiguous input"); auto p = range.begin; while (p != range.end && *p != ' ') ++p; size_t size = to_unsigned(p - range.begin); value = {range.begin, size}; return advance(it, size); } auto read(scan_iterator it, monostate, const format_specs& = {}) -> scan_iterator { return it; } // An argument scanner that uses the default format, e.g. decimal for integers. struct default_arg_scanner { scan_iterator it; template FMT_INLINE auto operator()(T&& value) -> scan_iterator { return read(it, value); } }; // An argument scanner with format specifiers. struct arg_scanner { scan_iterator it; const format_specs& specs; template auto operator()(T&& value) -> scan_iterator { return read(it, value, specs); } }; struct scan_handler { private: scan_parse_context parse_ctx_; scan_context scan_ctx_; int next_arg_id_; using sentinel = scan_buffer::sentinel; public: FMT_CONSTEXPR scan_handler(string_view format, scan_buffer& buf, scan_args args) : parse_ctx_(format), scan_ctx_(buf, args), next_arg_id_(0) {} auto pos() const -> scan_buffer::iterator { return scan_ctx_.begin(); } void on_text(const char* begin, const char* end) { if (begin == end) return; auto it = scan_ctx_.begin(); for (; begin != end; ++begin, ++it) { if (it == sentinel() || *begin != *it) on_error("invalid input"); } scan_ctx_.advance_to(it); } FMT_CONSTEXPR auto on_arg_id() -> int { return on_arg_id(next_arg_id_++); } FMT_CONSTEXPR auto on_arg_id(int id) -> int { if (!scan_ctx_.arg(id)) on_error("argument index out of range"); return id; } FMT_CONSTEXPR auto on_arg_id(string_view id) -> int { if (id.data()) on_error("invalid format"); return 0; } void on_replacement_field(int arg_id, const char* begin) { scan_arg arg = scan_ctx_.arg(arg_id); if (arg.scan_custom(begin, parse_ctx_, scan_ctx_)) return; auto it = scan_ctx_.begin(); while (it != sentinel() && is_whitespace(*it)) ++it; scan_ctx_.advance_to(arg.visit(default_arg_scanner{it})); } auto on_format_specs(int arg_id, const char* begin, const char* end) -> const char* { scan_arg arg = scan_ctx_.arg(arg_id); if (arg.scan_custom(begin, parse_ctx_, scan_ctx_)) return parse_ctx_.begin(); auto specs = format_specs(); begin = parse_scan_specs(begin, end, specs, arg.type()); if (begin == end || *begin != '}') on_error("missing '}' in format string"); scan_ctx_.advance_to(arg.visit(arg_scanner{scan_ctx_.begin(), specs})); return begin; } FMT_NORETURN void on_error(const char* message) { report_error(message); } }; void vscan(detail::scan_buffer& buf, string_view fmt, scan_args args) { auto h = detail::scan_handler(fmt, buf, args); detail::parse_format_string(fmt, h); } template void make_args(std::array&, std::tuple&) {} template void make_args(std::array& args, std::tuple& values) { using element_type = typename std::tuple_element>::type; static_assert(std::is_same, element_type>::value, ""); args[I] = std::get(values); make_args(args, values); } } // namespace detail template class scan_data { private: std::tuple values_; Range range_; public: scan_data() = default; scan_data(T... values) : values_(std::move(values)...) {} auto value() const -> decltype(std::get<0>(values_)) { return std::get<0>(values_); } auto values() const -> const std::tuple& { return values_; } auto make_args() -> std::array { auto args = std::array(); detail::make_args<0>(args, values_); return args; } auto range() const -> Range { return range_; } auto begin() const -> decltype(range_.begin()) { return range_.begin(); } auto end() const -> decltype(range_.end()) { return range_.end(); } }; template auto make_scan_args(T&... args) -> std::array { return {{args...}}; } class scan_error {}; // A rudimentary version of std::expected for testing the API shape. template class expected { private: T value_; bool has_value_ = true; public: expected(T value) : value_(std::move(value)) {} explicit operator bool() const { return has_value_; } auto operator->() const -> const T* { return &value_; } auto error() -> E const { return E(); } }; template using scan_result = expected, scan_error>; auto vscan(string_view input, string_view fmt, scan_args args) -> string_view::iterator { auto&& buf = detail::string_scan_buffer(input); detail::vscan(buf, fmt, args); return input.begin() + (buf.begin().base() - input.data()); } // Scans the input and stores the results (in)to args. template auto scan_to(string_view input, string_view fmt, T&... args) -> string_view::iterator { return vscan(input, fmt, make_scan_args(args...)); } template auto scan(string_view input, string_view fmt) -> scan_result { auto data = scan_data(); vscan(input, fmt, data.make_args()); return data; } template ::value)> auto scan_to(Range&& input, string_view fmt, T&... args) -> decltype(std::begin(input)) { auto it = std::begin(input); detail::vscan(get_buffer(it), fmt, make_scan_args(args...)); return it; } template auto scan_to(FILE* f, string_view fmt, T&... args) -> bool { auto&& buf = detail::file_scan_buffer(f); detail::vscan(buf, fmt, make_scan_args(args...)); return buf.begin() != buf.end(); } FMT_END_NAMESPACE soci-4.1.4/3rdparty/fmt/test/util.cc0000664000175000017500000000235215100423533017174 0ustar zeitlinzeitlin// Formatting library for C++ - test utilities // // Copyright (c) 2012 - present, Victor Zverovich // All rights reserved. // // For the license information refer to format.h. #include "util.h" #include const char* const file_content = "Don't panic!"; fmt::buffered_file open_buffered_file(FILE** fp) { #if FMT_USE_FCNTL auto pipe = fmt::pipe(); pipe.write_end.write(file_content, std::strlen(file_content)); pipe.write_end.close(); fmt::buffered_file f = pipe.read_end.fdopen("r"); if (fp) *fp = f.get(); #else fmt::buffered_file f("test-file", "w"); fputs(file_content, f.get()); if (fp) *fp = f.get(); #endif return f; } std::locale do_get_locale(const char* name) { try { return std::locale(name); } catch (const std::runtime_error&) { } return std::locale::classic(); } std::locale get_locale(const char* name, const char* alt_name) { auto loc = do_get_locale(name); if (loc == std::locale::classic() && alt_name) loc = do_get_locale(alt_name); #ifdef __OpenBSD__ // Locales are not working in OpenBSD: // https://github.com/fmtlib/fmt/issues/3670. loc = std::locale::classic(); #endif if (loc == std::locale::classic()) fmt::print(stderr, "{} locale is missing.\n", name); return loc; } soci-4.1.4/3rdparty/fmt/test/ranges-odr-test.cc0000664000175000017500000000073615100423533021241 0ustar zeitlinzeitlin// Formatting library for C++ - the core API // // Copyright (c) 2012 - present, Victor Zverovich // All rights reserved. // // For the license information refer to format.h. #include #include "fmt/format.h" #include "fmt/ranges.h" #include "gtest/gtest.h" // call fmt::format from another translation unit to test ODR TEST(ranges_odr_test, format_vector) { auto v = std::vector{1, 2, 3, 5, 7, 11}; EXPECT_EQ(fmt::format("{}", v), "[1, 2, 3, 5, 7, 11]"); } soci-4.1.4/3rdparty/fmt/test/util.h0000664000175000017500000000340515100423533017036 0ustar zeitlinzeitlin// Formatting library for C++ - test utilities // // Copyright (c) 2012 - present, Victor Zverovich // All rights reserved. // // For the license information refer to format.h. #include #include #include #include #include "fmt/os.h" #ifdef _MSC_VER # define FMT_VSNPRINTF vsprintf_s #else # define FMT_VSNPRINTF vsnprintf #endif template void safe_sprintf(char (&buffer)[SIZE], const char* format, ...) { std::va_list args; va_start(args, format); FMT_VSNPRINTF(buffer, SIZE, format, args); va_end(args); } extern const char* const file_content; // Opens a buffered file for reading. auto open_buffered_file(FILE** fp = nullptr) -> fmt::buffered_file; template class basic_test_string { private: std::basic_string value_; static const Char empty[]; public: explicit basic_test_string(const Char* value = empty) : value_(value) {} auto value() const -> const std::basic_string& { return value_; } }; template const Char basic_test_string::empty[] = {0}; using test_string = basic_test_string; using test_wstring = basic_test_string; template auto operator<<(std::basic_ostream& os, const basic_test_string& s) -> std::basic_ostream& { os << s.value(); return os; } class date { int year_, month_, day_; public: date(int year, int month, int day) : year_(year), month_(month), day_(day) {} auto year() const -> int { return year_; } auto month() const -> int { return month_; } auto day() const -> int { return day_; } }; // Returns a locale with the given name if available or classic locale // otherwise. auto get_locale(const char* name, const char* alt_name = nullptr) -> std::locale; soci-4.1.4/3rdparty/fmt/test/color-test.cc0000664000175000017500000001435515100423533020320 0ustar zeitlinzeitlin// Formatting library for C++ - color tests // // Copyright (c) 2012 - present, Victor Zverovich // All rights reserved. // // For the license information refer to format.h. #include "fmt/color.h" #include // std::back_inserter #include "gtest-extra.h" // EXPECT_WRITE, EXPECT_THROW_MSG TEST(color_test, text_style) { EXPECT_FALSE(fmt::text_style().has_foreground()); EXPECT_FALSE(fmt::text_style().has_background()); EXPECT_FALSE(fmt::text_style().has_emphasis()); EXPECT_TRUE(fg(fmt::rgb(0)).has_foreground()); EXPECT_FALSE(fg(fmt::rgb(0)).has_background()); EXPECT_FALSE(fg(fmt::rgb(0)).has_emphasis()); EXPECT_TRUE(bg(fmt::rgb(0)).has_background()); EXPECT_FALSE(bg(fmt::rgb(0)).has_foreground()); EXPECT_FALSE(bg(fmt::rgb(0)).has_emphasis()); EXPECT_TRUE( (fg(fmt::rgb(0xFFFFFF)) | bg(fmt::rgb(0xFFFFFF))).has_foreground()); EXPECT_TRUE( (fg(fmt::rgb(0xFFFFFF)) | bg(fmt::rgb(0xFFFFFF))).has_background()); EXPECT_FALSE( (fg(fmt::rgb(0xFFFFFF)) | bg(fmt::rgb(0xFFFFFF))).has_emphasis()); EXPECT_EQ(fg(fmt::rgb(0x000000)) | fg(fmt::rgb(0x000000)), fg(fmt::rgb(0x000000))); EXPECT_EQ(fg(fmt::rgb(0x00000F)) | fg(fmt::rgb(0x00000F)), fg(fmt::rgb(0x00000F))); EXPECT_EQ(fg(fmt::rgb(0xC0F000)) | fg(fmt::rgb(0x000FEE)), fg(fmt::rgb(0xC0FFEE))); EXPECT_THROW_MSG( fg(fmt::terminal_color::black) | fg(fmt::terminal_color::black), fmt::format_error, "can't OR a terminal color"); EXPECT_THROW_MSG( fg(fmt::terminal_color::black) | fg(fmt::terminal_color::white), fmt::format_error, "can't OR a terminal color"); EXPECT_THROW_MSG( bg(fmt::terminal_color::black) | bg(fmt::terminal_color::black), fmt::format_error, "can't OR a terminal color"); EXPECT_THROW_MSG( bg(fmt::terminal_color::black) | bg(fmt::terminal_color::white), fmt::format_error, "can't OR a terminal color"); EXPECT_THROW_MSG(fg(fmt::terminal_color::black) | fg(fmt::color::black), fmt::format_error, "can't OR a terminal color"); EXPECT_THROW_MSG(bg(fmt::terminal_color::black) | bg(fmt::color::black), fmt::format_error, "can't OR a terminal color"); EXPECT_NO_THROW(fg(fmt::terminal_color::white) | bg(fmt::terminal_color::white)); EXPECT_NO_THROW(fg(fmt::terminal_color::white) | bg(fmt::rgb(0xFFFFFF))); EXPECT_NO_THROW(fg(fmt::terminal_color::white) | fmt::text_style()); EXPECT_NO_THROW(bg(fmt::terminal_color::white) | fmt::text_style()); } TEST(color_test, format) { EXPECT_EQ(fmt::format(fmt::text_style(), "no style"), "no style"); EXPECT_EQ(fmt::format(fg(fmt::rgb(255, 20, 30)), "rgb(255,20,30)"), "\x1b[38;2;255;020;030mrgb(255,20,30)\x1b[0m"); EXPECT_EQ(fmt::format(fg(fmt::rgb(255, 0, 0)) | fg(fmt::rgb(0, 20, 30)), "rgb(255,20,30)"), "\x1b[38;2;255;020;030mrgb(255,20,30)\x1b[0m"); EXPECT_EQ( fmt::format(fg(fmt::rgb(0, 0, 0)) | fg(fmt::rgb(0, 0, 0)), "rgb(0,0,0)"), "\x1b[38;2;000;000;000mrgb(0,0,0)\x1b[0m"); EXPECT_EQ(fmt::format(fg(fmt::color::blue), "blue"), "\x1b[38;2;000;000;255mblue\x1b[0m"); EXPECT_EQ( fmt::format(fg(fmt::color::blue) | bg(fmt::color::red), "two color"), "\x1b[38;2;000;000;255m\x1b[48;2;255;000;000mtwo color\x1b[0m"); EXPECT_EQ(fmt::format(fmt::emphasis::bold, "bold"), "\x1b[1mbold\x1b[0m"); EXPECT_EQ(fmt::format(fmt::emphasis::faint, "faint"), "\x1b[2mfaint\x1b[0m"); EXPECT_EQ(fmt::format(fmt::emphasis::italic, "italic"), "\x1b[3mitalic\x1b[0m"); EXPECT_EQ(fmt::format(fmt::emphasis::underline, "underline"), "\x1b[4munderline\x1b[0m"); EXPECT_EQ(fmt::format(fmt::emphasis::blink, "blink"), "\x1b[5mblink\x1b[0m"); EXPECT_EQ(fmt::format(fmt::emphasis::reverse, "reverse"), "\x1b[7mreverse\x1b[0m"); EXPECT_EQ(fmt::format(fmt::emphasis::conceal, "conceal"), "\x1b[8mconceal\x1b[0m"); EXPECT_EQ(fmt::format(fmt::emphasis::strikethrough, "strikethrough"), "\x1b[9mstrikethrough\x1b[0m"); EXPECT_EQ( fmt::format(fg(fmt::color::blue) | fmt::emphasis::bold, "blue/bold"), "\x1b[1m\x1b[38;2;000;000;255mblue/bold\x1b[0m"); EXPECT_EQ(fmt::format(fmt::emphasis::bold, "bold error"), "\x1b[1mbold error\x1b[0m"); EXPECT_EQ(fmt::format(fg(fmt::color::blue), "blue log"), "\x1b[38;2;000;000;255mblue log\x1b[0m"); EXPECT_EQ(fmt::format(fmt::text_style(), "hi"), "hi"); EXPECT_EQ(fmt::format(fg(fmt::terminal_color::red), "tred"), "\x1b[31mtred\x1b[0m"); EXPECT_EQ(fmt::format(bg(fmt::terminal_color::cyan), "tcyan"), "\x1b[46mtcyan\x1b[0m"); EXPECT_EQ(fmt::format(fg(fmt::terminal_color::bright_green), "tbgreen"), "\x1b[92mtbgreen\x1b[0m"); EXPECT_EQ(fmt::format(bg(fmt::terminal_color::bright_magenta), "tbmagenta"), "\x1b[105mtbmagenta\x1b[0m"); EXPECT_EQ(fmt::format(fg(fmt::terminal_color::red), "{}", "foo"), "\x1b[31mfoo\x1b[0m"); EXPECT_EQ(fmt::format("{}{}", fmt::styled("red", fg(fmt::color::red)), fmt::styled("bold", fmt::emphasis::bold)), "\x1b[38;2;255;000;000mred\x1b[0m\x1b[1mbold\x1b[0m"); EXPECT_EQ(fmt::format("{}", fmt::styled("bar", fg(fmt::color::blue) | fmt::emphasis::underline)), "\x1b[4m\x1b[38;2;000;000;255mbar\x1b[0m"); EXPECT_EQ( fmt::format( "{}", fmt::styled( "all", fmt::emphasis::bold | fmt::emphasis::faint | fmt::emphasis::italic | fmt::emphasis::underline | fmt::emphasis::blink | fmt::emphasis::reverse | fmt::emphasis::conceal | fmt::emphasis::strikethrough)), "\x1b[1;2;3;4;5;7;8;9mall\x1b[0m"); } TEST(color_test, format_to) { auto out = std::string(); fmt::format_to(std::back_inserter(out), fg(fmt::rgb(255, 20, 30)), "rgb(255,20,30){}{}{}", 1, 2, 3); EXPECT_EQ(fmt::to_string(out), "\x1b[38;2;255;020;030mrgb(255,20,30)123\x1b[0m"); } TEST(color_test, print) { EXPECT_WRITE(stdout, fmt::print(fg(fmt::rgb(255, 20, 30)), "rgb(255,20,30)"), "\x1b[38;2;255;020;030mrgb(255,20,30)\x1b[0m"); } soci-4.1.4/3rdparty/fmt/test/ranges-test.cc0000664000175000017500000006001315100423533020451 0ustar zeitlinzeitlin// Formatting library for C++ - ranges tests // // Copyright (c) 2012 - present, Victor Zverovich and {fmt} contributors // All rights reserved. // // For the license information refer to format.h. #include "fmt/ranges.h" #include #include #include #include #include #include #include #include #include #if FMT_CPLUSPLUS > 201703L && FMT_HAS_INCLUDE() # include #endif #include "fmt/format.h" #include "gtest/gtest.h" #if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 601 # define FMT_RANGES_TEST_ENABLE_C_STYLE_ARRAY #endif #ifdef FMT_RANGES_TEST_ENABLE_C_STYLE_ARRAY TEST(ranges_test, format_array) { int arr[] = {1, 2, 3, 5, 7, 11}; EXPECT_EQ(fmt::format("{}", arr), "[1, 2, 3, 5, 7, 11]"); } TEST(ranges_test, format_2d_array) { int arr[][2] = {{1, 2}, {3, 5}, {7, 11}}; EXPECT_EQ(fmt::format("{}", arr), "[[1, 2], [3, 5], [7, 11]]"); } TEST(ranges_test, format_array_of_literals) { const char* arr[] = {"1234", "abcd"}; EXPECT_EQ(fmt::format("{}", arr), "[\"1234\", \"abcd\"]"); EXPECT_EQ(fmt::format("{:n}", arr), "\"1234\", \"abcd\""); EXPECT_EQ(fmt::format("{:n:}", arr), "1234, abcd"); } #endif // FMT_RANGES_TEST_ENABLE_C_STYLE_ARRAY struct unformattable {}; TEST(ranges_test, format_vector) { auto v = std::vector{1, 2, 3, 5, 7, 11}; EXPECT_EQ(fmt::format("{}", v), "[1, 2, 3, 5, 7, 11]"); EXPECT_EQ(fmt::format("{::#x}", v), "[0x1, 0x2, 0x3, 0x5, 0x7, 0xb]"); EXPECT_EQ(fmt::format("{:n:#x}", v), "0x1, 0x2, 0x3, 0x5, 0x7, 0xb"); auto vc = std::vector{'a', 'b', 'c'}; auto vec = std::vector{'a', '\n', '\t'}; auto vvc = std::vector>{vc, vc}; EXPECT_EQ(fmt::format("{}", vc), "['a', 'b', 'c']"); EXPECT_EQ(fmt::format("{:s}", vc), "\"abc\""); EXPECT_EQ(fmt::format("{:?s}", vec), "\"a\\n\\t\""); EXPECT_EQ(fmt::format("{:s}", vec), "\"a\n\t\""); EXPECT_EQ(fmt::format("{::s}", vvc), "[\"abc\", \"abc\"]"); EXPECT_EQ(fmt::format("{}", vvc), "[['a', 'b', 'c'], ['a', 'b', 'c']]"); EXPECT_EQ(fmt::format("{:n}", vvc), "['a', 'b', 'c'], ['a', 'b', 'c']"); EXPECT_EQ(fmt::format("{:n:n}", vvc), "'a', 'b', 'c', 'a', 'b', 'c'"); EXPECT_EQ(fmt::format("{:n:n:}", vvc), "a, b, c, a, b, c"); EXPECT_FALSE(fmt::is_formattable::value); EXPECT_FALSE(fmt::is_formattable>::value); } TEST(ranges_test, format_nested_vector) { auto v = std::vector>{{1, 2}, {3, 5}, {7, 11}}; EXPECT_EQ(fmt::format("{}", v), "[[1, 2], [3, 5], [7, 11]]"); EXPECT_EQ(fmt::format("{:::#x}", v), "[[0x1, 0x2], [0x3, 0x5], [0x7, 0xb]]"); EXPECT_EQ(fmt::format("{:n:n:#x}", v), "0x1, 0x2, 0x3, 0x5, 0x7, 0xb"); } TEST(ranges_test, to_string_vector) { auto v = std::vector{"a", "b", "c"}; EXPECT_EQ(fmt::to_string(v), "[\"a\", \"b\", \"c\"]"); } TEST(ranges_test, format_map) { auto m = std::map{{"one", 1}, {"two", 2}}; EXPECT_EQ(fmt::format("{}", m), "{\"one\": 1, \"two\": 2}"); EXPECT_EQ(fmt::format("{:n}", m), "\"one\": 1, \"two\": 2"); EXPECT_FALSE((fmt::is_formattable>::value)); } struct test_map_value {}; FMT_BEGIN_NAMESPACE template <> struct formatter : formatter { auto format(test_map_value, format_context& ctx) const -> format_context::iterator { return formatter::format("foo", ctx); } }; template struct formatter> : formatter { auto format(std::pair, format_context& ctx) const -> format_context::iterator { return ctx.out(); } }; template struct is_tuple_formattable, char> : std::false_type {}; FMT_END_NAMESPACE TEST(ranges_test, format_map_custom_pair) { EXPECT_EQ(fmt::format("{}", std::map{{42, {}}}), "{42: \"foo\"}"); } TEST(ranges_test, format_set) { EXPECT_EQ(fmt::format("{}", std::set{"one", "two"}), "{\"one\", \"two\"}"); } // Models std::flat_set close enough to test if no ambiguous lookup of a // formatter happens due to the flat_set type matching is_set and // is_container_adaptor_like. template class flat_set { public: using key_type = T; using container_type = std::vector; using iterator = typename std::vector::iterator; using const_iterator = typename std::vector::const_iterator; template explicit flat_set(Ts&&... args) : c{std::forward(args)...} {} auto begin() -> iterator { return c.begin(); } auto end() -> iterator { return c.end(); } auto begin() const -> const_iterator { return c.begin(); } auto end() const -> const_iterator { return c.end(); } private: std::vector c; }; TEST(ranges_test, format_flat_set) { EXPECT_EQ(fmt::format("{}", flat_set{"one", "two"}), "{\"one\", \"two\"}"); EXPECT_FALSE(fmt::is_formattable>::value); } namespace adl { struct box { int value; }; auto begin(const box& b) -> const int* { return &b.value; } auto end(const box& b) -> const int* { return &b.value + 1; } } // namespace adl TEST(ranges_test, format_adl_begin_end) { auto b = adl::box{42}; EXPECT_EQ(fmt::format("{}", b), "[42]"); } TEST(ranges_test, format_pair) { auto p = std::pair(42, 1.5f); EXPECT_EQ(fmt::format("{}", p), "(42, 1.5)"); EXPECT_EQ(fmt::format("{:}", p), "(42, 1.5)"); EXPECT_EQ(fmt::format("{:n}", p), "421.5"); } TEST(ranges_test, format_tuple) { auto t = std::tuple(42, 1.5f, "this is tuple", 'i'); EXPECT_EQ(fmt::format("{}", t), "(42, 1.5, \"this is tuple\", 'i')"); EXPECT_EQ(fmt::format("{:n}", t), "421.5\"this is tuple\"'i'"); EXPECT_EQ(fmt::format("{}", std::tuple<>()), "()"); EXPECT_TRUE((fmt::is_formattable>::value)); EXPECT_FALSE((fmt::is_formattable>::value)); EXPECT_FALSE((fmt::is_formattable>::value)); EXPECT_FALSE((fmt::is_formattable>::value)); EXPECT_FALSE( (fmt::is_formattable>::value)); EXPECT_TRUE((fmt::is_formattable>::value)); } struct not_default_formattable {}; struct bad_format {}; FMT_BEGIN_NAMESPACE template <> struct formatter { auto parse(format_parse_context&) -> const char* { throw bad_format(); } auto format(not_default_formattable, format_context& ctx) -> format_context::iterator { return ctx.out(); } }; FMT_END_NAMESPACE TEST(ranges_test, tuple_parse_calls_element_parse) { auto f = fmt::formatter>(); auto ctx = fmt::format_parse_context(""); EXPECT_THROW(f.parse(ctx), bad_format); } struct tuple_like { int i; std::string str; template auto get() const noexcept -> fmt::enable_if_t { return i; } template auto get() const noexcept -> fmt::enable_if_t { return str; } }; template auto get(const tuple_like& t) noexcept -> decltype(t.get()) { return t.get(); } // https://github.com/llvm/llvm-project/issues/39218 FMT_PRAGMA_CLANG(diagnostic ignored "-Wmismatched-tags") namespace std { template <> struct tuple_size : public std::integral_constant {}; template struct tuple_element { using type = decltype(std::declval().get()); }; } // namespace std TEST(ranges_test, format_struct) { auto t = tuple_like{42, "foo"}; EXPECT_EQ(fmt::format("{}", t), "(42, \"foo\")"); } TEST(ranges_test, format_to) { char buf[10]; auto end = fmt::format_to(buf, "{}", std::vector{1, 2, 3}); *end = '\0'; EXPECT_STREQ(buf, "[1, 2, 3]"); } template struct path_like { auto begin() const -> const path_like*; auto end() const -> const path_like*; operator std::basic_string() const; }; TEST(ranges_test, disabled_range_formatting_of_path) { // Range formatting of path is disabled because of infinite recursion // (path element is itself a path). EXPECT_EQ((fmt::range_format_kind, char>::value), fmt::range_format::disabled); EXPECT_EQ((fmt::range_format_kind, char>::value), fmt::range_format::disabled); } struct vector_string : std::vector { using base = std::vector; using base::base; }; struct vector_debug_string : std::vector { using base = std::vector; using base::base; }; FMT_BEGIN_NAMESPACE template <> struct range_format_kind : std::integral_constant {}; template <> struct range_format_kind : std::integral_constant {}; FMT_END_NAMESPACE TEST(ranges_test, range_format_string) { const vector_string v{'f', 'o', 'o'}; EXPECT_EQ(fmt::format("{}", v), "foo"); } TEST(ranges_test, range_format_debug_string) { const vector_debug_string v{'f', 'o', 'o'}; EXPECT_EQ(fmt::format("{}", v), "\"foo\""); } // A range that provides non-const only begin()/end() to test fmt::join // handles that. // // Some ranges (e.g. those produced by range-v3's views::filter()) can cache // information during iteration so they only provide non-const begin()/end(). template class non_const_only_range { private: std::vector vec; public: using const_iterator = typename ::std::vector::const_iterator; template explicit non_const_only_range(Args&&... args) : vec(std::forward(args)...) {} auto begin() -> const_iterator { return vec.begin(); } auto end() -> const_iterator { return vec.end(); } }; template class noncopyable_range { private: std::vector vec; public: using iterator = typename ::std::vector::iterator; template explicit noncopyable_range(Args&&... args) : vec(std::forward(args)...) {} noncopyable_range(const noncopyable_range&) = delete; noncopyable_range(noncopyable_range&) = delete; auto begin() -> iterator { return vec.begin(); } auto end() -> iterator { return vec.end(); } }; TEST(ranges_test, range) { auto&& w = noncopyable_range(3u, 0); EXPECT_EQ(fmt::format("{}", w), "[0, 0, 0]"); EXPECT_EQ(fmt::format("{}", noncopyable_range(3u, 0)), "[0, 0, 0]"); auto x = non_const_only_range(3u, 0); EXPECT_EQ(fmt::format("{}", x), "[0, 0, 0]"); EXPECT_EQ(fmt::format("{}", non_const_only_range(3u, 0)), "[0, 0, 0]"); auto y = std::vector(3u, 0); EXPECT_EQ(fmt::format("{}", y), "[0, 0, 0]"); EXPECT_EQ(fmt::format("{}", std::vector(3u, 0)), "[0, 0, 0]"); const auto z = std::vector(3u, 0); EXPECT_EQ(fmt::format("{}", z), "[0, 0, 0]"); } enum test_enum { foo, bar }; auto format_as(test_enum e) -> int { return e; } TEST(ranges_test, enum_range) { auto v = std::vector{test_enum::foo}; EXPECT_EQ(fmt::format("{}", v), "[0]"); } #if !FMT_MSC_VERSION TEST(ranges_test, unformattable_range) { EXPECT_FALSE((fmt::is_formattable, char>::value)); } #endif TEST(ranges_test, join) { using fmt::join; int v1[3] = {1, 2, 3}; auto v2 = std::vector(); v2.push_back(1.2f); v2.push_back(3.4f); void* v3[2] = {&v1[0], &v1[1]}; EXPECT_EQ(fmt::format("({})", join(v1, v1 + 3, ", ")), "(1, 2, 3)"); EXPECT_EQ(fmt::format("({})", join(v1, v1 + 1, ", ")), "(1)"); EXPECT_EQ(fmt::format("({})", join(v1, v1, ", ")), "()"); EXPECT_EQ(fmt::format("({:03})", join(v1, v1 + 3, ", ")), "(001, 002, 003)"); EXPECT_EQ("(+01.20, +03.40)", fmt::format("({:+06.2f})", join(v2.begin(), v2.end(), ", "))); EXPECT_EQ(fmt::format("{0:{1}}", join(v1, v1 + 3, ", "), 1), "1, 2, 3"); EXPECT_EQ(fmt::format("{}, {}", v3[0], v3[1]), fmt::format("{}", join(v3, v3 + 2, ", "))); EXPECT_EQ(fmt::format("({})", join(v1, ", ")), "(1, 2, 3)"); EXPECT_EQ(fmt::format("({:+06.2f})", join(v2, ", ")), "(+01.20, +03.40)"); auto v4 = std::vector{foo, bar, foo}; EXPECT_EQ(fmt::format("{}", join(v4, " ")), "0 1 0"); } #ifdef __cpp_lib_byte TEST(ranges_test, join_bytes) { auto v = std::vector{std::byte(1), std::byte(2), std::byte(3)}; EXPECT_EQ(fmt::format("{}", fmt::join(v, ", ")), "1, 2, 3"); } #endif TEST(ranges_test, join_tuple) { // Value tuple args. auto t1 = std::tuple('a', 1, 2.0f); EXPECT_EQ(fmt::format("({})", fmt::join(t1, ", ")), "(a, 1, 2)"); // Testing lvalue tuple args. int x = 4; auto t2 = std::tuple('b', x); EXPECT_EQ(fmt::format("{}", fmt::join(t2, " + ")), "b + 4"); // Empty tuple. auto t3 = std::tuple<>(); EXPECT_EQ(fmt::format("{}", fmt::join(t3, "|")), ""); // Single element tuple. auto t4 = std::tuple(4.0f); EXPECT_EQ(fmt::format("{}", fmt::join(t4, "/")), "4"); // Tuple-like. auto t5 = tuple_like{42, "foo"}; EXPECT_EQ(fmt::format("{}", fmt::join(t5, ", ")), "42, foo"); #if FMT_TUPLE_JOIN_SPECIFIERS // Specs applied to each element. auto t5 = std::tuple(-3, 100, 1); EXPECT_EQ(fmt::format("{:+03}", fmt::join(t5, ", ")), "-03, +100, +01"); auto t6 = std::tuple(3, 3.14, 3.1415); EXPECT_EQ(fmt::format("{:5.5f}", fmt::join(t6, ", ")), "3.00000, 3.14000, 3.14150"); // Testing lvalue tuple args. int y = -1; auto t7 = std::tuple(3, y, y); EXPECT_EQ(fmt::format("{:03}", fmt::join(t7, ", ")), "003, -01, -01"); #endif } TEST(ranges_test, join_initializer_list) { EXPECT_EQ(fmt::format("{}", fmt::join({1, 2, 3}, ", ")), "1, 2, 3"); EXPECT_EQ(fmt::format("{}", fmt::join({"fmt", "rocks", "!"}, " ")), "fmt rocks !"); } struct zstring_sentinel {}; bool operator==(const char* p, zstring_sentinel) { return *p == '\0'; } bool operator!=(const char* p, zstring_sentinel) { return *p != '\0'; } struct zstring { const char* p; auto begin() const -> const char* { return p; } auto end() const -> zstring_sentinel { return {}; } }; #ifdef __cpp_lib_ranges struct cpp20_only_range { struct iterator { int val = 0; using value_type = int; using difference_type = std::ptrdiff_t; using iterator_concept = std::input_iterator_tag; iterator() = default; iterator(int i) : val(i) {} auto operator*() const -> int { return val; } auto operator++() -> iterator& { ++val; return *this; } void operator++(int) { ++*this; } auto operator==(const iterator& rhs) const -> bool { return val == rhs.val; } }; int lo; int hi; auto begin() const -> iterator { return iterator(lo); } auto end() const -> iterator { return iterator(hi); } }; static_assert(std::input_iterator); #endif TEST(ranges_test, join_sentinel) { auto hello = zstring{"hello"}; EXPECT_EQ(fmt::format("{}", hello), "['h', 'e', 'l', 'l', 'o']"); EXPECT_EQ(fmt::format("{::}", hello), "[h, e, l, l, o]"); EXPECT_EQ(fmt::format("{}", fmt::join(hello, "_")), "h_e_l_l_o"); } TEST(ranges_test, join_range) { auto&& w = noncopyable_range(3u, 0); EXPECT_EQ(fmt::format("{}", fmt::join(w, ",")), "0,0,0"); EXPECT_EQ(fmt::format("{}", fmt::join(noncopyable_range(3u, 0), ",")), "0,0,0"); auto x = non_const_only_range(3u, 0); EXPECT_EQ(fmt::format("{}", fmt::join(x, ",")), "0,0,0"); EXPECT_EQ(fmt::format("{}", fmt::join(non_const_only_range(3u, 0), ",")), "0,0,0"); auto y = std::vector(3u, 0); EXPECT_EQ(fmt::format("{}", fmt::join(y, ",")), "0,0,0"); EXPECT_EQ(fmt::format("{}", fmt::join(std::vector(3u, 0), ",")), "0,0,0"); const auto z = std::vector(3u, 0); EXPECT_EQ(fmt::format("{}", fmt::join(z, ",")), "0,0,0"); #ifdef __cpp_lib_ranges EXPECT_EQ(fmt::format("{}", cpp20_only_range{.lo = 0, .hi = 5}), "[0, 1, 2, 3, 4]"); EXPECT_EQ( fmt::format("{}", fmt::join(cpp20_only_range{.lo = 0, .hi = 5}, ",")), "0,1,2,3,4"); #endif } namespace adl { struct vec { int n[2] = {42, 43}; }; auto begin(const vec& v) -> const int* { return v.n; } auto end(const vec& v) -> const int* { return v.n + 2; } } // namespace adl TEST(ranges_test, format_join_adl_begin_end) { EXPECT_EQ(fmt::format("{}", fmt::join(adl::vec(), "/")), "42/43"); } #if defined(__cpp_lib_ranges) && __cpp_lib_ranges >= 202207L TEST(ranges_test, nested_ranges) { auto l = std::list{1, 2, 3}; auto r = std::views::iota(0, 3) | std::views::transform([&l](auto i) { return std::views::take(std::ranges::subrange(l), i); }) | std::views::transform(std::views::reverse); EXPECT_EQ(fmt::format("{}", r), "[[], [1], [2, 1]]"); } #endif TEST(ranges_test, is_printable) { using fmt::detail::is_printable; EXPECT_TRUE(is_printable(0x0323)); EXPECT_FALSE(is_printable(0x0378)); EXPECT_FALSE(is_printable(0x110000)); } TEST(ranges_test, escape) { using vec = std::vector; EXPECT_EQ(fmt::format("{}", vec{"\n\r\t\"\\"}), "[\"\\n\\r\\t\\\"\\\\\"]"); EXPECT_EQ(fmt::format("{}", vec{"\x07"}), "[\"\\x07\"]"); EXPECT_EQ(fmt::format("{}", vec{"\x7f"}), "[\"\\x7f\"]"); EXPECT_EQ(fmt::format("{}", vec{"n\xcc\x83"}), "[\"n\xcc\x83\"]"); if (fmt::detail::use_utf8) { EXPECT_EQ(fmt::format("{}", vec{"\xcd\xb8"}), "[\"\\u0378\"]"); // Unassigned Unicode code points. EXPECT_EQ(fmt::format("{}", vec{"\xf0\xaa\x9b\x9e"}), "[\"\\U0002a6de\"]"); // Broken utf-8. EXPECT_EQ(fmt::format("{}", vec{"\xf4\x8f\xbf\xc0"}), "[\"\\xf4\\x8f\\xbf\\xc0\"]"); EXPECT_EQ(fmt::format("{}", vec{"\xf0\x28"}), "[\"\\xf0(\"]"); EXPECT_EQ(fmt::format("{}", vec{"\xe1\x28"}), "[\"\\xe1(\"]"); EXPECT_EQ(fmt::format("{}", vec{std::string("\xf0\x28\0\0anything", 12)}), "[\"\\xf0(\\x00\\x00anything\"]"); // Correct utf-8. EXPECT_EQ(fmt::format("{}", vec{"🦄"}), "[\"🦄\"]"); } EXPECT_EQ(fmt::format("{}", std::vector>{{'x'}}), "[['x']]"); // Disabled due to a clang 17 bug: https://github.com/fmtlib/fmt/issues/4144. #if FMT_CLANG_VERSION >= 1800 EXPECT_EQ(fmt::format("{}", std::tuple>{{'x'}}), "(['x'])"); #endif } template struct fmt_ref_view { R* r; auto begin() const -> decltype(r->begin()) { return r->begin(); } auto end() const -> decltype(r->end()) { return r->end(); } }; TEST(ranges_test, range_of_range_of_mixed_const) { auto v = std::vector>{{1, 2, 3}, {4, 5}}; EXPECT_EQ(fmt::format("{}", v), "[[1, 2, 3], [4, 5]]"); auto r = fmt_ref_view{&v}; EXPECT_EQ(fmt::format("{}", r), "[[1, 2, 3], [4, 5]]"); } TEST(ranges_test, vector_char) { EXPECT_EQ(fmt::format("{}", std::vector{'a', 'b'}), "['a', 'b']"); } TEST(ranges_test, container_adaptor) { { using fmt::detail::is_container_adaptor_like; using T = std::nullptr_t; static_assert(is_container_adaptor_like>::value, ""); static_assert(is_container_adaptor_like>::value, ""); static_assert(is_container_adaptor_like>::value, ""); static_assert(!is_container_adaptor_like>::value, ""); } { auto s = std::stack(); s.push(1); s.push(2); EXPECT_EQ(fmt::format("{}", s), "[1, 2]"); EXPECT_EQ(fmt::format("{}", const_cast(s)), "[1, 2]"); } { auto q = std::queue(); q.push(1); q.push(2); EXPECT_EQ(fmt::format("{}", q), "[1, 2]"); } { auto q = std::priority_queue(); q.push(3); q.push(1); q.push(2); q.push(4); EXPECT_EQ(fmt::format("{}", q), "[4, 3, 2, 1]"); } { auto s = std::stack(); s.push('a'); s.push('b'); // See https://cplusplus.github.io/LWG/issue3881. EXPECT_EQ(fmt::format("{}", s), "['a', 'b']"); } { struct my_container_adaptor { using value_type = int; using container_type = std::vector; void push(const value_type& v) { c.push_back(v); } protected: container_type c; }; auto m = my_container_adaptor(); m.push(1); m.push(2); EXPECT_EQ(fmt::format("{}", m), "[1, 2]"); } EXPECT_FALSE(fmt::is_formattable>::value); } struct tieable { int a = 3; double b = 0.42; }; auto format_as(const tieable& t) -> std::tuple { return std::tie(t.a, t.b); } TEST(ranges_test, format_as_tie) { EXPECT_EQ(fmt::format("{}", tieable()), "(3, 0.42)"); } struct lvalue_qualified_begin_end { int arr[5] = {1, 2, 3, 4, 5}; auto begin() & -> const int* { return arr; } auto end() & -> const int* { return arr + 5; } }; TEST(ranges_test, lvalue_qualified_begin_end) { EXPECT_EQ(fmt::format("{}", lvalue_qualified_begin_end{}), "[1, 2, 3, 4, 5]"); } #if !defined(__cpp_lib_ranges) || __cpp_lib_ranges <= 202106L # define ENABLE_STD_VIEWS_TESTS 0 #elif FMT_CLANG_VERSION # if FMT_CLANG_VERSION > 1500 # define ENABLE_STD_VIEWS_TESTS 1 # else # define ENABLE_STD_VIEWS_TESTS 0 # endif #else # define ENABLE_STD_VIEWS_TESTS 1 #endif #if ENABLE_STD_VIEWS_TESTS TEST(ranges_test, input_range_join) { auto iss = std::istringstream("1 2 3 4 5"); auto view = std::views::istream(iss); EXPECT_EQ("1, 2, 3, 4, 5", fmt::format("{}", fmt::join(view.begin(), view.end(), ", "))); } TEST(ranges_test, input_range_join_overload) { auto iss = std::istringstream("1 2 3 4 5"); EXPECT_EQ( "1.2.3.4.5", fmt::format("{}", fmt::join(std::views::istream(iss), "."))); } namespace views_filter_view_test { struct codec_mask { static constexpr auto codecs = std::array{0, 1, 2, 3}; int except = 0; }; auto format_as(codec_mask mask) { // Careful not to capture param by reference here, it will dangle. return codec_mask::codecs | std::views::filter([mask](auto c) { return c != mask.except; }); } } // namespace views_filter_view_test TEST(ranges_test, format_as_with_ranges_mutable_begin_end) { using namespace views_filter_view_test; { auto make_filter_view = []() { return codec_mask::codecs | std::views::filter([](auto c) { return c != 2; }); }; auto r = make_filter_view(); EXPECT_EQ("[0, 1, 3]", fmt::format("{}", r)); EXPECT_EQ("[0, 1, 3]", fmt::format("{}", make_filter_view())); } { auto mask = codec_mask{2}; const auto const_mask = codec_mask{2}; EXPECT_EQ("[0, 1, 3]", fmt::format("{}", mask)); EXPECT_EQ("[0, 1, 3]", fmt::format("{}", const_mask)); EXPECT_EQ("[0, 1, 3]", fmt::format("{}", codec_mask{2})); } } #endif TEST(ranges_test, std_istream_iterator_join) { auto&& iss = std::istringstream("1 2 3 4 5"); auto first = std::istream_iterator(iss); auto last = std::istream_iterator(); EXPECT_EQ("1, 2, 3, 4, 5", fmt::format("{}", fmt::join(first, last, ", "))); } // Mirrors C++20 std::ranges::basic_istream_view::iterator. struct noncopyable_istream_iterator : std::istream_iterator { using base = std::istream_iterator; explicit noncopyable_istream_iterator(std::istringstream& iss) : base{iss} {} noncopyable_istream_iterator(const noncopyable_istream_iterator&) = delete; noncopyable_istream_iterator(noncopyable_istream_iterator&&) = default; }; static_assert(!std::is_copy_constructible::value, ""); TEST(ranges_test, movable_only_istream_iter_join) { auto&& iss = std::istringstream("1 2 3 4 5"); auto first = noncopyable_istream_iterator(iss); auto last = std::istream_iterator(); EXPECT_EQ("1, 2, 3, 4, 5", fmt::format("{}", fmt::join(std::move(first), last, ", "))); } struct movable_iter_range { std::istringstream iss{"1 2 3 4 5"}; noncopyable_istream_iterator begin() { return noncopyable_istream_iterator{iss}; } std::istream_iterator end() { return {}; } }; TEST(ranges_test, movable_only_istream_iter_join2) { EXPECT_EQ("[1, 2, 3, 4, 5]", fmt::format("{}", movable_iter_range{})); } struct not_range { void begin() const {} void end() const {} }; static_assert(!fmt::is_formattable{}, ""); soci-4.1.4/3rdparty/fmt/test/posix-mock-test.cc0000664000175000017500000002562215100423533021272 0ustar zeitlinzeitlin// Tests of the C++ interface to POSIX functions that require mocks // // Copyright (c) 2012 - present, Victor Zverovich // All rights reserved. // // For the license information refer to format.h. // Disable bogus MSVC warnings. #if !defined(_CRT_SECURE_NO_WARNINGS) && defined(_MSC_VER) # define _CRT_SECURE_NO_WARNINGS #endif #include "posix-mock.h" #include #include #include #include #include "../src/os.cc" #ifdef _WIN32 # include # undef max #endif #include "gmock/gmock.h" #include "gtest-extra.h" #include "util.h" using fmt::buffered_file; using testing::_; using testing::Return; using testing::StrEq; template struct scoped_mock : testing::StrictMock { scoped_mock() { Mock::instance = this; } ~scoped_mock() { Mock::instance = nullptr; } }; namespace { int open_count; int close_count; int dup_count; int dup2_count; int fdopen_count; int read_count; int write_count; int pipe_count; int fopen_count; int fclose_count; int fileno_count; size_t read_nbyte; size_t write_nbyte; bool sysconf_error; enum { none, max_size, error } fstat_sim; } // namespace #define EMULATE_EINTR(func, error_result) \ if (func##_count != 0) { \ if (func##_count++ != 3) { \ errno = EINTR; \ return error_result; \ } \ } #ifndef _MSC_VER int test::open(const char* path, int oflag, int mode) { EMULATE_EINTR(open, -1); return ::open(path, oflag, mode); } #endif #ifndef _WIN32 long test::sysconf(int name) { long result = ::sysconf(name); if (!sysconf_error) return result; // Simulate an error. errno = EINVAL; return -1; } static off_t max_file_size() { return std::numeric_limits::max(); } int test::fstat(int fd, struct stat* buf) { int result = ::fstat(fd, buf); if (fstat_sim == max_size) buf->st_size = max_file_size(); return result; } #else static LONGLONG max_file_size() { return std::numeric_limits::max(); } DWORD test::GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh) { if (fstat_sim == error) { SetLastError(ERROR_ACCESS_DENIED); return INVALID_FILE_SIZE; } if (fstat_sim == max_size) { DWORD max = std::numeric_limits::max(); *lpFileSizeHigh = max >> 1; return max; } return ::GetFileSize(hFile, lpFileSizeHigh); } #endif int test::close(int fildes) { // Close the file first because close shouldn't be retried. int result = ::FMT_POSIX(close(fildes)); EMULATE_EINTR(close, -1); return result; } int test::dup(int fildes) { EMULATE_EINTR(dup, -1); return ::FMT_POSIX(dup(fildes)); } int test::dup2(int fildes, int fildes2) { EMULATE_EINTR(dup2, -1); return ::FMT_POSIX(dup2(fildes, fildes2)); } FILE* test::fdopen(int fildes, const char* mode) { EMULATE_EINTR(fdopen, nullptr); return ::FMT_POSIX(fdopen(fildes, mode)); } test::ssize_t test::read(int fildes, void* buf, test::size_t nbyte) { read_nbyte = nbyte; EMULATE_EINTR(read, -1); return ::FMT_POSIX(read(fildes, buf, nbyte)); } test::ssize_t test::write(int fildes, const void* buf, test::size_t nbyte) { write_nbyte = nbyte; EMULATE_EINTR(write, -1); return ::FMT_POSIX(write(fildes, buf, nbyte)); } #ifndef _WIN32 int test::pipe(int fildes[2]) { EMULATE_EINTR(pipe, -1); return ::pipe(fildes); } #else int test::pipe(int* pfds, unsigned psize, int textmode) { EMULATE_EINTR(pipe, -1); return _pipe(pfds, psize, textmode); } #endif FILE* test::fopen(const char* filename, const char* mode) { EMULATE_EINTR(fopen, nullptr); return ::fopen(filename, mode); } int test::fclose(FILE* stream) { EMULATE_EINTR(fclose, EOF); return ::fclose(stream); } int(test::fileno)(FILE* stream) { EMULATE_EINTR(fileno, -1); #ifdef fileno return FMT_POSIX(fileno(stream)); #else return ::FMT_POSIX(fileno(stream)); #endif } #ifndef _WIN32 # define EXPECT_RETRY(statement, func, message) \ func##_count = 1; \ statement; \ EXPECT_EQ(4, func##_count); \ func##_count = 0; # define EXPECT_EQ_POSIX(expected, actual) EXPECT_EQ(expected, actual) #else # define EXPECT_RETRY(statement, func, message) \ func##_count = 1; \ EXPECT_SYSTEM_ERROR(statement, EINTR, message); \ func##_count = 0; # define EXPECT_EQ_POSIX(expected, actual) #endif #if FMT_USE_FCNTL void write_file(fmt::cstring_view filename, fmt::string_view content) { fmt::buffered_file f(filename, "w"); f.print("{}", content); } using fmt::file; TEST(os_test, getpagesize) { # ifdef _WIN32 SYSTEM_INFO si = {}; GetSystemInfo(&si); EXPECT_EQ(si.dwPageSize, fmt::getpagesize()); # else EXPECT_EQ(sysconf(_SC_PAGESIZE), fmt::getpagesize()); sysconf_error = true; EXPECT_SYSTEM_ERROR(fmt::getpagesize(), EINVAL, "cannot get memory page size"); sysconf_error = false; # endif } TEST(file_test, open_retry) { # ifndef _WIN32 write_file("temp", "there must be something here"); std::unique_ptr f{nullptr}; EXPECT_RETRY(f.reset(new file("temp", file::RDONLY)), open, "cannot open file temp"); char c = 0; f->read(&c, 1); # endif } TEST(file_test, close_no_retry_in_dtor) { auto pipe = fmt::pipe(); std::unique_ptr f(new file(std::move(pipe.read_end))); int saved_close_count = 0; EXPECT_WRITE( stderr, { close_count = 1; f.reset(nullptr); saved_close_count = close_count; close_count = 0; }, system_error_message(EINTR, "cannot close file") + "\n"); EXPECT_EQ(2, saved_close_count); } TEST(file_test, close_no_retry) { auto pipe = fmt::pipe(); close_count = 1; EXPECT_SYSTEM_ERROR(pipe.read_end.close(), EINTR, "cannot close file"); EXPECT_EQ(2, close_count); close_count = 0; } TEST(file_test, size) { std::string content = "top secret, destroy before reading"; write_file("temp", content); file f("temp", file::RDONLY); EXPECT_GE(f.size(), 0); EXPECT_EQ(content.size(), static_cast(f.size())); # ifdef _WIN32 auto error_code = std::error_code(); fstat_sim = error; try { f.size(); } catch (const std::system_error& e) { error_code = e.code(); } fstat_sim = none; EXPECT_EQ(error_code, std::error_code(ERROR_ACCESS_DENIED, fmt::system_category())); # else f.close(); EXPECT_SYSTEM_ERROR(f.size(), EBADF, "cannot get file attributes"); # endif } TEST(file_test, max_size) { write_file("temp", ""); file f("temp", file::RDONLY); fstat_sim = max_size; EXPECT_GE(f.size(), 0); EXPECT_EQ(max_file_size(), f.size()); fstat_sim = none; } TEST(file_test, read_retry) { auto pipe = fmt::pipe(); enum { SIZE = 4 }; pipe.write_end.write("test", SIZE); pipe.write_end.close(); char buffer[SIZE]; size_t count = 0; EXPECT_RETRY(count = pipe.read_end.read(buffer, SIZE), read, "cannot read from file"); EXPECT_EQ_POSIX(static_cast(SIZE), count); } TEST(file_test, write_retry) { auto pipe = fmt::pipe(); enum { SIZE = 4 }; size_t count = 0; EXPECT_RETRY(count = pipe.write_end.write("test", SIZE), write, "cannot write to file"); pipe.write_end.close(); # ifndef _WIN32 EXPECT_EQ(static_cast(SIZE), count); char buffer[SIZE + 1]; pipe.read_end.read(buffer, SIZE); buffer[SIZE] = '\0'; EXPECT_STREQ("test", buffer); # endif } # ifdef _WIN32 TEST(file_test, convert_read_count) { auto pipe = fmt::pipe(); char c; size_t size = UINT_MAX; if (sizeof(unsigned) != sizeof(size_t)) ++size; read_count = 1; read_nbyte = 0; EXPECT_THROW(pipe.read_end.read(&c, size), std::system_error); read_count = 0; EXPECT_EQ(UINT_MAX, read_nbyte); } TEST(file_test, convert_write_count) { auto pipe = fmt::pipe(); char c; size_t size = UINT_MAX; if (sizeof(unsigned) != sizeof(size_t)) ++size; write_count = 1; write_nbyte = 0; EXPECT_THROW(pipe.write_end.write(&c, size), std::system_error); write_count = 0; EXPECT_EQ(UINT_MAX, write_nbyte); } # endif TEST(file_test, dup_no_retry) { int stdout_fd = FMT_POSIX(fileno(stdout)); dup_count = 1; EXPECT_SYSTEM_ERROR( file::dup(stdout_fd), EINTR, fmt::format("cannot duplicate file descriptor {}", stdout_fd)); dup_count = 0; } TEST(file_test, dup2_retry) { int stdout_fd = FMT_POSIX(fileno(stdout)); file f1 = file::dup(stdout_fd), f2 = file::dup(stdout_fd); EXPECT_RETRY(f1.dup2(f2.descriptor()), dup2, fmt::format("cannot duplicate file descriptor {} to {}", f1.descriptor(), f2.descriptor())); } TEST(file_test, dup2_no_except_retry) { int stdout_fd = FMT_POSIX(fileno(stdout)); file f1 = file::dup(stdout_fd), f2 = file::dup(stdout_fd); std::error_code ec; dup2_count = 1; f1.dup2(f2.descriptor(), ec); # ifndef _WIN32 EXPECT_EQ(4, dup2_count); # else EXPECT_EQ(EINTR, ec.value()); # endif dup2_count = 0; } TEST(file_test, pipe_no_retry) { pipe_count = 1; EXPECT_SYSTEM_ERROR(fmt::pipe(), EINTR, "cannot create pipe"); pipe_count = 0; } TEST(file_test, fdopen_no_retry) { auto pipe = fmt::pipe(); fdopen_count = 1; EXPECT_SYSTEM_ERROR(pipe.read_end.fdopen("r"), EINTR, "cannot associate stream with file descriptor"); fdopen_count = 0; } TEST(buffered_file_test, open_retry) { write_file("temp", "there must be something here"); std::unique_ptr f{nullptr}; EXPECT_RETRY(f.reset(new buffered_file("temp", "r")), fopen, "cannot open file temp"); # ifndef _WIN32 char c = 0; if (fread(&c, 1, 1, f->get()) < 1) throw fmt::system_error(errno, "fread failed"); # endif } TEST(buffered_file_test, close_no_retry_in_dtor) { auto pipe = fmt::pipe(); std::unique_ptr f( new buffered_file(pipe.read_end.fdopen("r"))); int saved_fclose_count = 0; EXPECT_WRITE( stderr, { fclose_count = 1; f.reset(nullptr); saved_fclose_count = fclose_count; fclose_count = 0; }, system_error_message(EINTR, "cannot close file") + "\n"); EXPECT_EQ(2, saved_fclose_count); } TEST(buffered_file_test, close_no_retry) { auto pipe = fmt::pipe(); buffered_file f = pipe.read_end.fdopen("r"); fclose_count = 1; EXPECT_SYSTEM_ERROR(f.close(), EINTR, "cannot close file"); EXPECT_EQ(2, fclose_count); fclose_count = 0; } TEST(buffered_file_test, fileno_no_retry) { auto pipe = fmt::pipe(); buffered_file f = pipe.read_end.fdopen("r"); fileno_count = 1; EXPECT_SYSTEM_ERROR((f.descriptor)(), EINTR, "cannot get file descriptor"); EXPECT_EQ(2, fileno_count); fileno_count = 0; } #endif // FMT_USE_FCNTL struct test_mock { static test_mock* instance; }* test_mock::instance; TEST(scoped_mock, scope) { { scoped_mock mock; EXPECT_EQ(&mock, test_mock::instance); test_mock& copy = mock; static_cast(copy); } EXPECT_EQ(nullptr, test_mock::instance); } soci-4.1.4/3rdparty/fmt/test/std-test.cc0000664000175000017500000004170215100423533017770 0ustar zeitlinzeitlin// Formatting library for C++ - tests of formatters for standard library types // // Copyright (c) 2012 - present, Victor Zverovich // All rights reserved. // // For the license information refer to format.h. #include "fmt/std.h" #include #include #include #include #include "fmt/os.h" // fmt::system_category #include "fmt/ranges.h" #include "gtest-extra.h" // StartsWith #ifdef __cpp_lib_filesystem TEST(std_test, path) { using std::filesystem::path; EXPECT_EQ(fmt::format("{}", path("/usr/bin")), "/usr/bin"); // see #4303 const path p = "/usr/bin"; EXPECT_EQ(fmt::format("{}", p), "/usr/bin"); EXPECT_EQ(fmt::format("{:?}", path("/usr/bin")), "\"/usr/bin\""); EXPECT_EQ(fmt::format("{:8}", path("foo")), "foo "); EXPECT_EQ(fmt::format("{}", path("foo\"bar")), "foo\"bar"); EXPECT_EQ(fmt::format("{:?}", path("foo\"bar")), "\"foo\\\"bar\""); EXPECT_EQ(fmt::format("{:g}", path("/usr/bin")), "/usr/bin"); # ifdef _WIN32 EXPECT_EQ(fmt::format("{}", path("C:\\foo")), "C:\\foo"); EXPECT_EQ(fmt::format("{:g}", path("C:\\foo")), "C:/foo"); EXPECT_EQ(fmt::format("{}", path(L"\x0428\x0447\x0443\x0447\x044B\x043D\x0448" L"\x0447\x044B\x043D\x0430")), "Шчучыншчына"); EXPECT_EQ(fmt::format("{}", path(L"\xd800")), "�"); EXPECT_EQ(fmt::format("{}", path(L"HEAD \xd800 TAIL")), "HEAD � TAIL"); EXPECT_EQ(fmt::format("{}", path(L"HEAD \xD83D\xDE00 TAIL")), "HEAD \xF0\x9F\x98\x80 TAIL"); EXPECT_EQ(fmt::format("{}", path(L"HEAD \xD83D\xD83D\xDE00 TAIL")), "HEAD �\xF0\x9F\x98\x80 TAIL"); EXPECT_EQ(fmt::format("{:?}", path(L"\xd800")), "\"\\ud800\""); # endif } // Intentionally delayed include to test #4303 # include "fmt/ranges.h" // Test ambiguity problem described in #2954. TEST(ranges_std_test, format_vector_path) { auto p = std::filesystem::path("foo/bar.txt"); auto c = std::vector{"abc", "def"}; EXPECT_EQ(fmt::format("path={}, range={}", p, c), "path=foo/bar.txt, range=[\"abc\", \"def\"]"); } // Test that path is not escaped twice in the debug mode. TEST(ranges_std_test, format_quote_path) { auto vec = std::vector{"path1/file1.txt", "path2/file2.txt"}; EXPECT_EQ(fmt::format("{}", vec), "[\"path1/file1.txt\", \"path2/file2.txt\"]"); # ifdef __cpp_lib_optional auto o = std::optional("path/file.txt"); EXPECT_EQ(fmt::format("{}", o), "optional(\"path/file.txt\")"); EXPECT_EQ(fmt::format("{:?}", o), "optional(\"path/file.txt\")"); # endif } #endif TEST(std_test, thread_id) { EXPECT_FALSE(fmt::format("{}", std::this_thread::get_id()).empty()); } TEST(std_test, complex) { using limits = std::numeric_limits; EXPECT_EQ(fmt::format("{}", std::complex(1, limits::quiet_NaN())), "(1+nan i)"); EXPECT_EQ(fmt::format("{}", std::complex(1, -limits::infinity())), "(1-inf i)"); EXPECT_EQ(fmt::format("{}", std::complex(1, 2)), "(1+2i)"); EXPECT_EQ(fmt::format("{}", std::complex(1, 2.2)), "(1+2.2i)"); EXPECT_EQ(fmt::format("{}", std::complex(1, -2.2)), "(1-2.2i)"); EXPECT_EQ(fmt::format("{}", std::complex(0, 2.2)), "2.2i"); EXPECT_EQ(fmt::format("{}", std::complex(0, -2.2)), "-2.2i"); EXPECT_EQ(fmt::format("{:+}", std::complex(0, 2.2)), "+2.2i"); EXPECT_EQ(fmt::format("{:+}", std::complex(0, -2.2)), "-2.2i"); EXPECT_EQ(fmt::format("{:+}", std::complex(1, -2.2)), "(+1-2.2i)"); EXPECT_EQ(fmt::format("{:+}", std::complex(1, 2.2)), "(+1+2.2i)"); EXPECT_EQ(fmt::format("{: }", std::complex(1, 2.2)), "( 1+2.2i)"); EXPECT_EQ(fmt::format("{: }", std::complex(1, -2.2)), "( 1-2.2i)"); EXPECT_EQ(fmt::format("{:8}", std::complex(1, 2)), "(1+2i) "); EXPECT_EQ(fmt::format("{:-<8}", std::complex(1, 2)), "(1+2i)--"); EXPECT_EQ(fmt::format("{:>20.2f}", std::complex(1, 2.2)), " (1.00+2.20i)"); EXPECT_EQ(fmt::format("{:<20.2f}", std::complex(1, 2.2)), "(1.00+2.20i) "); EXPECT_EQ(fmt::format("{:<20.2f}", std::complex(1, -2.2)), "(1.00-2.20i) "); EXPECT_EQ(fmt::format("{:<{}.{}f}", std::complex(1, -2.2), 20, 2), "(1.00-2.20i) "); } #ifdef __cpp_lib_source_location TEST(std_test, source_location) { std::source_location loc = std::source_location::current(); EXPECT_EQ(fmt::format("{}", loc), fmt::format("{}:{}:{}: {}", loc.file_name(), loc.line(), loc.column(), loc.function_name())); } #endif TEST(std_test, optional) { #ifdef __cpp_lib_optional EXPECT_EQ(fmt::format("{}", std::optional{}), "none"); EXPECT_EQ(fmt::format("{}", std::pair{1, "second"}), "(1, \"second\")"); EXPECT_EQ(fmt::format("{}", std::vector{std::optional{1}, std::optional{2}, std::optional{3}}), "[optional(1), optional(2), optional(3)]"); EXPECT_EQ( fmt::format("{}", std::optional>{{"nested"}}), "optional(optional(\"nested\"))"); EXPECT_EQ( fmt::format("{:<{}}", std::optional{std::string{"left aligned"}}, 30), "optional(\"left aligned\" )"); EXPECT_EQ( fmt::format("{::d}", std::optional{std::vector{'h', 'e', 'l', 'l', 'o'}}), "optional([104, 101, 108, 108, 111])"); EXPECT_EQ(fmt::format("{}", std::optional{std::string{"string"}}), "optional(\"string\")"); EXPECT_EQ(fmt::format("{}", std::optional{'C'}), "optional(\'C\')"); EXPECT_EQ(fmt::format("{:.{}f}", std::optional{3.14}, 1), "optional(3.1)"); struct unformattable {}; EXPECT_FALSE((fmt::is_formattable::value)); EXPECT_FALSE((fmt::is_formattable>::value)); EXPECT_TRUE((fmt::is_formattable>::value)); EXPECT_TRUE((fmt::is_formattable>::value)); #endif } TEST(std_test, expected) { #ifdef __cpp_lib_expected EXPECT_EQ(fmt::format("{}", std::expected{}), "expected()"); EXPECT_EQ(fmt::format("{}", std::expected{1}), "expected(1)"); EXPECT_EQ(fmt::format("{}", std::expected{std::unexpected(1)}), "unexpected(1)"); EXPECT_EQ(fmt::format("{}", std::expected{"test"}), "expected(\"test\")"); EXPECT_EQ(fmt::format( "{}", std::expected{std::unexpected("test")}), "unexpected(\"test\")"); EXPECT_EQ(fmt::format("{}", std::expected{'a'}), "expected('a')"); EXPECT_EQ(fmt::format("{}", std::expected{std::unexpected('a')}), "unexpected('a')"); struct unformattable1 {}; struct unformattable2 {}; EXPECT_FALSE((fmt::is_formattable::value)); EXPECT_FALSE((fmt::is_formattable::value)); EXPECT_FALSE((fmt::is_formattable< std::expected>::value)); EXPECT_FALSE( (fmt::is_formattable>::value)); EXPECT_FALSE( (fmt::is_formattable>::value)); EXPECT_TRUE((fmt::is_formattable>::value)); EXPECT_TRUE((fmt::is_formattable>::value)); #endif } namespace my_nso { enum class my_number { one, two, }; auto format_as(my_number number) -> fmt::string_view { return number == my_number::one ? "first" : "second"; } class my_class { public: int av; private: friend auto format_as(const my_class& elm) -> std::string { return fmt::to_string(elm.av); } }; class my_class_int { public: int av; private: friend auto format_as(const my_class_int& elm) -> int { return elm.av; } }; } // namespace my_nso TEST(std_test, expected_format_as) { #ifdef __cpp_lib_expected EXPECT_EQ( fmt::format( "{}", std::expected{my_nso::my_number::one}), "expected(\"first\")"); EXPECT_EQ( fmt::format("{}", std::expected{my_nso::my_class{7}}), "expected(\"7\")"); EXPECT_EQ(fmt::format("{}", std::expected{ my_nso::my_class_int{8}}), "expected(8)"); #endif } TEST(std_test, optional_format_as) { #ifdef __cpp_lib_optional EXPECT_EQ(fmt::format("{}", std::optional{}), "none"); EXPECT_EQ(fmt::format("{}", std::optional{my_nso::my_number::one}), "optional(\"first\")"); EXPECT_EQ(fmt::format("{}", std::optional{}), "none"); EXPECT_EQ(fmt::format("{}", std::optional{my_nso::my_class{7}}), "optional(\"7\")"); EXPECT_EQ(fmt::format("{}", std::optional{my_nso::my_class_int{8}}), "optional(8)"); #endif } struct throws_on_move { throws_on_move() = default; [[noreturn]] throws_on_move(throws_on_move&&) { throw std::runtime_error("Thrown by throws_on_move"); } throws_on_move(const throws_on_move&) = default; }; namespace fmt { template <> struct formatter : formatter { auto format(const throws_on_move&, format_context& ctx) const -> decltype(ctx.out()) { string_view str(""); return formatter::format(str, ctx); } }; } // namespace fmt TEST(std_test, variant) { #ifdef __cpp_lib_variant EXPECT_EQ(fmt::format("{}", std::monostate{}), "monostate"); using V0 = std::variant; V0 v0(42); V0 v1(1.5f); V0 v2("hello"); V0 v3('i'); EXPECT_EQ(fmt::format("{}", v0), "variant(42)"); EXPECT_EQ(fmt::format("{}", v1), "variant(1.5)"); EXPECT_EQ(fmt::format("{}", v2), "variant(\"hello\")"); EXPECT_EQ(fmt::format("{}", v3), "variant('i')"); struct unformattable {}; EXPECT_FALSE((fmt::is_formattable::value)); EXPECT_FALSE((fmt::is_formattable>::value)); EXPECT_FALSE((fmt::is_formattable>::value)); EXPECT_FALSE((fmt::is_formattable>::value)); EXPECT_FALSE( (fmt::is_formattable>::value)); EXPECT_TRUE((fmt::is_formattable>::value)); using V1 = std::variant; V1 v4{}; V1 v5{std::in_place_index<1>, "yes, this is variant"}; EXPECT_EQ(fmt::format("{}", v4), "variant(monostate)"); EXPECT_EQ(fmt::format("{}", v5), "variant(\"yes, this is variant\")"); volatile int i = 42; // Test compile error before GCC 11 described in #3068. EXPECT_EQ(fmt::format("{}", i), "42"); std::variant v6; try { throws_on_move thrower; v6.emplace(std::move(thrower)); } catch (const std::runtime_error&) { } // v6 is now valueless by exception EXPECT_EQ(fmt::format("{}", v6), "variant(valueless by exception)"); #endif } TEST(std_test, variant_format_as) { #ifdef __cpp_lib_variant EXPECT_EQ(fmt::format("{}", std::variant{}), "variant(\"first\")"); EXPECT_EQ(fmt::format( "{}", std::variant{my_nso::my_number::one}), "variant(\"first\")"); EXPECT_EQ( fmt::format("{}", std::variant{my_nso::my_class{7}}), "variant(\"7\")"); EXPECT_EQ( fmt::format("{}", std::variant{my_nso::my_class_int{8}}), "variant(8)"); #endif } TEST(std_test, error_code) { auto& generic = std::generic_category(); EXPECT_EQ(fmt::format("{}", std::error_code(42, generic)), "generic:42"); EXPECT_EQ(fmt::format("{:>12}", std::error_code(42, generic)), " generic:42"); EXPECT_EQ(fmt::format("{:12}", std::error_code(42, generic)), "generic:42 "); EXPECT_EQ(fmt::format("{}", std::error_code(42, fmt::system_category())), "system:42"); EXPECT_EQ(fmt::format("{}", std::error_code(-42, fmt::system_category())), "system:-42"); auto ec = std::make_error_code(std::errc::value_too_large); EXPECT_EQ(fmt::format("{:s}", ec), ec.message()); EXPECT_EQ(fmt::format("{:?}", std::error_code(42, generic)), "\"generic:42\""); EXPECT_EQ(fmt::format("{}", std::map{ {std::error_code(42, generic), 0}}), "{\"generic:42\": 0}"); } template void exception_test() { try { throw std::runtime_error("Test Exception"); } catch (const Catch& ex) { EXPECT_EQ("Test Exception", fmt::format("{}", ex)); EXPECT_EQ("std::runtime_error: Test Exception", fmt::format("{:t}", ex)); } } namespace my_ns1 { namespace my_ns2 { struct my_exception : public std::exception { private: std::string msg; public: my_exception(const std::string& s) : msg(s) {} const char* what() const noexcept override; }; const char* my_exception::what() const noexcept { return msg.c_str(); } } // namespace my_ns2 } // namespace my_ns1 TEST(std_test, exception) { using testing::StartsWith; exception_test(); exception_test(); try { using namespace my_ns1::my_ns2; throw my_exception("My Exception"); } catch (const std::exception& ex) { EXPECT_EQ("my_ns1::my_ns2::my_exception: My Exception", fmt::format("{:t}", ex)); EXPECT_EQ("My Exception", fmt::format("{:}", ex)); } try { throw std::system_error(std::error_code(), "message"); } catch (const std::system_error& ex) { EXPECT_THAT(fmt::format("{:t}", ex), StartsWith("std::system_error: ")); } #ifdef __cpp_lib_filesystem // Tests that the inline namespace is stripped out, e.g. // std::filesystem::__cxx11::* -> std::filesystem::*. try { throw std::filesystem::filesystem_error("message", std::error_code()); } catch (const std::filesystem::filesystem_error& ex) { EXPECT_THAT(fmt::format("{:t}", ex), StartsWith("std::filesystem::filesystem_error: ")); } #endif } #if FMT_USE_RTTI TEST(std_test, type_info) { EXPECT_EQ(fmt::format("{}", typeid(std::runtime_error)), "std::runtime_error"); } #endif TEST(std_test, format_bit_reference) { std::bitset<2> bs(1); EXPECT_EQ(fmt::format("{} {}", bs[0], bs[1]), "true false"); std::vector v = {true, false}; EXPECT_EQ(fmt::format("{} {}", v[0], v[1]), "true false"); } TEST(std_test, format_const_bit_reference) { const std::bitset<2> bs(1); EXPECT_EQ(fmt::format("{} {}", bs[0], bs[1]), "true false"); const std::vector v = {true, false}; EXPECT_EQ(fmt::format("{} {}", v[0], v[1]), "true false"); } TEST(std_test, format_bitset) { auto bs = std::bitset<6>(42); EXPECT_EQ(fmt::format("{}", bs), "101010"); EXPECT_EQ(fmt::format("{:0>8}", bs), "00101010"); EXPECT_EQ(fmt::format("{:-^12}", bs), "---101010---"); } TEST(std_test, format_atomic) { std::atomic b(false); EXPECT_EQ(fmt::format("{}", b), "false"); const std::atomic cb(true); EXPECT_EQ(fmt::format("{}", cb), "true"); } #ifdef __cpp_lib_atomic_flag_test TEST(std_test, format_atomic_flag) { std::atomic_flag f; (void)f.test_and_set(); EXPECT_EQ(fmt::format("{}", f), "true"); f.clear(); const std::atomic_flag& cf = f; EXPECT_EQ(fmt::format("{}", cf), "false"); } #endif // __cpp_lib_atomic_flag_test TEST(std_test, format_unique_ptr) { std::unique_ptr up(new int(1)); EXPECT_EQ(fmt::format("{}", fmt::ptr(up.get())), fmt::format("{}", fmt::ptr(up))); struct custom_deleter { void operator()(int* p) const { delete p; } }; std::unique_ptr upcd(new int(1)); EXPECT_EQ(fmt::format("{}", fmt::ptr(upcd.get())), fmt::format("{}", fmt::ptr(upcd))); } TEST(std_test, format_shared_ptr) { std::shared_ptr sp(new int(1)); EXPECT_EQ(fmt::format("{}", fmt::ptr(sp.get())), fmt::format("{}", fmt::ptr(sp))); } TEST(std_test, format_reference_wrapper) { int num = 35; EXPECT_EQ(fmt::to_string(std::cref(num)), "35"); EXPECT_EQ(fmt::to_string(std::ref(num)), "35"); EXPECT_EQ(fmt::format("{}", std::cref(num)), "35"); EXPECT_EQ(fmt::format("{}", std::ref(num)), "35"); } // Regression test for https://github.com/fmtlib/fmt/issues/4424. struct type_with_format_as {}; int format_as(type_with_format_as) { return 20; } TEST(std_test, format_reference_wrapper_with_format_as) { type_with_format_as t; EXPECT_EQ(fmt::to_string(std::cref(t)), "20"); EXPECT_EQ(fmt::to_string(std::ref(t)), "20"); EXPECT_EQ(fmt::format("{}", std::cref(t)), "20"); EXPECT_EQ(fmt::format("{}", std::ref(t)), "20"); } struct type_with_format_as_string {}; std::string format_as(type_with_format_as_string) { return "foo"; } TEST(std_test, format_reference_wrapper_with_format_as_string) { type_with_format_as_string t; EXPECT_EQ(fmt::to_string(std::cref(t)), "foo"); EXPECT_EQ(fmt::to_string(std::ref(t)), "foo"); EXPECT_EQ(fmt::format("{}", std::cref(t)), "foo"); EXPECT_EQ(fmt::format("{}", std::ref(t)), "foo"); } soci-4.1.4/3rdparty/fmt/test/fuzzing/0000775000175000017500000000000015100423533017402 5ustar zeitlinzeitlinsoci-4.1.4/3rdparty/fmt/test/fuzzing/float.cc0000664000175000017500000000230315100423533021014 0ustar zeitlinzeitlin// A fuzzer for floating-point formatter. // For the license information refer to format.h. #include #include #include #include #include #include "fuzzer-common.h" void check_round_trip(fmt::string_view format_str, double value) { auto buffer = fmt::memory_buffer(); fmt::format_to(std::back_inserter(buffer), format_str, value); if (std::isnan(value)) { auto nan = std::signbit(value) ? "-nan" : "nan"; if (fmt::string_view(buffer.data(), buffer.size()) != nan) throw std::runtime_error("round trip failure"); return; } buffer.push_back('\0'); char* ptr = nullptr; if (std::strtod(buffer.data(), &ptr) != value) throw std::runtime_error("round trip failure"); if (ptr + 1 != buffer.end()) throw std::runtime_error("unparsed output"); } extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { if (size <= sizeof(double) || !std::numeric_limits::is_iec559) return 0; check_round_trip("{}", assign_from_buf(data)); // A larger than necessary precision is used to trigger the fallback // formatter. check_round_trip("{:.50g}", assign_from_buf(data)); return 0; } soci-4.1.4/3rdparty/fmt/test/fuzzing/CMakeLists.txt0000664000175000017500000000231115100423533022137 0ustar zeitlinzeitlin# Copyright (c) 2019, Paul Dreik # License: see LICENSE.rst in the fmt root directory # Link in the main function. Useful for reproducing, kcov, gdb, afl, valgrind. # (Note that libFuzzer can also reproduce, just pass it the files.) option(FMT_FUZZ_LINKMAIN "Enables the reproduce mode, instead of libFuzzer" On) # For oss-fuzz - insert $LIB_FUZZING_ENGINE into the link flags, but only for # the fuzz targets, otherwise the CMake configuration step fails. set(FMT_FUZZ_LDFLAGS "" CACHE STRING "LDFLAGS for the fuzz targets") # Adds a binary for reproducing, i.e. no fuzzing, just enables replaying data # through the fuzzers. function(add_fuzzer source) get_filename_component(basename ${source} NAME_WE) set(name ${basename}-fuzzer) add_executable(${name} ${source} fuzzer-common.h) if (FMT_FUZZ_LINKMAIN) target_sources(${name} PRIVATE main.cc) endif () target_link_libraries(${name} PRIVATE fmt) if (FMT_FUZZ_LDFLAGS) target_link_libraries(${name} PRIVATE ${FMT_FUZZ_LDFLAGS}) endif () target_compile_features(${name} PRIVATE cxx_std_14) endfunction() foreach (source chrono-duration.cc chrono-timepoint.cc float.cc named-arg.cc one-arg.cc two-args.cc) add_fuzzer(${source}) endforeach () soci-4.1.4/3rdparty/fmt/test/fuzzing/.gitignore0000664000175000017500000000006615100423533021374 0ustar zeitlinzeitlin# ignore artifacts from the build.sh script build-*/ soci-4.1.4/3rdparty/fmt/test/fuzzing/chrono-duration.cc0000664000175000017500000000634715100423533023036 0ustar zeitlinzeitlin// Copyright (c) 2019, Paul Dreik // For the license information refer to format.h. #include #include #include "fuzzer-common.h" template void invoke_inner(fmt::string_view format_str, Rep rep) { auto value = std::chrono::duration(rep); try { #if FMT_FUZZ_FORMAT_TO_STRING std::string message = fmt::format(format_str, value); #else auto buf = fmt::memory_buffer(); fmt::format_to(std::back_inserter(buf), format_str, value); #endif } catch (std::exception&) { } } // Rep is a duration's representation type. template void invoke_outer(const uint8_t* data, size_t size, int period) { // Always use a fixed location of the data. static_assert(sizeof(Rep) <= fixed_size, "fixed size is too small"); if (size <= fixed_size + 1) return; const Rep rep = assign_from_buf(data); data += fixed_size; size -= fixed_size; // data is already allocated separately in libFuzzer so reading past the end // will most likely be detected anyway. const auto format_str = fmt::string_view(as_chars(data), size); // yocto, zepto, zetta and yotta are not handled. switch (period) { case 1: invoke_inner(format_str, rep); break; case 2: invoke_inner(format_str, rep); break; case 3: invoke_inner(format_str, rep); break; case 4: invoke_inner(format_str, rep); break; case 5: invoke_inner(format_str, rep); break; case 6: invoke_inner(format_str, rep); break; case 7: invoke_inner(format_str, rep); break; case 8: invoke_inner(format_str, rep); break; case 9: invoke_inner(format_str, rep); break; case 10: invoke_inner(format_str, rep); break; case 11: invoke_inner(format_str, rep); break; case 12: invoke_inner(format_str, rep); break; case 13: invoke_inner(format_str, rep); break; case 14: invoke_inner(format_str, rep); break; case 15: invoke_inner(format_str, rep); break; } } extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { if (size <= 4) return 0; const auto representation = data[0]; const auto period = data[1]; data += 2; size -= 2; switch (representation) { case 1: invoke_outer(data, size, period); break; case 2: invoke_outer(data, size, period); break; case 3: invoke_outer(data, size, period); break; case 4: invoke_outer(data, size, period); break; case 5: invoke_outer(data, size, period); break; case 6: invoke_outer(data, size, period); break; case 7: invoke_outer(data, size, period); break; case 8: invoke_outer(data, size, period); break; case 9: invoke_outer(data, size, period); break; case 10: invoke_outer(data, size, period); break; case 11: invoke_outer(data, size, period); break; case 12: invoke_outer(data, size, period); break; } return 0; } soci-4.1.4/3rdparty/fmt/test/fuzzing/README.md0000664000175000017500000000142515100423533020663 0ustar zeitlinzeitlin# Running the fuzzers locally There is a [helper script](build.sh) to build the fuzzers, which has only been tested on Debian and Ubuntu linux so far. There should be no problems fuzzing on Windows (using clang>=8) or on Mac, but the script will probably not work out of the box. Something along ```sh mkdir build cd build export CXX=clang++ export CXXFLAGS="-fsanitize=fuzzer-no-link -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION= -g" cmake .. -DFMT_SAFE_DURATION_CAST=On -DFMT_FUZZ=On -DFMT_FUZZ_LINKMAIN=Off -DFMT_FUZZ_LDFLAGS="-fsanitize=fuzzer" cmake --build . ``` should work to build the fuzzers for all platforms which clang supports. Execute a fuzzer with for instance ```sh cd build export UBSAN_OPTIONS=halt_on_error=1 mkdir out_chrono bin/fuzzer_chrono_duration out_chrono ``` soci-4.1.4/3rdparty/fmt/test/fuzzing/chrono-timepoint.cc0000664000175000017500000000147415100423533023215 0ustar zeitlinzeitlin// Copyright (c) 2021, Paul Dreik // For license information refer to format.h. #include #include "fuzzer-common.h" /* * a fuzzer for the chrono timepoints formatters * C is a clock (std::chrono::system_clock etc) */ template void doit(const uint8_t* data, size_t size) { using Rep = typename C::time_point::rep; constexpr auto N = sizeof(Rep); if (size < N) return; const auto x = assign_from_buf(data); typename C::duration dur{x}; typename C::time_point timepoint{dur}; data += N; size -= N; data_to_string format_str(data, size); std::string message = fmt::format(format_str.get(), timepoint); } extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { try { doit(data, size); } catch (...) { } return 0; } soci-4.1.4/3rdparty/fmt/test/fuzzing/one-arg.cc0000664000175000017500000000400015100423533021233 0ustar zeitlinzeitlin// Copyright (c) 2019, Paul Dreik // For the license information refer to format.h. #include #include #include #include "fuzzer-common.h" template const T* from_repr(const Repr& r) { return &r; } template <> const std::tm* from_repr(const std::time_t& t) { return std::localtime(&t); } template void invoke_fmt(const uint8_t* data, size_t size) { static_assert(sizeof(Repr) <= fixed_size, "Nfixed is too small"); if (size <= fixed_size) return; auto repr = assign_from_buf(data); const T* value = from_repr(repr); if (!value) return; data += fixed_size; size -= fixed_size; data_to_string format_str(data, size); try { #if FMT_FUZZ_FORMAT_TO_STRING std::string message = fmt::format(format_str.get(), *value); #else auto buf = fmt::memory_buffer(); fmt::format_to(std::back_inserter(buf), format_str.get(), *value); #endif } catch (std::exception&) { } } extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { if (size <= 3) return 0; const auto first = data[0]; data++; size--; switch (first) { case 0: invoke_fmt(data, size); break; case 1: invoke_fmt(data, size); break; case 2: invoke_fmt(data, size); break; case 3: invoke_fmt(data, size); break; case 4: invoke_fmt(data, size); break; case 5: invoke_fmt(data, size); break; case 6: invoke_fmt(data, size); break; case 7: invoke_fmt(data, size); break; case 8: invoke_fmt(data, size); break; case 9: invoke_fmt(data, size); break; case 10: invoke_fmt(data, size); break; case 11: invoke_fmt(data, size); break; case 12: invoke_fmt(data, size); break; case 13: invoke_fmt(data, size); break; } return 0; } soci-4.1.4/3rdparty/fmt/test/fuzzing/build.sh0000775000175000017500000000410115100423533021034 0ustar zeitlinzeitlin#!/bin/sh # # Creates fuzzer builds of various kinds # - oss-fuzz emulated mode (makes sure a simulated invocation by oss-fuzz works) # - libFuzzer build (you will need clang) # - afl build (you will need afl) # # # Copyright (c) 2019 Paul Dreik # # For the license information refer to format.h. set -e me=$(basename $0) root=$(readlink -f "$(dirname "$0")/../..") echo $me: root=$root here=$(pwd) CXXFLAGSALL="-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION= -g" CMAKEFLAGSALL="$root -GNinja -DCMAKE_BUILD_TYPE=Debug -DFMT_DOC=Off -DFMT_TEST=Off -DFMT_FUZZ=On -DCMAKE_CXX_STANDARD=17" CLANG=clang++-11 # For performance analysis of the fuzzers. builddir=$here/build-fuzzers-perfanalysis mkdir -p $builddir cd $builddir CXX="ccache g++" CXXFLAGS="$CXXFLAGSALL -g" cmake \ $CMAKEFLAGSALL \ -DFMT_FUZZ_LINKMAIN=On \ -DCMAKE_BUILD_TYPE=Release cmake --build $builddir # Builds the fuzzers as oss-fuzz does. builddir=$here/build-fuzzers-ossfuzz mkdir -p $builddir cd $builddir CXX=$CLANG \ CXXFLAGS="$CXXFLAGSALL -fsanitize=fuzzer-no-link" cmake \ cmake $CMAKEFLAGSALL \ -DFMT_FUZZ_LINKMAIN=Off \ -DFMT_FUZZ_LDFLAGS="-fsanitize=fuzzer" cmake --build $builddir # Builds fuzzers for local fuzzing with libfuzzer with asan+usan. builddir=$here/build-fuzzers-libfuzzer mkdir -p $builddir cd $builddir CXX=$CLANG \ CXXFLAGS="$CXXFLAGSALL -fsanitize=fuzzer-no-link,address,undefined" cmake \ cmake $CMAKEFLAGSALL \ -DFMT_FUZZ_LINKMAIN=Off \ -DFMT_FUZZ_LDFLAGS="-fsanitize=fuzzer" cmake --build $builddir # Builds a fast fuzzer for making coverage fast. builddir=$here/build-fuzzers-fast mkdir -p $builddir cd $builddir CXX=$CLANG \ CXXFLAGS="$CXXFLAGSALL -fsanitize=fuzzer-no-link -O3" cmake \ cmake $CMAKEFLAGSALL \ -DFMT_FUZZ_LINKMAIN=Off \ -DFMT_FUZZ_LDFLAGS="-fsanitize=fuzzer" \ -DCMAKE_BUILD_TYPE=Release cmake --build $builddir # Builds fuzzers for local fuzzing with afl. builddir=$here/build-fuzzers-afl mkdir -p $builddir cd $builddir CXX="afl-g++" \ CXXFLAGS="$CXXFLAGSALL -fsanitize=address,undefined" \ cmake $CMAKEFLAGSALL \ -DFMT_FUZZ_LINKMAIN=On cmake --build $builddir echo $me: all good soci-4.1.4/3rdparty/fmt/test/fuzzing/two-args.cc0000664000175000017500000000444715100423533021465 0ustar zeitlinzeitlin// Copyright (c) 2019, Paul Dreik // For the license information refer to format.h. #include #include #include #include #include "fuzzer-common.h" template void invoke_fmt(const uint8_t* data, size_t size) { static_assert(sizeof(Item1) <= fixed_size, "size1 exceeded"); static_assert(sizeof(Item2) <= fixed_size, "size2 exceeded"); if (size <= fixed_size + fixed_size) return; const Item1 item1 = assign_from_buf(data); data += fixed_size; size -= fixed_size; const Item2 item2 = assign_from_buf(data); data += fixed_size; size -= fixed_size; auto format_str = fmt::string_view(as_chars(data), size); #if FMT_FUZZ_FORMAT_TO_STRING std::string message = fmt::format(format_str, item1, item2); #else auto buf = fmt::memory_buffer(); fmt::format_to(std::back_inserter(buf), format_str, item1, item2); #endif } // For dynamic dispatching to an explicit instantiation. template void invoke(int index, Callback callback) { switch (index) { case 0: callback(bool()); break; case 1: callback(char()); break; case 2: using sc = signed char; callback(sc()); break; case 3: using uc = unsigned char; callback(uc()); break; case 4: callback(short()); break; case 5: using us = unsigned short; callback(us()); break; case 6: callback(int()); break; case 7: callback(unsigned()); break; case 8: callback(long()); break; case 9: using ul = unsigned long; callback(ul()); break; case 10: callback(float()); break; case 11: callback(double()); break; case 12: using LD = long double; callback(LD()); break; case 13: using ptr = void*; callback(ptr()); break; } } extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { if (size <= 3) return 0; // Switch types depending on the first byte of the input. const auto type1 = data[0] & 0x0F; const auto type2 = (data[0] & 0xF0) >> 4; data++; size--; try { invoke(type1, [=](auto param1) { invoke(type2, [=](auto param2) { invoke_fmt(data, size); }); }); } catch (std::exception&) { } return 0; } soci-4.1.4/3rdparty/fmt/test/fuzzing/main.cc0000664000175000017500000000112015100423533020627 0ustar zeitlinzeitlin#include #include #include #include "fuzzer-common.h" extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size); int main(int argc, char** argv) { for (int i = 1; i < argc; ++i) { std::ifstream in(argv[i]); assert(in); in.seekg(0, std::ios_base::end); const auto size = in.tellg(); assert(size >= 0); in.seekg(0, std::ios_base::beg); std::vector buf(static_cast(size)); in.read(buf.data(), size); assert(in.gcount() == size); LLVMFuzzerTestOneInput(as_bytes(buf.data()), buf.size()); } } soci-4.1.4/3rdparty/fmt/test/fuzzing/named-arg.cc0000664000175000017500000000433215100423533021546 0ustar zeitlinzeitlin// Copyright (c) 2019, Paul Dreik // For the license information refer to format.h. #include #include #include #include #include "fuzzer-common.h" template void invoke_fmt(const uint8_t* data, size_t size, unsigned arg_name_size) { static_assert(sizeof(T) <= fixed_size, "fixed_size too small"); if (size <= fixed_size) return; const T value = assign_from_buf(data); data += fixed_size; size -= fixed_size; if (arg_name_size <= 0 || arg_name_size >= size) return; data_to_string arg_name(data, arg_name_size, true); data += arg_name_size; size -= arg_name_size; data_to_string format_str(data, size); try { #if FMT_FUZZ_FORMAT_TO_STRING std::string message = fmt::format(format_str.get(), fmt::arg(arg_name.data(), value)); #else fmt::memory_buffer out; fmt::format_to(std::back_inserter(out), format_str.get(), fmt::arg(arg_name.data(), value)); #endif } catch (std::exception&) { } } // For dynamic dispatching to an explicit instantiation. template void invoke(int type, Callback callback) { switch (type) { case 0: callback(bool()); break; case 1: callback(char()); break; case 2: using sc = signed char; callback(sc()); break; case 3: using uc = unsigned char; callback(uc()); break; case 4: callback(short()); break; case 5: using us = unsigned short; callback(us()); break; case 6: callback(int()); break; case 7: callback(unsigned()); break; case 8: callback(long()); break; case 9: using ul = unsigned long; callback(ul()); break; case 10: callback(float()); break; case 11: callback(double()); break; case 12: using LD = long double; callback(LD()); break; } } extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { if (size <= 3) return 0; // Switch types depending on the first byte of the input. const auto type = data[0] & 0x0F; const unsigned arg_name_size = (data[0] & 0xF0) >> 4; data++; size--; invoke(type, [=](auto arg) { invoke_fmt(data, size, arg_name_size); }); return 0; } soci-4.1.4/3rdparty/fmt/test/fuzzing/fuzzer-common.h0000664000175000017500000000456315100423533022376 0ustar zeitlinzeitlin// Copyright (c) 2019, Paul Dreik // For the license information refer to format.h. #ifndef FUZZER_COMMON_H #define FUZZER_COMMON_H #include #include // std::uint8_t #include // memcpy #include // One can format to either a string, or a buffer. The latter is faster, but // one may be interested in formatting to a string instead to verify it works // as intended. To avoid a combinatoric explosion, select this at compile time // instead of dynamically from the fuzz data. #define FMT_FUZZ_FORMAT_TO_STRING 0 // If {fmt} is given a buffer that is separately allocated, chances that address // sanitizer detects out of bound reads is much higher. However, it slows down // the fuzzing. #define FMT_FUZZ_SEPARATE_ALLOCATION 1 // The size of the largest possible type in use. // To let the the fuzzer mutation be efficient at cross pollinating between // different types, use a fixed size format. The same bit pattern, interpreted // as another type, is likely interesting. constexpr auto fixed_size = 16; // Casts data to a char pointer. template inline const char* as_chars(const T* data) { return reinterpret_cast(data); } // Casts data to a byte pointer. template inline const std::uint8_t* as_bytes(const T* data) { return reinterpret_cast(data); } // Blits bytes from data to form an (assumed trivially constructible) object // of type Item. template inline Item assign_from_buf(const std::uint8_t* data) { auto item = Item(); std::memcpy(&item, data, sizeof(Item)); return item; } // Reads a boolean value by looking at the first byte from data. template <> inline bool assign_from_buf(const std::uint8_t* data) { return *data != 0; } struct data_to_string { #if FMT_FUZZ_SEPARATE_ALLOCATION std::vector buffer; data_to_string(const uint8_t* data, size_t size, bool add_terminator = false) : buffer(size + (add_terminator ? 1 : 0)) { if (size) { std::memcpy(buffer.data(), data, size); } } fmt::string_view get() const { return {buffer.data(), buffer.size()}; } #else fmt::string_view sv; data_to_string(const uint8_t* data, size_t size, bool = false) : str(as_chars(data), size) {} fmt::string_view get() const { return sv; } #endif const char* data() const { return get().data(); } }; #endif // FUZZER_COMMON_H soci-4.1.4/3rdparty/fmt/test/printf-test.cc0000664000175000017500000004412315100423533020500 0ustar zeitlinzeitlin// Formatting library for C++ - printf tests // // Copyright (c) 2012 - present, Victor Zverovich // All rights reserved. // // For the license information refer to format.h. #include "fmt/printf.h" #include #include #include #include "fmt/xchar.h" // DEPRECATED! #include "gtest-extra.h" #include "util.h" using fmt::format; using fmt::format_error; using fmt::detail::max_value; const unsigned big_num = INT_MAX + 1u; // Makes format string argument positional. static auto make_positional(fmt::string_view format) -> std::string { std::string s(format.data(), format.size()); s.replace(s.find('%'), 1, "%1$"); return s; } // A wrapper around fmt::sprintf to workaround bogus warnings about invalid // format strings in MSVC. template auto test_sprintf(fmt::string_view format, const Args&... args) -> std::string { return fmt::sprintf(format, args...); } template auto test_sprintf(fmt::basic_string_view format, const Args&... args) -> std::wstring { return fmt::sprintf(format, args...); } #define EXPECT_PRINTF(expected_output, format, arg) \ EXPECT_EQ(expected_output, test_sprintf(format, arg)) \ << "format: " << format; \ EXPECT_EQ(expected_output, fmt::sprintf(make_positional(format), arg)) TEST(printf_test, no_args) { EXPECT_EQ("test", test_sprintf("test")); } TEST(printf_test, escape) { EXPECT_EQ("%", test_sprintf("%%")); EXPECT_EQ("before %", test_sprintf("before %%")); EXPECT_EQ("% after", test_sprintf("%% after")); EXPECT_EQ("before % after", test_sprintf("before %% after")); EXPECT_EQ("%s", test_sprintf("%%s")); } TEST(printf_test, positional_args) { EXPECT_EQ("42", test_sprintf("%1$d", 42)); EXPECT_EQ("before 42", test_sprintf("before %1$d", 42)); EXPECT_EQ("42 after", test_sprintf("%1$d after", 42)); EXPECT_EQ("before 42 after", test_sprintf("before %1$d after", 42)); EXPECT_EQ("answer = 42", test_sprintf("%1$s = %2$d", "answer", 42)); EXPECT_EQ("42 is the answer", test_sprintf("%2$d is the %1$s", "answer", 42)); EXPECT_EQ("abracadabra", test_sprintf("%1$s%2$s%1$s", "abra", "cad")); } TEST(printf_test, automatic_arg_indexing) { EXPECT_EQ("abc", test_sprintf("%c%c%c", 'a', 'b', 'c')); } TEST(printf_test, number_is_too_big_in_arg_index) { EXPECT_THROW_MSG(test_sprintf(format("%{}$", big_num)), format_error, "argument not found"); EXPECT_THROW_MSG(test_sprintf(format("%{}$d", big_num)), format_error, "argument not found"); } TEST(printf_test, switch_arg_indexing) { EXPECT_THROW_MSG(test_sprintf("%1$d%", 1, 2), format_error, "cannot switch from manual to automatic argument indexing"); EXPECT_THROW_MSG(test_sprintf(format("%1$d%{}d", big_num), 1, 2), format_error, "number is too big"); EXPECT_THROW_MSG(test_sprintf("%1$d%d", 1, 2), format_error, "cannot switch from manual to automatic argument indexing"); EXPECT_THROW_MSG(test_sprintf("%d%1$", 1, 2), format_error, "cannot switch from automatic to manual argument indexing"); EXPECT_THROW_MSG(test_sprintf(format("%d%{}$d", big_num), 1, 2), format_error, "cannot switch from automatic to manual argument indexing"); EXPECT_THROW_MSG(test_sprintf("%d%1$d", 1, 2), format_error, "cannot switch from automatic to manual argument indexing"); // Indexing errors override width errors. EXPECT_THROW_MSG(test_sprintf(format("%d%1${}d", big_num), 1, 2), format_error, "number is too big"); EXPECT_THROW_MSG(test_sprintf(format("%1$d%{}d", big_num), 1, 2), format_error, "number is too big"); } TEST(printf_test, invalid_arg_index) { EXPECT_THROW_MSG(test_sprintf("%0$d", 42), format_error, "argument not found"); EXPECT_THROW_MSG(test_sprintf("%2$d", 42), format_error, "argument not found"); EXPECT_THROW_MSG(test_sprintf(format("%{}$d", INT_MAX), 42), format_error, "argument not found"); EXPECT_THROW_MSG(test_sprintf("%2$", 42), format_error, "argument not found"); EXPECT_THROW_MSG(test_sprintf(format("%{}$d", big_num), 42), format_error, "argument not found"); } TEST(printf_test, default_align_right) { EXPECT_PRINTF(" 42", "%5d", 42); EXPECT_PRINTF(" abc", "%5s", "abc"); } TEST(printf_test, zero_flag) { EXPECT_PRINTF("00042", "%05d", 42); EXPECT_PRINTF("-0042", "%05d", -42); EXPECT_PRINTF("00042", "%05d", 42); EXPECT_PRINTF("-0042", "%05d", -42); EXPECT_PRINTF("-004.2", "%06g", -4.2); EXPECT_PRINTF("+00042", "%00+6d", 42); EXPECT_PRINTF(" 42", "%05.d", 42); EXPECT_PRINTF(" 0042", "%05.4d", 42); // '0' flag is ignored for non-numeric types. EXPECT_PRINTF(" x", "%05c", 'x'); } TEST(printf_test, plus_flag) { EXPECT_PRINTF("+42", "%+d", 42); EXPECT_PRINTF("-42", "%+d", -42); EXPECT_PRINTF("+0042", "%+05d", 42); EXPECT_PRINTF("+0042", "%0++5d", 42); // '+' flag is ignored for non-numeric types. EXPECT_PRINTF("x", "%+c", 'x'); // '+' flag wins over space flag EXPECT_PRINTF("+42", "%+ d", 42); EXPECT_PRINTF("-42", "%+ d", -42); EXPECT_PRINTF("+42", "% +d", 42); EXPECT_PRINTF("-42", "% +d", -42); EXPECT_PRINTF("+0042", "% +05d", 42); EXPECT_PRINTF("+0042", "%0+ 5d", 42); // '+' flag and space flag are both ignored for non-numeric types. EXPECT_PRINTF("x", "%+ c", 'x'); EXPECT_PRINTF("x", "% +c", 'x'); } TEST(printf_test, minus_flag) { EXPECT_PRINTF("abc ", "%-5s", "abc"); EXPECT_PRINTF("abc ", "%0--5s", "abc"); EXPECT_PRINTF("7 ", "%-5d", 7); EXPECT_PRINTF("97 ", "%-5hhi", 'a'); EXPECT_PRINTF("a ", "%-5c", 'a'); // '0' flag is ignored if '-' flag is given EXPECT_PRINTF("7 ", "%-05d", 7); EXPECT_PRINTF("7 ", "%0-5d", 7); EXPECT_PRINTF("a ", "%-05c", 'a'); EXPECT_PRINTF("a ", "%0-5c", 'a'); EXPECT_PRINTF("97 ", "%-05hhi", 'a'); EXPECT_PRINTF("97 ", "%0-5hhi", 'a'); // '-' and space flag don't interfere EXPECT_PRINTF(" 42", "%- d", 42); } TEST(printf_test, space_flag) { EXPECT_PRINTF(" 42", "% d", 42); EXPECT_PRINTF("-42", "% d", -42); EXPECT_PRINTF(" 0042", "% 05d", 42); EXPECT_PRINTF(" 0042", "%0 5d", 42); // ' ' flag is ignored for non-numeric types. EXPECT_PRINTF("x", "% c", 'x'); } TEST(printf_test, hash_flag) { EXPECT_PRINTF("042", "%#o", 042); EXPECT_PRINTF(fmt::format("0{:o}", static_cast(-042)), "%#o", -042); EXPECT_PRINTF("0", "%#o", 0); EXPECT_PRINTF("0x42", "%#x", 0x42); EXPECT_PRINTF("0X42", "%#X", 0x42); EXPECT_PRINTF(fmt::format("0x{:x}", static_cast(-0x42)), "%#x", -0x42); EXPECT_PRINTF("0", "%#x", 0); EXPECT_PRINTF("0x0042", "%#06x", 0x42); EXPECT_PRINTF("0x0042", "%0##6x", 0x42); EXPECT_PRINTF("-42.000000", "%#f", -42.0); EXPECT_PRINTF("-42.000000", "%#F", -42.0); char buffer[256]; safe_sprintf(buffer, "%#e", -42.0); EXPECT_PRINTF(buffer, "%#e", -42.0); safe_sprintf(buffer, "%#E", -42.0); EXPECT_PRINTF(buffer, "%#E", -42.0); EXPECT_PRINTF("-42.0000", "%#g", -42.0); EXPECT_PRINTF("-42.0000", "%#G", -42.0); EXPECT_PRINTF("0x1.p+4", "%#a", 16.0); EXPECT_PRINTF("0X1.P+4", "%#A", 16.0); // '#' flag is ignored for non-numeric types. EXPECT_PRINTF("x", "%#c", 'x'); } TEST(printf_test, width) { EXPECT_PRINTF(" abc", "%5s", "abc"); // Width cannot be specified twice. EXPECT_THROW_MSG(test_sprintf("%5-5d", 42), format_error, "invalid format specifier"); EXPECT_THROW_MSG(test_sprintf(format("%{}d", big_num), 42), format_error, "number is too big"); EXPECT_THROW_MSG(test_sprintf(format("%1${}d", big_num), 42), format_error, "number is too big"); } TEST(printf_test, dynamic_width) { EXPECT_EQ(" 42", test_sprintf("%*d", 5, 42)); EXPECT_EQ("42 ", test_sprintf("%*d", -5, 42)); EXPECT_THROW_MSG(test_sprintf("%*d", 5.0, 42), format_error, "width is not integer"); EXPECT_THROW_MSG(test_sprintf("%*d"), format_error, "argument not found"); EXPECT_THROW_MSG(test_sprintf("%*d", big_num, 42), format_error, "number is too big"); } TEST(printf_test, int_precision) { EXPECT_PRINTF("00042", "%.5d", 42); EXPECT_PRINTF("-00042", "%.5d", -42); EXPECT_PRINTF("00042", "%.5x", 0x42); EXPECT_PRINTF("0x00042", "%#.5x", 0x42); EXPECT_PRINTF("00042", "%.5o", 042); EXPECT_PRINTF("00042", "%#.5o", 042); EXPECT_PRINTF(" 00042", "%7.5d", 42); EXPECT_PRINTF(" 00042", "%7.5x", 0x42); EXPECT_PRINTF(" 0x00042", "%#10.5x", 0x42); EXPECT_PRINTF(" 00042", "%7.5o", 042); EXPECT_PRINTF(" 00042", "%#10.5o", 042); EXPECT_PRINTF("00042 ", "%-7.5d", 42); EXPECT_PRINTF("00042 ", "%-7.5x", 0x42); EXPECT_PRINTF("0x00042 ", "%-#10.5x", 0x42); EXPECT_PRINTF("00042 ", "%-7.5o", 042); EXPECT_PRINTF("00042 ", "%-#10.5o", 042); } TEST(printf_test, float_precision) { char buffer[256]; safe_sprintf(buffer, "%.3e", 1234.5678); EXPECT_PRINTF(buffer, "%.3e", 1234.5678); EXPECT_PRINTF("1234.568", "%.3f", 1234.5678); EXPECT_PRINTF("1.23e+03", "%.3g", 1234.5678); safe_sprintf(buffer, "%.3a", 1234.5678); EXPECT_PRINTF(buffer, "%.3a", 1234.5678); } TEST(printf_test, string_precision) { char test[] = {'H', 'e', 'l', 'l', 'o'}; EXPECT_EQ(fmt::sprintf("%.4s", test), "Hell"); } TEST(printf_test, ignore_precision_for_non_numeric_arg) { EXPECT_PRINTF("abc", "%.5s", "abc"); } TEST(printf_test, dynamic_precision) { EXPECT_EQ("00042", test_sprintf("%.*d", 5, 42)); EXPECT_EQ("42", test_sprintf("%.*d", -5, 42)); EXPECT_THROW_MSG(test_sprintf("%.*d", 5.0, 42), format_error, "precision is not integer"); EXPECT_THROW_MSG(test_sprintf("%.*d"), format_error, "argument not found"); EXPECT_THROW_MSG(test_sprintf("%.*d", big_num, 42), format_error, "number is too big"); if (sizeof(long long) != sizeof(int)) { long long prec = static_cast(INT_MIN) - 1; EXPECT_THROW_MSG(test_sprintf("%.*d", prec, 42), format_error, "number is too big"); } } template struct make_signed { using type = T; }; #define SPECIALIZE_MAKE_SIGNED(T, S) \ template <> struct make_signed { \ using type = S; \ } SPECIALIZE_MAKE_SIGNED(char, signed char); SPECIALIZE_MAKE_SIGNED(unsigned char, signed char); SPECIALIZE_MAKE_SIGNED(unsigned short, short); SPECIALIZE_MAKE_SIGNED(unsigned, int); SPECIALIZE_MAKE_SIGNED(unsigned long, long); SPECIALIZE_MAKE_SIGNED(unsigned long long, long long); // Test length format specifier ``length_spec``. template void test_length(const char* length_spec, U value) { long long signed_value = 0; unsigned long long unsigned_value = 0; // Apply integer promotion to the argument. unsigned long long max = max_value(); using fmt::detail::const_check; if (const_check(max <= static_cast(max_value()))) { signed_value = static_cast(value); unsigned_value = static_cast(value); } else if (const_check(max <= max_value())) { signed_value = static_cast(value); unsigned_value = static_cast(value); } if (sizeof(U) <= sizeof(int) && sizeof(int) < sizeof(T)) { signed_value = static_cast(value); unsigned_value = static_cast( static_cast::type>(value)); } else { signed_value = static_cast::type>(value); unsigned_value = static_cast::type>(value); } std::ostringstream os; os << signed_value; EXPECT_PRINTF(os.str(), fmt::format("%{}d", length_spec), value); EXPECT_PRINTF(os.str(), fmt::format("%{}i", length_spec), value); os.str(""); os << unsigned_value; EXPECT_PRINTF(os.str(), fmt::format("%{}u", length_spec), value); os.str(""); os << std::oct << unsigned_value; EXPECT_PRINTF(os.str(), fmt::format("%{}o", length_spec), value); os.str(""); os << std::hex << unsigned_value; EXPECT_PRINTF(os.str(), fmt::format("%{}x", length_spec), value); os.str(""); os << std::hex << std::uppercase << unsigned_value; EXPECT_PRINTF(os.str(), fmt::format("%{}X", length_spec), value); } template void test_length(const char* length_spec) { T min = std::numeric_limits::min(), max = max_value(); test_length(length_spec, 42); test_length(length_spec, -42); test_length(length_spec, min); test_length(length_spec, max); long long long_long_min = std::numeric_limits::min(); if (static_cast(min) > long_long_min) test_length(length_spec, static_cast(min) - 1); unsigned long long long_long_max = max_value(); if (static_cast(max) < long_long_max) test_length(length_spec, static_cast(max) + 1); test_length(length_spec, std::numeric_limits::min()); test_length(length_spec, max_value()); test_length(length_spec, std::numeric_limits::min()); test_length(length_spec, max_value()); test_length(length_spec, std::numeric_limits::min()); test_length(length_spec, max_value()); test_length(length_spec, std::numeric_limits::min()); test_length(length_spec, max_value()); test_length(length_spec, std::numeric_limits::min()); test_length(length_spec, max_value()); } TEST(printf_test, length) { test_length("hh"); test_length("hh"); test_length("hh"); test_length("h"); test_length("h"); test_length("l"); test_length("l"); test_length("ll"); test_length("ll"); test_length("j"); test_length("z"); test_length("t"); long double max = max_value(); EXPECT_PRINTF(fmt::format("{:.6}", max), "%g", max); EXPECT_PRINTF(fmt::format("{:.6}", max), "%Lg", max); } TEST(printf_test, bool) { EXPECT_PRINTF("1", "%d", true); } TEST(printf_test, int) { EXPECT_PRINTF("-42", "%d", -42); EXPECT_PRINTF("-42", "%i", -42); unsigned u = 0 - 42u; EXPECT_PRINTF(fmt::format("{}", u), "%u", -42); EXPECT_PRINTF(fmt::format("{:o}", u), "%o", -42); EXPECT_PRINTF(fmt::format("{:x}", u), "%x", -42); EXPECT_PRINTF(fmt::format("{:X}", u), "%X", -42); } TEST(printf_test, long_long) { // fmt::printf allows passing long long arguments to %d without length // specifiers. long long max = max_value(); EXPECT_PRINTF(fmt::format("{}", max), "%d", max); } TEST(printf_test, float) { EXPECT_PRINTF("392.650000", "%f", 392.65); EXPECT_PRINTF("392.65", "%.2f", 392.65); EXPECT_PRINTF("392.6", "%.1f", 392.65); EXPECT_PRINTF("393", "%.f", 392.65); EXPECT_PRINTF("392.650000", "%F", 392.65); char buffer[256]; safe_sprintf(buffer, "%e", 392.65); EXPECT_PRINTF(buffer, "%e", 392.65); safe_sprintf(buffer, "%E", 392.65); EXPECT_PRINTF(buffer, "%E", 392.65); EXPECT_PRINTF("392.65", "%g", 392.65); EXPECT_PRINTF("392.65", "%G", 392.65); EXPECT_PRINTF("392", "%g", 392.0); EXPECT_PRINTF("392", "%G", 392.0); EXPECT_PRINTF("4.56e-07", "%g", 0.000000456); safe_sprintf(buffer, "%a", -392.65); EXPECT_EQ(buffer, format("{:a}", -392.65)); safe_sprintf(buffer, "%A", -392.65); EXPECT_EQ(buffer, format("{:A}", -392.65)); } TEST(printf_test, inf) { double inf = std::numeric_limits::infinity(); for (const char* type = "fega"; *type; ++type) { EXPECT_PRINTF("inf", fmt::format("%{}", *type), inf); char upper = static_cast(std::toupper(*type)); EXPECT_PRINTF("INF", fmt::format("%{}", upper), inf); } } TEST(printf_test, char) { EXPECT_PRINTF("x", "%c", 'x'); int max = max_value(); EXPECT_PRINTF(fmt::format("{}", static_cast(max)), "%c", max); } TEST(printf_test, string) { EXPECT_PRINTF("abc", "%s", "abc"); const char* null_str = nullptr; EXPECT_PRINTF("(null)", "%s", null_str); EXPECT_PRINTF(" (null)", "%10s", null_str); } TEST(printf_test, pointer) { int n; void* p = &n; EXPECT_PRINTF(fmt::format("{}", p), "%p", p); p = nullptr; EXPECT_PRINTF("(nil)", "%p", p); EXPECT_PRINTF(" (nil)", "%10p", p); const char* s = "test"; EXPECT_PRINTF(fmt::format("{:p}", s), "%p", s); const char* null_str = nullptr; EXPECT_PRINTF("(nil)", "%p", null_str); } enum test_enum { answer = 42 }; auto format_as(test_enum e) -> int { return e; } TEST(printf_test, enum) { EXPECT_PRINTF("42", "%d", answer); volatile test_enum volatile_enum = answer; EXPECT_PRINTF("42", "%d", volatile_enum); } #if FMT_USE_FCNTL TEST(printf_test, examples) { const char* weekday = "Thursday"; const char* month = "August"; int day = 21; EXPECT_WRITE(stdout, fmt::printf("%1$s, %3$d %2$s", weekday, month, day), "Thursday, 21 August"); } TEST(printf_test, printf_error) { auto pipe = fmt::pipe(); int result = fmt::fprintf(pipe.read_end.fdopen("r").get(), "test"); EXPECT_LT(result, 0); } #endif TEST(printf_test, vprintf) { int n = 42; auto store = fmt::make_format_args(n); auto args = fmt::basic_format_args(store); EXPECT_EQ(fmt::vsprintf(fmt::string_view("%d"), args), "42"); EXPECT_WRITE(stdout, fmt::vfprintf(stdout, fmt::string_view("%d"), args), "42"); } template void check_format_string_regression(fmt::string_view s, const Args&... args) { fmt::sprintf(s, args...); } TEST(printf_test, check_format_string_regression) { check_format_string_regression("%c%s", 'x', ""); } TEST(printf_test, fixed_large_exponent) { EXPECT_EQ("1000000000000000000000", fmt::sprintf("%.*f", -13, 1e21)); } TEST(printf_test, make_printf_args) { int n = 42; EXPECT_EQ("[42] something happened", fmt::vsprintf(fmt::string_view("[%d] %s happened"), {fmt::make_printf_args(n, "something")})); EXPECT_EQ(L"[42] something happened", fmt::vsprintf(fmt::basic_string_view(L"[%d] %s happened"), {fmt::make_printf_args(n, L"something")})); } soci-4.1.4/3rdparty/fmt/test/base-test.cc0000664000175000017500000006614515100423533020120 0ustar zeitlinzeitlin// Formatting library for C++ - core tests // // Copyright (c) 2012 - present, Victor Zverovich // All rights reserved. // // For the license information refer to format.h. // Turn assertion failures into exceptions for testing. // clang-format off #include "test-assert.h" // clang-format on #include "fmt/base.h" #include // INT_MAX #include // strlen #include // std::equal_to #include // std::back_insert_iterator, std::distance #include // std::numeric_limits #include // std::string #include // std::is_same #include "gmock/gmock.h" #ifdef FMT_FORMAT_H_ # error base-test includes format.h #endif using testing::_; using testing::Invoke; using testing::Return; auto copy(fmt::string_view s, fmt::appender out) -> fmt::appender { for (char c : s) *out++ = c; return out; } TEST(string_view_test, value_type) { static_assert(std::is_same::value, ""); } TEST(string_view_test, ctor) { EXPECT_STREQ(fmt::string_view("abc").data(), "abc"); EXPECT_EQ(fmt::string_view("abc").size(), 3u); EXPECT_STREQ(fmt::string_view(std::string("defg")).data(), "defg"); EXPECT_EQ(fmt::string_view(std::string("defg")).size(), 4u); } TEST(string_view_test, length) { // Test that string_view::size() returns string length, not buffer size. char str[100] = "some string"; EXPECT_EQ(fmt::string_view(str).size(), strlen(str)); EXPECT_LT(strlen(str), sizeof(str)); } // Check string_view's comparison operator. template