From 80f1c65e1c4e7a0ed6a5192deae8bb3547477f28 Mon Sep 17 00:00:00 2001 From: KimLS Date: Sat, 29 Jul 2017 00:11:57 -0700 Subject: [PATCH] Update fmt lib, add recast, wip on recast pathfinder interface (broken atm) --- CMakeLists.txt | 4 +- common/CMakeLists.txt | 2 + common/perl_eqdb.cpp | 4 +- common/perl_eqdb_res.cpp | 4 +- libs/CMakeLists.txt | 3 +- libs/format/.travis.yml | 8 +- libs/format/CMakeLists.txt | 32 +- libs/format/ChangeLog.rst | 110 +++ libs/format/README.rst | 33 +- libs/format/cppformat/format.h | 2 - libs/format/cppformat/posix.h | 2 - libs/format/doc/CMakeLists.txt | 6 +- libs/format/doc/_templates/layout.html | 51 +- libs/format/doc/api.rst | 90 ++- libs/format/doc/basic-bootstrap/layout.html | 3 +- libs/format/doc/build.py | 74 +- libs/format/doc/conf.py | 7 +- libs/format/doc/html/_sources/api.txt | 90 ++- libs/format/doc/html/_sources/index.txt | 61 +- libs/format/doc/html/_sources/syntax.txt | 16 +- libs/format/doc/html/_sources/usage.txt | 25 +- libs/format/doc/html/_static/pygments.css | 4 + libs/format/doc/html/api.html | 537 +++++++++++---- libs/format/doc/html/contents.html | 43 +- libs/format/doc/html/genindex.html | 151 ++++- libs/format/doc/html/index.html | 119 ++-- libs/format/doc/html/objects.inv | Bin 3626 -> 4204 bytes libs/format/doc/html/search.html | 39 +- libs/format/doc/html/searchindex.js | 2 +- libs/format/doc/html/syntax.html | 58 +- libs/format/doc/html/usage.html | 76 ++- libs/format/doc/index.rst | 61 +- libs/format/doc/syntax.rst | 16 +- libs/format/doc/usage.rst | 25 +- libs/format/fmt/CMakeLists.txt | 54 +- libs/format/fmt/format.cc | 534 ++------------- libs/format/fmt/format.h | 638 +++++++++++------- libs/format/fmt/ostream.cc | 34 +- libs/format/fmt/ostream.h | 72 +- libs/format/fmt/posix.cc | 57 +- libs/format/fmt/posix.h | 96 +-- libs/format/fmt/time.h | 125 +++- libs/format/support/appveyor-build.py | 31 +- libs/format/support/appveyor.yml | 4 + libs/format/support/cmake/cxx11.cmake | 14 +- libs/format/support/travis-build.py | 125 ++-- .../format/support/update-converity-branch.py | 30 +- libs/format/test/CMakeLists.txt | 23 +- .../test/add-subdirectory-test/CMakeLists.txt | 6 +- .../test/find-package-test/CMakeLists.txt | 6 +- libs/format/test/format-impl-test.cc | 6 +- libs/format/test/format-test.cc | 87 ++- libs/format/test/gmock/gmock.h | 5 +- libs/format/test/gtest-extra-test.cc | 2 +- libs/format/test/gtest-extra.cc | 2 +- libs/format/test/gtest-extra.h | 8 +- libs/format/test/gtest/gtest.h | 6 +- libs/format/test/mock-allocator.h | 10 +- libs/format/test/ostream-test.cc | 24 +- libs/format/test/posix-mock-test.cc | 8 +- libs/format/test/posix-test.cc | 2 +- libs/format/test/printf-test.cc | 40 +- libs/format/test/util-test.cc | 40 +- libs/format/test/util.h | 7 + zone/map.cpp | 80 +-- zone/pathfinder_interface.cpp | 8 +- zone/pathfinder_nav_mesh.cpp | 268 ++++++++ zone/pathfinder_nav_mesh.h | 12 +- 68 files changed, 2560 insertions(+), 1662 deletions(-) delete mode 100644 libs/format/cppformat/format.h delete mode 100644 libs/format/cppformat/posix.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ce1a3bc9b..a3d38e1bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -309,7 +309,7 @@ IF(EQEMU_BUILD_PERL) INCLUDE_DIRECTORIES(SYSTEM "${PERL_INCLUDE_PATH}") ENDIF(EQEMU_BUILD_PERL) -SET(SERVER_LIBS common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY} libuv fmt) +SET(SERVER_LIBS common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY} libuv fmt recast_navigation) FIND_PACKAGE(Sodium REQUIRED) IF(SODIUM_FOUND) @@ -357,6 +357,8 @@ INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/cereal") INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/libuv/include" ) INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/libuv/src") INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/format") +INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/recast/detour/include") +INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/recast/recast/include") IF(EQEMU_BUILD_SERVER OR EQEMU_BUILD_LOGIN OR EQEMU_BUILD_TESTS OR EQEMU_BUILD_HC) ADD_SUBDIRECTORY(common) diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index d65efd183..8a9d2c673 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -3,6 +3,7 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.8) SET(common_sources base_packet.cpp classes.cpp + compression.cpp condition.cpp crash.cpp crc16.cpp @@ -113,6 +114,7 @@ SET(common_headers base_data.h bodytypes.h classes.h + compression.h condition.h crash.h crc16.h diff --git a/common/perl_eqdb.cpp b/common/perl_eqdb.cpp index 2cd9fa38d..06fb7f958 100644 --- a/common/perl_eqdb.cpp +++ b/common/perl_eqdb.cpp @@ -28,9 +28,9 @@ typedef const char Const_char; #ifdef EMBPERL -#include "../common/global_define.h" -#include "../common/useperl.h" +#include "global_define.h" #include "eqdb.h" +#include "useperl.h" #ifdef THIS /* this macro seems to leak out on some systems */ #undef THIS diff --git a/common/perl_eqdb_res.cpp b/common/perl_eqdb_res.cpp index 2782a6f05..61b2f4043 100644 --- a/common/perl_eqdb_res.cpp +++ b/common/perl_eqdb_res.cpp @@ -28,9 +28,9 @@ typedef const char Const_char; #ifdef EMBPERL -#include "../common/global_define.h" -#include "../common/useperl.h" +#include "global_define.h" #include "eqdb_res.h" +#include "useperl.h" XS(XS_EQDBRes_num_rows); /* prototype to pass -Wmissing-prototypes */ diff --git a/libs/CMakeLists.txt b/libs/CMakeLists.txt index cb5a25998..801f5fdd9 100644 --- a/libs/CMakeLists.txt +++ b/libs/CMakeLists.txt @@ -3,4 +3,5 @@ IF(EQEMU_BUILD_LUA) ENDIF(EQEMU_BUILD_LUA) ADD_SUBDIRECTORY(libuv) -ADD_SUBDIRECTORY(format) \ No newline at end of file +ADD_SUBDIRECTORY(format) +ADD_SUBDIRECTORY(recast) \ No newline at end of file diff --git a/libs/format/.travis.yml b/libs/format/.travis.yml index d6b81a2a6..c359852e4 100644 --- a/libs/format/.travis.yml +++ b/libs/format/.travis.yml @@ -1,4 +1,5 @@ language: cpp +dist: trusty sudo: required # the doc target uses sudo to install dependencies os: @@ -22,12 +23,5 @@ matrix: - os: osx env: BUILD=Doc -addons: - apt: - sources: - - kubuntu-backports # cmake 2.8.12 - packages: - - cmake - script: - support/travis-build.py diff --git a/libs/format/CMakeLists.txt b/libs/format/CMakeLists.txt index 789b7e122..b08f9cbe9 100644 --- a/libs/format/CMakeLists.txt +++ b/libs/format/CMakeLists.txt @@ -1,6 +1,6 @@ message(STATUS "CMake version: ${CMAKE_VERSION}") -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 2.8.12) # Determine if fmt is built as a subproject (using add_subdirectory) # or if it is the master project. @@ -9,12 +9,22 @@ if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) set(MASTER_PROJECT ON) endif () +# Joins arguments and places the results in ${result_var}. +function(join result_var) + set(result ) + foreach (arg ${ARGN}) + set(result "${result}${arg}") + endforeach () + set(${result_var} "${result}" PARENT_SCOPE) +endfunction() + # Set the default CMAKE_BUILD_TYPE to Release. # This should be done before the project command since the latter can set # CMAKE_BUILD_TYPE itself (it does so for nmake). if (NOT CMAKE_BUILD_TYPE) - set(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.") + join(doc "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or " + "CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.") + set(CMAKE_BUILD_TYPE Release CACHE STRING ${doc}) endif () option(FMT_PEDANTIC "Enable extra warnings and expensive tests." OFF) @@ -28,13 +38,17 @@ option(FMT_USE_CPP11 "Enable the addition of C++11 compiler flags." ON) project(FMT) # Starting with cmake 3.0 VERSION is part of the project command. -set(FMT_VERSION 3.0.0) -if (NOT FMT_VERSION MATCHES "^([0-9]+).([0-9]+).([0-9]+)$") - message(FATAL_ERROR "Invalid version format ${FMT_VERSION}.") +file(READ fmt/format.h format_h) +if (NOT format_h MATCHES "FMT_VERSION ([0-9]+)([0-9][0-9])([0-9][0-9])") + message(FATAL_ERROR "Cannot get FMT_VERSION from format.h.") endif () -set(CPACK_PACKAGE_VERSION_MAJOR ${CMAKE_MATCH_1}) -set(CPACK_PACKAGE_VERSION_MINOR ${CMAKE_MATCH_2}) -set(CPACK_PACKAGE_VERSION_PATCH ${CMAKE_MATCH_3}) +# Use math to skip leading zeros if any. +math(EXPR CPACK_PACKAGE_VERSION_MAJOR ${CMAKE_MATCH_1}) +math(EXPR CPACK_PACKAGE_VERSION_MINOR ${CMAKE_MATCH_2}) +math(EXPR CPACK_PACKAGE_VERSION_PATCH ${CMAKE_MATCH_3}) +join(FMT_VERSION ${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}. + ${CPACK_PACKAGE_VERSION_PATCH}) +message(STATUS "Version: ${FMT_VERSION}") message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") diff --git a/libs/format/ChangeLog.rst b/libs/format/ChangeLog.rst index 0e065451d..4a16be951 100644 --- a/libs/format/ChangeLog.rst +++ b/libs/format/ChangeLog.rst @@ -1,3 +1,113 @@ +4.0.0 - 2017-06-27 +------------------ + +* Removed old compatibility headers ``cppformat/*.h`` and CMake options (`#527 `_). Thanks `@maddinat0r (Alex Martin) `_. + +* Added ``string.h`` containing ``fmt::to_string()`` as alternative to ``std::to_string()`` as well as other string writer functionality (`#326 `_ and `#441 `_): + + .. code:: c++ + + #include "fmt/string.h" + + std::string answer = fmt::to_string(42); + + Thanks to `@glebov-andrey (Andrey Glebov) `_. + +* Moved ``fmt::printf()`` to new ``printf.h`` header and allowed ``%s`` as generic specifier (`#453 `_), made ``%.f`` more conformant to regular ``printf()`` (`#490 `_), added custom writer support (`#476 `_) and implemented missing custom argument formatting (`#339 `_ and `#340 `_): + + .. code:: c++ + + #include "fmt/printf.h" + + // %s format specifier can be used with any argument type. + fmt::printf("%s", 42); + + Thanks `@mojoBrendan `_, `@manylegged (Arthur Danskin) `_ and `@spacemoose (Glen Stark) `_. See also `#360 `_, `#335 `_ and `#331 `_. + +* Added ``container.h`` containing a ``BasicContainerWriter`` to write to containers like ``std::vector`` (`#450 `_). Thanks `@polyvertex (Jean-Charles Lefebvre) `_. + +* Added ``fmt::join()`` function that takes a range and formats its elements separated by a given string (`#466 `_): + + .. code:: c++ + + #include "fmt/format.h" + + std::vector v = {1.2, 3.4, 5.6}; + // Prints "(+01.20, +03.40, +05.60)". + fmt::print("({:+06.2f})", fmt::join(v.begin(), v.end(), ", ")); + + Thanks `@olivier80 `_. + +* Added support for custom formatting specifications to simplify customization of built-in formatting (`#444 `_). Thanks `@polyvertex (Jean-Charles Lefebvre) `_. See also `#439 `_. + +* Added ``fmt::format_system_error()`` for error code formatting (`#323 `_ and `#526 `_). Thanks `@maddinat0r (Alex Martin) `_. + +* Added thread-safe ``fmt::localtime()`` and ``fmt::gmtime()`` as replacement for the standard version to ``time.h`` (`#396 `_). Thanks `@codicodi `_. + +* Internal improvements to ``NamedArg`` and ``ArgLists`` (`#389 `_ and `#390 `_). Thanks `@chronoxor `_. + +* Fixed crash due to bug in ``FormatBuf`` (`#493 `_). Thanks `@effzeh `_. See also `#480 `_ and `#491 `_. + +* Fixed handling of wide strings in ``fmt::StringWriter``. + +* Improved compiler error messages (`#357 `_). + +* Fixed various warnings and issues with various compilers (`#494 `_, `#499 `_, `#483 `_, `#519 `_, `#485 `_, `#482 `_, `#475 `_, `#473 `_ and `#414 `_). Thanks `@chronoxor `_, `@zhaohuaxishi `_, `@pkestene (Pierre Kestener) `_, `@dschmidt (Dominik Schmidt) `_ and `@0x414c (Alexey Gorishny) `_ . + +* Improved CMake: targets are now namespaced (`#511 `_ and `#513 `_), supported header-only ``printf.h`` (`#354 `_), fixed issue with minimal supported library subset (`#418 `_, `#419 `_ and `#420 `_). Thanks `@bjoernthiel (Bjoern Thiel) `_, + `@niosHD (Mario Werner) `_, `@LogicalKnight (Sean LK) `_ and `@alabuzhev (Alex Alabuzhev) `_. + +* Improved documentation. Thanks to `@pwm1234 (Phil) `_ for `#393 `_. + +3.0.2 - 2017-06-14 +------------------ + +* Added ``FMT_VERSION`` macro (`#411 `_). + +* Used ``FMT_NULL`` instead of literal ``0`` (`#409 `_). Thanks `@alabuzhev (Alex Alabuzhev) `_. + +* Added extern templates for ``format_float`` (`#413 `_). + +* Fixed implicit conversion issue (`#507 `_). + +* Fixed signbit detection (`#423 `_). + +* Fixed naming collision (`#425 `_). + +* Fixed missing intrinsic for C++/CLI (`#457 `_). Thanks `@calumr (Calum Robinson) `_ + +* Fixed Android detection (`#458 `_). Thanks `@Gachapen (Magnus Bjerke Vik) `_. + +* Use lean ``windows.h`` if not in header-only mode (`#503 `_). Thanks `@Quentin01 (Quentin Buathier) `_. + +* Fixed issue with CMake exporting C++11 flag (`#445 `_). Thanks `@EricWF (Eric) `_. + +* Fixed issue with nvcc and MSVC compiler bug and MinGW (`#505 `_). + +* Fixed DLL issues (`#469 `_ and `#502 `_). Thanks `@richardeakin (Richard Eakin) `_ and `@AndreasSchoenle (Andreas Schönle) `_. + +* Fixed test compilation under FreeBSD (`#433 `_). + +* Fixed various warnings (`#403 `_, `#410 `_ and `#510 `_). Thanks `@Lecetem `_, `@chenhayat (Chen Hayat) `_ and `@trozen `_. + +* Removed redundant include (`#479 `_). + +* Fixed documentation issues. + +3.0.1 - 2016-11-01 +------------------ +* Fixed handling of thousands seperator (`#353 `_) + +* Fixed handling of ``unsigned char`` strings (`#373 `_) + +* Corrected buffer growth when formatting time (`#367 `_) + +* Removed warnings under MSVC and clang (`#318 `_, `#250 `_, also merged `#385 `_ and `#361 `_). Thanks `@jcelerier (Jean-Michaël Celerier) `_ and `@nmoehrle (Nils Moehrle) `_. + +* Fixed compilation issues under Android (`#327 `_, `#345 `_ and `#381 `_), FreeBSD (`#358 `_), Cygwin (`#388 `_), MinGW (`#355 `_) as well as other issues (`#350 `_, `#366 `_, `#348 `_, `#402 `_, `#405 `_). Thanks to `@dpantele (Dmitry) `_, `@hghwng (Hugh Wang) `_, `@arvedarved (Tilman Keskinöz) `_, `@LogicalKnight (Sean) `_ and `@JanHellwig (Jan Hellwig) `_. + +* Fixed some documentation issues and extended specification (`#320 `_, `#333 `_, `#347 `_, `#362 `_). Thanks to `@smellman (Taro Matsuzawa aka. btm) `_. + 3.0.0 - 2016-05-07 ------------------ diff --git a/libs/format/README.rst b/libs/format/README.rst index f9707ff53..ea2a6da41 100644 --- a/libs/format/README.rst +++ b/libs/format/README.rst @@ -20,9 +20,11 @@ alternative to IOStreams. Features -------- -* Two APIs: faster concatenation-based write API and slower (but still - very fast) replacement-based format API with positional arguments for - localization. +* Two APIs: faster concatenation-based `write API + `_ and slower, + but still very fast, replacement-based `format API + `_ with positional arguments + for localization. * Write API similar to the one used by IOStreams but stateless allowing faster implementation. * Format API with `format string syntax @@ -35,10 +37,10 @@ Features * Support for user-defined types. * High speed: performance of the format API is close to that of glibc's `printf `_ - and better than performance of IOStreams. See `Speed tests`_ and + and better than the performance of IOStreams. See `Speed tests`_ and `Fast integer to string conversion in C++ `_. -* Small code size both in terms of source code (format consists of a single +* Small code size both in terms of source code (the core library consists of a single header file and a single source file) and compiled code. See `Compile time and code bloat`_. * Reliability: the library has an extensive set of `unit tests @@ -89,6 +91,8 @@ An object of any user-defined type for which there is an overloaded .. code:: c++ + #include "fmt/ostream.h" + class Date { int year_, month_, day_; public: @@ -132,6 +136,12 @@ Projects using this library * `AMPL/MP `_: An open-source library for mathematical programming +* `CUAUV `_: Cornell University's autonomous underwater vehicle + +* `Drake `_: A planning, control, and analysis toolbox for nonlinear dynamical systems (MIT) + +* `Envoy `_: C++ L7 proxy and communication bus (Lyft) + * `HarpyWar/pvpgn `_: Player vs Player Gaming Network with tweaks @@ -139,6 +149,8 @@ Projects using this library * `Keypirinha `_: A semantic launcher for Windows +* `Kodi `_ (formerly xbmc): Home theater software + * `Lifeline `_: A 2D game * `MongoDB Smasher `_: A small tool to generate randomized datasets @@ -158,6 +170,12 @@ Projects using this library * `Salesforce Analytics Cloud `_: Business intelligence software +* `Scylla `_: A Cassandra-compatible NoSQL data store that can handle + 1 million transactions per second on a single server + +* `Seastar `_: An advanced, open-source C++ framework for + high-performance server applications on modern hardware + * `spdlog `_: Super fast C++ logging library * `Stellar `_: Financial platform @@ -390,6 +408,11 @@ It only applies if you distribute the documentation of fmt. Acknowledgments --------------- +The fmt library is maintained by Victor Zverovich (`vitaut `_) +and Jonathan Müller (`foonathan `_) with contributions from many +other people. See `Contributors `_ and `Releases `_ for some of the names. Let us know if your contribution +is not listed or mentioned incorrectly and we'll make it right. + The benchmark section of this readme file and the performance tests are taken from the excellent `tinyformat `_ library written by Chris Foster. Boost Format library is acknowledged transitively diff --git a/libs/format/cppformat/format.h b/libs/format/cppformat/format.h deleted file mode 100644 index 3fbf86b89..000000000 --- a/libs/format/cppformat/format.h +++ /dev/null @@ -1,2 +0,0 @@ -#include "../fmt/format.h" -#warning Including cppformat/format.h is deprecated. Include fmt/format.h instead. diff --git a/libs/format/cppformat/posix.h b/libs/format/cppformat/posix.h deleted file mode 100644 index 97b6fadcd..000000000 --- a/libs/format/cppformat/posix.h +++ /dev/null @@ -1,2 +0,0 @@ -#include "../fmt/posix.h" -#warning Including cppformat/posix.h is deprecated. Include fmt/posix.h instead. diff --git a/libs/format/doc/CMakeLists.txt b/libs/format/doc/CMakeLists.txt index fc5a0a244..df3e9b1e9 100644 --- a/libs/format/doc/CMakeLists.txt +++ b/libs/format/doc/CMakeLists.txt @@ -5,6 +5,8 @@ if (NOT DOXYGEN) endif () add_custom_target(doc - COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/build.py ${FMT_VERSION}) + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/build.py ${FMT_VERSION} + SOURCES build.py conf.py _templates/layout.html) -install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html/ DESTINATION share/doc/fmt) +install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html/ + DESTINATION share/doc/fmt OPTIONAL) diff --git a/libs/format/doc/_templates/layout.html b/libs/format/doc/_templates/layout.html index 261e2eb4f..0ac2dec78 100644 --- a/libs/format/doc/_templates/layout.html +++ b/libs/format/doc/_templates/layout.html @@ -8,8 +8,9 @@ {# Google Analytics #} {%- for scriptfile in script_files %} diff --git a/libs/format/doc/build.py b/libs/format/doc/build.py index 9721e2986..55992b9ff 100644 --- a/libs/format/doc/build.py +++ b/libs/format/doc/build.py @@ -8,30 +8,35 @@ from distutils.version import LooseVersion def pip_install(package, commit=None, **kwargs): "Install package using pip." + min_version = kwargs.get('min_version') + if min_version: + from pkg_resources import get_distribution, DistributionNotFound + try: + installed_version = get_distribution(os.path.basename(package)).version + if LooseVersion(installed_version) >= min_version: + print('{} {} already installed'.format(package, min_version)) + return + except DistributionNotFound: + pass if commit: - check_version = kwargs.get('check_version', '') - #output = check_output(['pip', 'show', package.split('/')[1]]) - #if check_version in output: - # print('{} already installed'.format(package)) - # return - package = 'git+git://github.com/{0}.git@{1}'.format(package, commit) - print('Installing {}'.format(package)) - check_call(['pip', 'install', '--upgrade', package]) + package = 'git+https://github.com/{0}.git@{1}'.format(package, commit) + print('Installing {0}'.format(package)) + check_call(['pip', 'install', package]) -def build_docs(version='dev'): +def create_build_env(dirname='virtualenv'): # Create virtualenv. - doc_dir = os.path.dirname(os.path.realpath(__file__)) - virtualenv_dir = 'virtualenv' - check_call(['virtualenv', virtualenv_dir]) + if not os.path.exists(dirname): + check_call(['virtualenv', dirname]) import sysconfig scripts_dir = os.path.basename(sysconfig.get_path('scripts')) - activate_this_file = os.path.join(virtualenv_dir, scripts_dir, - 'activate_this.py') + activate_this_file = os.path.join(dirname, scripts_dir, 'activate_this.py') with open(activate_this_file) as f: exec(f.read(), dict(__file__=activate_this_file)) + # Import get_distribution after activating virtualenv to get info about + # the correct packages. + from pkg_resources import get_distribution, DistributionNotFound # Upgrade pip because installation of sphinx with pip 1.1 available on Travis # is broken (see #207) and it doesn't support the show command. - from pkg_resources import get_distribution, DistributionNotFound pip_version = get_distribution('pip').version if LooseVersion(pip_version) < LooseVersion('1.5.4'): print("Updating pip") @@ -46,27 +51,35 @@ def build_docs(version='dev'): except DistributionNotFound: pass # Install Sphinx and Breathe. - pip_install('fmtlib/sphinx', - '12dde8afdb0a7bb5576e2656692c3478c69d8cc3', - check_version='1.4a0.dev-20151013') + pip_install('sphinx-doc/sphinx', '12b83372ac9316e8cbe86e7fed889296a4cc29ee', + min_version='1.4.1.dev20160531') pip_install('michaeljones/breathe', - '1c9d7f80378a92cffa755084823a78bb38ee4acc') + '6b1c5bb7a1866f15fc328b8716258354b10c1daa', + min_version='4.2.0') + +def build_docs(version='dev', **kwargs): + doc_dir = kwargs.get('doc_dir', os.path.dirname(os.path.realpath(__file__))) + work_dir = kwargs.get('work_dir', '.') + include_dir = kwargs.get('include_dir', + os.path.join(os.path.dirname(doc_dir), 'fmt')) # Build docs. cmd = ['doxygen', '-'] p = Popen(cmd, stdin=PIPE) + doxyxml_dir = os.path.join(work_dir, 'doxyxml') p.communicate(input=r''' PROJECT_NAME = fmt GENERATE_LATEX = NO GENERATE_MAN = NO GENERATE_RTF = NO CASE_SENSE_NAMES = NO - INPUT = {0}/format.h {0}/ostream.h + INPUT = {0}/container.h {0}/format.h {0}/ostream.h \ + {0}/printf.h {0}/string.h QUIET = YES JAVADOC_AUTOBRIEF = YES AUTOLINK_SUPPORT = NO GENERATE_HTML = NO GENERATE_XML = YES - XML_OUTPUT = doxyxml + XML_OUTPUT = {1} ALIASES = "rst=\verbatim embed:rst" ALIASES += "endrst=\endverbatim" MACRO_EXPANSION = YES @@ -76,24 +89,29 @@ def build_docs(version='dev'): FMT_USE_USER_DEFINED_LITERALS=1 \ FMT_API= EXCLUDE_SYMBOLS = fmt::internal::* StringValue write_str - '''.format(os.path.join(os.path.dirname(doc_dir), 'fmt')).encode('UTF-8')) + '''.format(include_dir, doxyxml_dir).encode('UTF-8')) if p.returncode != 0: raise CalledProcessError(p.returncode, cmd) + html_dir = os.path.join(work_dir, 'html') + versions = ['3.0.0', '2.0.0', '1.1.0'] check_call(['sphinx-build', - '-Dbreathe_projects.format=' + os.path.join(os.getcwd(), 'doxyxml'), - '-Dversion=' + version, '-Drelease=' + version, '-Aversion=' + version, - '-b', 'html', doc_dir, 'html']) + '-Dbreathe_projects.format=' + os.path.abspath(doxyxml_dir), + '-Dversion=' + version, '-Drelease=' + version, + '-Aversion=' + version, '-Aversions=' + ','.join(versions), + '-b', 'html', doc_dir, html_dir]) try: check_call(['lessc', '--clean-css', '--include-path=' + os.path.join(doc_dir, 'bootstrap'), os.path.join(doc_dir, 'fmt.less'), - 'html/_static/fmt.css']) + os.path.join(html_dir, '_static', 'fmt.css')]) except OSError as e: if e.errno != errno.ENOENT: raise - print('lessc not found; make sure that Less (http://lesscss.org/) is installed') + print('lessc not found; make sure that Less (http://lesscss.org/) ' + + 'is installed') sys.exit(1) - return 'html' + return html_dir if __name__ == '__main__': + create_build_env() build_docs(sys.argv[1]) diff --git a/libs/format/doc/conf.py b/libs/format/doc/conf.py index 7af3e4815..1e9010e79 100644 --- a/libs/format/doc/conf.py +++ b/libs/format/doc/conf.py @@ -228,8 +228,7 @@ latex_documents = [ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', 'format', u'format Documentation', - [u'Victor Zverovich'], 1) + ('index', 'fmt', u'fmt documentation', [u'Victor Zverovich'], 1) ] # If true, show URL addresses after external links. @@ -242,8 +241,8 @@ man_pages = [ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - ('index', 'format', u'format Documentation', - u'Victor Zverovich', 'format', 'One line description of project.', + ('index', 'fmt', u'fmt documentation', + u'Victor Zverovich', 'fmt', 'One line description of project.', 'Miscellaneous'), ] diff --git a/libs/format/doc/html/_sources/api.txt b/libs/format/doc/html/_sources/api.txt index 5270a68d4..8dbef39e1 100644 --- a/libs/format/doc/html/_sources/api.txt +++ b/libs/format/doc/html/_sources/api.txt @@ -11,8 +11,8 @@ namespace is usually omitted in examples. Format API ========== -The following functions use :ref:`format string syntax ` similar -to the one used by Python's `str.format +The following functions defined in ``fmt/format.h`` use :ref:`format string +syntax ` similar to the one used by Python's `str.format `_ function. They take *format_str* and *args* as arguments. @@ -22,6 +22,11 @@ arguments in the resulting string. *args* is an argument list representing arbitrary arguments. +The `performance of the format API +`_ is close +to that of glibc's ``printf`` and better than the performance of IOStreams. +For even better speed use the `write API`_. + .. _format: .. doxygenfunction:: format(CStringRef, ArgList) @@ -40,8 +45,9 @@ arguments in the resulting string. Date and time formatting ------------------------ -The library supports `strftime `_-like -date and time formatting:: +The library supports `strftime +`_-like date and time +formatting:: #include "fmt/time.h" @@ -52,6 +58,36 @@ date and time formatting:: The format string syntax is described in the documentation of `strftime `_. +Formatting user-defined types +----------------------------- + +A custom ``format_arg`` function may be implemented and used to format any +user-defined type. That is how date and time formatting described in the +previous section is implemented in :file:`fmt/time.h`. The following example +shows how to implement custom formatting for a user-defined structure. + +:: + + struct MyStruct { double a, b; }; + + void format_arg(fmt::BasicFormatter &f, + const char *&format_str, const MyStruct &s) { + f.writer().write("[MyStruct: a={:.1f}, b={:.2f}]", s.a, s.b); + } + + MyStruct m = { 1, 2 }; + std::string s = fmt::format("m={}", n); + // s == "m=[MyStruct: a=1.0, b=2.00]" + +Note in the example above the ``format_arg`` function ignores the contents of +``format_str`` so the type will always be formatted as specified. See +``format_arg`` in :file:`fmt/time.h` for an advanced example of how to use +the ``format_str`` argument to customize the formatted output. + +This section shows how to define a custom format function for a user-defined +type. The next section describes how to get ``fmt`` to use a conventional stream +output ``operator<<`` when one is defined for a user-defined type. + ``std::ostream`` support ------------------------ @@ -63,7 +99,7 @@ formatting of user-defined types that have overloaded ``operator<<``:: class Date { int year_, month_, day_; public: - Date(int year, int month, int day) : year_(year), month_(month), day_(day) {} + Date(int year, int month, int day): year_(year), month_(month), day_(day) {} friend std::ostream &operator<<(std::ostream &os, const Date &d) { return os << d.year_ << '-' << d.month_ << '-' << d.day_; @@ -75,8 +111,6 @@ formatting of user-defined types that have overloaded ``operator<<``:: .. doxygenfunction:: print(std::ostream&, CStringRef, ArgList) -.. doxygenfunction:: fprintf(std::ostream&, CStringRef, ArgList) - Argument formatters ------------------- @@ -86,7 +120,7 @@ custom argument formatter class:: // A custom argument formatter that formats negative integers as unsigned // with the ``x`` format specifier. class CustomArgFormatter : - public fmt::BasicArgFormatter { + public fmt::BasicArgFormatter { public: CustomArgFormatter(fmt::BasicFormatter &f, fmt::FormatSpec &s, const char *fmt) @@ -120,22 +154,43 @@ custom argument formatter class:: .. doxygenclass:: fmt::ArgFormatter :members: -Printf formatting functions ---------------------------- +Printf formatting +----------------- +The header ``fmt/printf.h`` provides ``printf``-like formatting functionality. The following functions use `printf format string syntax `_ with -a POSIX extension for positional arguments. +the POSIX extension for positional arguments. Unlike their standard +counterparts, the ``fmt`` functions are type-safe and throw an exception if an +argument type doesn't match its format specification. .. doxygenfunction:: printf(CStringRef, ArgList) .. doxygenfunction:: fprintf(std::FILE *, CStringRef, ArgList) +.. doxygenfunction:: fprintf(std::ostream&, CStringRef, ArgList) + .. doxygenfunction:: sprintf(CStringRef, ArgList) +.. doxygenclass:: fmt::PrintfFormatter + :members: + +.. doxygenclass:: fmt::BasicPrintfArgFormatter + :members: + +.. doxygenclass:: fmt::PrintfArgFormatter + :members: + Write API ========= +The write API provides classes for writing formatted data into character +streams. It is usually faster than the `format API`_ but, as IOStreams, +may result in larger compiled code size. The main writer class is +`~fmt::BasicMemoryWriter` which stores its output in a memory buffer and +provides direct access to it. It is possible to create custom writers that +store output elsewhere by subclassing `~fmt::BasicWriter`. + .. doxygenclass:: fmt::BasicWriter :members: @@ -145,6 +200,12 @@ Write API .. doxygenclass:: fmt::BasicArrayWriter :members: +.. doxygenclass:: fmt::BasicStringWriter + :members: + +.. doxygenclass:: fmt::BasicContainerWriter + :members: + .. doxygenfunction:: bin(int) .. doxygenfunction:: oct(int) @@ -169,6 +230,8 @@ Utilities .. doxygenclass:: fmt::ArgList :members: +.. doxygenfunction:: fmt::to_string(const T&) + .. doxygenclass:: fmt::BasicStringRef :members: @@ -185,6 +248,8 @@ System errors .. doxygenclass:: fmt::SystemError :members: +.. doxygenfunction:: fmt::format_system_error + .. doxygenclass:: fmt::WindowsError :members: @@ -202,7 +267,8 @@ A custom allocator class can be specified as a template argument to It is also possible to write a formatting function that uses a custom allocator:: - typedef std::basic_string, CustomAllocator> CustomString; + typedef std::basic_string, CustomAllocator> + CustomString; CustomString format(CustomAllocator alloc, fmt::CStringRef format_str, fmt::ArgList args) { diff --git a/libs/format/doc/html/_sources/index.txt b/libs/format/doc/html/_sources/index.txt index 4e17d4b54..ce9b7bf94 100644 --- a/libs/format/doc/html/_sources/index.txt +++ b/libs/format/doc/html/_sources/index.txt @@ -10,9 +10,9 @@ alternative to C++ IOStreams.
What users say:
- Thanks for creating this library. It’s been a hole in C++ for a long time. - I’ve used both boost::format and loki::SPrintf, and neither felt like the - right answer. This does. + Thanks for creating this library. It’s been a hole in C++ for a long + time. I’ve used both boost::format and loki::SPrintf, and neither felt + like the right answer. This does.
@@ -24,8 +24,8 @@ Format API The replacement-based Format API provides a safe alternative to ``printf``, ``sprintf`` and friends with comparable or `better performance `_. -The `format string syntax `_ is similar -to the one used by `str.format `_ +The `format string syntax `_ is similar to the one used by +`str.format `_ in Python: .. code:: c++ @@ -98,8 +98,8 @@ literal operators, they must be made visible with the directive Write API --------- -The concatenation-based Write API (experimental) provides a -`fast `_ +The concatenation-based Write API (experimental) provides a `fast +`_ stateless alternative to IOStreams: .. code:: c++ @@ -112,8 +112,9 @@ stateless alternative to IOStreams: Safety ------ -The library is fully type safe, automatic memory management prevents buffer overflow, -errors in format strings are reported using exceptions. For example, the code +The library is fully type safe, automatic memory management prevents buffer +overflow, errors in format strings are reported using exceptions. For example, +the code .. code:: c++ @@ -138,19 +139,21 @@ formatted into a narrow string. You can use a wide format string instead: fmt::format(L"Cyrillic letter {}", L'\x42e'); For comparison, writing a wide character to ``std::ostream`` results in -its numeric value being written to the stream (i.e. 1070 instead of letter 'ю' which -is represented by ``L'\x42e'`` if we use Unicode) which is rarely what is needed. +its numeric value being written to the stream (i.e. 1070 instead of letter 'ю' +which is represented by ``L'\x42e'`` if we use Unicode) which is rarely what is +needed. .. _portability: Portability ----------- -The library is highly portable. Here is an incomplete list of operating systems and -compilers where it has been tested and known to work: +The library is highly portable. Here is an incomplete list of operating systems +and compilers where it has been tested and known to work: -* 64-bit (amd64) GNU/Linux with GCC 4.4.3, `4.6.3 `_, - 4.7.2, 4.8.1 and Intel C++ Compiler (ICC) 14.0.2 +* 64-bit (amd64) GNU/Linux with GCC 4.4.3, + `4.6.3 `_, 4.7.2, 4.8.1, and Intel C++ + Compiler (ICC) 14.0.2 * 32-bit (i386) GNU/Linux with GCC 4.4.3, 4.6.3 @@ -161,21 +164,21 @@ compilers where it has been tested and known to work: * 32-bit Windows with Visual C++ 2010 -Although the library uses C++11 features when available, it also works with older -compilers and standard library implementations. The only thing to keep in mind -for C++98 portability: +Although the library uses C++11 features when available, it also works with +older compilers and standard library implementations. The only thing to keep in +mind for C++98 portability: * Variadic templates: minimum GCC 4.4, Clang 2.9 or VS2013. This feature allows - the Format API to accept an unlimited number of arguments. With older compilers - the maximum is 15. + the Format API to accept an unlimited number of arguments. With older + compilers the maximum is 15. -* User-defined literals: minimum GCC 4.7, Clang 3.1 or VS2015. The suffixes - ``_format`` and ``_a`` are functionally equivalent to the functions +* User-defined literals: minimum GCC 4.7, Clang 3.1 or VS2015. The suffixes + ``_format`` and ``_a`` are functionally equivalent to the functions ``fmt::format`` and ``fmt::arg``. -The output of all formatting functions is consistent across platforms. In particular, -formatting a floating-point infinity always gives ``inf`` while the output -of ``printf`` is platform-dependent in this case. For example, +The output of all formatting functions is consistent across platforms. In +particular, formatting a floating-point infinity always gives ``inf`` while the +output of ``printf`` is platform-dependent in this case. For example, .. code:: @@ -188,10 +191,10 @@ always prints ``inf``. Ease of Use ----------- -fmt has a small self-contained code base consisting of a single header file -and a single source file and no external dependencies. A permissive BSD `license -`_ allows using the library both -in open-source and commercial projects. +fmt has a small self-contained code base with the core library consisting of +a single header file and a single source file and no external dependencies. +A permissive BSD `license `_ allows +using the library both in open-source and commercial projects. .. raw:: html diff --git a/libs/format/doc/html/_sources/syntax.txt b/libs/format/doc/html/_sources/syntax.txt index feda3e44d..1051467a0 100644 --- a/libs/format/doc/html/_sources/syntax.txt +++ b/libs/format/doc/html/_sources/syntax.txt @@ -49,12 +49,10 @@ mini-language" or interpretation of the *format_spec*. Most built-in types support a common formatting mini-language, which is described in the next section. -A *format_spec* field can also include nested replacement fields within it. -These nested replacement fields can contain only an argument index; -format specifications are not allowed. Formatting is performed as if the -replacement fields within the format_spec are substituted before the -*format_spec* string is interpreted. This allows the formatting of a value -to be dynamically specified. +A *format_spec* field can also include nested replacement fields in certain +positions within it. These nested replacement fields can contain only an +argument id; format specifications are not allowed. This allows the +formatting of a value to be dynamically specified. See the :ref:`formatexamples` section for some examples. @@ -80,8 +78,8 @@ The general form of a *standard format specifier* is: sign: "+" | "-" | " " width: `integer` | "{" `arg_id` "}" precision: `integer` | "{" `arg_id` "}" - type: `int_type` | "c" | "e" | "E" | "f" | "F" | "g" | "G" | "p" | "s" - int_type: "b" | "B" | "d" | "o" | "x" | "X" + type: `int_type` | "a" | "A" | "c" | "e" | "E" | "f" | "F" | "g" | "G" | "p" | "s" + int_type: "b" | "B" | "d" | "n" | "o" | "x" | "X" The *fill* character can be any character other than '{' or '}'. The presence of a fill character is signaled by the character following it, which must be @@ -234,7 +232,7 @@ The available presentation types for floating-point values are: +=========+==========================================================+ | ``'a'`` | Hexadecimal floating point format. Prints the number in | | | base 16 with prefix ``"0x"`` and lower-case letters for | -| | digits above 9. Uses 'p' to indicate the exponent. | +| | digits above 9. Uses ``'p'`` to indicate the exponent. | +---------+----------------------------------------------------------+ | ``'A'`` | Same as ``'a'`` except it uses upper-case letters for | | | the prefix, digits above 9 and to indicate the exponent. | diff --git a/libs/format/doc/html/_sources/usage.txt b/libs/format/doc/html/_sources/usage.txt index 27d96edec..dff312dfa 100644 --- a/libs/format/doc/html/_sources/usage.txt +++ b/libs/format/doc/html/_sources/usage.txt @@ -54,6 +54,23 @@ To build a `shared library`__ set the ``BUILD_SHARED_LIBS`` CMake variable to __ http://en.wikipedia.org/wiki/Library_%28computing%29#Shared_libraries +Header-only usage with CMake +============================ + +In order to add ``fmtlib`` into an existing ``CMakeLists.txt`` file, you can add the ``fmt`` library directory into your main project, which will enable the ``fmt`` library:: + + add_subdirectory(fmt) + +If you have a project called ``foo`` that you would like to link against the fmt library in a header-only fashion, you can enable with with:: + + target_link_libraries(foo PRIVATE fmt::fmt-header-only) + +And then to ensure that the ``fmt`` library does not always get built, you can modify the call to ``add_subdirectory`` to read :: + + add_subdirectory(fmt EXCLUDE_FROM_ALL) + +This will ensure that the ``fmt`` library is exluded from calls to ``make``, ``make all``, or ``cmake --build .``. + Building the documentation ========================== @@ -62,7 +79,11 @@ system: * `Python `_ with pip and virtualenv * `Doxygen `_ -* `Less `_ with less-plugin-clean-css +* `Less `_ with ``less-plugin-clean-css``. + Ubuntu doesn't package the ``clean-css`` plugin so you should use ``npm`` + instead of ``apt`` to install both ``less`` and the plugin:: + + sudo npm install -g less less-plugin-clean-css. First generate makefiles or project files using CMake as described in the previous section. Then compile the ``doc`` target/project, for example:: @@ -87,4 +108,4 @@ Homebrew fmt can be installed on OS X using `Homebrew `_:: - brew install cppformat + brew install fmt diff --git a/libs/format/doc/html/_static/pygments.css b/libs/format/doc/html/_static/pygments.css index 8213e90be..20c4814dc 100644 --- a/libs/format/doc/html/_static/pygments.css +++ b/libs/format/doc/html/_static/pygments.css @@ -47,8 +47,10 @@ .highlight .mh { color: #208050 } /* Literal.Number.Hex */ .highlight .mi { color: #208050 } /* Literal.Number.Integer */ .highlight .mo { color: #208050 } /* Literal.Number.Oct */ +.highlight .sa { color: #4070a0 } /* Literal.String.Affix */ .highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ .highlight .sc { color: #4070a0 } /* Literal.String.Char */ +.highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */ .highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ .highlight .s2 { color: #4070a0 } /* Literal.String.Double */ .highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ @@ -59,7 +61,9 @@ .highlight .s1 { color: #4070a0 } /* Literal.String.Single */ .highlight .ss { color: #517918 } /* Literal.String.Symbol */ .highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ +.highlight .fm { color: #06287e } /* Name.Function.Magic */ .highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ .highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ .highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ +.highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */ .highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ \ No newline at end of file diff --git a/libs/format/doc/html/api.html b/libs/format/doc/html/api.html index 073c02b99..e8b323871 100644 --- a/libs/format/doc/html/api.html +++ b/libs/format/doc/html/api.html @@ -8,7 +8,7 @@ - API Reference — fmt 3.0.0 documentation + API Reference — fmt 4.0.0 documentation @@ -17,10 +17,11 @@ @@ -35,8 +36,9 @@ diff --git a/libs/format/doc/html/contents.html b/libs/format/doc/html/contents.html index 9daa5e953..e2d5789ee 100644 --- a/libs/format/doc/html/contents.html +++ b/libs/format/doc/html/contents.html @@ -8,7 +8,7 @@ - Contents — fmt 3.0.0 documentation + Contents — fmt 4.0.0 documentation @@ -17,10 +17,11 @@ @@ -34,8 +35,9 @@ diff --git a/libs/format/doc/html/genindex.html b/libs/format/doc/html/genindex.html index 5f0142ca3..89ffacf4b 100644 --- a/libs/format/doc/html/genindex.html +++ b/libs/format/doc/html/genindex.html @@ -9,7 +9,7 @@ - Index — fmt 3.0.0 documentation + Index — fmt 4.0.0 documentation @@ -18,10 +18,11 @@ @@ -34,8 +35,9 @@ diff --git a/libs/format/doc/html/index.html b/libs/format/doc/html/index.html index 9d1316431..e159b2170 100644 --- a/libs/format/doc/html/index.html +++ b/libs/format/doc/html/index.html @@ -8,7 +8,7 @@ - Overview — fmt 3.0.0 documentation + Overview — fmt 4.0.0 documentation @@ -17,10 +17,11 @@ @@ -33,8 +34,9 @@ diff --git a/libs/format/doc/html/objects.inv b/libs/format/doc/html/objects.inv index 21d47b1482e68b4f998a8ccdcc176011f917b781..018ffadc32d673aa5e5c1762d0d10b0981e71c77 100644 GIT binary patch delta 4129 zcmV++5Z>>q9PA*FHvu$}I6r?}TW=f5m44T+5RkkosQX38J~*BpK=8~&pvN=7E*3&v zWhN9Ukd$oi!~XXDs!2*D)h+f#-Yl}2feorz=R2pW&gDDRCI9&IuQ%`CUH|%NQk{p( zI~SIVb9(OXr+@mqzMK6a{OOP97iT|W&~NW1SMPqfdfz@O->ok%-z|S{e_Sl@+0;gq^hm{oiodwkG(0`I67N5| z@|DMo0+R@q+oSM%|9ZhOmIDxpjyPs7P z(ZC2A4D6j18*G0&N{*(EkGY$*XUQ$b(tZ1VIqkIU>R6-|s|Eekyk011P5*-ZGF;V+(};V@Uyh((sG5A(^)nMn>+d$x z+B!#@CGU3xdHwA^b=3VjVy-_9nUmUxRxcdy>Yq>JWSdhEXNyF1uY}p+O{M$eq+{X?oui-Z9+>4np-Xd9@ zKz?22sf5_3wcVV?bh6=VCoS#Q;J4b)-0h#x+O_pRsrB$2;FQ+xeL%b7_7j3r+B*~D zcI5->c95E8hfuDX7`xbhinRnW7hQNKX=-K zeb|55s^P%w4Z$08&u#<1gTC+`FjFID_Y`!njSczd32}(4@peb6JBi*CmbF-GleOzx z8#Vs-arpI7`~%sW$3xB?B3Nz4Rfl4im+t;P&0`k}wg_q?feK7Nl|RRT!QHzsU4QGe zKU++*6FQ#O<>l>i@ui1#qKvPaXu%e5nO1*k`Ive@>aEBL)DAwrzls})*DyOr&2H+4 z@iL%wqvn;at%(N@>(!dnG^%dy(Dq-o9~#$Vrt(OlYC&p-K6wUuB=k~U$5X8r*7P`_ zIo8?rOz0n>^W(SGI^9*vWtaO2bZ>MM!b`Z5xphzA5PnL@-ud@d*YDGLTzpw|G?#zv z53iaq8W2xjQrVX{QqgF$TXyQ*ImT7?NqX|(`GUiE1V5d3LcqA^bBRGh-Cg#{L-*F~ zxNv_Dw3}7!WjCqwmfHqFGy=8SEis?gKiQXO0QtU-%PxBKc5HQx+9ZCw`l)(-Hvg}Y zf4HA~5I|pzfiBIQUVxk?clYLYcLsm|oW6F7GmLwVv!Ox{U8F=AI9hBGIz=wWxRFBl zt`m>u7*|dIc5q@gMs(Tnx{0huzUl-2j94#1v@ckwIQk)5zx|`YnHnceCm3 z{Cu^J0Q!5HpI^}P)wlWDecj03F5TUoTVB*(UX&~SfUSqeMJR)JTF&2HU!B9ev`q7m z&d@O2Ok*Eh|1h1!GL0fLb3V??HY=5kkZ?Zy61(P+)(^qwlF^(k({!yUG#=JmV@>-7(z35 zj&o;{l`Lk$rK5u6{^+w30fVGqj&+)9&j@2wlVCEl)KEd4At9*bS$}`v$L;T73>Ab? z)H-eglgS1lvkl5ArA5{;yUew;BeAWvS}W{>vEDhXym6jUm6(v;kHKb6I}yC6F>7Z$ z51bOGh*pGX&0QLUEvc}=5$2B9Yq0O36*ikFafh6J6$Qwx!WAP}4?5T@n40hl)2_+5pTv>lYoHH?-Bso{YgltE} zd=P>O3#YJwa>S)1oNya04b%i;^eAi&sAbvz zkdQAtha-5Vu}48h76L()d;=BUXrv8P6Hg@}fn=r?qFiJpk|e`cVRv`qW|{I>`I0p? zlA03&C7dNfjUb#xMFOfW^^vkSP=V~Lgr|mU6c?=+;@W>$Zn4mkN5Rz_s6e)0LSSiq z43trxNDL}SB12|M=3%qg-G3k9a>p2jDg~J(qb{R@bLBJ95xFQLBPEk#5<}FCN)HD- z+EYs`p~}#VoJCQD6p@VOL?x^XWAPPtp@dqt&_IaHJm};_6wFECvmT4@qg0kfmKkLn z0Ue#Tg5rN+#ymj9#^PtgG-!r|_qyZ_^CoB(I7mJ`jdC{x|E|7AJ;KQj0LmsJ5I|0_ z)|N}9B0-GPY)LX@XEl2Z9X>@3eyBXO7<3YzX7pgx5CV@5YS2b*&LYOwyC$5nEQBHH zS{_W)&T|8jf=EO?QV2ZF=o_jM$fJdOq4o(>y(oXYFrY`4CxjF-z#FQP&KRo__k}m2 zo*U#sWLyfq!LUXCO;v%?SQ~Rx79|{;j^HAJ`W(<}GyaCER78iPDalDo1qU+>OalAF zQ*!8})f=kPgrP(eox=2$x0~&}=)N&MTg4GEo zX%BzW8b&JsBZ)D1LK1NV&P1GWRv_Ekq)c*Tyn-MC2^?M`w8HuZucQY1luCjhD?VC* zk%+CpNr+sAsA9^nT_g8PW+cL5w1OBkwI+$^(fI*AQ?zKHPRY=6u;WH6NWm#q8WD>B zB$J*b@D_#sTT-KkmBp=s;br9j07jyfR3v|+>CGvkwN6N#XqRk|f*4M7cncj_CNHth z7L7>C3T?ZT;0s0?2A}bRoN@RHJeft5iw+h9XC3BEz%HW7pvyw%gmz&RIFlLlgeAd2 z0@3sHm@JA1cNyy~NgM?(f{w~_hyJ;2Q|6M!#1S8fpafDg3S1WQN+kCdd`n{Ej0b!<81!#*1$?D>uJ;66Om2f`xlP${**>hTmb zI;I$kosk(=`kbM#St!RtG7$vcCoV04|DY)QvJ5m0ghdCg%juE<({)4>Vvv8)G?i9a zr@>$b!h%LSf<%K)E(kO-nF*&kBPfq7sh&h@e5=vICXqX=WGeEYs9;1!w4GUT&;(?3 zG-iX8j5G0|2eL9q0-Avet93bXH^`}(8BGL9GK^MWgXh6T>p+)6Bt{6CY|f0AE{OCk z;0MD6O(ui{21*k% zs4Pa1)0O-HEI7xR%18w#(@$B@Im7#_D%W@8R-B_7DA$9 z4uPQcWQd(oI8cwZPNwHHF~uB^6N!b5R+ci0phxLIFJZd82|EBYh~@HD%7^lHc{-n7{N(1h5AHVYfHo~|ZI#av z*|faDlBw%jdZ!?NCgyV!lPG3)0=e3+%}0^cu|Yv-r4@_T=d?N_a?pGTeDFX3IQ;#oaR z+gwp?_oQXIpCNJFVGC}s1+!k4=vFSLSIz%e4>(&Tw+x?;0;qnrS(uNT@2^Xota@G$ z+yueJmUfnpFD|d`P5AKI;0Af$iS~3o1@-2-&co%s z3yaw~J$Li!k6%{zli!Cw{^9)M?0XFQ<-^U@hwrXF9v_wOSC^L`7I%N&&ldM?wMvWg zFrQzBiCZpr2ai8qUw>skaSW$yclf9YqX98LOv9?0OW4e#{7@}dCugHK14jpfmzT47TDaA0@jriSGl4Bm^=8+dH*1y$mb`?f%c-ljsyh2`No3i#Z zcKjun#LjeYjsV2`Ri-F`Gl>b%$LWT zRJ$S5$LC)U?4@7UqNA^S&>iy4L5z=@aT;+?nR)>IO4WbOr!Awup|t*P?R=ZnI%dho zEk#^C%~MO=ZzJaVW1l&xwdm;8wp{)DX}sBl6a0HG_a0UG*ghp4s$7d6c=eCzezs_x z%JnOm(NVNx3ffhvU9l#$H#ZGW->_xd75`UH8{BORl^xQ!*cTWz<22&7+xM4bdZ?-? zga1=B9;<)8zpnDOrDMm6=vJ&N0r_QjGWkYZDj^K^k*66|Sqc8jln5hx7bv*3t zVnZ-I1NQJUe%#CIg4x}1Yq6tTVoT2&HU8gW=yiWl{2keu$3xC7qF1fQjrPSZFWr2e zrm>9$8w9nMK&Gdk%g-TTaB~-`)l&yZvz0lV)#c^gV)obpNtE%Urs}i7Tcl-Ld`%r7 z^+x0bYD)*-F5+6^EzFLH2f=dtv|Oe8(PGi&%|6{3J!(LB4R_L6cLes~D@t}+#*MDO zRMUSrdtA0Om+cN8HDNR$o;=;zl{iq*XtP_is=^%OM)q0y=F`j3z;Fa#O%v zUPA5rpXUy1XUz^X;X9+v@x`hYh18p|qiaN-`2OmL(SMMSB7Zl(`6Ph890GjRL+DM5qaIk;aq;6Oz%NN%6yWfpl@ny3Wom6b>%BfsK zE&46s+vkQI9eN}7TPvD{R)8GiUN*6p(A>2mZ5-o9)!+AC0}K&ev^>O;^~g74^4}5b zRm$uN)-K2Y2lahW2X9yF0`%(wx2l?IQ#AjT(Hc)O+VL z#mm*~A8C4iLC=>@)0O+SM!H+L`+K*zsK2}@m)@YH9v)|*4BqNI|8RYE4(PN<(~!>4 z8H}sg1=l}RlUQCL7MY3jX;Ne!mhLXCMgDO9=k1Wymvla<{K74s&cbZEO4HSH*Qo8Y zwPhbSzn#VEu3B}mDY<33nB|LyW!ir?3q4r+wl!;nQRlOK{&|_say6NB(Xc7?d*IL8 z_%h&PyXwsrtj|}<7Hr0km-7_5+fg^SaGEj2|78pF^SR(D3y+JAsbe{4Z-XH;bLTjB zCRxd1CR{oyNbZh4Dc;*l3g$!>n9__JlL&!9nnW9{FfJHa6JmGZubZoieFcAE6t#|< zz+|#P$ZUghN@)_d~Fm(@q5MY0TOg&jY8# zDWVl2T633%U`r~jaD@3Nq~^?!9B2rbg=I7wO$T8o&I8e~R|F@lQ<=tS7&SDpXiXl1 zt(>J!Qzi`~QgKOGrWxyu1qy#g`ax@ANK(wR7@|%(acD437=;fi1)UIgliLT2t6gjK!lEvPUW*L$Cw4NhoQ!=gJb|oQc^a$+>?LCS*G(=7SJS zSU80Zlp`)B;e^|0X`m($qX%KDsBPlWa`;S^DhuL+BPJUqX^4YjCvrl$mxfqrQ}7vk zYISDt6={_imQNyL5hyM@_%=<#8Xi5-G!r2scDft(`ZRYynQQz|<*u_`eh2p>2LIWW(^PrO# zQ7|Wk&w41nk5X9{S!R@RL`iho3W|pr^8mjYik}VBsNIrV>5@0ho1j_Xngn2S&xmT3araip1$ak>8RjJFD4y=#+tqO4h4^(!r zf*3TlCW+`l;Zn|-BKd(iCPSf*y1@#tLLfj`l?W0Z6k2~iuq{zoMMOua-a$cWazXcl zWLj{|s6-YCsM-OokKCHPtl9)U9q+!CxtNKuqVIfp0-cm|4Z6qHCO{4j8^c?EEl zh(Z=Ya9FDaNhE2TT~>p@(V=m44M7PD>rq}DdNqIL9U9s!k_&^tvnRB?`yt9R^lXG7 z;c~A<4BpdXM3LOSRX@*|~ zjXXgj*3QJP@3@{}b#N#_T443iDQM8E7z$uy#uZZ37d8upMlqR)YVXk`SpvSQK-!AE zH1&Ukby

v{6W7luE6b1vTUbE*d-nqbDrbyDr!Ul*|!L2zvggDcW7@H26R_*kye& zYMkm@O1&jv7AHE0LLUVKafn(l<&mDKW$0?S>=-eR>&s7l?AjA8c>+8mBxGbPnM4kX z8Hw6ZZCD{2E#8l$Z|;6RNz46#yRX@wU(A1Rhi)V{@952!5^0etbX%S=^aIKfBw3HX zK+3=wT9ebhy9bsDXbrL*fRaE_0CrLWjSYTii}zr=U_3a-nL>SuF?!%-AJ8l&nSud9 z)1AOTvaB;!dY;k8=EQ_&$|R15Xd)!*24PFC2X+uaSvR zN>GCja2n!Tkg7efkR2ETyun(jwaAnb%}T;Rrbwn67g9_*>S z7K|C5>IpbQW*lgpz!F+{;;f<)O_xj*wW)N|7ClCxIH$ojw*fYeme3qpq#b`WZ{S=s zYFYRM0^gx1v(ybOf{6o06e5D`gB^90P|h)P7i>D6(Vh=N-_FqGubr!01y>)X|5#0{ ziyz$d?!n!qEl}NtEsrW(|DE!=n@nb*+~ZoF-KA-LO1m$zeY!rIzA7KjsyHr3*46YO zbvd+!*mC6-t8Ow0igLA~hHZbPp69VSVc(g;e}7GjuT^@)pw+nk)6Gu6t8~}Rmit+3 zSl0Q|#rBJ}SwGI=!z67Mcs^UKoUbP3_W$u?^y`;VXY&OdVp*J_gK6u#G{;?Xk>(Rb z!9BKMj4haSx*)Mczx$^7xAlOtWpaz~<-q6bXX}NzU4MUFTzlE^^2bg(2rf3S2g}D- z7ZY|SyniKRjlAnbJG!3ZaQ#PQxAix>A}7LkPpqpG)|X6n4STtDa{jq|JbSF->Pr{M Ux~V&HYooqORA1Woe;TK4r#q_B-v9sr diff --git a/libs/format/doc/html/search.html b/libs/format/doc/html/search.html index 54b2f380c..a8f742f30 100644 --- a/libs/format/doc/html/search.html +++ b/libs/format/doc/html/search.html @@ -8,7 +8,7 @@ - Search — fmt 3.0.0 documentation + Search — fmt 4.0.0 documentation @@ -17,10 +17,11 @@ @@ -40,8 +41,9 @@ diff --git a/libs/format/doc/html/searchindex.js b/libs/format/doc/html/searchindex.js index f6532839a..fecf16d98 100644 --- a/libs/format/doc/html/searchindex.js +++ b/libs/format/doc/html/searchindex.js @@ -1 +1 @@ -Search.setIndex({envversion:47,filenames:["api","contents","index","syntax","usage"],objects:{"":{"fmt::ArgFormatter":[0,1,1,"_CPPv2N3fmt12ArgFormatterE"],"fmt::ArgFormatter::ArgFormatter":[0,2,1,"_CPPv2N3fmt12ArgFormatter12ArgFormatterER14BasicFormatterI4CharER10FormatSpecPK4Char"],"fmt::ArgList":[0,1,1,"_CPPv2N3fmt7ArgListE"],"fmt::ArgList::operator[]":[0,2,1,"_CPPv2N3fmt7ArgListixEj"],"fmt::ArgVisitor":[0,1,1,"_CPPv2N3fmt10ArgVisitorE"],"fmt::ArgVisitor::visit":[0,2,1,"_CPPv2N3fmt10ArgVisitor5visitERK3Arg"],"fmt::ArgVisitor::visit_any_double":[0,2,1,"_CPPv2N3fmt10ArgVisitor16visit_any_doubleE1T"],"fmt::ArgVisitor::visit_any_int":[0,2,1,"_CPPv2N3fmt10ArgVisitor13visit_any_intE1T"],"fmt::ArgVisitor::visit_bool":[0,2,1,"_CPPv2N3fmt10ArgVisitor10visit_boolEb"],"fmt::ArgVisitor::visit_char":[0,2,1,"_CPPv2N3fmt10ArgVisitor10visit_charEi"],"fmt::ArgVisitor::visit_cstring":[0,2,1,"_CPPv2N3fmt10ArgVisitor13visit_cstringEPKc"],"fmt::ArgVisitor::visit_custom":[0,2,1,"_CPPv2N3fmt10ArgVisitor12visit_customEN3Arg11CustomValueE"],"fmt::ArgVisitor::visit_double":[0,2,1,"_CPPv2N3fmt10ArgVisitor12visit_doubleEd"],"fmt::ArgVisitor::visit_int":[0,2,1,"_CPPv2N3fmt10ArgVisitor9visit_intEi"],"fmt::ArgVisitor::visit_long_double":[0,2,1,"_CPPv2N3fmt10ArgVisitor17visit_long_doubleEe"],"fmt::ArgVisitor::visit_long_long":[0,2,1,"_CPPv2N3fmt10ArgVisitor15visit_long_longE8LongLong"],"fmt::ArgVisitor::visit_pointer":[0,2,1,"_CPPv2N3fmt10ArgVisitor13visit_pointerEPKv"],"fmt::ArgVisitor::visit_string":[0,2,1,"_CPPv2N3fmt10ArgVisitor12visit_stringEN3Arg11StringValueIcEE"],"fmt::ArgVisitor::visit_uint":[0,2,1,"_CPPv2N3fmt10ArgVisitor10visit_uintEj"],"fmt::ArgVisitor::visit_ulong_long":[0,2,1,"_CPPv2N3fmt10ArgVisitor16visit_ulong_longE9ULongLong"],"fmt::ArgVisitor::visit_wstring":[0,2,1,"_CPPv2N3fmt10ArgVisitor13visit_wstringEN3Arg11StringValueIwEE"],"fmt::BasicArgFormatter":[0,1,1,"_CPPv2N3fmt17BasicArgFormatterE"],"fmt::BasicArgFormatter::BasicArgFormatter":[0,2,1,"_CPPv2N3fmt17BasicArgFormatter17BasicArgFormatterER14BasicFormatterI4Char4ImplER10FormatSpecPK4Char"],"fmt::BasicArgFormatter::visit_custom":[0,2,1,"_CPPv2N3fmt17BasicArgFormatter12visit_customEN8internal3Arg11CustomValueE"],"fmt::BasicArrayWriter":[0,1,1,"_CPPv2N3fmt16BasicArrayWriterE"],"fmt::BasicArrayWriter::BasicArrayWriter":[0,2,1,"_CPPv2N3fmt16BasicArrayWriter16BasicArrayWriterERASIZE_4Char"],"fmt::BasicCStringRef":[0,1,1,"_CPPv2N3fmt15BasicCStringRefE"],"fmt::BasicCStringRef::BasicCStringRef":[0,2,1,"_CPPv2N3fmt15BasicCStringRef15BasicCStringRefERKNSt12basic_stringI4CharEE"],"fmt::BasicCStringRef::c_str":[0,2,1,"_CPPv2N3fmt15BasicCStringRef5c_strEv"],"fmt::BasicFormatter":[0,1,1,"_CPPv2N3fmt14BasicFormatterE"],"fmt::BasicFormatter::BasicFormatter":[0,2,1,"_CPPv2N3fmt14BasicFormatter14BasicFormatterERK7ArgListR11BasicWriterI4CharE"],"fmt::BasicFormatter::Char":[0,3,1,"_CPPv2N3fmt14BasicFormatter4CharE"],"fmt::BasicFormatter::format":[0,2,1,"_CPPv2N3fmt14BasicFormatter6formatERPK4CharRKN8internal3ArgE"],"fmt::BasicFormatter::writer":[0,2,1,"_CPPv2N3fmt14BasicFormatter6writerEv"],"fmt::BasicMemoryWriter":[0,1,1,"_CPPv2N3fmt17BasicMemoryWriterE"],"fmt::BasicMemoryWriter::BasicMemoryWriter":[0,2,1,"_CPPv2N3fmt17BasicMemoryWriter17BasicMemoryWriterERR17BasicMemoryWriter"],"fmt::BasicMemoryWriter::operator=":[0,2,1,"_CPPv2N3fmt17BasicMemoryWriteraSERR17BasicMemoryWriter"],"fmt::BasicStringRef":[0,1,1,"_CPPv2N3fmt14BasicStringRefE"],"fmt::BasicStringRef::BasicStringRef":[0,2,1,"_CPPv2N3fmt14BasicStringRef14BasicStringRefERKNSt12basic_stringI4CharEE"],"fmt::BasicStringRef::data":[0,2,1,"_CPPv2N3fmt14BasicStringRef4dataEv"],"fmt::BasicStringRef::size":[0,2,1,"_CPPv2N3fmt14BasicStringRef4sizeEv"],"fmt::BasicStringRef::to_string":[0,2,1,"_CPPv2N3fmt14BasicStringRef9to_stringEv"],"fmt::BasicWriter":[0,1,1,"_CPPv2N3fmt11BasicWriterE"],"fmt::BasicWriter::c_str":[0,2,1,"_CPPv2N3fmt11BasicWriter5c_strEv"],"fmt::BasicWriter::data":[0,2,1,"_CPPv2N3fmt11BasicWriter4dataEv"],"fmt::BasicWriter::operator<<":[0,2,1,"_CPPv2N3fmt11BasicWriterlsEe"],"fmt::BasicWriter::size":[0,2,1,"_CPPv2N3fmt11BasicWriter4sizeEv"],"fmt::BasicWriter::str":[0,2,1,"_CPPv2N3fmt11BasicWriter3strEv"],"fmt::BasicWriter::write":[0,2,1,"_CPPv2N3fmt11BasicWriter5writeE15BasicCStringRefI4CharE7ArgList"],"fmt::BasicWriter::~BasicWriter":[0,2,1,"_CPPv2N3fmt11BasicWriterD0Ev"],"fmt::Buffer":[0,1,1,"_CPPv2N3fmt6BufferE"],"fmt::Buffer::append":[0,2,1,"_CPPv2N3fmt6Buffer6appendEPK1UPK1U"],"fmt::Buffer::capacity":[0,2,1,"_CPPv2N3fmt6Buffer8capacityEv"],"fmt::Buffer::grow":[0,2,1,"_CPPv2N3fmt6Buffer4growENSt6size_tE"],"fmt::Buffer::reserve":[0,2,1,"_CPPv2N3fmt6Buffer7reserveENSt6size_tE"],"fmt::Buffer::resize":[0,2,1,"_CPPv2N3fmt6Buffer6resizeENSt6size_tE"],"fmt::Buffer::size":[0,2,1,"_CPPv2N3fmt6Buffer4sizeEv"],"fmt::SystemError":[0,1,1,"_CPPv2N3fmt11SystemErrorE"],"fmt::SystemError::SystemError":[0,2,1,"_CPPv2N3fmt11SystemError11SystemErrorEi10CStringRef"],"fmt::WindowsError":[0,1,1,"_CPPv2N3fmt12WindowsErrorE"],"fmt::WindowsError::WindowsError":[0,2,1,"_CPPv2N3fmt12WindowsError12WindowsErrorEi10CStringRef"],"fmt::arg":[0,2,1,"_CPPv2N3fmt3argE9StringRefRK1T"],"fmt::bin":[0,2,1,"_CPPv2N3fmt3binEi"],"fmt::format":[0,2,1,"_CPPv2N3fmt6formatE10CStringRef7ArgList"],"fmt::fprintf":[0,2,1,"_CPPv2N3fmt7fprintfERNSt7ostreamE10CStringRef7ArgList"],"fmt::hex":[0,2,1,"_CPPv2N3fmt3hexEi"],"fmt::hexu":[0,2,1,"_CPPv2N3fmt4hexuEi"],"fmt::literals::operator\"\"_a":[0,2,1,"_CPPv2N3fmt8literalsli2_aEPKcNSt6size_tE"],"fmt::literals::operator\"\"_format":[0,2,1,"_CPPv2N3fmt8literalsli7_formatEPKcNSt6size_tE"],"fmt::oct":[0,2,1,"_CPPv2N3fmt3octEi"],"fmt::pad":[0,2,1,"_CPPv2N3fmt3padEij4Char"],"fmt::print":[0,2,1,"_CPPv2N3fmt5printERNSt7ostreamE10CStringRef7ArgList"],"fmt::printf":[0,2,1,"_CPPv2N3fmt6printfER11BasicWriterI4CharE15BasicCStringRefI4CharE7ArgList"],"fmt::sprintf":[0,2,1,"_CPPv2N3fmt7sprintfE10CStringRef7ArgList"],FMT_CAPTURE:[0,0,1,"c.FMT_CAPTURE"],FMT_VARIADIC:[0,0,1,"c.FMT_VARIADIC"]}},objnames:{"0":["c","macro","C macro"],"1":["cpp","class","C++ class"],"2":["cpp","function","C++ function"],"3":["cpp","type","C++ type"]},objtypes:{"0":"c:macro","1":"cpp:class","2":"cpp:function","3":"cpp:type"},terms:{"0000cafe":0,"0b101010":3,"0x2a":3,"0xcafe":0,"\u044e":2,"_format":[0,2],"boolean":3,"case":[0,2,3],"char":[0,2,3],"class":0,"const":[0,2],"default":[0,3],"final":3,"float":[0,2,3],"int":[0,3],"long":[0,2],"new":[0,3],"null":0,"public":0,"return":[0,2],"switch":3,"throw":[0,2],"true":[3,4],"void":0,"while":2,abov:[0,3],abra:[2,3],abracadabra:3,absent:3,accept:2,access:[0,3],across:2,add:[3,4],addit:3,after:3,align:[0,3],aligntypespec:0,all:[0,2,3],allow:[0,2,3],also:[0,2,3],altern:[2,3,4],although:[2,3],alwai:[2,3],amd64:2,android:1,ani:[0,3],answer:[0,2],anyth:3,appear:3,append:0,appli:2,appropri:[0,3],arbitrari:0,archiv:4,arg:[0,2],arg_id:3,argformatt:0,arglist:0,argvisitor:0,arrai:0,arraywrit:0,associ:0,assum:3,automat:[2,3],avail:[2,3,4],avoid:2,awar:3,base:[0,2,3],basic_str:0,basicargformatt:0,basicarraywrit:0,basiccstringref:0,basicformatt:0,basicmemorywrit:0,basicstringref:0,basicwrit:0,becaus:2,been:[2,4],befor:[3,4],begin:0,behavior:3,better:2,bin:[0,3],binari:3,bit:2,bool:0,boost:2,both:[2,3],brace:[0,3],breviti:0,brew:4,bring:[2,3],bsd:2,buffer:[0,2],build:1,build_shared_lib:4,built:[3,4],c_str:[0,2],cad:[2,3],call:0,can:[0,2,3,4],cannot:[0,2],capac:0,capacity_:0,captur:0,caught:2,caus:3,center:3,cerr:0,chang:0,char_trait:0,charact:[0,2,3],chartyp:0,choic:4,clang:2,clean:4,cmake:4,code:[0,2],colon:3,commerci:2,common:[0,3],compar:2,comparison:[2,3],compat:[0,2],compil:[0,2,4],comput:0,concaten:2,consid:3,consist:2,construct:[0,2],contain:[0,2,3],content:0,conveni:0,convers:3,convert:[0,3],copi:3,correspond:0,count:3,cppformat:[2,4],creat:[2,4],css:4,cstringref:0,curious:0,curli:3,current:[0,3,4],custom_format:0,customalloc:0,customargformatt:0,custommemorywrit:0,customstr:0,customvalu:0,cyril:2,dai:0,data:[0,3],day_:0,dbuild_shared_lib:4,decim:3,defin:[0,2,3],definit:0,depend:[0,2,3],describ:[0,3,4],descript:[0,2],destroi:0,detail:3,determin:3,differ:[0,3],digit:[0,3],direct:2,directli:0,directori:[0,4],dispatch:0,displai:3,doc:4,document:[0,1],doe:2,doesn:0,don:[0,2],doubl:[0,2,3],download:4,doxygen:4,dynam:[0,3],each:3,easier:2,either:3,elaps:0,element:0,els:[0,2],emul:2,enabl:3,end:0,ensur:2,environ:4,equival:[0,2,3],errno:[0,2],error_cod:0,escap:3,even:3,exampl:[0,1,2],except:[2,3],experiment:2,expon:3,extens:0,extern:2,fals:3,fast:2,featur:2,felt:2,ffffffd6:0,field:[0,3],file:[0,2,4],filenam:0,fill:[0,3],find:0,first:[3,4],fit:0,fix:[0,3],fmt:[0,2,3,4],fmt_:0,fmt_captur:0,fmt_variad:0,follow:[0,3,4],fopen:0,forc:3,form:[0,3],formal:3,format_spec:3,format_str:0,formaterror:2,formatspec:0,formerli:2,forti:2,fprintf:0,freeli:4,friend:[0,2],from:[0,2,3,4],fulli:2,func:0,gcc:2,gener:[0,2,3,4],get:3,getlasterror:0,git:4,github:2,give:2,given:[0,3],gnu:2,goe:2,goodby:2,grammar:3,grow:0,happi:2,have:[0,4],header:[0,2,4],hello:2,here:2,hex:[0,2,3],hexadecim:[2,3],hexu:0,hfile:0,hfile_error:0,highli:2,hold:[0,4],hole:2,homebrew:1,how:3,html:4,http:4,i386:2,icc:2,id_continu:3,id_start:3,ident:2,identifi:3,impl:0,implement:[0,2,3],implicitli:3,includ:[0,3,4],incomplet:2,increas:0,index:[0,3],indic:3,individu:3,inf:[2,3],infin:[2,3],inform:0,initi:0,insert:[2,3],instal:4,instead:[2,3],int_typ:3,integ:[0,2,3],integr:0,intel:2,intern:0,interpret:3,intformatspec:0,invok:4,iostream:2,just:3,keep:2,known:[0,2],languag:[0,1],larg:3,lead:3,least:0,left:[2,3],legaci:0,length:0,less:[3,4],letter:[0,2,3],librari:[0,1,2],licens:2,lifetim:0,lightweight:2,like:[0,2],line:[0,4],linux:2,list:[0,2],liter:[0,2,3],local:[2,3],localtim:0,loki:2,longlong:0,look:[0,2],lower:[0,3],lpofstruct:0,mac:[2,4],macro:0,made:2,madeup:0,magnitud:3,mai:[0,2,3],main:0,make:[0,2,4],makefil:4,manag:2,mani:3,maximum:[2,3],mean:3,memori:[0,2],memorywrit:[0,2],messag:[0,2],method:0,might:4,mind:2,mini:1,minimum:[2,3],minu:3,mkdir:4,month:0,month_:0,most:[0,3],move:0,msbuild:4,multipl:2,must:[2,3],myargvisitor:0,name:[0,2],namedarg:0,namespac:[0,2],nan:3,narrow:2,nativ:4,natur:2,ndk:1,need:[0,2,3,4],neg:[0,3],neither:2,nest:3,new_siz:0,next:3,nix:4,non:3,none:3,normal:3,notat:3,note:[2,3],noth:2,now:4,nullptr:0,number:[0,2,3],numer:[0,2,3],numeric_limit:2,object:[0,3],oct:[0,3],octal:3,of_read:0,offer:2,older:2,omit:[0,2,3],onc:4,onli:[2,3],open:[0,2],openfil:0,oper:[0,2],option:3,order:[2,3],org:4,other:[0,2,3,4],otherwis:2,out:[0,2],output:[0,2,3,4],overflow:2,overload:0,own:3,pad:[0,3],panic:[0,2],paramet:0,pars:0,part:0,particular:2,pass:0,path:4,pattern:0,perform:[2,3],permiss:2,pip:4,place:3,placement:2,platform:[0,2,4],plugin:4,pod:0,point:[0,2,3],pointer:[0,3],posit:[0,2,3],posix:0,possibl:[0,2],preced:3,precis:3,precompil:4,prefix:[0,3],presenc:3,present:3,prevent:2,previou:4,print:[0,2,3],print_error:0,process:0,produc:2,project:[2,4],protect:0,provid:[0,2,4],ptr_:0,python:[0,2,4],rang:4,rare:2,rather:2,recur:0,releas:4,remov:3,repeat:3,replac:[0,2,3],report:2,repositori:[2,4],repres:[0,2],represent:3,reserv:0,resid:0,resiz:0,respect:3,result:[0,2,3],returntyp:0,right:[0,2,3],round:3,run:4,runtim:0,runtime_error:0,safe:2,sai:2,same:[0,3],scientif:3,script:4,second:[0,3],section:[3,4],see:[0,3,4],self:2,separ:3,sequenc:3,set:[2,3,4],sever:[0,4],shalt:3,share:4,should:[3,4],show:3,shown:3,sign:3,signal:3,signatur:0,signific:3,similar:[0,2,3],simpl:3,singl:2,size:[0,3],size_t:0,slightli:2,sln:4,small:2,softwar:4,some:[0,3],sourc:2,space:[0,3],spec:0,specif:[0,1],specifi:[0,3],sprintf:[0,2],standard:[0,2,3],start:[3,4],stateless:2,stdafx:4,stderr:[0,2],stdout:[0,2],store:0,str:[0,2],stream:[0,2],strftime:0,string:[0,1,2],stringref:0,stringvalu:0,studio:4,subclass:0,subset:0,substitut:3,suffix:2,superclass:0,sure:0,surround:[0,3],syntax:[0,1,2],systemerror:0,take:0,target:4,templat:[0,2],term:3,termin:0,terser:2,test:[2,4],text:[0,3],textual:3,than:[2,3],thank:2,thei:[0,2,3],them:4,thi:[0,2,3,4],thing:2,thou:3,time_t:0,to_str:0,too:3,total:0,track:2,trail:3,translat:3,treat:3,two:2,type:[0,2,3],type_cod:0,typedef:0,typenam:0,typespec:0,typic:4,udlarg:0,udlformat:0,ulonglong:0,unchang:3,unicod:2,unknown:[0,2],unless:3,unlimit:2,unsign:0,updat:0,upper:[0,3],uppercas:3,usag:1,user:[0,2],usual:0,valid:[0,3],valu:[0,2,3],vari:0,variabl:[0,4],variad:[0,2],variou:3,vcproj:4,vector:0,virtual:0,virtualenv:4,visibl:2,visit:0,visit_any_doubl:0,visit_any_int:0,visit_bool:0,visit_char:0,visit_cstr:0,visit_custom:0,visit_doubl:0,visit_int:0,visit_long_doubl:0,visit_long_long:0,visit_point:0,visit_str:0,visit_uint:0,visit_ulong_long:0,visit_wstr:0,visitor:0,visual:[2,4],vs2013:2,vs2015:2,wai:0,warraywrit:0,wchar_t:0,wcstringref:0,well:3,what:2,when:[0,2,3],where:[0,2,4],whether:3,which:[2,3],whose:3,wide:[0,2,4],width:[0,3],window:[0,2,4],windowserror:0,within:3,wmemorywrit:0,word:3,work:[2,4],workflow:4,world:2,wrapper:2,writer:0,written:[0,2],wstringref:0,wwriter:0,www:4,x42e:2,xcode:4,xcodeproj:4,year:0,year_:0,you:[0,2,3,4],your:[2,4],zero:3},titles:["API Reference","Contents","Overview","Format String Syntax","Usage"],titleterms:{"function":0,alloc:0,android:4,api:[0,2],argument:0,build:4,content:1,custom:0,date:0,document:4,eas:2,error:0,exampl:3,format:[0,2,3],formatt:0,homebrew:4,languag:3,librari:4,mini:3,ndk:4,ostream:0,overview:2,portabl:2,printf:0,refer:0,safeti:2,specif:3,std:0,string:3,support:0,syntax:3,system:0,time:0,usag:4,util:0,write:[0,2]}}) \ No newline at end of file +Search.setIndex({envversion:49,filenames:["api","contents","index","syntax","usage"],objects:{"":{"fmt::ArgFormatter":[0,1,1,"_CPPv2N3fmt12ArgFormatterE"],"fmt::ArgFormatter::ArgFormatter":[0,2,1,"_CPPv2N3fmt12ArgFormatter12ArgFormatterER14BasicFormatterI4CharER10FormatSpecPK4Char"],"fmt::ArgList":[0,1,1,"_CPPv2N3fmt7ArgListE"],"fmt::ArgList::operator[]":[0,2,1,"_CPPv2NK3fmt7ArgListixEj"],"fmt::ArgVisitor":[0,1,1,"_CPPv2N3fmt10ArgVisitorE"],"fmt::ArgVisitor::visit":[0,2,1,"_CPPv2N3fmt10ArgVisitor5visitERK3Arg"],"fmt::ArgVisitor::visit_any_double":[0,2,1,"_CPPv2N3fmt10ArgVisitor16visit_any_doubleE1T"],"fmt::ArgVisitor::visit_any_int":[0,2,1,"_CPPv2N3fmt10ArgVisitor13visit_any_intE1T"],"fmt::ArgVisitor::visit_bool":[0,2,1,"_CPPv2N3fmt10ArgVisitor10visit_boolEb"],"fmt::ArgVisitor::visit_char":[0,2,1,"_CPPv2N3fmt10ArgVisitor10visit_charEi"],"fmt::ArgVisitor::visit_cstring":[0,2,1,"_CPPv2N3fmt10ArgVisitor13visit_cstringEPKc"],"fmt::ArgVisitor::visit_custom":[0,2,1,"_CPPv2N3fmt10ArgVisitor12visit_customEN3Arg11CustomValueE"],"fmt::ArgVisitor::visit_double":[0,2,1,"_CPPv2N3fmt10ArgVisitor12visit_doubleEd"],"fmt::ArgVisitor::visit_int":[0,2,1,"_CPPv2N3fmt10ArgVisitor9visit_intEi"],"fmt::ArgVisitor::visit_long_double":[0,2,1,"_CPPv2N3fmt10ArgVisitor17visit_long_doubleEe"],"fmt::ArgVisitor::visit_long_long":[0,2,1,"_CPPv2N3fmt10ArgVisitor15visit_long_longE8LongLong"],"fmt::ArgVisitor::visit_pointer":[0,2,1,"_CPPv2N3fmt10ArgVisitor13visit_pointerEPKv"],"fmt::ArgVisitor::visit_string":[0,2,1,"_CPPv2N3fmt10ArgVisitor12visit_stringEN3Arg11StringValueIcEE"],"fmt::ArgVisitor::visit_uint":[0,2,1,"_CPPv2N3fmt10ArgVisitor10visit_uintEj"],"fmt::ArgVisitor::visit_ulong_long":[0,2,1,"_CPPv2N3fmt10ArgVisitor16visit_ulong_longE9ULongLong"],"fmt::ArgVisitor::visit_wstring":[0,2,1,"_CPPv2N3fmt10ArgVisitor13visit_wstringEN3Arg11StringValueIwEE"],"fmt::BasicArgFormatter":[0,1,1,"_CPPv2N3fmt17BasicArgFormatterE"],"fmt::BasicArgFormatter::BasicArgFormatter":[0,2,1,"_CPPv2N3fmt17BasicArgFormatter17BasicArgFormatterER14BasicFormatterI4Char4ImplER4SpecPK4Char"],"fmt::BasicArgFormatter::visit_custom":[0,2,1,"_CPPv2N3fmt17BasicArgFormatter12visit_customEN8internal3Arg11CustomValueE"],"fmt::BasicArrayWriter":[0,1,1,"_CPPv2N3fmt16BasicArrayWriterE"],"fmt::BasicArrayWriter::BasicArrayWriter":[0,2,1,"_CPPv2N3fmt16BasicArrayWriter16BasicArrayWriterERASIZE_4Char"],"fmt::BasicCStringRef":[0,1,1,"_CPPv2N3fmt15BasicCStringRefE"],"fmt::BasicCStringRef::BasicCStringRef":[0,2,1,"_CPPv2N3fmt15BasicCStringRef15BasicCStringRefERKNSt12basic_stringI4CharNSt11char_traitsI4CharEE9AllocatorEE"],"fmt::BasicCStringRef::c_str":[0,2,1,"_CPPv2NK3fmt15BasicCStringRef5c_strEv"],"fmt::BasicContainerWriter":[0,1,1,"_CPPv2N3fmt20BasicContainerWriterE"],"fmt::BasicContainerWriter::BasicContainerWriter":[0,2,1,"_CPPv2N3fmt20BasicContainerWriter20BasicContainerWriterER9Container"],"fmt::BasicFormatter":[0,1,1,"_CPPv2N3fmt14BasicFormatterE"],"fmt::BasicFormatter::BasicFormatter":[0,2,1,"_CPPv2N3fmt14BasicFormatter14BasicFormatterERK7ArgListR11BasicWriterI4CharE"],"fmt::BasicFormatter::Char":[0,3,1,"_CPPv2N3fmt14BasicFormatter4CharE"],"fmt::BasicFormatter::format":[0,2,1,"_CPPv2N3fmt14BasicFormatter6formatERPK4CharRKN8internal3ArgE"],"fmt::BasicFormatter::writer":[0,2,1,"_CPPv2N3fmt14BasicFormatter6writerEv"],"fmt::BasicMemoryWriter":[0,1,1,"_CPPv2N3fmt17BasicMemoryWriterE"],"fmt::BasicMemoryWriter::BasicMemoryWriter":[0,2,1,"_CPPv2N3fmt17BasicMemoryWriter17BasicMemoryWriterERR17BasicMemoryWriter"],"fmt::BasicMemoryWriter::operator=":[0,2,1,"_CPPv2N3fmt17BasicMemoryWriteraSERR17BasicMemoryWriter"],"fmt::BasicPrintfArgFormatter":[0,1,1,"_CPPv2N3fmt23BasicPrintfArgFormatterE"],"fmt::BasicPrintfArgFormatter::BasicPrintfArgFormatter":[0,2,1,"_CPPv2N3fmt23BasicPrintfArgFormatter23BasicPrintfArgFormatterER11BasicWriterI4CharER4Spec"],"fmt::BasicPrintfArgFormatter::visit_bool":[0,2,1,"_CPPv2N3fmt23BasicPrintfArgFormatter10visit_boolEb"],"fmt::BasicPrintfArgFormatter::visit_char":[0,2,1,"_CPPv2N3fmt23BasicPrintfArgFormatter10visit_charEi"],"fmt::BasicPrintfArgFormatter::visit_cstring":[0,2,1,"_CPPv2N3fmt23BasicPrintfArgFormatter13visit_cstringEPKc"],"fmt::BasicPrintfArgFormatter::visit_custom":[0,2,1,"_CPPv2N3fmt23BasicPrintfArgFormatter12visit_customEN8internal3Arg11CustomValueE"],"fmt::BasicPrintfArgFormatter::visit_pointer":[0,2,1,"_CPPv2N3fmt23BasicPrintfArgFormatter13visit_pointerEPKv"],"fmt::BasicStringRef":[0,1,1,"_CPPv2N3fmt14BasicStringRefE"],"fmt::BasicStringRef::BasicStringRef":[0,2,1,"_CPPv2N3fmt14BasicStringRef14BasicStringRefERKNSt12basic_stringI4CharNSt11char_traitsI4CharEE9AllocatorEE"],"fmt::BasicStringRef::data":[0,2,1,"_CPPv2NK3fmt14BasicStringRef4dataEv"],"fmt::BasicStringRef::size":[0,2,1,"_CPPv2NK3fmt14BasicStringRef4sizeEv"],"fmt::BasicStringRef::to_string":[0,2,1,"_CPPv2NK3fmt14BasicStringRef9to_stringEv"],"fmt::BasicStringWriter":[0,1,1,"_CPPv2N3fmt17BasicStringWriterE"],"fmt::BasicStringWriter::BasicStringWriter":[0,2,1,"_CPPv2N3fmt17BasicStringWriter17BasicStringWriterERK9Allocator"],"fmt::BasicStringWriter::move_to":[0,2,1,"_CPPv2N3fmt17BasicStringWriter7move_toERNSt12basic_stringI4CharNSt11char_traitsI4CharEE9AllocatorEE"],"fmt::BasicWriter":[0,1,1,"_CPPv2N3fmt11BasicWriterE"],"fmt::BasicWriter::c_str":[0,2,1,"_CPPv2NK3fmt11BasicWriter5c_strEv"],"fmt::BasicWriter::data":[0,2,1,"_CPPv2NK3fmt11BasicWriter4dataEv"],"fmt::BasicWriter::operator<<":[0,2,1,"_CPPv2N3fmt11BasicWriterlsEe"],"fmt::BasicWriter::size":[0,2,1,"_CPPv2NK3fmt11BasicWriter4sizeEv"],"fmt::BasicWriter::str":[0,2,1,"_CPPv2NK3fmt11BasicWriter3strEv"],"fmt::BasicWriter::write":[0,2,1,"_CPPv2N3fmt11BasicWriter5writeE15BasicCStringRefI4CharE7ArgList"],"fmt::BasicWriter::~BasicWriter":[0,2,1,"_CPPv2N3fmt11BasicWriterD0Ev"],"fmt::Buffer":[0,1,1,"_CPPv2N3fmt6BufferE"],"fmt::Buffer::append":[0,2,1,"_CPPv2N3fmt6Buffer6appendEPK1UPK1U"],"fmt::Buffer::capacity":[0,2,1,"_CPPv2NK3fmt6Buffer8capacityEv"],"fmt::Buffer::grow":[0,2,1,"_CPPv2N3fmt6Buffer4growENSt6size_tE"],"fmt::Buffer::reserve":[0,2,1,"_CPPv2N3fmt6Buffer7reserveENSt6size_tE"],"fmt::Buffer::resize":[0,2,1,"_CPPv2N3fmt6Buffer6resizeENSt6size_tE"],"fmt::Buffer::size":[0,2,1,"_CPPv2NK3fmt6Buffer4sizeEv"],"fmt::PrintfArgFormatter":[0,1,1,"_CPPv2N3fmt18PrintfArgFormatterE"],"fmt::PrintfArgFormatter::PrintfArgFormatter":[0,2,1,"_CPPv2N3fmt18PrintfArgFormatter18PrintfArgFormatterER11BasicWriterI4CharER10FormatSpec"],"fmt::PrintfFormatter":[0,1,1,"_CPPv2N3fmt15PrintfFormatterE"],"fmt::PrintfFormatter::PrintfFormatter":[0,2,1,"_CPPv2N3fmt15PrintfFormatter15PrintfFormatterERK7ArgListR11BasicWriterI4CharE"],"fmt::PrintfFormatter::format":[0,2,1,"_CPPv2N3fmt15PrintfFormatter6formatE15BasicCStringRefI4CharE"],"fmt::SystemError":[0,1,1,"_CPPv2N3fmt11SystemErrorE"],"fmt::SystemError::SystemError":[0,2,1,"_CPPv2N3fmt11SystemError11SystemErrorEi10CStringRef"],"fmt::WindowsError":[0,1,1,"_CPPv2N3fmt12WindowsErrorE"],"fmt::WindowsError::WindowsError":[0,2,1,"_CPPv2N3fmt12WindowsError12WindowsErrorEi10CStringRef"],"fmt::arg":[0,2,1,"_CPPv2N3fmt3argE9StringRefRK1T"],"fmt::bin":[0,2,1,"_CPPv2N3fmt3binEi"],"fmt::format":[0,2,1,"_CPPv2N3fmt6formatE10CStringRef7ArgList"],"fmt::format_system_error":[0,2,1,"_CPPv2N3fmt19format_system_errorERN3fmt6WriterEiN3fmt9StringRefE"],"fmt::fprintf":[0,2,1,"_CPPv2N3fmt7fprintfERNSt7ostreamE10CStringRef7ArgList"],"fmt::hex":[0,2,1,"_CPPv2N3fmt3hexEi"],"fmt::hexu":[0,2,1,"_CPPv2N3fmt4hexuEi"],"fmt::oct":[0,2,1,"_CPPv2N3fmt3octEi"],"fmt::pad":[0,2,1,"_CPPv2N3fmt3padEij4Char"],"fmt::print":[0,2,1,"_CPPv2N3fmt5printERNSt7ostreamE10CStringRef7ArgList"],"fmt::printf":[0,2,1,"_CPPv2N3fmt6printfER7WWriter11WCStringRefDpRK4Args"],"fmt::sprintf":[0,2,1,"_CPPv2N3fmt7sprintfE10CStringRef7ArgList"],"fmt::to_string":[0,2,1,"_CPPv2N3fmt9to_stringERK1T"],FMT_CAPTURE:[0,0,1,"c.FMT_CAPTURE"],FMT_VARIADIC:[0,0,1,"c.FMT_VARIADIC"]}},objnames:{"0":["c","macro","C macro"],"1":["cpp","class","C++ class"],"2":["cpp","function","C++ function"],"3":["cpp","type","C++ type"]},objtypes:{"0":"c:macro","1":"cpp:class","2":"cpp:function","3":"cpp:type"},terms:{"0000cafe":0,"0b101010":3,"0x2a":3,"0xcafe":0,"\u044e":2,"_format":[0,2],"boolean":3,"case":[0,2,3],"char":[0,2,3],"class":0,"const":[0,2],"default":[0,3],"final":3,"float":[0,2,3],"function":[0,2,3],"int":[0,3],"long":[0,2],"new":[0,3],"null":0,"public":0,"return":[0,2],"switch":3,"throw":[0,2],"true":[3,4],"void":0,"while":2,abov:[0,3],abra:[2,3],abracadabra:3,absent:3,accept:2,access:[0,3],across:2,add:[3,4],add_subdirectori:4,addit:[0,3],advanc:0,after:3,against:4,align:[0,3],aligntypespec:0,all:[0,2,3,4],allow:[0,2,3],also:[0,2,3],altern:[2,3,4],although:[2,3],alwai:[0,2,3,4],amd64:2,android:1,ani:[0,3],answer:[0,2],anyth:3,appear:3,append:0,appli:2,appropri:[0,3],apt:4,arbitrari:0,archiv:4,arg:[0,2],arg_id:3,argformatt:0,argformatterbas:0,arglist:0,argvisitor:0,arrai:0,arraywrit:0,associ:0,assum:3,automat:[2,3],avail:[2,3,4],avoid:2,awar:3,base:[0,2,3],basic_str:0,basicargformatt:0,basicarraywrit:0,basiccontainerwrit:0,basiccstringref:0,basicformatt:0,basicmemorywrit:0,basicprintfargformatt:0,basicstringref:0,basicstringwrit:0,basicwrit:0,becaus:2,been:[2,4],befor:[3,4],begin:0,behavior:3,better:[0,2],bin:[0,3],binari:3,bit:2,bool:0,boost:2,both:[2,3,4],brace:[0,3],breviti:0,brew:4,bring:[2,3],bsd:2,buffer:[0,2],build:[0,1],build_shared_lib:4,built:[3,4],c_str:[0,2],cad:[2,3],call:[0,4],can:[0,2,3,4],cannot:[0,2],capac:0,capacity_:0,captur:0,caught:2,caus:3,center:3,cerr:0,certain:3,chang:0,char_trait:0,charact:[0,2,3],chartyp:0,choic:4,clang:2,clean:4,clear:0,close:0,cmake:1,cmakelist:4,code:[0,2],colon:3,commerci:2,common:[0,3],compar:2,comparison:[2,3],compat:[0,2],compil:[0,2,4],comput:0,concaten:2,consid:3,consist:2,construct:[0,2],constructor:0,contain:[0,2,3],content:0,conveni:0,convent:0,convers:3,convert:[0,3],copi:3,core:2,correspond:0,count:3,counterpart:0,cppformat:2,creat:[0,2,4],css:4,cstringref:0,curious:0,curli:3,current:[0,3,4],custom_format:0,customalloc:0,customargformatt:0,custommemorywrit:0,customstr:0,customvalu:0,cyril:2,dai:0,data:[0,3],day_:0,dbuild_shared_lib:4,decim:3,definit:0,depend:[0,2,3],describ:[0,3,4],descript:[0,2],dest:0,destroi:0,detail:3,determin:3,differ:[0,3],digit:[0,3],direct:[0,2],directli:0,directori:[0,4],dispatch:0,displai:3,doc:[0,4],document:[0,1],doe:[2,4],doesn:[0,4],don:[0,2],doubl:[0,2,3],download:4,doxygen:[0,4],doxygenfunct:0,doxyxml:0,dynam:[0,3],each:3,easier:2,either:3,elaps:0,element:0,els:[0,2],elsewher:0,emul:2,enabl:[3,4],end:0,ensur:[2,4],environ:4,equival:[2,3],errno:[0,2],error_cod:0,escap:3,even:[0,3],exampl:[0,1,2],except:[0,2,3],exclude_from_al:4,exist:4,exlud:4,experiment:2,expon:3,extens:0,extern:2,fals:3,fashion:4,fast:2,faster:0,featur:2,felt:2,ffffffd6:0,field:[0,3],file:[0,2,4],filenam:0,fill:[0,3],find:0,first:[3,4],fit:0,fix:[0,3],fmt:[0,2,3,4],fmt_:0,fmt_captur:0,fmt_variad:0,fmtlib:4,follow:[0,3,4],foo:4,foonathan:0,fopen:0,forc:3,form:[0,3],formal:3,format_arg:0,format_spec:3,format_str:0,format_system_error:0,formaterror:2,formatspec:0,formatterbas:0,formerli:2,forti:2,fprintf:0,freeli:4,friend:[0,2],from:[0,2,3,4],fulli:2,func:0,gcc:2,gener:[0,2,3,4],get:[0,3,4],getlasterror:0,git:4,github:2,give:2,given:[0,3],glibc:0,gnu:2,goe:2,goodby:2,grammar:3,grow:0,happi:2,have:[0,4],header:[0,1,2],hello:2,here:2,hex:[0,2,3],hexadecim:[2,3],hexu:0,hfile:0,hfile_error:0,highli:2,hold:[0,4],hole:2,home:0,homebrew:1,how:[0,3],html:4,http:4,i386:2,icc:2,id_continu:3,id_start:3,ident:2,identifi:3,ignor:0,impl:0,implement:[0,2,3],implicitli:3,includ:[0,3,4],incomplet:2,increas:0,index:0,indic:3,individu:3,inf:[2,3],infin:[2,3],inform:0,inherit:0,initi:0,insert:[2,3],instal:4,instead:[2,3,4],int_typ:3,integ:[0,2,3],integr:0,intel:2,intern:0,interpret:3,intformatspec:0,invok:4,iostream:[0,2],just:3,keep:2,known:[0,2],languag:[0,1],larg:3,larger:0,lead:3,least:0,left:[2,3],legaci:0,length:0,less:[3,4],letter:[0,2,3],librari:[0,1,2],licens:2,lifetim:0,lightweight:2,like:[0,2,4],line:[0,4],link:4,linux:2,list:[0,2],liter:[0,2,3],local:[2,3],localtim:0,loki:2,longlong:0,look:[0,2],lower:[0,3],lpofstruct:0,mac:[2,4],macro:0,made:2,madeup:0,magnitud:3,mai:[0,2,3],main:[0,4],make:[0,2,4],makefil:4,manag:2,mani:3,match:0,maximum:[2,3],mean:3,memori:[0,2],memorybuff:0,memorywrit:[0,2],messag:[0,2],method:0,might:4,mind:2,mini:1,minimum:[2,3],minu:3,mkdir:4,modifi:4,month:0,month_:0,most:[0,3],move:0,move_to:0,msbuild:4,multipl:2,must:[2,3],myargvisitor:0,mystruct:0,name:[0,2],namedargwithtyp:0,namespac:[0,2],nan:3,narrow:2,nativ:4,natur:2,ndk:1,need:[0,2,3,4],neg:[0,3],neither:2,nest:3,new_siz:0,next:[0,3],nix:4,non:3,none:3,normal:3,notat:3,note:[0,2,3],noth:2,now:4,npm:4,nullptr:0,number:[0,2,3],numer:[0,2,3],numeric_limit:2,object:[0,3],oct:[0,3],octal:3,of_read:0,offer:2,older:2,omit:[0,2,3],onc:4,onli:[1,2,3],open:[0,2],openfil:0,oper:[0,2],option:3,order:[2,3,4],org:4,other:[0,2,3,4],otherwis:2,out:[0,2],output:[0,2,3,4],overflow:2,overload:0,own:3,packag:4,pad:[0,3],panic:[0,2],paramet:0,pars:0,part:0,particular:2,pass:0,path:4,pattern:0,perform:[0,2],permiss:2,pip:4,place:3,placement:2,platform:[0,2,4],plugin:4,pod:0,point:[0,2,3],pointer:[0,3],posit:[0,2,3],posix:0,possibl:[0,2],preced:3,precis:3,precompil:4,prefix:[0,3],presenc:3,present:3,prevent:2,previou:[0,4],print:[0,2,3],print_error:0,printfargformatt:0,printfformatt:0,privat:4,process:0,produc:2,program:0,project:[0,2,4],protect:0,provid:[0,2,4],ptr_:0,python:[0,2,4],rang:4,rare:2,rather:2,read:4,recur:0,releas:4,remov:3,repeat:3,replac:[0,2,3],report:2,repositori:[2,4],repres:[0,2],represent:3,reserv:0,resid:0,resiz:0,respect:3,result:[0,2,3],returntyp:0,right:[0,2,3],round:3,run:4,runtim:0,runtime_error:0,runtimeerror:0,safe:[0,2],sai:2,same:[0,3],scientif:3,script:4,second:[0,3],section:[0,3,4],see:[0,3,4],self:2,separ:3,sequenc:3,set:[2,3,4],sever:[0,4],shalt:3,share:4,should:[3,4],show:[0,3],shown:3,sign:3,signal:3,signatur:0,signific:3,similar:[0,2,3],similarli:0,simpl:3,singl:2,size:[0,3],size_t:0,slightli:2,sln:4,small:2,softwar:4,some:[0,3],sourc:2,space:[0,3],spec:0,specif:[0,1],specifi:[0,3],speed:0,sprintf:[0,2],standard:[0,2,3],start:[3,4],stateless:2,stdafx:4,stderr:[0,2],stdout:[0,2],store:0,str:[0,2],stream:[0,2],strftime:0,string:[0,1,2],stringref:0,stringvalu:0,stringwrit:0,struct:0,structur:0,studio:4,subclass:0,subset:0,sudo:4,suffix:2,superclass:0,sure:0,surround:[0,3],syntax:[0,1,2],systemerror:0,take:0,target:4,target_link_librari:4,templat:[0,2],term:3,termin:0,terser:2,test:[2,4],text:[0,3],textual:3,than:[0,2,3],thank:2,thei:[0,2,3],them:4,thi:[0,2,3,4],thing:2,thou:3,time_t:0,to_str:0,too:3,total:0,track:2,trail:3,translat:3,treat:3,two:2,txt:4,type_cod:0,typedef:0,typenam:0,typespec:0,typic:4,ubuntu:4,ulonglong:0,unchang:3,unicod:2,unknown:[0,2],unless:3,unlik:0,unlimit:2,unsign:0,updat:0,upper:[0,3],uppercas:3,usag:1,usual:0,valid:[0,3],valu:[0,2,3],value_typ:0,vari:0,variabl:[0,4],variad:[0,2],variou:3,vcproj:4,vecformat:0,vector:0,virtual:0,virtualenv:4,visibl:2,visit:0,visit_any_doubl:0,visit_any_int:0,visit_bool:0,visit_char:0,visit_cstr:0,visit_custom:0,visit_doubl:0,visit_int:0,visit_long_doubl:0,visit_long_long:0,visit_point:0,visit_str:0,visit_uint:0,visit_ulong_long:0,visit_wstr:0,visitor:0,visual:[2,4],vs2013:2,vs2015:2,wai:0,warraywrit:0,wchar_t:0,wcstringref:0,well:3,what:2,when:[0,2,3],where:[0,2,4],whether:3,which:[0,2,3,4],whose:3,wide:[0,2,4],width:[0,3],window:[0,2,4],windowserror:0,within:3,wmemorywrit:0,word:3,work:[2,4],workflow:4,world:2,would:4,wrapper:2,writer:0,written:[0,2],wstringref:0,wstringwrit:0,wwriter:0,www:4,x42e:2,xcode:4,xcodeproj:4,xml:0,year:0,year_:0,you:[0,2,3,4],your:[2,4],zero:3},titles:["API Reference","Contents","Overview","Format String Syntax","Usage"],titleterms:{alloc:0,android:4,api:[0,2],argument:0,build:4,cmake:4,content:1,custom:0,date:0,defin:0,document:4,eas:2,error:0,exampl:3,format:[0,2,3],formatt:0,header:4,homebrew:4,languag:3,librari:4,mini:3,ndk:4,onli:4,ostream:0,overview:2,portabl:2,printf:0,refer:0,safeti:2,specif:3,std:0,string:3,support:0,syntax:3,system:0,time:0,type:0,usag:4,user:0,util:0,write:[0,2]}}) \ No newline at end of file diff --git a/libs/format/doc/html/syntax.html b/libs/format/doc/html/syntax.html index ded1e98dc..55ec80507 100644 --- a/libs/format/doc/html/syntax.html +++ b/libs/format/doc/html/syntax.html @@ -8,7 +8,7 @@ - Format String Syntax — fmt 3.0.0 documentation + Format String Syntax — fmt 4.0.0 documentation @@ -17,10 +17,11 @@ @@ -34,8 +35,9 @@ diff --git a/libs/format/doc/html/usage.html b/libs/format/doc/html/usage.html index b2c90f581..12d59bf21 100644 --- a/libs/format/doc/html/usage.html +++ b/libs/format/doc/html/usage.html @@ -8,7 +8,7 @@ - Usage — fmt 3.0.0 documentation + Usage — fmt 4.0.0 documentation @@ -17,10 +17,11 @@ @@ -35,8 +36,9 @@ diff --git a/libs/format/doc/index.rst b/libs/format/doc/index.rst index 4e17d4b54..ce9b7bf94 100644 --- a/libs/format/doc/index.rst +++ b/libs/format/doc/index.rst @@ -10,9 +10,9 @@ alternative to C++ IOStreams.

What users say:
- Thanks for creating this library. It’s been a hole in C++ for a long time. - I’ve used both boost::format and loki::SPrintf, and neither felt like the - right answer. This does. + Thanks for creating this library. It’s been a hole in C++ for a long + time. I’ve used both boost::format and loki::SPrintf, and neither felt + like the right answer. This does.
@@ -24,8 +24,8 @@ Format API The replacement-based Format API provides a safe alternative to ``printf``, ``sprintf`` and friends with comparable or `better performance `_. -The `format string syntax `_ is similar -to the one used by `str.format `_ +The `format string syntax `_ is similar to the one used by +`str.format `_ in Python: .. code:: c++ @@ -98,8 +98,8 @@ literal operators, they must be made visible with the directive Write API --------- -The concatenation-based Write API (experimental) provides a -`fast `_ +The concatenation-based Write API (experimental) provides a `fast +`_ stateless alternative to IOStreams: .. code:: c++ @@ -112,8 +112,9 @@ stateless alternative to IOStreams: Safety ------ -The library is fully type safe, automatic memory management prevents buffer overflow, -errors in format strings are reported using exceptions. For example, the code +The library is fully type safe, automatic memory management prevents buffer +overflow, errors in format strings are reported using exceptions. For example, +the code .. code:: c++ @@ -138,19 +139,21 @@ formatted into a narrow string. You can use a wide format string instead: fmt::format(L"Cyrillic letter {}", L'\x42e'); For comparison, writing a wide character to ``std::ostream`` results in -its numeric value being written to the stream (i.e. 1070 instead of letter 'ю' which -is represented by ``L'\x42e'`` if we use Unicode) which is rarely what is needed. +its numeric value being written to the stream (i.e. 1070 instead of letter 'ю' +which is represented by ``L'\x42e'`` if we use Unicode) which is rarely what is +needed. .. _portability: Portability ----------- -The library is highly portable. Here is an incomplete list of operating systems and -compilers where it has been tested and known to work: +The library is highly portable. Here is an incomplete list of operating systems +and compilers where it has been tested and known to work: -* 64-bit (amd64) GNU/Linux with GCC 4.4.3, `4.6.3 `_, - 4.7.2, 4.8.1 and Intel C++ Compiler (ICC) 14.0.2 +* 64-bit (amd64) GNU/Linux with GCC 4.4.3, + `4.6.3 `_, 4.7.2, 4.8.1, and Intel C++ + Compiler (ICC) 14.0.2 * 32-bit (i386) GNU/Linux with GCC 4.4.3, 4.6.3 @@ -161,21 +164,21 @@ compilers where it has been tested and known to work: * 32-bit Windows with Visual C++ 2010 -Although the library uses C++11 features when available, it also works with older -compilers and standard library implementations. The only thing to keep in mind -for C++98 portability: +Although the library uses C++11 features when available, it also works with +older compilers and standard library implementations. The only thing to keep in +mind for C++98 portability: * Variadic templates: minimum GCC 4.4, Clang 2.9 or VS2013. This feature allows - the Format API to accept an unlimited number of arguments. With older compilers - the maximum is 15. + the Format API to accept an unlimited number of arguments. With older + compilers the maximum is 15. -* User-defined literals: minimum GCC 4.7, Clang 3.1 or VS2015. The suffixes - ``_format`` and ``_a`` are functionally equivalent to the functions +* User-defined literals: minimum GCC 4.7, Clang 3.1 or VS2015. The suffixes + ``_format`` and ``_a`` are functionally equivalent to the functions ``fmt::format`` and ``fmt::arg``. -The output of all formatting functions is consistent across platforms. In particular, -formatting a floating-point infinity always gives ``inf`` while the output -of ``printf`` is platform-dependent in this case. For example, +The output of all formatting functions is consistent across platforms. In +particular, formatting a floating-point infinity always gives ``inf`` while the +output of ``printf`` is platform-dependent in this case. For example, .. code:: @@ -188,10 +191,10 @@ always prints ``inf``. Ease of Use ----------- -fmt has a small self-contained code base consisting of a single header file -and a single source file and no external dependencies. A permissive BSD `license -`_ allows using the library both -in open-source and commercial projects. +fmt has a small self-contained code base with the core library consisting of +a single header file and a single source file and no external dependencies. +A permissive BSD `license `_ allows +using the library both in open-source and commercial projects. .. raw:: html diff --git a/libs/format/doc/syntax.rst b/libs/format/doc/syntax.rst index feda3e44d..1051467a0 100644 --- a/libs/format/doc/syntax.rst +++ b/libs/format/doc/syntax.rst @@ -49,12 +49,10 @@ mini-language" or interpretation of the *format_spec*. Most built-in types support a common formatting mini-language, which is described in the next section. -A *format_spec* field can also include nested replacement fields within it. -These nested replacement fields can contain only an argument index; -format specifications are not allowed. Formatting is performed as if the -replacement fields within the format_spec are substituted before the -*format_spec* string is interpreted. This allows the formatting of a value -to be dynamically specified. +A *format_spec* field can also include nested replacement fields in certain +positions within it. These nested replacement fields can contain only an +argument id; format specifications are not allowed. This allows the +formatting of a value to be dynamically specified. See the :ref:`formatexamples` section for some examples. @@ -80,8 +78,8 @@ The general form of a *standard format specifier* is: sign: "+" | "-" | " " width: `integer` | "{" `arg_id` "}" precision: `integer` | "{" `arg_id` "}" - type: `int_type` | "c" | "e" | "E" | "f" | "F" | "g" | "G" | "p" | "s" - int_type: "b" | "B" | "d" | "o" | "x" | "X" + type: `int_type` | "a" | "A" | "c" | "e" | "E" | "f" | "F" | "g" | "G" | "p" | "s" + int_type: "b" | "B" | "d" | "n" | "o" | "x" | "X" The *fill* character can be any character other than '{' or '}'. The presence of a fill character is signaled by the character following it, which must be @@ -234,7 +232,7 @@ The available presentation types for floating-point values are: +=========+==========================================================+ | ``'a'`` | Hexadecimal floating point format. Prints the number in | | | base 16 with prefix ``"0x"`` and lower-case letters for | -| | digits above 9. Uses 'p' to indicate the exponent. | +| | digits above 9. Uses ``'p'`` to indicate the exponent. | +---------+----------------------------------------------------------+ | ``'A'`` | Same as ``'a'`` except it uses upper-case letters for | | | the prefix, digits above 9 and to indicate the exponent. | diff --git a/libs/format/doc/usage.rst b/libs/format/doc/usage.rst index 27d96edec..dff312dfa 100644 --- a/libs/format/doc/usage.rst +++ b/libs/format/doc/usage.rst @@ -54,6 +54,23 @@ To build a `shared library`__ set the ``BUILD_SHARED_LIBS`` CMake variable to __ http://en.wikipedia.org/wiki/Library_%28computing%29#Shared_libraries +Header-only usage with CMake +============================ + +In order to add ``fmtlib`` into an existing ``CMakeLists.txt`` file, you can add the ``fmt`` library directory into your main project, which will enable the ``fmt`` library:: + + add_subdirectory(fmt) + +If you have a project called ``foo`` that you would like to link against the fmt library in a header-only fashion, you can enable with with:: + + target_link_libraries(foo PRIVATE fmt::fmt-header-only) + +And then to ensure that the ``fmt`` library does not always get built, you can modify the call to ``add_subdirectory`` to read :: + + add_subdirectory(fmt EXCLUDE_FROM_ALL) + +This will ensure that the ``fmt`` library is exluded from calls to ``make``, ``make all``, or ``cmake --build .``. + Building the documentation ========================== @@ -62,7 +79,11 @@ system: * `Python `_ with pip and virtualenv * `Doxygen `_ -* `Less `_ with less-plugin-clean-css +* `Less `_ with ``less-plugin-clean-css``. + Ubuntu doesn't package the ``clean-css`` plugin so you should use ``npm`` + instead of ``apt`` to install both ``less`` and the plugin:: + + sudo npm install -g less less-plugin-clean-css. First generate makefiles or project files using CMake as described in the previous section. Then compile the ``doc`` target/project, for example:: @@ -87,4 +108,4 @@ Homebrew fmt can be installed on OS X using `Homebrew `_:: - brew install cppformat + brew install fmt diff --git a/libs/format/fmt/CMakeLists.txt b/libs/format/fmt/CMakeLists.txt index 3fc872622..90eaf575f 100644 --- a/libs/format/fmt/CMakeLists.txt +++ b/libs/format/fmt/CMakeLists.txt @@ -1,26 +1,52 @@ # Define the fmt library, its includes and the needed defines. -# format.cc is added to FMT_HEADERS for the header-only configuration. -set(FMT_HEADERS format.h format.cc ostream.h ostream.cc time.h) +# *.cc are added to FMT_HEADERS for the header-only configuration. +set(FMT_HEADERS container.h format.h format.cc ostream.h ostream.cc printf.h + printf.cc string.h time.h) if (HAVE_OPEN) set(FMT_HEADERS ${FMT_HEADERS} posix.h) set(FMT_SOURCES ${FMT_SOURCES} posix.cc) endif () -add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} ../ChangeLog.rst) +add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} ../README.rst ../ChangeLog.rst) +add_library(fmt::fmt ALIAS fmt) -option(FMT_CPPFORMAT "Build cppformat library for backward compatibility." OFF) -if (FMT_CPPFORMAT) - message(WARNING "The cppformat library is deprecated, use fmt instead.") - add_library(cppformat ${FMT_SOURCES} ${FMT_HEADERS}) +# Starting with cmake 3.1 the CXX_STANDARD property can be used instead. +# Note: Don't make -std=c++11 public or interface, since it breaks projects +# that use C++14. +target_compile_options(fmt PRIVATE ${CPP11_FLAG}) +if (FMT_PEDANTIC) + target_compile_options(fmt PRIVATE ${PEDANTIC_COMPILE_FLAGS}) endif () -include_directories(fmt INTERFACE +target_include_directories(fmt PUBLIC $ $) set_target_properties(fmt PROPERTIES VERSION ${FMT_VERSION} SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR}) +if (BUILD_SHARED_LIBS) + if (UNIX AND NOT APPLE) + # Fix rpmlint warning: + # unused-direct-shlib-dependency /usr/lib/libformat.so.1.1.0 /lib/libm.so.6. + target_link_libraries(fmt -Wl,--as-needed) + endif () + target_compile_definitions(fmt PRIVATE FMT_EXPORT INTERFACE FMT_SHARED) +endif () + +#------------------------------------------------------------------------------ +# additionally define a header only library when cmake is new enough +if (CMAKE_VERSION VERSION_GREATER 3.1.0 OR CMAKE_VERSION VERSION_EQUAL 3.1.0) + add_library(fmt-header-only INTERFACE) + add_library(fmt::fmt-header-only ALIAS fmt-header-only) + + target_compile_definitions(fmt-header-only INTERFACE FMT_HEADER_ONLY=1) + + target_include_directories(fmt-header-only INTERFACE + $ + $) +endif () + # Install targets. if (FMT_INSTALL) include(CMakePackageConfigHelpers) @@ -47,18 +73,18 @@ if (FMT_INSTALL) ${PROJECT_SOURCE_DIR}/support/cmake/fmt-config.cmake.in ${project_config} INSTALL_DESTINATION ${FMT_CMAKE_DIR}) - export(TARGETS ${INSTALL_TARGETS} FILE ${PROJECT_BINARY_DIR}/${targets_export_name}.cmake) + export(TARGETS ${INSTALL_TARGETS} NAMESPACE fmt:: + FILE ${PROJECT_BINARY_DIR}/${targets_export_name}.cmake) # Install version, config and target files. install( FILES ${project_config} ${version_config} DESTINATION ${FMT_CMAKE_DIR}) - install(EXPORT ${targets_export_name} DESTINATION ${FMT_CMAKE_DIR}) + install(EXPORT ${targets_export_name} DESTINATION ${FMT_CMAKE_DIR} + NAMESPACE fmt::) # Install the library and headers. - install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name} DESTINATION ${FMT_LIB_DIR}) + install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name} + DESTINATION ${FMT_LIB_DIR}) install(FILES ${FMT_HEADERS} DESTINATION include/fmt) - if (FMT_CPPFORMAT) - install(TARGETS cppformat DESTINATION ${FMT_LIB_DIR}) - endif () endif () diff --git a/libs/format/fmt/format.cc b/libs/format/fmt/format.cc index ae5d11034..09d2ea9fd 100644 --- a/libs/format/fmt/format.cc +++ b/libs/format/fmt/format.cc @@ -41,6 +41,9 @@ #endif #if FMT_USE_WINDOWS_H +# if !defined(FMT_HEADER_ONLY) && !defined(WIN32_LEAN_AND_MEAN) +# define WIN32_LEAN_AND_MEAN +# endif # if defined(NOMINMAX) || defined(FMT_WIN_MINMAX) # include # else @@ -50,8 +53,6 @@ # endif #endif -using fmt::internal::Arg; - #if FMT_EXCEPTIONS # define FMT_TRY try # define FMT_CATCH(x) catch (x) @@ -79,6 +80,11 @@ static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) { } namespace fmt { + +FMT_FUNC internal::RuntimeError::~RuntimeError() FMT_DTOR_NOEXCEPT {} +FMT_FUNC FormatError::~FormatError() FMT_DTOR_NOEXCEPT {} +FMT_FUNC SystemError::~SystemError() FMT_DTOR_NOEXCEPT {} + namespace { #ifndef _MSC_VER @@ -100,27 +106,6 @@ inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) { # define FMT_SWPRINTF swprintf #endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) -// Checks if a value fits in int - used to avoid warnings about comparing -// signed and unsigned integers. -template -struct IntChecker { - template - static bool fits_in_int(T value) { - unsigned max = INT_MAX; - return value <= max; - } - static bool fits_in_int(bool) { return true; } -}; - -template <> -struct IntChecker { - template - static bool fits_in_int(T value) { - return value >= INT_MIN && value <= INT_MAX; - } - static bool fits_in_int(int) { return true; } -}; - const char RESET_COLOR[] = "\x1b[0m"; typedef void (*FormatFunc)(Writer &, int, StringRef); @@ -186,7 +171,8 @@ int safe_strerror( : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {} int run() { - strerror_r(0, 0, ""); // Suppress a warning about unused strerror_r. + // Suppress a warning about unused strerror_r. + strerror_r(0, FMT_NULL, ""); return handle(strerror_r(error_code_, buffer_, buffer_size_)); } }; @@ -225,222 +211,19 @@ void report_error(FormatFunc func, int error_code, std::fwrite(full_message.data(), full_message.size(), 1, stderr); std::fputc('\n', stderr); } - -// IsZeroInt::visit(arg) returns true iff arg is a zero integer. -class IsZeroInt : public ArgVisitor { - public: - template - bool visit_any_int(T value) { return value == 0; } -}; - -// Checks if an argument is a valid printf width specifier and sets -// left alignment if it is negative. -class WidthHandler : public ArgVisitor { - private: - FormatSpec &spec_; - - FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler); - - public: - explicit WidthHandler(FormatSpec &spec) : spec_(spec) {} - - void report_unhandled_arg() { - FMT_THROW(FormatError("width is not integer")); - } - - template - unsigned visit_any_int(T value) { - typedef typename internal::IntTraits::MainType UnsignedType; - UnsignedType width = static_cast(value); - if (internal::is_negative(value)) { - spec_.align_ = ALIGN_LEFT; - width = 0 - width; - } - if (width > INT_MAX) - FMT_THROW(FormatError("number is too big")); - return static_cast(width); - } -}; - -class PrecisionHandler : public ArgVisitor { - public: - void report_unhandled_arg() { - FMT_THROW(FormatError("precision is not integer")); - } - - template - int visit_any_int(T value) { - if (!IntChecker::is_signed>::fits_in_int(value)) - FMT_THROW(FormatError("number is too big")); - return static_cast(value); - } -}; - -template -struct is_same { - enum { value = 0 }; -}; - -template -struct is_same { - enum { value = 1 }; -}; - -// An argument visitor that converts an integer argument to T for printf, -// if T is an integral type. If T is void, the argument is converted to -// corresponding signed or unsigned type depending on the type specifier: -// 'd' and 'i' - signed, other - unsigned) -template -class ArgConverter : public ArgVisitor, void> { - private: - internal::Arg &arg_; - wchar_t type_; - - FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter); - - public: - ArgConverter(internal::Arg &arg, wchar_t type) - : arg_(arg), type_(type) {} - - void visit_bool(bool value) { - if (type_ != 's') - visit_any_int(value); - } - - template - void visit_any_int(U value) { - bool is_signed = type_ == 'd' || type_ == 'i'; - using internal::Arg; - typedef typename internal::Conditional< - is_same::value, U, T>::type TargetType; - if (sizeof(TargetType) <= sizeof(int)) { - // Extra casts are used to silence warnings. - if (is_signed) { - arg_.type = Arg::INT; - arg_.int_value = static_cast(static_cast(value)); - } else { - arg_.type = Arg::UINT; - typedef typename internal::MakeUnsigned::Type Unsigned; - arg_.uint_value = static_cast(static_cast(value)); - } - } else { - if (is_signed) { - arg_.type = Arg::LONG_LONG; - // glibc's printf doesn't sign extend arguments of smaller types: - // std::printf("%lld", -42); // prints "4294967254" - // but we don't have to do the same because it's a UB. - arg_.long_long_value = static_cast(value); - } else { - arg_.type = Arg::ULONG_LONG; - arg_.ulong_long_value = - static_cast::Type>(value); - } - } - } -}; - -// Converts an integer argument to char for printf. -class CharConverter : public ArgVisitor { - private: - internal::Arg &arg_; - - FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter); - - public: - explicit CharConverter(internal::Arg &arg) : arg_(arg) {} - - template - void visit_any_int(T value) { - arg_.type = internal::Arg::CHAR; - arg_.int_value = static_cast(value); - } -}; } // namespace -namespace internal { - -template -class PrintfArgFormatter : - public ArgFormatterBase, Char> { - - void write_null_pointer() { - this->spec().type_ = 0; - this->write("(nil)"); - } - - typedef ArgFormatterBase, Char> Base; - - public: - PrintfArgFormatter(BasicWriter &w, FormatSpec &s) - : ArgFormatterBase, Char>(w, s) {} - - void visit_bool(bool value) { - FormatSpec &fmt_spec = this->spec(); - if (fmt_spec.type_ != 's') - return this->visit_any_int(value); - fmt_spec.type_ = 0; - this->write(value); - } - - void visit_char(int value) { - const FormatSpec &fmt_spec = this->spec(); - BasicWriter &w = this->writer(); - if (fmt_spec.type_ && fmt_spec.type_ != 'c') - w.write_int(value, fmt_spec); - typedef typename BasicWriter::CharPtr CharPtr; - CharPtr out = CharPtr(); - if (fmt_spec.width_ > 1) { - Char fill = ' '; - out = w.grow_buffer(fmt_spec.width_); - if (fmt_spec.align_ != ALIGN_LEFT) { - std::fill_n(out, fmt_spec.width_ - 1, fill); - out += fmt_spec.width_ - 1; - } else { - std::fill_n(out + 1, fmt_spec.width_ - 1, fill); - } - } else { - out = w.grow_buffer(1); - } - *out = static_cast(value); - } - - void visit_cstring(const char *value) { - if (value) - Base::visit_cstring(value); - else if (this->spec().type_ == 'p') - write_null_pointer(); - else - this->write("(null)"); - } - - void visit_pointer(const void *value) { - if (value) - return Base::visit_pointer(value); - this->spec().type_ = 0; - write_null_pointer(); - } - - void visit_custom(Arg::CustomValue c) { - BasicFormatter formatter(ArgList(), this->writer()); - const Char format_str[] = {'}', 0}; - const Char *format = format_str; - c.format(&formatter, c.value, &format); - } -}; -} // namespace internal -} // namespace fmt - -FMT_FUNC void fmt::SystemError::init( +FMT_FUNC void SystemError::init( int err_code, CStringRef format_str, ArgList args) { error_code_ = err_code; MemoryWriter w; - internal::format_system_error(w, err_code, format(format_str, args)); + format_system_error(w, err_code, format(format_str, args)); std::runtime_error &base = *this; base = std::runtime_error(w.str()); } template -int fmt::internal::CharTraits::format_float( +int internal::CharTraits::format_float( char *buffer, std::size_t size, const char *format, unsigned width, int precision, T value) { if (width == 0) { @@ -454,7 +237,7 @@ int fmt::internal::CharTraits::format_float( } template -int fmt::internal::CharTraits::format_float( +int internal::CharTraits::format_float( wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, int precision, T value) { if (width == 0) { @@ -468,7 +251,7 @@ int fmt::internal::CharTraits::format_float( } template -const char fmt::internal::BasicData::DIGITS[] = +const char internal::BasicData::DIGITS[] = "0001020304050607080910111213141516171819" "2021222324252627282930313233343536373839" "4041424344454647484950515253545556575859" @@ -487,40 +270,40 @@ const char fmt::internal::BasicData::DIGITS[] = factor * 1000000000 template -const uint32_t fmt::internal::BasicData::POWERS_OF_10_32[] = { +const uint32_t internal::BasicData::POWERS_OF_10_32[] = { 0, FMT_POWERS_OF_10(1) }; template -const uint64_t fmt::internal::BasicData::POWERS_OF_10_64[] = { +const uint64_t internal::BasicData::POWERS_OF_10_64[] = { 0, FMT_POWERS_OF_10(1), - FMT_POWERS_OF_10(fmt::ULongLong(1000000000)), + FMT_POWERS_OF_10(ULongLong(1000000000)), // Multiply several constants instead of using a single long long constant // to avoid warnings about C++98 not supporting long long. - fmt::ULongLong(1000000000) * fmt::ULongLong(1000000000) * 10 + ULongLong(1000000000) * ULongLong(1000000000) * 10 }; -FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) { +FMT_FUNC void internal::report_unknown_type(char code, const char *type) { (void)type; if (std::isprint(static_cast(code))) { - FMT_THROW(fmt::FormatError( - fmt::format("unknown format code '{}' for {}", code, type))); + FMT_THROW(FormatError( + format("unknown format code '{}' for {}", code, type))); } - FMT_THROW(fmt::FormatError( - fmt::format("unknown format code '\\x{:02x}' for {}", + FMT_THROW(FormatError( + format("unknown format code '\\x{:02x}' for {}", static_cast(code), type))); } #if FMT_USE_WINDOWS_H -FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) { +FMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(StringRef s) { static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16"; if (s.size() > INT_MAX) FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG)); int s_size = static_cast(s.size()); int length = MultiByteToWideChar( - CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, 0, 0); + CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0); if (length == 0) FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); buffer_.resize(length + 1); @@ -531,30 +314,31 @@ FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) { buffer_[length] = 0; } -FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) { +FMT_FUNC internal::UTF16ToUTF8::UTF16ToUTF8(WStringRef s) { if (int error_code = convert(s)) { FMT_THROW(WindowsError(error_code, "cannot convert string from UTF-16 to UTF-8")); } } -FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) { +FMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s) { if (s.size() > INT_MAX) return ERROR_INVALID_PARAMETER; int s_size = static_cast(s.size()); - int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, 0, 0, 0, 0); + int length = WideCharToMultiByte( + CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL); if (length == 0) return GetLastError(); buffer_.resize(length + 1); length = WideCharToMultiByte( - CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, 0, 0); + CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL); if (length == 0) return GetLastError(); buffer_[length] = 0; return 0; } -FMT_FUNC void fmt::WindowsError::init( +FMT_FUNC void WindowsError::init( int err_code, CStringRef format_str, ArgList args) { error_code_ = err_code; MemoryWriter w; @@ -563,17 +347,17 @@ FMT_FUNC void fmt::WindowsError::init( base = std::runtime_error(w.str()); } -FMT_FUNC void fmt::internal::format_windows_error( - fmt::Writer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT { +FMT_FUNC void internal::format_windows_error( + Writer &out, int error_code, StringRef message) FMT_NOEXCEPT { FMT_TRY { MemoryBuffer buffer; buffer.resize(INLINE_BUFFER_SIZE); for (;;) { wchar_t *system_message = &buffer[0]; - int result = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - 0, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - system_message, static_cast(buffer.size()), 0); + int result = FormatMessageW( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + system_message, static_cast(buffer.size()), FMT_NULL); if (result != 0) { UTF16ToUTF8 utf8_message; if (utf8_message.convert(system_message) == ERROR_SUCCESS) { @@ -592,12 +376,11 @@ FMT_FUNC void fmt::internal::format_windows_error( #endif // FMT_USE_WINDOWS_H -FMT_FUNC void fmt::internal::format_system_error( - fmt::Writer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT { +FMT_FUNC void format_system_error( + Writer &out, int error_code, StringRef message) FMT_NOEXCEPT { FMT_TRY { - MemoryBuffer buffer; - buffer.resize(INLINE_BUFFER_SIZE); + internal::MemoryBuffer buffer; + buffer.resize(internal::INLINE_BUFFER_SIZE); for (;;) { char *system_message = &buffer[0]; int result = safe_strerror(error_code, system_message, buffer.size()); @@ -614,11 +397,11 @@ FMT_FUNC void fmt::internal::format_system_error( } template -void fmt::internal::ArgMap::init(const ArgList &args) { +void internal::ArgMap::init(const ArgList &args) { if (!map_.empty()) return; typedef internal::NamedArg NamedArg; - const NamedArg *named_arg = 0; + const NamedArg *named_arg = FMT_NULL; bool use_values = args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE; if (use_values) { @@ -659,18 +442,18 @@ void fmt::internal::ArgMap::init(const ArgList &args) { } template -void fmt::internal::FixedBuffer::grow(std::size_t) { +void internal::FixedBuffer::grow(std::size_t) { FMT_THROW(std::runtime_error("buffer overflow")); } -FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg( +FMT_FUNC internal::Arg internal::FormatterBase::do_get_arg( unsigned arg_index, const char *&error) { - Arg arg = args_[arg_index]; + internal::Arg arg = args_[arg_index]; switch (arg.type) { - case Arg::NONE: + case internal::Arg::NONE: error = "argument index out of range"; break; - case Arg::NAMED_ARG: + case internal::Arg::NAMED_ARG: arg = *static_cast(arg.pointer); break; default: @@ -679,203 +462,31 @@ FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg( return arg; } -template -void fmt::internal::PrintfFormatter::parse_flags( - FormatSpec &spec, const Char *&s) { - for (;;) { - switch (*s++) { - case '-': - spec.align_ = ALIGN_LEFT; - break; - case '+': - spec.flags_ |= SIGN_FLAG | PLUS_FLAG; - break; - case '0': - spec.fill_ = '0'; - break; - case ' ': - spec.flags_ |= SIGN_FLAG; - break; - case '#': - spec.flags_ |= HASH_FLAG; - break; - default: - --s; - return; - } - } -} - -template -Arg fmt::internal::PrintfFormatter::get_arg( - const Char *s, unsigned arg_index) { - (void)s; - const char *error = 0; - Arg arg = arg_index == UINT_MAX ? - next_arg(error) : FormatterBase::get_arg(arg_index - 1, error); - if (error) - FMT_THROW(FormatError(!*s ? "invalid format string" : error)); - return arg; -} - -template -unsigned fmt::internal::PrintfFormatter::parse_header( - const Char *&s, FormatSpec &spec) { - unsigned arg_index = UINT_MAX; - Char c = *s; - if (c >= '0' && c <= '9') { - // Parse an argument index (if followed by '$') or a width possibly - // preceded with '0' flag(s). - unsigned value = parse_nonnegative_int(s); - if (*s == '$') { // value is an argument index - ++s; - arg_index = value; - } else { - if (c == '0') - spec.fill_ = '0'; - if (value != 0) { - // Nonzero value means that we parsed width and don't need to - // parse it or flags again, so return now. - spec.width_ = value; - return arg_index; - } - } - } - parse_flags(spec, s); - // Parse width. - if (*s >= '0' && *s <= '9') { - spec.width_ = parse_nonnegative_int(s); - } else if (*s == '*') { - ++s; - spec.width_ = WidthHandler(spec).visit(get_arg(s)); - } - return arg_index; -} - -template -void fmt::internal::PrintfFormatter::format( - BasicWriter &writer, BasicCStringRef format_str) { - const Char *start = format_str.c_str(); - const Char *s = start; - while (*s) { - Char c = *s++; - if (c != '%') continue; - if (*s == c) { - write(writer, start, s); - start = ++s; - continue; - } - write(writer, start, s - 1); - - FormatSpec spec; - spec.align_ = ALIGN_RIGHT; - - // Parse argument index, flags and width. - unsigned arg_index = parse_header(s, spec); - - // Parse precision. - if (*s == '.') { - ++s; - if ('0' <= *s && *s <= '9') { - spec.precision_ = static_cast(parse_nonnegative_int(s)); - } else if (*s == '*') { - ++s; - spec.precision_ = PrecisionHandler().visit(get_arg(s)); - } - } - - Arg arg = get_arg(s, arg_index); - if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg)) - spec.flags_ &= ~to_unsigned(HASH_FLAG); - if (spec.fill_ == '0') { - if (arg.type <= Arg::LAST_NUMERIC_TYPE) - spec.align_ = ALIGN_NUMERIC; - else - spec.fill_ = ' '; // Ignore '0' flag for non-numeric types. - } - - // Parse length and convert the argument to the required type. - switch (*s++) { - case 'h': - if (*s == 'h') - ArgConverter(arg, *++s).visit(arg); - else - ArgConverter(arg, *s).visit(arg); - break; - case 'l': - if (*s == 'l') - ArgConverter(arg, *++s).visit(arg); - else - ArgConverter(arg, *s).visit(arg); - break; - case 'j': - ArgConverter(arg, *s).visit(arg); - break; - case 'z': - ArgConverter(arg, *s).visit(arg); - break; - case 't': - ArgConverter(arg, *s).visit(arg); - break; - case 'L': - // printf produces garbage when 'L' is omitted for long double, no - // need to do the same. - break; - default: - --s; - ArgConverter(arg, *s).visit(arg); - } - - // Parse type. - if (!*s) - FMT_THROW(FormatError("invalid format string")); - spec.type_ = static_cast(*s++); - if (arg.type <= Arg::LAST_INTEGER_TYPE) { - // Normalize type. - switch (spec.type_) { - case 'i': case 'u': - spec.type_ = 'd'; - break; - case 'c': - // TODO: handle wchar_t - CharConverter(arg).visit(arg); - break; - } - } - - start = s; - - // Format argument. - internal::PrintfArgFormatter(writer, spec).visit(arg); - } - write(writer, start, s); -} - -FMT_FUNC void fmt::report_system_error( +FMT_FUNC void report_system_error( int error_code, fmt::StringRef message) FMT_NOEXCEPT { // 'fmt::' is for bcc32. - fmt::report_error(internal::format_system_error, error_code, message); + report_error(format_system_error, error_code, message); } #if FMT_USE_WINDOWS_H -FMT_FUNC void fmt::report_windows_error( +FMT_FUNC void report_windows_error( int error_code, fmt::StringRef message) FMT_NOEXCEPT { // 'fmt::' is for bcc32. - fmt::report_error(internal::format_windows_error, error_code, message); + report_error(internal::format_windows_error, error_code, message); } #endif -FMT_FUNC void fmt::print(std::FILE *f, CStringRef format_str, ArgList args) { +FMT_FUNC void print(std::FILE *f, CStringRef format_str, ArgList args) { MemoryWriter w; w.write(format_str, args); std::fwrite(w.data(), 1, w.size(), f); } -FMT_FUNC void fmt::print(CStringRef format_str, ArgList args) { +FMT_FUNC void print(CStringRef format_str, ArgList args) { print(stdout, format_str, args); } -FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) { +FMT_FUNC void print_colored(Color c, CStringRef format, ArgList args) { char escape[] = "\x1b[30m"; escape[3] = static_cast('0' + c); std::fputs(escape, stdout); @@ -883,53 +494,42 @@ FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) { std::fputs(RESET_COLOR, stdout); } -FMT_FUNC int fmt::fprintf(std::FILE *f, CStringRef format, ArgList args) { - MemoryWriter w; - printf(w, format, args); - std::size_t size = w.size(); - return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast(size); -} - #ifndef FMT_HEADER_ONLY -template struct fmt::internal::BasicData; +template struct internal::BasicData; // Explicit instantiations for char. -template void fmt::internal::FixedBuffer::grow(std::size_t); +template void internal::FixedBuffer::grow(std::size_t); -template void fmt::internal::ArgMap::init(const fmt::ArgList &args); +template void internal::ArgMap::init(const ArgList &args); -template void fmt::internal::PrintfFormatter::format( - BasicWriter &writer, CStringRef format); - -template int fmt::internal::CharTraits::format_float( +template FMT_API int internal::CharTraits::format_float( char *buffer, std::size_t size, const char *format, unsigned width, int precision, double value); -template int fmt::internal::CharTraits::format_float( +template FMT_API int internal::CharTraits::format_float( char *buffer, std::size_t size, const char *format, unsigned width, int precision, long double value); // Explicit instantiations for wchar_t. -template void fmt::internal::FixedBuffer::grow(std::size_t); +template void internal::FixedBuffer::grow(std::size_t); -template void fmt::internal::ArgMap::init(const fmt::ArgList &args); +template void internal::ArgMap::init(const ArgList &args); -template void fmt::internal::PrintfFormatter::format( - BasicWriter &writer, WCStringRef format); - -template int fmt::internal::CharTraits::format_float( +template FMT_API int internal::CharTraits::format_float( wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, int precision, double value); -template int fmt::internal::CharTraits::format_float( +template FMT_API int internal::CharTraits::format_float( wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, int precision, long double value); #endif // FMT_HEADER_ONLY +} // namespace fmt + #ifdef _MSC_VER # pragma warning(pop) #endif diff --git a/libs/format/fmt/format.h b/libs/format/fmt/format.h index 47a8b74d8..6ee9d2a21 100644 --- a/libs/format/fmt/format.h +++ b/libs/format/fmt/format.h @@ -25,7 +25,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#pragma once +#ifndef FMT_FORMAT_H_ +#define FMT_FORMAT_H_ #include #include @@ -37,7 +38,10 @@ #include #include #include -#include +#include // for std::pair + +// The fmt library version in the form major * 10000 + minor * 100 + patch. +#define FMT_VERSION 40000 #ifdef _SECURE_SCL # define FMT_SECURE_SCL _SECURE_SCL @@ -49,7 +53,13 @@ # include #endif -#if defined(_MSC_VER) && _MSC_VER <= 1500 +#ifdef _MSC_VER +# define FMT_MSC_VER _MSC_VER +#else +# define FMT_MSC_VER 0 +#endif + +#if FMT_MSC_VER && FMT_MSC_VER <= 1500 typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; typedef __int64 intmax_t; @@ -97,8 +107,10 @@ typedef __int64 intmax_t; #endif #if defined(__clang__) && !defined(FMT_ICC_VERSION) +# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) # pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdocumentation" +# pragma clang diagnostic ignored "-Wdocumentation-unknown-command" +# pragma clang diagnostic ignored "-Wpadded" #endif #ifdef __GNUC_LIBSTD__ @@ -129,7 +141,7 @@ typedef __int64 intmax_t; // since version 2013. # define FMT_USE_VARIADIC_TEMPLATES \ (FMT_HAS_FEATURE(cxx_variadic_templates) || \ - (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1800) + (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1800) #endif #ifndef FMT_USE_RVALUE_REFERENCES @@ -140,19 +152,15 @@ typedef __int64 intmax_t; # else # define FMT_USE_RVALUE_REFERENCES \ (FMT_HAS_FEATURE(cxx_rvalue_references) || \ - (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600) + (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1600) # endif #endif -#if FMT_USE_RVALUE_REFERENCES -# include // for std::move -#endif - // Check if exceptions are disabled. #if defined(__GNUC__) && !defined(__EXCEPTIONS) # define FMT_EXCEPTIONS 0 #endif -#if defined(_MSC_VER) && !_HAS_EXCEPTIONS +#if FMT_MSC_VER && !_HAS_EXCEPTIONS # define FMT_EXCEPTIONS 0 #endif #ifndef FMT_EXCEPTIONS @@ -172,20 +180,50 @@ typedef __int64 intmax_t; # define FMT_USE_NOEXCEPT 0 #endif +#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ + (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \ + FMT_MSC_VER >= 1900 +# define FMT_DETECTED_NOEXCEPT noexcept +#else +# define FMT_DETECTED_NOEXCEPT throw() +#endif + #ifndef FMT_NOEXCEPT # if FMT_EXCEPTIONS -# if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ - (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \ - _MSC_VER >= 1900 -# define FMT_NOEXCEPT noexcept -# else -# define FMT_NOEXCEPT throw() -# endif +# define FMT_NOEXCEPT FMT_DETECTED_NOEXCEPT # else # define FMT_NOEXCEPT # endif #endif +// This is needed because GCC still uses throw() in its headers when exceptions +// are disabled. +#if FMT_GCC_VERSION +# define FMT_DTOR_NOEXCEPT FMT_DETECTED_NOEXCEPT +#else +# define FMT_DTOR_NOEXCEPT FMT_NOEXCEPT +#endif + +#ifndef FMT_OVERRIDE +# if (defined(FMT_USE_OVERRIDE) && FMT_USE_OVERRIDE) || FMT_HAS_FEATURE(cxx_override) || \ + (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \ + FMT_MSC_VER >= 1900 +# define FMT_OVERRIDE override +# else +# define FMT_OVERRIDE +# endif +#endif + +#ifndef FMT_NULL +# if FMT_HAS_FEATURE(cxx_nullptr) || \ + (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \ + FMT_MSC_VER >= 1600 +# define FMT_NULL nullptr +# else +# define FMT_NULL NULL +# endif +#endif + // A macro to disallow the copy constructor and operator= functions // This should be used in the private: declarations for a class #ifndef FMT_USE_DELETED_FUNCTIONS @@ -193,7 +231,7 @@ typedef __int64 intmax_t; #endif #if FMT_USE_DELETED_FUNCTIONS || FMT_HAS_FEATURE(cxx_deleted_functions) || \ - (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1800 + (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1800 # define FMT_DELETED_OR_UNDEFINED = delete # define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ TypeName(const TypeName&) = delete; \ @@ -205,6 +243,20 @@ typedef __int64 intmax_t; TypeName& operator=(const TypeName&) #endif +#ifndef FMT_USE_DEFAULTED_FUNCTIONS +# define FMT_USE_DEFAULTED_FUNCTIONS 0 +#endif + +#ifndef FMT_DEFAULTED_COPY_CTOR +# if FMT_USE_DEFAULTED_FUNCTIONS || FMT_HAS_FEATURE(cxx_defaulted_functions) || \ + (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1800 +# define FMT_DEFAULTED_COPY_CTOR(TypeName) \ + TypeName(const TypeName&) = default; +# else +# define FMT_DEFAULTED_COPY_CTOR(TypeName) +# endif +#endif + #ifndef FMT_USE_USER_DEFINED_LITERALS // All compilers which support UDLs also support variadic templates. This // makes the fmt::literals implementation easier. However, an explicit check @@ -213,28 +265,42 @@ typedef __int64 intmax_t; # define FMT_USE_USER_DEFINED_LITERALS \ FMT_USE_VARIADIC_TEMPLATES && FMT_USE_RVALUE_REFERENCES && \ (FMT_HAS_FEATURE(cxx_user_literals) || \ - (FMT_GCC_VERSION >= 407 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1900) && \ + (FMT_GCC_VERSION >= 407 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900) && \ (!defined(FMT_ICC_VERSION) || FMT_ICC_VERSION >= 1500) #endif +#ifndef FMT_USE_EXTERN_TEMPLATES +# define FMT_USE_EXTERN_TEMPLATES \ + (FMT_CLANG_VERSION >= 209 || (FMT_GCC_VERSION >= 303 && FMT_HAS_GXX_CXX11)) +#endif + +#ifdef FMT_HEADER_ONLY +// If header only do not use extern templates. +# undef FMT_USE_EXTERN_TEMPLATES +# define FMT_USE_EXTERN_TEMPLATES 0 +#endif + #ifndef FMT_ASSERT # define FMT_ASSERT(condition, message) assert((condition) && message) #endif +// __builtin_clz is broken in clang with Microsoft CodeGen: +// https://github.com/fmtlib/fmt/issues/519 +#ifndef _MSC_VER +# if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz) +# define FMT_BUILTIN_CLZ(n) __builtin_clz(n) +# endif -#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz) -# define FMT_BUILTIN_CLZ(n) __builtin_clz(n) +# if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll) +# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) +# endif #endif -#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll) -# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) -#endif - -// Some compilers masquerade as both MSVC and GCC-likes or +// Some compilers masquerade as both MSVC and GCC-likes or // otherwise support __builtin_clz and __builtin_clzll, so // only define FMT_BUILTIN_CLZ using the MSVC intrinsics // if the clz and clzll builtins are not available. -#if defined(_MSC_VER) && !defined(FMT_BUILTIN_CLZLL) +#if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL) && !defined(_MANAGED) # include // _BitScanReverse, _BitScanReverse64 namespace fmt { @@ -246,7 +312,7 @@ inline uint32_t clz(uint32_t x) { assert(x != 0); // Static analysis complains about using uninitialized data - // "r", but the only way that can happen is if "x" is 0, + // "r", but the only way that can happen is if "x" is 0, // which the callers guarantee to not happen. # pragma warning(suppress: 6102) return 31 - r; @@ -272,7 +338,7 @@ inline uint32_t clzll(uint64_t x) { assert(x != 0); // Static analysis complains about using uninitialized data - // "r", but the only way that can happen is if "x" is 0, + // "r", but the only way that can happen is if "x" is 0, // which the callers guarantee to not happen. # pragma warning(suppress: 6102) return 63 - r; @@ -297,14 +363,12 @@ inline DummyInt _ecvt_s(...) { return DummyInt(); } inline DummyInt isinf(...) { return DummyInt(); } inline DummyInt _finite(...) { return DummyInt(); } inline DummyInt isnan(...) { return DummyInt(); } -#ifndef _MSC_VER inline DummyInt _isnan(...) { return DummyInt(); } -#endif // A helper function to suppress bogus "conditional expression is constant" // warnings. template -inline T check(T value) { return value; } +inline T const_check(T value) { return value; } } } // namespace fmt @@ -323,8 +387,8 @@ class numeric_limits : using namespace fmt::internal; // The resolution "priority" is: // isinf macro > std::isinf > ::isinf > fmt::internal::isinf - if (check(sizeof(isinf(x)) == sizeof(bool) || - sizeof(isinf(x)) == sizeof(int))) { + if (const_check(sizeof(isinf(x)) == sizeof(bool) || + sizeof(isinf(x)) == sizeof(int))) { return isinf(x) != 0; } return !_finite(static_cast(x)); @@ -334,8 +398,8 @@ class numeric_limits : template static bool isnotanumber(T x) { using namespace fmt::internal; - if (check(sizeof(isnan(x)) == sizeof(bool) || - sizeof(isnan(x)) == sizeof(int))) { + if (const_check(sizeof(isnan(x)) == sizeof(bool) || + sizeof(isnan(x)) == sizeof(int))) { return isnan(x) != 0; } return _isnan(static_cast(x)) != 0; @@ -344,8 +408,10 @@ class numeric_limits : // Portable version of signbit. static bool isnegative(double x) { using namespace fmt::internal; - if (check(sizeof(signbit(x)) == sizeof(int))) + if (const_check(sizeof(signbit(x)) == sizeof(bool) || + sizeof(signbit(x)) == sizeof(int))) { return signbit(x) != 0; + } if (x < 0) return true; if (!isnotanumber(x)) return false; int dec = 0, sign = 0; @@ -376,13 +442,19 @@ typedef BasicWriter WWriter; template class ArgFormatter; +struct FormatSpec; + +template +class BasicPrintfArgFormatter; + template > class BasicFormatter; /** \rst - A string reference. It can be constructed from a C string or ``std::string``. + A string reference. It can be constructed from a C string or + ``std::basic_string``. You can use one of the following typedefs for common character types: @@ -425,10 +497,12 @@ class BasicStringRef { /** \rst - Constructs a string reference from an ``std::string`` object. + Constructs a string reference from a ``std::basic_string`` object. \endrst */ - BasicStringRef(const std::basic_string &s) + template + BasicStringRef( + const std::basic_string, Allocator> &s) : data_(s.c_str()), size_(s.size()) {} /** @@ -481,7 +555,7 @@ typedef BasicStringRef WStringRef; /** \rst A reference to a null terminated string. It can be constructed from a C - string or ``std::string``. + string or ``std::basic_string``. You can use one of the following typedefs for common character types: @@ -514,10 +588,13 @@ class BasicCStringRef { /** \rst - Constructs a string reference from an ``std::string`` object. + Constructs a string reference from a ``std::basic_string`` object. \endrst */ - BasicCStringRef(const std::basic_string &s) : data_(s.c_str()) {} + template + BasicCStringRef( + const std::basic_string, Allocator> &s) + : data_(s.c_str()) {} /** Returns the pointer to a C string. */ const Char *c_str() const { return data_; } @@ -526,13 +603,13 @@ class BasicCStringRef { typedef BasicCStringRef CStringRef; typedef BasicCStringRef WCStringRef; -/** - A formatting error such as invalid format string. -*/ +/** A formatting error such as invalid format string. */ class FormatError : public std::runtime_error { public: explicit FormatError(CStringRef message) : std::runtime_error(message.c_str()) {} + FormatError(const FormatError &ferr) : std::runtime_error(ferr) {} + FMT_API ~FormatError() FMT_DTOR_NOEXCEPT; }; namespace internal { @@ -590,7 +667,7 @@ class Buffer { std::size_t size_; std::size_t capacity_; - Buffer(T *ptr = 0, std::size_t capacity = 0) + Buffer(T *ptr = FMT_NULL, std::size_t capacity = 0) : ptr_(ptr), size_(0), capacity_(capacity) {} /** @@ -648,7 +725,8 @@ class Buffer { template template void Buffer::append(const U *begin, const U *end) { - std::size_t new_size = size_ + internal::to_unsigned(end - begin); + FMT_ASSERT(end >= begin, "negative value"); + std::size_t new_size = size_ + (end - begin); if (new_size > capacity_) grow(new_size); std::uninitialized_copy(begin, end, @@ -658,8 +736,8 @@ void Buffer::append(const U *begin, const U *end) { namespace internal { -// A memory buffer for trivially copyable/constructible types with the first SIZE -// elements stored in the object itself. +// A memory buffer for trivially copyable/constructible types with the first +// SIZE elements stored in the object itself. template > class MemoryBuffer : private Allocator, public Buffer { private: @@ -671,7 +749,7 @@ class MemoryBuffer : private Allocator, public Buffer { } protected: - void grow(std::size_t size); + void grow(std::size_t size) FMT_OVERRIDE; public: explicit MemoryBuffer(const Allocator &alloc = Allocator()) @@ -720,7 +798,7 @@ void MemoryBuffer::grow(std::size_t size) { std::size_t new_capacity = this->capacity_ + this->capacity_ / 2; if (size > new_capacity) new_capacity = size; - T *new_ptr = this->allocate(new_capacity); + T *new_ptr = this->allocate(new_capacity, FMT_NULL); // The following code doesn't throw, so the raw pointer above doesn't leak. std::uninitialized_copy(this->ptr_, this->ptr_ + this->size_, make_ptr(new_ptr, new_capacity)); @@ -742,7 +820,7 @@ class FixedBuffer : public fmt::Buffer { FixedBuffer(Char *array, std::size_t size) : fmt::Buffer(array, size) {} protected: - FMT_API void grow(std::size_t size); + FMT_API void grow(std::size_t size) FMT_OVERRIDE; }; template @@ -774,6 +852,15 @@ class CharTraits : public BasicCharTraits { const char *format, unsigned width, int precision, T value); }; +#if FMT_USE_EXTERN_TEMPLATES +extern template int CharTraits::format_float + (char *buffer, std::size_t size, + const char* format, unsigned width, int precision, double value); +extern template int CharTraits::format_float + (char *buffer, std::size_t size, + const char* format, unsigned width, int precision, long double value); +#endif + template <> class CharTraits : public BasicCharTraits { public: @@ -785,6 +872,15 @@ class CharTraits : public BasicCharTraits { const wchar_t *format, unsigned width, int precision, T value); }; +#if FMT_USE_EXTERN_TEMPLATES +extern template int CharTraits::format_float + (wchar_t *buffer, std::size_t size, + const wchar_t* format, unsigned width, int precision, double value); +extern template int CharTraits::format_float + (wchar_t *buffer, std::size_t size, + const wchar_t* format, unsigned width, int precision, long double value); +#endif + // Checks if a number is negative - used to avoid warnings. template struct SignChecker { @@ -831,6 +927,10 @@ struct FMT_API BasicData { static const char DIGITS[]; }; +#if FMT_USE_EXTERN_TEMPLATES +extern template struct BasicData; +#endif + typedef BasicData<> Data; #ifdef FMT_BUILTIN_CLZLL @@ -919,12 +1019,14 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits, } unsigned index = static_cast(value * 2); *--buffer = Data::DIGITS[index + 1]; + thousands_sep(buffer); *--buffer = Data::DIGITS[index]; } template inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) { - return format_decimal(buffer, value, num_digits, NoThousandsSep()); + format_decimal(buffer, value, num_digits, NoThousandsSep()); + return; } #ifndef _WIN32 @@ -974,9 +1076,6 @@ FMT_API void format_windows_error(fmt::Writer &out, int error_code, fmt::StringRef message) FMT_NOEXCEPT; #endif -FMT_API void format_system_error(fmt::Writer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT; - // A formatting argument value. struct Value { template @@ -1026,6 +1125,8 @@ struct Arg : Value { template struct NamedArg; +template +struct NamedArgWithType; template struct Null {}; @@ -1074,7 +1175,9 @@ struct ConvertToIntImpl2 { template struct ConvertToInt { - enum { enable_conversion = sizeof(convert(get())) == sizeof(Yes) }; + enum { + enable_conversion = sizeof(fmt::internal::convert(get())) == sizeof(Yes) + }; enum { value = ConvertToIntImpl2::value }; }; @@ -1100,12 +1203,59 @@ template struct Conditional { typedef F type; }; // For bcc32 which doesn't understand ! in template arguments. -template +template struct Not { enum { value = 0 }; }; -template<> +template <> struct Not { enum { value = 1 }; }; +template +struct FalseType { enum { value = 0 }; }; + +template struct LConvCheck { + LConvCheck(int) {} +}; + +// Returns the thousands separator for the current locale. +// We check if ``lconv`` contains ``thousands_sep`` because on Android +// ``lconv`` is stubbed as an empty struct. +template +inline StringRef thousands_sep( + LConv *lc, LConvCheck = 0) { + return lc->thousands_sep; +} + +inline fmt::StringRef thousands_sep(...) { return ""; } + +#define FMT_CONCAT(a, b) a##b + +#if FMT_GCC_VERSION >= 303 +# define FMT_UNUSED __attribute__((unused)) +#else +# define FMT_UNUSED +#endif + +#ifndef FMT_USE_STATIC_ASSERT +# define FMT_USE_STATIC_ASSERT 0 +#endif + +#if FMT_USE_STATIC_ASSERT || FMT_HAS_FEATURE(cxx_static_assert) || \ + (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600 +# define FMT_STATIC_ASSERT(cond, message) static_assert(cond, message) +#else +# define FMT_CONCAT_(a, b) FMT_CONCAT(a, b) +# define FMT_STATIC_ASSERT(cond, message) \ + typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED +#endif + +template +void format_arg(Formatter &, const Char *, const T &) { + FMT_STATIC_ASSERT(FalseType::value, + "Cannot format argument. To enable the use of ostream " + "operator<< include fmt/ostream.h. Otherwise provide " + "an overload of format_arg."); +} + // Makes an Arg object from any type. template class MakeValue : public Arg { @@ -1127,7 +1277,7 @@ class MakeValue : public Arg { // characters and strings into narrow strings as in // fmt::format("{}", L"test"); // To fix this, use a wide format string: fmt::format(L"{}", L"test"). -#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) +#if !FMT_MSC_VER || defined(_NATIVE_WCHAR_T_DEFINED) MakeValue(typename WCharHelper::Unsupported); #endif MakeValue(typename WCharHelper::Unsupported); @@ -1149,9 +1299,9 @@ class MakeValue : public Arg { template static void format_custom_arg( void *formatter, const void *arg, void *format_str_ptr) { - format(*static_cast(formatter), - *static_cast(format_str_ptr), - *static_cast(arg)); + format_arg(*static_cast(formatter), + *static_cast(format_str_ptr), + *static_cast(arg)); } public: @@ -1173,7 +1323,7 @@ class MakeValue : public Arg { MakeValue(long value) { // To minimize the number of types we need to deal with, long is // translated either to int or to long long depending on its size. - if (check(sizeof(long) == sizeof(int))) + if (const_check(sizeof(long) == sizeof(int))) int_value = static_cast(value); else long_long_value = value; @@ -1183,7 +1333,7 @@ class MakeValue : public Arg { } MakeValue(unsigned long value) { - if (check(sizeof(unsigned long) == sizeof(unsigned))) + if (const_check(sizeof(unsigned long) == sizeof(unsigned))) uint_value = static_cast(value); else ulong_long_value = value; @@ -1215,7 +1365,9 @@ class MakeValue : public Arg { FMT_MAKE_VALUE(char *, string.value, CSTRING) FMT_MAKE_VALUE(const char *, string.value, CSTRING) + FMT_MAKE_VALUE(signed char *, sstring.value, CSTRING) FMT_MAKE_VALUE(const signed char *, sstring.value, CSTRING) + FMT_MAKE_VALUE(unsigned char *, ustring.value, CSTRING) FMT_MAKE_VALUE(const unsigned char *, ustring.value, CSTRING) FMT_MAKE_STR_VALUE(const std::string &, STRING) FMT_MAKE_STR_VALUE(StringRef, STRING) @@ -1244,23 +1396,22 @@ class MakeValue : public Arg { } template - MakeValue(const T &value, - typename EnableIf::value, int>::type = 0) { - int_value = value; - } - - template - static uint64_t type(const T &) { - return ConvertToInt::value ? Arg::INT : Arg::CUSTOM; + static typename EnableIf::value>::value, uint64_t>::type + type(const T &) { + return Arg::CUSTOM; } // Additional template param `Char_` is needed here because make_type always // uses char. template MakeValue(const NamedArg &value) { pointer = &value; } + template + MakeValue(const NamedArgWithType &value) { pointer = &value; } template static uint64_t type(const NamedArg &) { return Arg::NAMED_ARG; } + template + static uint64_t type(const NamedArgWithType &) { return Arg::NAMED_ARG; } }; template @@ -1269,7 +1420,7 @@ public: MakeArg() { type = Arg::NONE; } - + template MakeArg(const T &value) : Arg(MakeValue(value)) { @@ -1286,14 +1437,19 @@ struct NamedArg : Arg { : Arg(MakeArg< BasicFormatter >(value)), name(argname) {} }; +template +struct NamedArgWithType : NamedArg { + NamedArgWithType(BasicStringRef argname, const T &value) + : NamedArg(argname, value) {} +}; + class RuntimeError : public std::runtime_error { protected: RuntimeError() : std::runtime_error("") {} + RuntimeError(const RuntimeError &rerr) : std::runtime_error(rerr) {} + FMT_API ~RuntimeError() FMT_DTOR_NOEXCEPT; }; -template -class PrintfArgFormatter; - template class ArgMap; } // namespace internal @@ -1315,10 +1471,7 @@ class ArgList { }; internal::Arg::Type type(unsigned index) const { - unsigned shift = index * 4; - uint64_t mask = 0xf; - return static_cast( - (types_ & (mask << shift)) >> shift); + return type(types_, index); } template @@ -1335,6 +1488,8 @@ class ArgList { ArgList(ULongLong types, const internal::Arg *args) : types_(types), args_(args) {} + uint64_t types() const { return types_; } + /** Returns the argument at specified index. */ internal::Arg operator[](unsigned index) const { using internal::Arg; @@ -1360,6 +1515,13 @@ class ArgList { } return args_[index]; } + + static internal::Arg::Type type(uint64_t types, unsigned index) { + unsigned shift = index * 4; + uint64_t mask = 0xf; + return static_cast( + (types & (mask << shift)) >> shift); + } }; #define FMT_DISPATCH(call) static_cast(this)->call @@ -1488,9 +1650,10 @@ class ArgVisitor { */ Result visit(const Arg &arg) { switch (arg.type) { - default: + case Arg::NONE: + case Arg::NAMED_ARG: FMT_ASSERT(false, "invalid argument type"); - return Result(); + break; case Arg::INT: return FMT_DISPATCH(visit_int(arg.int_value)); case Arg::UINT: @@ -1518,6 +1681,7 @@ class ArgVisitor { case Arg::CUSTOM: return FMT_DISPATCH(visit_custom(arg.custom)); } + return Result(); } }; @@ -1542,6 +1706,7 @@ struct TypeSpec : EmptySpec { int precision() const { return -1; } bool flag(unsigned) const { return false; } char type() const { return TYPE; } + char type_prefix() const { return TYPE; } char fill() const { return ' '; } }; @@ -1577,6 +1742,7 @@ struct AlignTypeSpec : AlignSpec { bool flag(unsigned) const { return false; } char type() const { return TYPE; } + char type_prefix() const { return TYPE; } }; // A full format specifier. @@ -1592,6 +1758,7 @@ struct FormatSpec : AlignSpec { bool flag(unsigned f) const { return (flags_ & f) != 0; } int precision() const { return precision_; } char type() const { return type_; } + char type_prefix() const { return type_; } }; // An integer format specifier. @@ -1756,22 +1923,22 @@ class ArgMap { public: FMT_API void init(const ArgList &args); - const internal::Arg* find(const fmt::BasicStringRef &name) const { + const internal::Arg *find(const fmt::BasicStringRef &name) const { // The list is unsorted, so just return the first matching name. for (typename MapType::const_iterator it = map_.begin(), end = map_.end(); it != end; ++it) { if (it->first == name) return &it->second; } - return 0; + return FMT_NULL; } }; -template +template class ArgFormatterBase : public ArgVisitor { private: BasicWriter &writer_; - FormatSpec &spec_; + Spec &spec_; FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatterBase); @@ -1781,9 +1948,12 @@ class ArgFormatterBase : public ArgVisitor { writer_.write_int(reinterpret_cast(p), spec_); } + // workaround MSVC two-phase lookup issue + typedef internal::Arg Arg; + protected: BasicWriter &writer() { return writer_; } - FormatSpec &spec() { return spec_; } + Spec &spec() { return spec_; } void write(bool value) { const char *str_value = value ? "true" : "false"; @@ -1792,12 +1962,14 @@ class ArgFormatterBase : public ArgVisitor { } void write(const char *value) { - Arg::StringValue str = {value, value != 0 ? std::strlen(value) : 0}; + Arg::StringValue str = {value, value ? std::strlen(value) : 0}; writer_.write_str(str, spec_); } public: - ArgFormatterBase(BasicWriter &w, FormatSpec &s) + typedef Spec SpecType; + + ArgFormatterBase(BasicWriter &w, Spec &s) : writer_(w), spec_(s) {} template @@ -1807,8 +1979,10 @@ class ArgFormatterBase : public ArgVisitor { void visit_any_double(T value) { writer_.write_double(value, spec_); } void visit_bool(bool value) { - if (spec_.type_) - return visit_any_int(value); + if (spec_.type_) { + visit_any_int(value); + return; + } write(value); } @@ -1823,21 +1997,21 @@ class ArgFormatterBase : public ArgVisitor { typedef typename BasicWriter::CharPtr CharPtr; Char fill = internal::CharTraits::cast(spec_.fill()); CharPtr out = CharPtr(); - const unsigned CHAR_WIDTH = 1; - if (spec_.width_ > CHAR_WIDTH) { + const unsigned CHAR_SIZE = 1; + if (spec_.width_ > CHAR_SIZE) { out = writer_.grow_buffer(spec_.width_); if (spec_.align_ == ALIGN_RIGHT) { - std::uninitialized_fill_n(out, spec_.width_ - CHAR_WIDTH, fill); - out += spec_.width_ - CHAR_WIDTH; + std::uninitialized_fill_n(out, spec_.width_ - CHAR_SIZE, fill); + out += spec_.width_ - CHAR_SIZE; } else if (spec_.align_ == ALIGN_CENTER) { out = writer_.fill_padding(out, spec_.width_, - internal::check(CHAR_WIDTH), fill); + internal::const_check(CHAR_SIZE), fill); } else { - std::uninitialized_fill_n(out + CHAR_WIDTH, - spec_.width_ - CHAR_WIDTH, fill); + std::uninitialized_fill_n(out + CHAR_SIZE, + spec_.width_ - CHAR_SIZE, fill); } } else { - out = writer_.grow_buffer(CHAR_WIDTH); + out = writer_.grow_buffer(CHAR_SIZE); } *out = internal::CharTraits::cast(value); } @@ -1848,13 +2022,14 @@ class ArgFormatterBase : public ArgVisitor { write(value); } - void visit_string(Arg::StringValue value) { + // Qualification with "internal" here and below is a workaround for nvcc. + void visit_string(internal::Arg::StringValue value) { writer_.write_str(value, spec_); } using ArgVisitor::visit_wstring; - void visit_wstring(Arg::StringValue value) { + void visit_wstring(internal::Arg::StringValue value) { writer_.write_str(value, spec_); } @@ -1910,26 +2085,6 @@ class FormatterBase { w << BasicStringRef(start, internal::to_unsigned(end - start)); } }; - -// A printf formatter. -template -class PrintfFormatter : private FormatterBase { - private: - void parse_flags(FormatSpec &spec, const Char *&s); - - // Returns the argument with specified index or, if arg_index is equal - // to the maximum unsigned value, the next argument. - Arg get_arg(const Char *s, - unsigned arg_index = (std::numeric_limits::max)()); - - // Parses argument index, flags and width and returns the argument index. - unsigned parse_header(const Char *&s, FormatSpec &spec); - - public: - explicit PrintfFormatter(const ArgList &args) : FormatterBase(args) {} - FMT_API void format(BasicWriter &writer, - BasicCStringRef format_str); -}; } // namespace internal /** @@ -1949,8 +2104,8 @@ class PrintfFormatter : private FormatterBase { will be called. \endrst */ -template -class BasicArgFormatter : public internal::ArgFormatterBase { +template +class BasicArgFormatter : public internal::ArgFormatterBase { private: BasicFormatter &formatter_; const Char *format_; @@ -1965,11 +2120,11 @@ class BasicArgFormatter : public internal::ArgFormatterBase { \endrst */ BasicArgFormatter(BasicFormatter &formatter, - FormatSpec &spec, const Char *fmt) - : internal::ArgFormatterBase(formatter.writer(), spec), + Spec &spec, const Char *fmt) + : internal::ArgFormatterBase(formatter.writer(), spec), formatter_(formatter), format_(fmt) {} - /** Formats argument of a custom (user-defined) type. */ + /** Formats an argument of a custom (user-defined) type. */ void visit_custom(internal::Arg::CustomValue c) { c.format(&formatter_, c.value, &format_); } @@ -1977,12 +2132,14 @@ class BasicArgFormatter : public internal::ArgFormatterBase { /** The default argument formatter. */ template -class ArgFormatter : public BasicArgFormatter, Char> { +class ArgFormatter : + public BasicArgFormatter, Char, FormatSpec> { public: /** Constructs an argument formatter object. */ ArgFormatter(BasicFormatter &formatter, FormatSpec &spec, const Char *fmt) - : BasicArgFormatter, Char>(formatter, spec, fmt) {} + : BasicArgFormatter, + Char, FormatSpec>(formatter, spec, fmt) {} }; /** This template formats data and writes the output to a writer. */ @@ -2058,13 +2215,13 @@ inline uint64_t make_type(const T &arg) { return MakeValue< BasicFormatter >::type(arg); } -template +template struct ArgArray; -template +template struct ArgArray { typedef Value Type[N > 0 ? N : 1]; - + template static Value make(const T &value) { #ifdef __clang__ @@ -2079,7 +2236,7 @@ struct ArgArray { } }; -template +template struct ArgArray { typedef Arg Type[N + 1]; // +1 for the list end Arg::NONE @@ -2219,7 +2376,7 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { */ class SystemError : public internal::RuntimeError { private: - void init(int err_code, CStringRef format_str, ArgList args); + FMT_API void init(int err_code, CStringRef format_str, ArgList args); protected: int error_code_; @@ -2231,17 +2388,10 @@ class SystemError : public internal::RuntimeError { public: /** \rst - Constructs a :class:`fmt::SystemError` object with the description - of the form - - .. parsed-literal:: - **: ** - - where ** is the formatted message and ** is - the system message corresponding to the error code. - *error_code* is a system error code as given by ``errno``. - If *error_code* is not a valid error code such as -1, the system message - may look like "Unknown error -1" and is platform-dependent. + Constructs a :class:`fmt::SystemError` object with a description + formatted with `fmt::format_system_error`. *message* and additional + arguments passed into the constructor are formatted similarly to + `fmt::format`. **Example**:: @@ -2257,11 +2407,33 @@ class SystemError : public internal::RuntimeError { SystemError(int error_code, CStringRef message) { init(error_code, message, ArgList()); } + FMT_DEFAULTED_COPY_CTOR(SystemError) FMT_VARIADIC_CTOR(SystemError, init, int, CStringRef) + FMT_API ~SystemError() FMT_DTOR_NOEXCEPT; + int error_code() const { return error_code_; } }; +/** + \rst + Formats an error returned by an operating system or a language runtime, + for example a file opening error, and writes it to *out* in the following + form: + + .. parsed-literal:: + **: ** + + where ** is the passed message and ** is + the system message corresponding to the error code. + *error_code* is a system error code as given by ``errno``. + If *error_code* is not a valid error code such as -1, the system message + may look like "Unknown error -1" and is platform-dependent. + \endrst + */ +FMT_API void format_system_error(fmt::Writer &out, int error_code, + fmt::StringRef message) FMT_NOEXCEPT; + /** \rst This template provides operations for formatting and writing data into @@ -2350,16 +2522,16 @@ class BasicWriter { void write_int(T value, Spec spec); // Formats a floating-point number (double or long double). - template - void write_double(T value, const FormatSpec &spec); + template + void write_double(T value, const Spec &spec); // Writes a formatted string. template CharPtr write_str(const StrChar *s, std::size_t size, const AlignSpec &spec); - template + template void write_str(const internal::Arg::StringValue &str, - const FormatSpec &spec); + const Spec &spec); // This following methods are private to disallow writing wide characters // and strings to a char stream. If you want to print a wide string as a @@ -2378,10 +2550,11 @@ class BasicWriter { template void append_float_length(Char *&, T) {} - template + template friend class internal::ArgFormatterBase; - friend class internal::PrintfArgFormatter; + template + friend class BasicPrintfArgFormatter; protected: /** @@ -2577,9 +2750,9 @@ typename BasicWriter::CharPtr BasicWriter::write_str( } template -template +template void BasicWriter::write_str( - const internal::Arg::StringValue &s, const FormatSpec &spec) { + const internal::Arg::StringValue &s, const Spec &spec) { // Check if StrChar is convertible to Char. internal::CharTraits::convert(StrChar()); if (spec.type_ && spec.type_ != 's') @@ -2589,7 +2762,6 @@ void BasicWriter::write_str( if (str_size == 0) { if (!str_value) { FMT_THROW(FormatError("string pointer is null")); - return; } } std::size_t precision = static_cast(spec.precision_); @@ -2704,7 +2876,7 @@ void BasicWriter::write_int(T value, Spec spec) { UnsignedType n = abs_value; if (spec.flag(HASH_FLAG)) { prefix[prefix_size++] = '0'; - prefix[prefix_size++] = spec.type(); + prefix[prefix_size++] = spec.type_prefix(); } unsigned num_digits = 0; do { @@ -2724,7 +2896,7 @@ void BasicWriter::write_int(T value, Spec spec) { UnsignedType n = abs_value; if (spec.flag(HASH_FLAG)) { prefix[prefix_size++] = '0'; - prefix[prefix_size++] = spec.type(); + prefix[prefix_size++] = spec.type_prefix(); } unsigned num_digits = 0; do { @@ -2754,9 +2926,12 @@ void BasicWriter::write_int(T value, Spec spec) { } case 'n': { unsigned num_digits = internal::count_digits(abs_value); - fmt::StringRef sep = std::localeconv()->thousands_sep; + fmt::StringRef sep = ""; +#if !(defined(ANDROID) || defined(__ANDROID__)) + sep = internal::thousands_sep(std::localeconv()); +#endif unsigned size = static_cast( - num_digits + sep.size() * (num_digits - 1) / 3); + num_digits + sep.size() * ((num_digits - 1) / 3)); CharPtr p = prepare_int_buffer(size, spec, prefix, prefix_size) + 1; internal::format_decimal(get(p), abs_value, 0, internal::ThousandsSep(sep)); break; @@ -2769,8 +2944,8 @@ void BasicWriter::write_int(T value, Spec spec) { } template -template -void BasicWriter::write_double(T value, const FormatSpec &spec) { +template +void BasicWriter::write_double(T value, const Spec &spec) { // Check type. char type = spec.type(); bool upper = false; @@ -2781,7 +2956,7 @@ void BasicWriter::write_double(T value, const FormatSpec &spec) { case 'e': case 'f': case 'g': case 'a': break; case 'F': -#ifdef _MSC_VER +#if FMT_MSC_VER // MSVC's printf doesn't support 'F'. type = 'f'; #endif @@ -2871,10 +3046,10 @@ void BasicWriter::write_double(T value, const FormatSpec &spec) { // Format using snprintf. Char fill = internal::CharTraits::cast(spec.fill()); unsigned n = 0; - Char *start = 0; + Char *start = FMT_NULL; for (;;) { std::size_t buffer_size = buffer_.capacity() - offset; -#ifdef _MSC_VER +#if FMT_MSC_VER // MSVC's vsnprintf_s doesn't work with zero size, so reserve // space for at least one extra character to make the size non-zero. // Note that the buffer's capacity will increase by more than 1. @@ -3148,56 +3323,6 @@ FMT_API void print(std::FILE *f, CStringRef format_str, ArgList args); */ FMT_API void print(CStringRef format_str, ArgList args); -template -void printf(BasicWriter &w, BasicCStringRef format, ArgList args) { - internal::PrintfFormatter(args).format(w, format); -} - -/** - \rst - Formats arguments and returns the result as a string. - - **Example**:: - - std::string message = fmt::sprintf("The answer is %d", 42); - \endrst -*/ -inline std::string sprintf(CStringRef format, ArgList args) { - MemoryWriter w; - printf(w, format, args); - return w.str(); -} - -inline std::wstring sprintf(WCStringRef format, ArgList args) { - WMemoryWriter w; - printf(w, format, args); - return w.str(); -} - -/** - \rst - Prints formatted data to the file *f*. - - **Example**:: - - fmt::fprintf(stderr, "Don't %s!", "panic"); - \endrst - */ -FMT_API int fprintf(std::FILE *f, CStringRef format, ArgList args); - -/** - \rst - Prints formatted data to ``stdout``. - - **Example**:: - - fmt::printf("Elapsed time: %.2f seconds", 1.23); - \endrst - */ -inline int printf(CStringRef format, ArgList args) { - return fprintf(stdout, format, args); -} - /** Fast integer formatter. */ @@ -3314,13 +3439,13 @@ inline void format_decimal(char *&buffer, T value) { \endrst */ template -inline internal::NamedArg arg(StringRef name, const T &arg) { - return internal::NamedArg(name, arg); +inline internal::NamedArgWithType arg(StringRef name, const T &arg) { + return internal::NamedArgWithType(name, arg); } template -inline internal::NamedArg arg(WStringRef name, const T &arg) { - return internal::NamedArg(name, arg); +inline internal::NamedArgWithType arg(WStringRef name, const T &arg) { + return internal::NamedArgWithType(name, arg); } // The following two functions are deleted intentionally to disable @@ -3349,7 +3474,6 @@ void arg(WStringRef, const internal::NamedArg&) FMT_DELETED_OR_UNDEFINED; #define FMT_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N #define FMT_RSEQ_N() 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 -#define FMT_CONCAT(a, b) a##b #define FMT_FOR_EACH_(N, f, ...) \ FMT_EXPAND(FMT_CONCAT(FMT_FOR_EACH, N)(f, __VA_ARGS__)) #define FMT_FOR_EACH(f, ...) \ @@ -3463,12 +3587,7 @@ FMT_VARIADIC(std::string, format, CStringRef) FMT_VARIADIC_W(std::wstring, format, WCStringRef) FMT_VARIADIC(void, print, CStringRef) FMT_VARIADIC(void, print, std::FILE *, CStringRef) - FMT_VARIADIC(void, print_colored, Color, CStringRef) -FMT_VARIADIC(std::string, sprintf, CStringRef) -FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef) -FMT_VARIADIC(int, printf, CStringRef) -FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef) namespace internal { template @@ -3533,7 +3652,7 @@ inline internal::Arg BasicFormatter::get_arg( template inline internal::Arg BasicFormatter::parse_arg_index(const Char *&s) { - const char *error = 0; + const char *error = FMT_NULL; internal::Arg arg = *s < '0' || *s > '9' ? next_arg(error) : get_arg(internal::parse_nonnegative_int(s), error); if (error) { @@ -3551,7 +3670,7 @@ inline internal::Arg BasicFormatter::parse_arg_name(const Char *&s) { do { c = *++s; } while (internal::is_name_start(c) || ('0' <= c && c <= '9')); - const char *error = 0; + const char *error = FMT_NULL; internal::Arg arg = get_arg(BasicStringRef(start, s - start), error); if (error) FMT_THROW(FormatError(error)); @@ -3563,7 +3682,7 @@ const Char *BasicFormatter::format( const Char *&format_str, const internal::Arg &arg) { using internal::Arg; const Char *s = format_str; - FormatSpec spec; + typename ArgFormatter::SpecType spec; if (*s == ':') { if (arg.type == Arg::CUSTOM) { arg.custom.format(this, arg.custom.value, &s); @@ -3749,6 +3868,66 @@ void BasicFormatter::format(BasicCStringRef format_str) { } write(writer_, start, s); } + +template +struct ArgJoin { + It first; + It last; + BasicCStringRef sep; + + ArgJoin(It first, It last, const BasicCStringRef& sep) : + first(first), + last(last), + sep(sep) {} +}; + +template +ArgJoin join(It first, It last, const BasicCStringRef& sep) { + return ArgJoin(first, last, sep); +} + +template +ArgJoin join(It first, It last, const BasicCStringRef& sep) { + return ArgJoin(first, last, sep); +} + +#if FMT_HAS_GXX_CXX11 +template +auto join(const Range& range, const BasicCStringRef& sep) + -> ArgJoin { + return join(std::begin(range), std::end(range), sep); +} + +template +auto join(const Range& range, const BasicCStringRef& sep) + -> ArgJoin { + return join(std::begin(range), std::end(range), sep); +} +#endif + +template +void format_arg(fmt::BasicFormatter &f, + const Char *&format_str, const ArgJoin& e) { + const Char* end = format_str; + if (*end == ':') + ++end; + while (*end && *end != '}') + ++end; + if (*end != '}') + FMT_THROW(FormatError("missing '}' in format string")); + + It it = e.first; + if (it != e.last) { + const Char* save = format_str; + f.format(format_str, internal::MakeArg >(*it++)); + while (it != e.last) { + f.writer().write(e.sep); + format_str = save; + f.format(format_str, internal::MakeArg >(*it++)); + } + } + format_str = end + 1; +} } // namespace fmt #if FMT_USE_USER_DEFINED_LITERALS @@ -3771,7 +3950,7 @@ struct UdlArg { const Char *str; template - NamedArg operator=(T &&value) const { + NamedArgWithType operator=(T &&value) const { return {str, std::forward(value)}; } }; @@ -3830,3 +4009,4 @@ operator"" _a(const wchar_t *s, std::size_t) { return {s}; } # define FMT_FUNC #endif +#endif // FMT_FORMAT_H_ diff --git a/libs/format/fmt/ostream.cc b/libs/format/fmt/ostream.cc index 0ba303478..2d443f730 100644 --- a/libs/format/fmt/ostream.cc +++ b/libs/format/fmt/ostream.cc @@ -4,34 +4,15 @@ Copyright (c) 2012 - 2016, Victor Zverovich All rights reserved. - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + For the license information refer to format.h. */ #include "ostream.h" namespace fmt { -namespace { -// Write the content of w to os. -void write(std::ostream &os, Writer &w) { +namespace internal { +FMT_FUNC void write(std::ostream &os, Writer &w) { const char *data = w.data(); typedef internal::MakeUnsigned::Type UnsignedStreamSize; UnsignedStreamSize size = w.size(); @@ -49,13 +30,6 @@ void write(std::ostream &os, Writer &w) { FMT_FUNC void print(std::ostream &os, CStringRef format_str, ArgList args) { MemoryWriter w; w.write(format_str, args); - write(os, w); -} - -FMT_FUNC int fprintf(std::ostream &os, CStringRef format, ArgList args) { - MemoryWriter w; - printf(w, format, args); - write(os, w); - return static_cast(w.size()); + internal::write(os, w); } } // namespace fmt diff --git a/libs/format/fmt/ostream.h b/libs/format/fmt/ostream.h index 458d31de3..84a02d173 100644 --- a/libs/format/fmt/ostream.h +++ b/libs/format/fmt/ostream.h @@ -4,25 +4,7 @@ Copyright (c) 2012 - 2016, Victor Zverovich All rights reserved. - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + For the license information refer to format.h. */ #ifndef FMT_OSTREAM_H_ @@ -42,28 +24,27 @@ class FormatBuf : public std::basic_streambuf { typedef typename std::basic_streambuf::traits_type traits_type; Buffer &buffer_; - Char *start_; public: - FormatBuf(Buffer &buffer) : buffer_(buffer), start_(&buffer[0]) { - this->setp(start_, start_ + buffer_.capacity()); - } + FormatBuf(Buffer &buffer) : buffer_(buffer) {} - int_type overflow(int_type ch = traits_type::eof()) { - if (!traits_type::eq_int_type(ch, traits_type::eof())) { - size_t buf_size = size(); - buffer_.resize(buf_size); - buffer_.reserve(buf_size * 2); + protected: + // The put-area is actually always empty. This makes the implementation + // simpler and has the advantage that the streambuf and the buffer are always + // in sync and sputc never writes into uninitialized memory. The obvious + // disadvantage is that each call to sputc always results in a (virtual) call + // to overflow. There is no disadvantage here for sputn since this always + // results in a call to xsputn. - start_ = &buffer_[0]; - start_[buf_size] = traits_type::to_char_type(ch); - this->setp(start_+ buf_size + 1, start_ + buf_size * 2); - } + int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE { + if (!traits_type::eq_int_type(ch, traits_type::eof())) + buffer_.push_back(static_cast(ch)); return ch; } - size_t size() const { - return to_unsigned(this->pptr() - start_); + std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE { + buffer_.append(s, s + count); + return count; } }; @@ -84,19 +65,22 @@ struct ConvertToIntImpl { value = sizeof(convert(get() << get())) == sizeof(No) }; }; + +// Write the content of w to os. +FMT_API void write(std::ostream &os, Writer &w); } // namespace internal // Formats a value. -template -void format(BasicFormatter &f, - const Char *&format_str, const T &value) { +template +void format_arg(BasicFormatter &f, + const Char *&format_str, const T &value) { internal::MemoryBuffer buffer; internal::FormatBuf format_buf(buffer); std::basic_ostream output(&format_buf); output << value; - BasicStringRef str(&buffer[0], format_buf.size()); + BasicStringRef str(&buffer[0], buffer.size()); typedef internal::MakeArg< BasicFormatter > MakeArg; format_str = f.format(format_str, MakeArg(str)); } @@ -112,18 +96,6 @@ void format(BasicFormatter &f, */ FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args); FMT_VARIADIC(void, print, std::ostream &, CStringRef) - -/** - \rst - Prints formatted data to the stream *os*. - - **Example**:: - - fprintf(cerr, "Don't %s!", "panic"); - \endrst - */ -FMT_API int fprintf(std::ostream &os, CStringRef format_str, ArgList args); -FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef) } // namespace fmt #ifdef FMT_HEADER_ONLY diff --git a/libs/format/fmt/posix.cc b/libs/format/fmt/posix.cc index 1ec746a46..356668c13 100644 --- a/libs/format/fmt/posix.cc +++ b/libs/format/fmt/posix.cc @@ -1,28 +1,10 @@ /* A C++ interface to POSIX functions. - Copyright (c) 2014 - 2016, Victor Zverovich + Copyright (c) 2012 - 2016, Victor Zverovich All rights reserved. - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + For the license information refer to format.h. */ // Disable bogus MSVC warnings. @@ -39,6 +21,9 @@ #ifndef _WIN32 # include #else +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif # include # include @@ -90,16 +75,16 @@ fmt::BufferedFile::BufferedFile( fmt::CStringRef filename, fmt::CStringRef mode) { FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), 0); if (!file_) - throw SystemError(errno, "cannot open file {}", filename); + FMT_THROW(SystemError(errno, "cannot open file {}", filename)); } void fmt::BufferedFile::close() { if (!file_) return; int result = FMT_SYSTEM(fclose(file_)); - file_ = 0; + file_ = FMT_NULL; if (result != 0) - throw SystemError(errno, "cannot close file"); + FMT_THROW(SystemError(errno, "cannot close file")); } // A macro used to prevent expansion of fileno on broken versions of MinGW. @@ -108,7 +93,7 @@ void fmt::BufferedFile::close() { int fmt::BufferedFile::fileno() const { int fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_)); if (fd == -1) - throw SystemError(errno, "cannot get file descriptor"); + FMT_THROW(SystemError(errno, "cannot get file descriptor")); return fd; } @@ -121,7 +106,7 @@ fmt::File::File(fmt::CStringRef path, int oflag) { FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode))); #endif if (fd_ == -1) - throw SystemError(errno, "cannot open file {}", path); + FMT_THROW(SystemError(errno, "cannot open file {}", path)); } fmt::File::~File() FMT_NOEXCEPT { @@ -139,7 +124,7 @@ void fmt::File::close() { int result = FMT_POSIX_CALL(close(fd_)); fd_ = -1; if (result != 0) - throw SystemError(errno, "cannot close file"); + FMT_THROW(SystemError(errno, "cannot close file")); } fmt::LongLong fmt::File::size() const { @@ -153,7 +138,7 @@ fmt::LongLong fmt::File::size() const { if (size_lower == INVALID_FILE_SIZE) { DWORD error = GetLastError(); if (error != NO_ERROR) - throw WindowsError(GetLastError(), "cannot get file size"); + FMT_THROW(WindowsError(GetLastError(), "cannot get file size")); } fmt::ULongLong long_size = size_upper; return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower; @@ -161,7 +146,7 @@ fmt::LongLong fmt::File::size() const { typedef struct stat Stat; Stat file_stat = Stat(); if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1) - throw SystemError(errno, "cannot get file attributes"); + FMT_THROW(SystemError(errno, "cannot get file attributes")); FMT_STATIC_ASSERT(sizeof(fmt::LongLong) >= sizeof(file_stat.st_size), "return type of File::size is not large enough"); return file_stat.st_size; @@ -172,7 +157,7 @@ std::size_t fmt::File::read(void *buffer, std::size_t count) { RWResult result = 0; FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count)))); if (result < 0) - throw SystemError(errno, "cannot read from file"); + FMT_THROW(SystemError(errno, "cannot read from file")); return internal::to_unsigned(result); } @@ -180,7 +165,7 @@ std::size_t fmt::File::write(const void *buffer, std::size_t count) { RWResult result = 0; FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count)))); if (result < 0) - throw SystemError(errno, "cannot write to file"); + FMT_THROW(SystemError(errno, "cannot write to file")); return internal::to_unsigned(result); } @@ -189,7 +174,7 @@ fmt::File fmt::File::dup(int fd) { // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html int new_fd = FMT_POSIX_CALL(dup(fd)); if (new_fd == -1) - throw SystemError(errno, "cannot duplicate file descriptor {}", fd); + FMT_THROW(SystemError(errno, "cannot duplicate file descriptor {}", fd)); return File(new_fd); } @@ -197,8 +182,8 @@ void fmt::File::dup2(int fd) { int result = 0; FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); if (result == -1) { - throw SystemError(errno, - "cannot duplicate file descriptor {} to {}", fd_, fd); + FMT_THROW(SystemError(errno, + "cannot duplicate file descriptor {} to {}", fd_, fd)); } } @@ -225,7 +210,7 @@ void fmt::File::pipe(File &read_end, File &write_end) { int result = FMT_POSIX_CALL(pipe(fds)); #endif if (result != 0) - throw SystemError(errno, "cannot create pipe"); + FMT_THROW(SystemError(errno, "cannot create pipe")); // The following assignments don't throw because read_fd and write_fd // are closed. read_end = File(fds[0]); @@ -236,7 +221,7 @@ fmt::BufferedFile fmt::File::fdopen(const char *mode) { // Don't retry as fdopen doesn't return EINTR. FILE *f = FMT_POSIX_CALL(fdopen(fd_, mode)); if (!f) - throw SystemError(errno, "cannot associate stream with file descriptor"); + FMT_THROW(SystemError(errno, "cannot associate stream with file descriptor")); BufferedFile file(f); fd_ = -1; return file; @@ -250,7 +235,7 @@ long fmt::getpagesize() { #else long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE)); if (size < 0) - throw SystemError(errno, "cannot get memory page size"); + FMT_THROW(SystemError(errno, "cannot get memory page size")); return size; #endif } diff --git a/libs/format/fmt/posix.h b/libs/format/fmt/posix.h index ab6d12e87..88512de55 100644 --- a/libs/format/fmt/posix.h +++ b/libs/format/fmt/posix.h @@ -1,34 +1,16 @@ /* A C++ interface to POSIX functions. - Copyright (c) 2014 - 2016, Victor Zverovich + Copyright (c) 2012 - 2016, Victor Zverovich All rights reserved. - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + For the license information refer to format.h. */ #ifndef FMT_POSIX_H_ #define FMT_POSIX_H_ -#ifdef __MINGW32__ +#if defined(__MINGW32__) || defined(__CYGWIN__) // Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/. # undef __STRICT_ANSI__ #endif @@ -41,7 +23,7 @@ #include -#ifdef __APPLE__ +#if defined __APPLE__ || defined(__FreeBSD__) # include // for LC_NUMERIC_MASK on OS X #endif @@ -69,25 +51,6 @@ # endif #endif -#if FMT_GCC_VERSION >= 407 -# define FMT_UNUSED __attribute__((unused)) -#else -# define FMT_UNUSED -#endif - -#ifndef FMT_USE_STATIC_ASSERT -# define FMT_USE_STATIC_ASSERT 0 -#endif - -#if FMT_USE_STATIC_ASSERT || FMT_HAS_FEATURE(cxx_static_assert) || \ - (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600 -# define FMT_STATIC_ASSERT(cond, message) static_assert(cond, message) -#else -# define FMT_CONCAT_(a, b) FMT_CONCAT(a, b) -# define FMT_STATIC_ASSERT(cond, message) \ - typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED -#endif - // Retries the expression while it evaluates to error_result and errno // equals to EINTR. #ifndef _WIN32 @@ -125,10 +88,10 @@ class BufferedFile { public: // Constructs a BufferedFile object which doesn't represent any file. - BufferedFile() FMT_NOEXCEPT : file_(0) {} + BufferedFile() FMT_NOEXCEPT : file_(FMT_NULL) {} // Destroys the object closing the file it represents if any. - ~BufferedFile() FMT_NOEXCEPT; + FMT_API ~BufferedFile() FMT_NOEXCEPT; #if !FMT_USE_RVALUE_REFERENCES // Emulate a move constructor and a move assignment operator if rvalue @@ -147,7 +110,7 @@ public: // A "move constructor" for moving from an lvalue. BufferedFile(BufferedFile &f) FMT_NOEXCEPT : file_(f.file_) { - f.file_ = 0; + f.file_ = FMT_NULL; } // A "move assignment operator" for moving from a temporary. @@ -161,7 +124,7 @@ public: BufferedFile &operator=(BufferedFile &other) { close(); file_ = other.file_; - other.file_ = 0; + other.file_ = FMT_NULL; return *this; } @@ -169,7 +132,7 @@ public: // BufferedFile file = BufferedFile(...); operator Proxy() FMT_NOEXCEPT { Proxy p = {file_}; - file_ = 0; + file_ = FMT_NULL; return p; } @@ -179,29 +142,29 @@ public: public: BufferedFile(BufferedFile &&other) FMT_NOEXCEPT : file_(other.file_) { - other.file_ = 0; + other.file_ = FMT_NULL; } BufferedFile& operator=(BufferedFile &&other) { close(); file_ = other.file_; - other.file_ = 0; + other.file_ = FMT_NULL; return *this; } #endif // Opens a file. - BufferedFile(CStringRef filename, CStringRef mode); + FMT_API BufferedFile(CStringRef filename, CStringRef mode); // Closes the file. - void close(); + FMT_API void close(); // Returns the pointer to a FILE object representing this file. FILE *get() const FMT_NOEXCEPT { return file_; } // We place parentheses around fileno to workaround a bug in some versions // of MinGW that define fileno as a macro. - int (fileno)() const; + FMT_API int (fileno)() const; void print(CStringRef format_str, const ArgList &args) { fmt::print(file_, format_str, args); @@ -234,7 +197,7 @@ class File { File() FMT_NOEXCEPT : fd_(-1) {} // Opens a file and constructs a File object representing this file. - File(CStringRef path, int oflag); + FMT_API File(CStringRef path, int oflag); #if !FMT_USE_RVALUE_REFERENCES // Emulate a move constructor and a move assignment operator if rvalue @@ -297,49 +260,50 @@ class File { #endif // Destroys the object closing the file it represents if any. - ~File() FMT_NOEXCEPT; + FMT_API ~File() FMT_NOEXCEPT; // Returns the file descriptor. int descriptor() const FMT_NOEXCEPT { return fd_; } // Closes the file. - void close(); + FMT_API void close(); // Returns the file size. The size has signed type for consistency with // stat::st_size. - LongLong size() const; + FMT_API LongLong size() const; // Attempts to read count bytes from the file into the specified buffer. - std::size_t read(void *buffer, std::size_t count); + FMT_API std::size_t read(void *buffer, std::size_t count); // Attempts to write count bytes from the specified buffer to the file. - std::size_t write(const void *buffer, std::size_t count); + FMT_API std::size_t write(const void *buffer, std::size_t count); // Duplicates a file descriptor with the dup function and returns // the duplicate as a file object. - static File dup(int fd); + FMT_API static File dup(int fd); // Makes fd be the copy of this file descriptor, closing fd first if // necessary. - void dup2(int fd); + FMT_API void dup2(int fd); // Makes fd be the copy of this file descriptor, closing fd first if // necessary. - void dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT; + FMT_API void dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT; // Creates a pipe setting up read_end and write_end file objects for reading // and writing respectively. - static void pipe(File &read_end, File &write_end); + FMT_API static void pipe(File &read_end, File &write_end); // Creates a BufferedFile object associated with this file and detaches // this File object from the file. - BufferedFile fdopen(const char *mode); + FMT_API BufferedFile fdopen(const char *mode); }; // Returns the memory page size. long getpagesize(); -#if defined(LC_NUMERIC_MASK) || defined(_MSC_VER) +#if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && \ + !defined(__ANDROID__) && !defined(__CYGWIN__) # define FMT_LOCALE #endif @@ -372,9 +336,9 @@ class Locale { public: typedef locale_t Type; - Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", NULL)) { + Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL)) { if (!locale_) - throw fmt::SystemError(errno, "cannot create locale"); + FMT_THROW(fmt::SystemError(errno, "cannot create locale")); } ~Locale() { freelocale(locale_); } @@ -383,7 +347,7 @@ class Locale { // Converts string to floating-point number and advances str past the end // of the parsed input. double strtod(const char *&str) const { - char *end = 0; + char *end = FMT_NULL; double result = strtod_l(str, &end, locale_); str = end; return result; diff --git a/libs/format/fmt/time.h b/libs/format/fmt/time.h index 863382c0b..c98b0e011 100644 --- a/libs/format/fmt/time.h +++ b/libs/format/fmt/time.h @@ -4,37 +4,25 @@ Copyright (c) 2012 - 2016, Victor Zverovich All rights reserved. - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + For the license information refer to format.h. */ #ifndef FMT_TIME_H_ #define FMT_TIME_H_ -#include "fmt/format.h" +#include "format.h" #include +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4702) // unreachable code +# pragma warning(disable: 4996) // "deprecated" functions +#endif + namespace fmt { template -void format(BasicFormatter &f, - const char *&format_str, const std::tm &tm) { +void format_arg(BasicFormatter &f, + const char *&format_str, const std::tm &tm) { if (*format_str == ':') ++format_str; const char *end = format_str; @@ -54,11 +42,102 @@ void format(BasicFormatter &f, buffer.resize(start + count); break; } + if (size >= format.size() * 256) { + // If the buffer is 256 times larger than the format string, assume + // that `strftime` gives an empty result. There doesn't seem to be a + // better way to distinguish the two cases: + // https://github.com/fmtlib/fmt/issues/367 + break; + } const std::size_t MIN_GROWTH = 10; - buffer.reserve(buffer.capacity() + size > MIN_GROWTH ? size : MIN_GROWTH); + buffer.reserve(buffer.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH)); } format_str = end + 1; } + +namespace internal{ +inline Null<> localtime_r(...) { return Null<>(); } +inline Null<> localtime_s(...) { return Null<>(); } +inline Null<> gmtime_r(...) { return Null<>(); } +inline Null<> gmtime_s(...) { return Null<>(); } } +// Thread-safe replacement for std::localtime +inline std::tm localtime(std::time_t time) { + struct LocalTime { + std::time_t time_; + std::tm tm_; + + LocalTime(std::time_t t): time_(t) {} + + bool run() { + using namespace fmt::internal; + return handle(localtime_r(&time_, &tm_)); + } + + bool handle(std::tm *tm) { return tm != FMT_NULL; } + + bool handle(internal::Null<>) { + using namespace fmt::internal; + return fallback(localtime_s(&tm_, &time_)); + } + + bool fallback(int res) { return res == 0; } + + bool fallback(internal::Null<>) { + using namespace fmt::internal; + std::tm *tm = std::localtime(&time_); + if (tm) tm_ = *tm; + return tm != FMT_NULL; + } + }; + LocalTime lt(time); + if (lt.run()) + return lt.tm_; + // Too big time values may be unsupported. + FMT_THROW(fmt::FormatError("time_t value out of range")); + return std::tm(); +} + +// Thread-safe replacement for std::gmtime +inline std::tm gmtime(std::time_t time) { + struct GMTime { + std::time_t time_; + std::tm tm_; + + GMTime(std::time_t t): time_(t) {} + + bool run() { + using namespace fmt::internal; + return handle(gmtime_r(&time_, &tm_)); + } + + bool handle(std::tm *tm) { return tm != FMT_NULL; } + + bool handle(internal::Null<>) { + using namespace fmt::internal; + return fallback(gmtime_s(&tm_, &time_)); + } + + bool fallback(int res) { return res == 0; } + + bool fallback(internal::Null<>) { + std::tm *tm = std::gmtime(&time_); + if (tm != FMT_NULL) tm_ = *tm; + return tm != FMT_NULL; + } + }; + GMTime gt(time); + if (gt.run()) + return gt.tm_; + // Too big time values may be unsupported. + FMT_THROW(fmt::FormatError("time_t value out of range")); + return std::tm(); +} +} //namespace fmt + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + #endif // FMT_TIME_H_ diff --git a/libs/format/support/appveyor-build.py b/libs/format/support/appveyor-build.py index a5b684ef3..3b747f3cc 100644 --- a/libs/format/support/appveyor-build.py +++ b/libs/format/support/appveyor-build.py @@ -10,22 +10,23 @@ platform = os.environ.get('PLATFORM') path = os.environ['PATH'] cmake_command = ['cmake', '-DFMT_PEDANTIC=ON', '-DCMAKE_BUILD_TYPE=' + config] if build == 'mingw': - cmake_command.append('-GMinGW Makefiles') - build_command = ['mingw32-make', '-j4'] - test_command = ['mingw32-make', 'test'] - # Remove the path to Git bin directory from $PATH because it breaks MinGW config. - path = path.replace(r'C:\Program Files (x86)\Git\bin', '') - os.environ['PATH'] = r'C:\MinGW\bin;' + path + cmake_command.append('-GMinGW Makefiles') + build_command = ['mingw32-make', '-j4'] + test_command = ['mingw32-make', 'test'] + # Remove the path to Git bin directory from $PATH because it breaks + # MinGW config. + path = path.replace(r'C:\Program Files (x86)\Git\bin', '') + os.environ['PATH'] = r'C:\MinGW\bin;' + path else: - # Add MSBuild 14.0 to PATH as described in - # http://help.appveyor.com/discussions/problems/2229-v140-not-found-on-vs2105rc. - os.environ['PATH'] = r'C:\Program Files (x86)\MSBuild\14.0\Bin;' + path - generator = 'Visual Studio 14 2015' - if platform == 'x64': - generator += ' Win64' - cmake_command.append('-G' + generator) - build_command = ['cmake', '--build', '.', '--config', config, '--', '/m:4'] - test_command = ['ctest', '-C', config] + # Add MSBuild 14.0 to PATH as described in + # http://help.appveyor.com/discussions/problems/2229-v140-not-found-on-vs2105rc. + os.environ['PATH'] = r'C:\Program Files (x86)\MSBuild\14.0\Bin;' + path + generator = 'Visual Studio 14 2015' + if platform == 'x64': + generator += ' Win64' + cmake_command.append('-G' + generator) + build_command = ['cmake', '--build', '.', '--config', config, '--', '/m:4'] + test_command = ['ctest', '-C', config] check_call(cmake_command) check_call(build_command) diff --git a/libs/format/support/appveyor.yml b/libs/format/support/appveyor.yml index 087512c31..a651c525f 100644 --- a/libs/format/support/appveyor.yml +++ b/libs/format/support/appveyor.yml @@ -20,3 +20,7 @@ build_script: on_failure: - appveyor PushArtifact Testing/Temporary/LastTest.log - appveyor AddTest test + +# Uncomment this to debug AppVeyor failures. +#on_finish: +# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) diff --git a/libs/format/support/cmake/cxx11.cmake b/libs/format/support/cmake/cxx11.cmake index 31ea1063e..21d125433 100644 --- a/libs/format/support/cmake/cxx11.cmake +++ b/libs/format/support/cmake/cxx11.cmake @@ -20,7 +20,14 @@ if (FMT_USE_CPP11) check_cxx_source_compiles(" #include int main() {}" FMT_CPP11_UNISTD_H) - if (FMT_CPP11_CMATH AND FMT_CPP11_UNISTD_H) + # Check if snprintf works with -std=c++11. It may not in MinGW. + check_cxx_source_compiles(" + #include + int main() { + char buffer[10]; + snprintf(buffer, 10, \"foo\"); + }" FMT_CPP11_SNPRINTF) + if (FMT_CPP11_CMATH AND FMT_CPP11_UNISTD_H AND FMT_CPP11_SNPRINTF) set(CPP11_FLAG -std=c++11) else () check_cxx_compiler_flag(-std=gnu++11 HAVE_STD_GNUPP11_FLAG) @@ -37,6 +44,11 @@ if (FMT_USE_CPP11) endif () endif () +if (CMAKE_CXX_STANDARD) + # Don't use -std compiler flag if CMAKE_CXX_STANDARD is specified. + set(CPP11_FLAG ) +endif () + set(CMAKE_REQUIRED_FLAGS ${CPP11_FLAG}) # Check if variadic templates are working and not affected by GCC bug 39653: diff --git a/libs/format/support/travis-build.py b/libs/format/support/travis-build.py index 6dc096669..910177920 100644 --- a/libs/format/support/travis-build.py +++ b/libs/format/support/travis-build.py @@ -6,34 +6,28 @@ import errno, os, re, shutil, sys, tempfile, urllib from subprocess import call, check_call, check_output, Popen, PIPE, STDOUT def rmtree_if_exists(dir): - try: - shutil.rmtree(dir) - except OSError as e: - if e.errno == errno.ENOENT: - pass + try: + shutil.rmtree(dir) + except OSError as e: + if e.errno == errno.ENOENT: + pass def makedirs_if_not_exist(dir): - try: - os.makedirs(dir) - except OSError as e: - if e.errno != errno.EEXIST: - raise + try: + os.makedirs(dir) + except OSError as e: + if e.errno != errno.EEXIST: + raise -fmt_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) - -build = os.environ['BUILD'] -if build == 'Doc': - travis = 'TRAVIS' in os.environ - # Install dependencies. - if travis: +def install_dependencies(): branch = os.environ['TRAVIS_BRANCH'] if branch != 'master': - print('Branch: ' + branch) - exit(0) # Ignore non-master branches - check_call('curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key | ' + - 'sudo apt-key add -', shell=True) - check_call('echo "deb https://deb.nodesource.com/node_0.10 precise main" | ' + - 'sudo tee /etc/apt/sources.list.d/nodesource.list', shell=True) + print('Branch: ' + branch) + exit(0) # Ignore non-master branches + check_call('curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key ' + + '| sudo apt-key add -', shell=True) + check_call('echo "deb https://deb.nodesource.com/node_0.10 precise main" ' + + '| sudo tee /etc/apt/sources.list.d/nodesource.list', shell=True) check_call(['sudo', 'apt-get', 'update']) check_call(['sudo', 'apt-get', 'install', 'python-virtualenv', 'nodejs']) check_call(['npm', 'install', '-g', 'less', 'less-plugin-clean-css']) @@ -41,39 +35,48 @@ if build == 'Doc': urllib.urlretrieve('http://mirrors.kernel.org/ubuntu/pool/main/d/doxygen/' + deb_file, deb_file) check_call(['sudo', 'dpkg', '-i', deb_file]) - sys.path.insert(0, os.path.join(fmt_dir, 'doc')) - import build - html_dir = build.build_docs() - repo = 'fmtlib.github.io' - if travis and 'KEY' not in os.environ: - # Don't update the repo if building on Travis from an account that doesn't - # have push access. - print('Skipping update of ' + repo) - exit(0) - # Clone the fmtlib.github.io repo. - rmtree_if_exists(repo) - git_url = 'https://github.com/' if travis else 'git@github.com:' - check_call(['git', 'clone', git_url + 'fmtlib/{}.git'.format(repo)]) - # Copy docs to the repo. - target_dir = os.path.join(repo, 'dev') - rmtree_if_exists(target_dir) - shutil.copytree(html_dir, target_dir, ignore=shutil.ignore_patterns('.*')) - if travis: - check_call(['git', 'config', '--global', 'user.name', 'amplbot']) - check_call(['git', 'config', '--global', 'user.email', 'viz@ampl.com']) - # Push docs to GitHub pages. - check_call(['git', 'add', '--all'], cwd=repo) - if call(['git', 'diff-index', '--quiet', 'HEAD'], cwd=repo): - check_call(['git', 'commit', '-m', 'Update documentation'], cwd=repo) - cmd = 'git push' + +fmt_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + +build = os.environ['BUILD'] +if build == 'Doc': + travis = 'TRAVIS' in os.environ if travis: - cmd += ' https://$KEY@github.com/fmtlib/fmtlib.github.io.git master' - p = Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT, cwd=repo) - # Print the output without the key. - print(p.communicate()[0].replace(os.environ['KEY'], '$KEY')) - if p.returncode != 0: - raise CalledProcessError(p.returncode, cmd) - exit(0) + install_dependencies() + sys.path.insert(0, os.path.join(fmt_dir, 'doc')) + import build + build.create_build_env() + html_dir = build.build_docs() + repo = 'fmtlib.github.io' + if travis and 'KEY' not in os.environ: + # Don't update the repo if building on Travis from an account that + # doesn't have push access. + print('Skipping update of ' + repo) + exit(0) + # Clone the fmtlib.github.io repo. + rmtree_if_exists(repo) + git_url = 'https://github.com/' if travis else 'git@github.com:' + check_call(['git', 'clone', git_url + 'fmtlib/{}.git'.format(repo)]) + # Copy docs to the repo. + target_dir = os.path.join(repo, 'dev') + rmtree_if_exists(target_dir) + shutil.copytree(html_dir, target_dir, ignore=shutil.ignore_patterns('.*')) + if travis: + check_call(['git', 'config', '--global', 'user.name', 'amplbot']) + check_call(['git', 'config', '--global', 'user.email', 'viz@ampl.com']) + # Push docs to GitHub pages. + check_call(['git', 'add', '--all'], cwd=repo) + if call(['git', 'diff-index', '--quiet', 'HEAD'], cwd=repo): + check_call(['git', 'commit', '-m', 'Update documentation'], cwd=repo) + cmd = 'git push' + if travis: + cmd += ' https://$KEY@github.com/fmtlib/fmtlib.github.io.git master' + p = Popen(cmd, shell=True, stdout=PIPE, stderr=STDOUT, cwd=repo) + # Print the output without the key. + print(p.communicate()[0].replace(os.environ['KEY'], '$KEY')) + if p.returncode != 0: + raise CalledProcessError(p.returncode, cmd) + exit(0) standard = os.environ['STANDARD'] install_dir = os.path.join(fmt_dir, "_install") @@ -83,11 +86,13 @@ test_build_dir = os.path.join(fmt_dir, "_build_test") # Configure library. makedirs_if_not_exist(build_dir) common_cmake_flags = [ - '-DCMAKE_INSTALL_PREFIX=' + install_dir, '-DCMAKE_BUILD_TYPE=' + build + '-DCMAKE_INSTALL_PREFIX=' + install_dir, '-DCMAKE_BUILD_TYPE=' + build ] extra_cmake_flags = [] if standard != '0x': - extra_cmake_flags = ['-DCMAKE_CXX_FLAGS=-std=c++' + standard, '-DFMT_USE_CPP11=OFF'] + extra_cmake_flags = [ + '-DCMAKE_CXX_FLAGS=-std=c++' + standard, '-DFMT_USE_CPP11=OFF' + ] check_call(['cmake', '-DFMT_DOC=OFF', '-DFMT_PEDANTIC=ON', fmt_dir] + common_cmake_flags + extra_cmake_flags, cwd=build_dir) @@ -98,9 +103,9 @@ check_call(['make', '-j4'], cwd=build_dir) env = os.environ.copy() env['CTEST_OUTPUT_ON_FAILURE'] = '1' if call(['make', 'test'], env=env, cwd=build_dir): - with open('Testing/Temporary/LastTest.log', 'r') as f: - print(f.read()) - sys.exit(-1) + with open('Testing/Temporary/LastTest.log', 'r') as f: + print(f.read()) + sys.exit(-1) # Install library. check_call(['make', 'install'], cwd=build_dir) diff --git a/libs/format/support/update-converity-branch.py b/libs/format/support/update-converity-branch.py index 36c0475ae..519f5d00d 100644 --- a/libs/format/support/update-converity-branch.py +++ b/libs/format/support/update-converity-branch.py @@ -8,23 +8,23 @@ import shutil, tempfile from subprocess import check_output, STDOUT class Git: - def __init__(self, dir): - self.dir = dir + def __init__(self, dir): + self.dir = dir - def __call__(self, *args): - output = check_output(['git'] + list(args), cwd=self.dir, stderr=STDOUT) - print(output) - return output + def __call__(self, *args): + output = check_output(['git'] + list(args), cwd=self.dir, stderr=STDOUT) + print(output) + return output dir = tempfile.mkdtemp() try: - git = Git(dir) - git('clone', '-b', 'coverity', 'git@github.com:fmtlib/fmt.git', dir) - output = git('merge', '-X', 'theirs', '--no-commit', 'origin/master') - if 'Fast-forward' not in output: - git('reset', 'HEAD', '.travis.yml') - git('checkout', '--', '.travis.yml') - git('commit', '-m', 'Update coverity branch') - git('push') + git = Git(dir) + git('clone', '-b', 'coverity', 'git@github.com:fmtlib/fmt.git', dir) + output = git('merge', '-X', 'theirs', '--no-commit', 'origin/master') + if 'Fast-forward' not in output: + git('reset', 'HEAD', '.travis.yml') + git('checkout', '--', '.travis.yml') + git('commit', '-m', 'Update coverity branch') + git('push') finally: - shutil.rmtree(dir) + shutil.rmtree(dir) diff --git a/libs/format/test/CMakeLists.txt b/libs/format/test/CMakeLists.txt index e4e868d54..31a418de7 100644 --- a/libs/format/test/CMakeLists.txt +++ b/libs/format/test/CMakeLists.txt @@ -56,11 +56,19 @@ if (CMAKE_COMPILER_IS_GNUCXX OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) set(PEDANTIC_COMPILE_FLAGS -Wall -Wextra -Wno-long-long -Wno-variadic-macros) endif () +function(add_fmt_executable name) + add_executable(${name} ${ARGN}) + if (MINGW) + target_link_libraries(${name} -static-libgcc -static-libstdc++) + endif () +endfunction() + # Adds a test. # Usage: add_fmt_test(name srcs...) function(add_fmt_test name) - add_executable(${name} ${name}.cc ${ARGN}) + add_fmt_executable(${name} ${name}.cc ${ARGN}) target_link_libraries(${name} test-main) + # define if certain c++ features can be used target_compile_definitions(${name} PRIVATE FMT_USE_TYPE_TRAITS=$ @@ -72,13 +80,17 @@ function(add_fmt_test name) endfunction() add_fmt_test(assert-test) +add_fmt_test(container-test) add_fmt_test(gtest-extra-test) add_fmt_test(format-test) add_fmt_test(format-impl-test) add_fmt_test(ostream-test) add_fmt_test(printf-test) +add_fmt_test(string-test) +add_fmt_test(time-test) add_fmt_test(util-test mock-allocator.h) add_fmt_test(macro-test) +add_fmt_test(custom-formatter-test) # Enable stricter options for one test to make sure that the header is free of # warnings. @@ -87,7 +99,8 @@ if (FMT_PEDANTIC AND MSVC) endif () if (HAVE_OPEN) - add_executable(posix-mock-test posix-mock-test.cc ../fmt/format.cc ${TEST_MAIN_SRC}) + add_fmt_executable(posix-mock-test + posix-mock-test.cc ../fmt/format.cc ../fmt/printf.cc ${TEST_MAIN_SRC}) target_include_directories(posix-mock-test PRIVATE ${PROJECT_SOURCE_DIR}) target_compile_definitions(posix-mock-test PRIVATE FMT_USE_FILE_DESCRIPTORS=1) target_link_libraries(posix-mock-test gmock) @@ -95,7 +108,7 @@ if (HAVE_OPEN) add_fmt_test(posix-test) endif () -add_executable(header-only-test +add_fmt_executable(header-only-test header-only-test.cc header-only-test2.cc test-main.cc) target_link_libraries(header-only-test gmock) if (TARGET fmt-header-only) @@ -109,6 +122,7 @@ endif () check_cxx_compiler_flag(-fno-exceptions HAVE_FNO_EXCEPTIONS_FLAG) if (HAVE_FNO_EXCEPTIONS_FLAG) add_library(noexception-test ../fmt/format.cc) + target_include_directories(noexception-test PRIVATE ${PROJECT_SOURCE_DIR}) target_compile_options(noexception-test PRIVATE -fno-exceptions) endif () @@ -116,6 +130,7 @@ if (FMT_PEDANTIC) # Test that the library compiles without windows.h. if (CMAKE_SYSTEM_NAME STREQUAL "Windows") add_library(no-windows-h-test ../fmt/format.cc) + target_include_directories(no-windows-h-test PRIVATE ${PROJECT_SOURCE_DIR}) target_compile_definitions(no-windows-h-test PRIVATE FMT_USE_WINDOWS_H=0) endif () @@ -125,7 +140,7 @@ if (FMT_PEDANTIC) "${CMAKE_CURRENT_BINARY_DIR}/compile-test" --build-generator ${CMAKE_GENERATOR} --build-makeprogram ${CMAKE_MAKE_PROGRAM} - --build-options + --build-options "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" "-DCPP11_FLAG=${CPP11_FLAG}" "-DSUPPORTS_USER_DEFINED_LITERALS=${SUPPORTS_USER_DEFINED_LITERALS}") diff --git a/libs/format/test/add-subdirectory-test/CMakeLists.txt b/libs/format/test/add-subdirectory-test/CMakeLists.txt index 5460363a8..d1edd8a52 100644 --- a/libs/format/test/add-subdirectory-test/CMakeLists.txt +++ b/libs/format/test/add-subdirectory-test/CMakeLists.txt @@ -5,9 +5,9 @@ project(fmt-test) add_subdirectory(../.. fmt) add_executable(library-test "main.cc") -target_link_libraries(library-test fmt) +target_link_libraries(library-test fmt::fmt) -if (TARGET fmt-header-only) +if (TARGET fmt::fmt-header-only) add_executable(header-only-test "main.cc") - target_link_libraries(header-only-test fmt-header-only) + target_link_libraries(header-only-test fmt::fmt-header-only) endif () diff --git a/libs/format/test/find-package-test/CMakeLists.txt b/libs/format/test/find-package-test/CMakeLists.txt index 1f28c30c6..40c075609 100644 --- a/libs/format/test/find-package-test/CMakeLists.txt +++ b/libs/format/test/find-package-test/CMakeLists.txt @@ -5,9 +5,9 @@ project(fmt-test) find_package(FMT REQUIRED) add_executable(library-test main.cc) -target_link_libraries(library-test fmt) +target_link_libraries(library-test fmt::fmt) -if (TARGET fmt-header-only) +if (TARGET fmt::fmt-header-only) add_executable(header-only-test main.cc) - target_link_libraries(header-only-test fmt-header-only) + target_link_libraries(header-only-test fmt::fmt-header-only) endif () diff --git a/libs/format/test/format-impl-test.cc b/libs/format/test/format-impl-test.cc index aff9ea54a..1eb5e9165 100644 --- a/libs/format/test/format-impl-test.cc +++ b/libs/format/test/format-impl-test.cc @@ -26,10 +26,12 @@ */ #define FMT_NOEXCEPT +#undef FMT_SHARED #include "test-assert.h" -// Include format.cc instead of format.h to test implementation-specific stuff. +// Include *.cc instead of *.h to test implementation-specific stuff. #include "fmt/format.cc" +#include "fmt/printf.cc" #include #include @@ -46,7 +48,7 @@ TEST(FormatTest, ArgConverter) { Arg arg = Arg(); arg.type = Arg::LONG_LONG; arg.long_long_value = std::numeric_limits::max(); - fmt::ArgConverter(arg, 'd').visit(arg); + fmt::internal::ArgConverter(arg, 'd').visit(arg); EXPECT_EQ(Arg::LONG_LONG, arg.type); } diff --git a/libs/format/test/format-test.cc b/libs/format/test/format-test.cc index 52ff8a1e0..6388d5a5c 100644 --- a/libs/format/test/format-test.cc +++ b/libs/format/test/format-test.cc @@ -43,8 +43,23 @@ // Test that the library compiles if None is defined to 0 as done by xlib.h. #define None 0 +struct LocaleMock { + static LocaleMock *instance; + + MOCK_METHOD0(localeconv, lconv *()); +} *LocaleMock::instance; + +namespace fmt { +namespace std { +using namespace ::std; +lconv *localeconv() { + return LocaleMock::instance ? + LocaleMock::instance->localeconv() : ::std::localeconv(); +} +} +} + #include "fmt/format.h" -#include "fmt/time.h" #include "util.h" #include "mock-allocator.h" @@ -235,7 +250,7 @@ TEST(WriterTest, Allocator) { std::size_t size = static_cast(1.5 * fmt::internal::INLINE_BUFFER_SIZE); std::vector mem(size); - EXPECT_CALL(alloc, allocate(size)).WillOnce(testing::Return(&mem[0])); + EXPECT_CALL(alloc, allocate(size, 0)).WillOnce(testing::Return(&mem[0])); for (int i = 0; i < fmt::internal::INLINE_BUFFER_SIZE + 1; ++i) w << '*'; EXPECT_CALL(alloc, deallocate(&mem[0], size)); @@ -917,7 +932,7 @@ TEST(FormatterTest, RuntimeWidth) { FormatError, "number is too big"); EXPECT_THROW_MSG(format("{0:{1}}", 0, -1l), FormatError, "negative width"); - if (fmt::internal::check(sizeof(long) > sizeof(int))) { + if (fmt::internal::const_check(sizeof(long) > sizeof(int))) { long value = INT_MAX; EXPECT_THROW_MSG(format("{0:{1}}", 0, (value + 1)), FormatError, "number is too big"); @@ -1036,7 +1051,7 @@ TEST(FormatterTest, RuntimePrecision) { FormatError, "number is too big"); EXPECT_THROW_MSG(format("{0:.{1}}", 0, -1l), FormatError, "negative precision"); - if (fmt::internal::check(sizeof(long) > sizeof(int))) { + if (fmt::internal::const_check(sizeof(long) > sizeof(int))) { long value = INT_MAX; EXPECT_THROW_MSG(format("{0:.{1}}", 0, (value + 1)), FormatError, "number is too big"); @@ -1209,13 +1224,24 @@ TEST(FormatterTest, FormatOct) { } TEST(FormatterTest, FormatIntLocale) { -#ifndef _WIN32 - const char *locale = "en_US.utf-8"; -#else - const char *locale = "English_United States"; -#endif - std::setlocale(LC_ALL, locale); - EXPECT_EQ("1,234,567", format("{:n}", 1234567)); + ScopedMock mock; + lconv lc = lconv(); + char sep[] = "--"; + lc.thousands_sep = sep; + EXPECT_CALL(mock, localeconv()).Times(3).WillRepeatedly(testing::Return(&lc)); + EXPECT_EQ("123", format("{:n}", 123)); + EXPECT_EQ("1--234", format("{:n}", 1234)); + EXPECT_EQ("1--234--567", format("{:n}", 1234567)); +} + +struct ConvertibleToLongLong { + operator fmt::LongLong() const { + return fmt::LongLong(1) << 32; + } +}; + +TEST(FormatterTest, FormatConvertibleToLongLong) { + EXPECT_EQ("100000000", format("{:x}", ConvertibleToLongLong())); } TEST(FormatterTest, FormatFloat) { @@ -1327,6 +1353,8 @@ TEST(FormatterTest, FormatUCharString) { EXPECT_EQ("test", format("{0:s}", str)); const unsigned char *const_str = str; EXPECT_EQ("test", format("{0:s}", const_str)); + unsigned char *ptr = str; + EXPECT_EQ("test", format("{0:s}", ptr)); } TEST(FormatterTest, FormatPointer) { @@ -1350,7 +1378,7 @@ TEST(FormatterTest, FormatCStringRef) { EXPECT_EQ("test", format("{0}", CStringRef("test"))); } -void format(fmt::BasicFormatter &f, const char *, const Date &d) { +void format_arg(fmt::BasicFormatter &f, const char *, const Date &d) { f.writer() << d.year() << '-' << d.month() << '-' << d.day(); } @@ -1363,7 +1391,7 @@ TEST(FormatterTest, FormatCustom) { class Answer {}; template -void format(fmt::BasicFormatter &f, const Char *, Answer) { +void format_arg(fmt::BasicFormatter &f, const Char *, Answer) { f.writer() << "42"; } @@ -1534,13 +1562,25 @@ TEST(FormatTest, Variadic) { EXPECT_EQ(L"abc1", format(L"{}c{}", L"ab", 1)); } -TEST(FormatTest, Time) { - std::tm tm = std::tm(); - tm.tm_year = 116; - tm.tm_mon = 3; - tm.tm_mday = 25; - EXPECT_EQ("The date is 2016-04-25.", - fmt::format("The date is {:%Y-%m-%d}.", tm)); +TEST(FormatTest, JoinArg) { + using fmt::join; + int v1[3] = { 1, 2, 3 }; + std::vector v2; + v2.push_back(1.2f); + v2.push_back(3.4f); + + EXPECT_EQ("(1, 2, 3)", format("({})", join(v1 + 0, v1 + 3, ", "))); + EXPECT_EQ("(1)", format("({})", join(v1 + 0, v1 + 1, ", "))); + EXPECT_EQ("()", format("({})", join(v1 + 0, v1 + 0, ", "))); + EXPECT_EQ("(001, 002, 003)", format("({:03})", join(v1 + 0, v1 + 3, ", "))); + EXPECT_EQ("(+01.20, +03.40)", format("({:+06.2f})", join(v2.begin(), v2.end(), ", "))); + + EXPECT_EQ(L"(1, 2, 3)", format(L"({})", join(v1 + 0, v1 + 3, L", "))); + +#if FMT_HAS_GXX_CXX11 + EXPECT_EQ("(1, 2, 3)", format("({})", join(v1, ", "))); + EXPECT_EQ("(+01.20, +03.40)", format("({:+06.2f})", join(v2, ", "))); +#endif } template @@ -1644,3 +1684,10 @@ FMT_VARIADIC(void, custom_format, const char *) TEST(FormatTest, CustomArgFormatter) { custom_format("{}", 42); } + +void convert(int); + +// Check if there is no collision with convert function in the global namespace. +TEST(FormatTest, ConvertCollision) { + fmt::format("{}", 42); +} diff --git a/libs/format/test/gmock/gmock.h b/libs/format/test/gmock/gmock.h index 17bde1e7e..84f58cdd1 100644 --- a/libs/format/test/gmock/gmock.h +++ b/libs/format/test/gmock/gmock.h @@ -10090,8 +10090,9 @@ class FunctionMockerBase : public UntypedFunctionMockerBase { // threads concurrently. Result InvokeWith(const ArgumentTuple& args) GTEST_LOCK_EXCLUDED_(g_gmock_mutex) { - return static_cast( - this->UntypedInvokeWith(&args))->GetValueAndDelete(); + const ResultHolder *rh = static_cast( + this->UntypedInvokeWith(&args)); + return rh ? rh->GetValueAndDelete() : Result(); } // Adds and returns a default action spec for this mock function. diff --git a/libs/format/test/gtest-extra-test.cc b/libs/format/test/gtest-extra-test.cc index 8f681c2cf..6a8c5676f 100644 --- a/libs/format/test/gtest-extra-test.cc +++ b/libs/format/test/gtest-extra-test.cc @@ -320,7 +320,7 @@ TEST(StreamingAssertionsTest, EXPECT_WRITE) { TEST(UtilTest, FormatSystemError) { fmt::MemoryWriter out; - fmt::internal::format_system_error(out, EDOM, "test message"); + fmt::format_system_error(out, EDOM, "test message"); EXPECT_EQ(out.str(), format_system_error(EDOM, "test message")); } diff --git a/libs/format/test/gtest-extra.cc b/libs/format/test/gtest-extra.cc index f7c296305..7640d1545 100644 --- a/libs/format/test/gtest-extra.cc +++ b/libs/format/test/gtest-extra.cc @@ -105,6 +105,6 @@ std::string read(File &f, std::size_t count) { std::string format_system_error(int error_code, fmt::StringRef message) { fmt::MemoryWriter out; - fmt::internal::format_system_error(out, error_code, message); + fmt::format_system_error(out, error_code, message); return out.str(); } diff --git a/libs/format/test/gtest-extra.h b/libs/format/test/gtest-extra.h index 649fbe275..5f7fe29d8 100644 --- a/libs/format/test/gtest-extra.h +++ b/libs/format/test/gtest-extra.h @@ -29,7 +29,7 @@ #define FMT_GTEST_EXTRA_H_ #include -#include +#include #include "fmt/format.h" @@ -172,4 +172,10 @@ std::string read(fmt::File &f, std::size_t count); #endif // FMT_USE_FILE_DESCRIPTORS +template +struct ScopedMock : testing::StrictMock { + ScopedMock() { Mock::instance = this; } + ~ScopedMock() { Mock::instance = 0; } +}; + #endif // FMT_GTEST_EXTRA_H_ diff --git a/libs/format/test/gtest/gtest.h b/libs/format/test/gtest/gtest.h index 4f3804f70..52d2ed6d0 100644 --- a/libs/format/test/gtest/gtest.h +++ b/libs/format/test/gtest/gtest.h @@ -2823,7 +2823,11 @@ inline int IsATTY(int /* fd */) { return 0; } inline int IsATTY(int fd) { return _isatty(fd); } # endif // GTEST_OS_WINDOWS_MOBILE inline int StrCaseCmp(const char* s1, const char* s2) { - return _stricmp(s1, s2); +# if _EMULATE_GLIBC + return strcasecmp(s1, s2); +# else + return _stricmp(s1, s2); +# endif } inline char* StrDup(const char* src) { return _strdup(src); } # endif // __BORLANDC__ diff --git a/libs/format/test/mock-allocator.h b/libs/format/test/mock-allocator.h index 7de1e1a09..34b9c11ab 100644 --- a/libs/format/test/mock-allocator.h +++ b/libs/format/test/mock-allocator.h @@ -36,8 +36,8 @@ class MockAllocator { MockAllocator() {} MockAllocator(const MockAllocator &) {} typedef T value_type; - MOCK_METHOD1_T(allocate, T* (std::size_t n)); - MOCK_METHOD2_T(deallocate, void (T* p, std::size_t n)); + MOCK_METHOD2_T(allocate, T *(std::size_t n, const T *h)); + MOCK_METHOD2_T(deallocate, void (T *p, std::size_t n)); }; template @@ -78,8 +78,10 @@ class AllocatorRef { Allocator *get() const { return alloc_; } - value_type* allocate(std::size_t n) { return alloc_->allocate(n); } - void deallocate(value_type* p, std::size_t n) { alloc_->deallocate(p, n); } + value_type *allocate(std::size_t n, const value_type *h) { + return alloc_->allocate(n, h); + } + void deallocate(value_type *p, std::size_t n) { alloc_->deallocate(p, n); } }; #endif // FMT_MOCK_ALLOCATOR_H_ diff --git a/libs/format/test/ostream-test.cc b/libs/format/test/ostream-test.cc index bbcce95e2..4081b43f8 100644 --- a/libs/format/test/ostream-test.cc +++ b/libs/format/test/ostream-test.cc @@ -25,7 +25,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include "fmt/ostream.cc" +#include "fmt/ostream.h" #include #include "gmock/gmock.h" @@ -35,13 +35,6 @@ using fmt::format; using fmt::FormatError; -template -std::basic_ostream &operator<<( - std::basic_ostream &os, const BasicTestString &s) { - os << s.value(); - return os; -} - std::ostream &operator<<(std::ostream &os, const Date &d) { os << d.year() << '-' << d.month() << '-' << d.day(); return os; @@ -128,22 +121,11 @@ TEST(OStreamTest, Print) { EXPECT_EQ("Don't panic!", os.str()); } -TEST(OStreamTest, PrintfCustom) { - EXPECT_EQ("abc", fmt::sprintf("%s", TestString("abc"))); -} - -TEST(OStreamTest, FPrintf) { - std::ostringstream os; - int ret = fmt::fprintf(os, "Don't %s!", "panic"); - EXPECT_EQ("Don't panic!", os.str()); - EXPECT_EQ(12, ret); -} - TEST(OStreamTest, WriteToOStream) { std::ostringstream os; fmt::MemoryWriter w; w << "foo"; - fmt::write(os, w); + fmt::internal::write(os, w); EXPECT_EQ("foo", os.str()); } @@ -188,5 +170,5 @@ TEST(OStreamTest, WriteToOStreamMaxSize) { data += n; size -= static_cast(n); } while (size != 0); - fmt::write(os, w); + fmt::internal::write(os, w); } diff --git a/libs/format/test/posix-mock-test.cc b/libs/format/test/posix-mock-test.cc index 2a89a8224..7a78327e3 100644 --- a/libs/format/test/posix-mock-test.cc +++ b/libs/format/test/posix-mock-test.cc @@ -453,12 +453,6 @@ TEST(BufferedFileTest, FilenoNoRetry) { fileno_count = 0; } -template -struct ScopedMock : testing::StrictMock { - ScopedMock() { Mock::instance = this; } - ~ScopedMock() { Mock::instance = 0; } -}; - struct TestMock { static TestMock *instance; } *TestMock::instance; @@ -508,7 +502,7 @@ LocaleType newlocale(int category_mask, const char *locale, LocaleType base) { return LocaleMock::instance->newlocale(category_mask, locale, base); } -#ifdef __APPLE__ +#if defined(__APPLE__) || defined(__FreeBSD__) typedef int FreeLocaleResult; #else typedef void FreeLocaleResult; diff --git a/libs/format/test/posix-test.cc b/libs/format/test/posix-test.cc index 2dd3f046f..e6332bf03 100644 --- a/libs/format/test/posix-test.cc +++ b/libs/format/test/posix-test.cc @@ -232,7 +232,7 @@ TEST(FileTest, MoveAssignmentClosesFile) { File OpenBufferedFile(int &fd) { File f = open_file(); fd = f.descriptor(); - return std::move(f); + return f; } TEST(FileTest, MoveFromTemporaryInCtor) { diff --git a/libs/format/test/printf-test.cc b/libs/format/test/printf-test.cc index c38a1e52f..81a041d77 100644 --- a/libs/format/test/printf-test.cc +++ b/libs/format/test/printf-test.cc @@ -29,6 +29,7 @@ #include #include +#include "fmt/printf.h" #include "fmt/format.h" #include "gtest-extra.h" #include "util.h" @@ -201,6 +202,8 @@ TEST(PrintfTest, HashFlag) { TEST(PrintfTest, Width) { EXPECT_PRINTF(" abc", "%5s", "abc"); + EXPECT_PRINTF(" -42", "%5s", "-42"); + EXPECT_PRINTF(" 0.123456", "%10s", 0.123456); // Width cannot be specified twice. EXPECT_THROW_MSG(fmt::sprintf("%5-5d", 42), FormatError, @@ -295,12 +298,13 @@ void TestLength(const char *length_spec, U value) { fmt::LongLong signed_value = 0; fmt::ULongLong unsigned_value = 0; // Apply integer promotion to the argument. - fmt::ULongLong max = std::numeric_limits::max(); - using fmt::internal::check; - if (check(max <= static_cast(std::numeric_limits::max()))) { + using std::numeric_limits; + fmt::ULongLong max = numeric_limits::max(); + using fmt::internal::const_check; + if (const_check(max <= static_cast(numeric_limits::max()))) { signed_value = static_cast(value); unsigned_value = static_cast(value); - } else if (check(max <= std::numeric_limits::max())) { + } else if (const_check(max <= numeric_limits::max())) { signed_value = static_cast(value); unsigned_value = static_cast(value); } @@ -379,11 +383,13 @@ TEST(PrintfTest, Bool) { TEST(PrintfTest, Int) { EXPECT_PRINTF("-42", "%d", -42); EXPECT_PRINTF("-42", "%i", -42); + EXPECT_PRINTF("-42", "%s", -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); + EXPECT_PRINTF(fmt::format("{}", u), "%s", u); } TEST(PrintfTest, LongLong) { @@ -395,7 +401,11 @@ TEST(PrintfTest, LongLong) { TEST(PrintfTest, 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); + EXPECT_PRINTF("392.65", "%s", 392.65); char buffer[BUFFER_SIZE]; safe_sprintf(buffer, "%e", 392.65); EXPECT_PRINTF(buffer, "%e", 392.65); @@ -420,6 +430,7 @@ TEST(PrintfTest, Inf) { TEST(PrintfTest, Char) { EXPECT_PRINTF("x", "%c", 'x'); + EXPECT_PRINTF("x", "%s", 'x'); int max = std::numeric_limits::max(); EXPECT_PRINTF(fmt::format("{}", static_cast(max)), "%c", max); //EXPECT_PRINTF("x", "%lc", L'x'); @@ -438,13 +449,17 @@ TEST(PrintfTest, Pointer) { int n; void *p = &n; EXPECT_PRINTF(fmt::format("{}", p), "%p", p); + EXPECT_PRINTF(fmt::format("{}", p), "%s", p); p = 0; EXPECT_PRINTF("(nil)", "%p", p); EXPECT_PRINTF(" (nil)", "%10p", p); + EXPECT_PRINTF("(nil)", "%s", p); + EXPECT_PRINTF(" (nil)", "%10s", p); const char *s = "test"; EXPECT_PRINTF(fmt::format("{:p}", s), "%p", s); const char *null_str = 0; EXPECT_PRINTF("(nil)", "%p", null_str); + EXPECT_PRINTF("(null)", "%s", null_str); } TEST(PrintfTest, Location) { @@ -477,3 +492,20 @@ TEST(PrintfTest, PrintfError) { TEST(PrintfTest, WideString) { EXPECT_EQ(L"abc", fmt::sprintf(L"%s", L"abc")); } + +TEST(PrintfTest, PrintfCustom) { + EXPECT_EQ("abc", fmt::sprintf("%s", TestString("abc"))); +} + +TEST(PrintfTest, OStream) { + std::ostringstream os; + int ret = fmt::fprintf(os, "Don't %s!", "panic"); + EXPECT_EQ("Don't panic!", os.str()); + EXPECT_EQ(12, ret); +} + +TEST(PrintfTest, Writer) { + fmt::MemoryWriter writer; + printf(writer, "%d", 42); + EXPECT_EQ("42", writer.str()); +} diff --git a/libs/format/test/util-test.cc b/libs/format/test/util-test.cc index 2134d0951..a38825580 100644 --- a/libs/format/test/util-test.cc +++ b/libs/format/test/util-test.cc @@ -64,7 +64,7 @@ namespace { struct Test {}; template -void format(fmt::BasicFormatter &f, const Char *, Test) { +void format_arg(fmt::BasicFormatter &f, const Char *, Test) { f.writer() << "test"; } @@ -83,8 +83,8 @@ void CheckForwarding( // Check if value_type is properly defined. AllocatorRef< MockAllocator >::value_type *ptr = &mem; // Check forwarding. - EXPECT_CALL(alloc, allocate(42)).WillOnce(Return(ptr)); - ref.allocate(42); + EXPECT_CALL(alloc, allocate(42, 0)).WillOnce(Return(ptr)); + ref.allocate(42, 0); EXPECT_CALL(alloc, deallocate(ptr, 42)); ref.deallocate(ptr, 42); } @@ -339,7 +339,7 @@ TEST(MemoryBufferTest, Grow) { EXPECT_EQ(10u, buffer.capacity()); int mem[20]; mem[7] = 0xdead; - EXPECT_CALL(alloc, allocate(20)).WillOnce(Return(mem)); + EXPECT_CALL(alloc, allocate(20, 0)).WillOnce(Return(mem)); buffer.grow(20); EXPECT_EQ(20u, buffer.capacity()); // Check if size elements have been copied @@ -360,7 +360,7 @@ TEST(MemoryBufferTest, Allocator) { MemoryBuffer buffer2((TestAllocator(&alloc))); EXPECT_EQ(&alloc, buffer2.get_allocator().get()); std::size_t size = 2 * fmt::internal::INLINE_BUFFER_SIZE; - EXPECT_CALL(alloc, allocate(size)).WillOnce(Return(&mem)); + EXPECT_CALL(alloc, allocate(size, 0)).WillOnce(Return(&mem)); buffer2.reserve(size); EXPECT_CALL(alloc, deallocate(&mem, size)); } @@ -373,13 +373,13 @@ TEST(MemoryBufferTest, ExceptionInDeallocate) { std::size_t size = 2 * fmt::internal::INLINE_BUFFER_SIZE; std::vector mem(size); { - EXPECT_CALL(alloc, allocate(size)).WillOnce(Return(&mem[0])); + EXPECT_CALL(alloc, allocate(size, 0)).WillOnce(Return(&mem[0])); buffer.resize(size); std::fill(&buffer[0], &buffer[0] + size, 'x'); } std::vector mem2(2 * size); { - EXPECT_CALL(alloc, allocate(2 * size)).WillOnce(Return(&mem2[0])); + EXPECT_CALL(alloc, allocate(2 * size, 0)).WillOnce(Return(&mem2[0])); std::exception e; EXPECT_CALL(alloc, deallocate(&mem[0], size)).WillOnce(testing::Throw(e)); EXPECT_THROW(buffer.reserve(2 * size), std::exception); @@ -581,7 +581,7 @@ struct CustomFormatter { typedef char Char; }; -void format(CustomFormatter &, const char *&s, const Test &) { +void format_arg(CustomFormatter &, const char *&s, const Test &) { s = "custom_format"; } @@ -708,7 +708,7 @@ TEST(ArgVisitorTest, VisitUnhandledArg) { TEST(ArgVisitorTest, VisitInvalidArg) { Arg arg = Arg(); - arg.type = static_cast(Arg::CUSTOM + 1); + arg.type = static_cast(Arg::NONE); EXPECT_ASSERT(TestVisitor().visit(arg), "invalid argument type"); } @@ -834,10 +834,10 @@ void check_throw_error(int error_code, FormatErrorMessage format) { TEST(UtilTest, FormatSystemError) { fmt::MemoryWriter message; - fmt::internal::format_system_error(message, EDOM, "test"); + fmt::format_system_error(message, EDOM, "test"); EXPECT_EQ(fmt::format("test: {}", get_system_error(EDOM)), message.str()); message.clear(); - fmt::internal::format_system_error( + fmt::format_system_error( message, EDOM, fmt::StringRef(0, std::numeric_limits::max())); EXPECT_EQ(fmt::format("error {}", EDOM), message.str()); } @@ -846,12 +846,12 @@ TEST(UtilTest, SystemError) { fmt::SystemError e(EDOM, "test"); EXPECT_EQ(fmt::format("test: {}", get_system_error(EDOM)), e.what()); EXPECT_EQ(EDOM, e.error_code()); - check_throw_error(EDOM, fmt::internal::format_system_error); + check_throw_error(EDOM, fmt::format_system_error); } TEST(UtilTest, ReportSystemError) { fmt::MemoryWriter out; - fmt::internal::format_system_error(out, EDOM, "test error"); + fmt::format_system_error(out, EDOM, "test error"); out << '\n'; EXPECT_WRITE(stderr, fmt::report_system_error(EDOM, "test error"), out.str()); } @@ -956,3 +956,17 @@ TEST(UtilTest, Conditional) { fmt::internal::Conditional::type *pc = &c; (void)pc; } + +struct TestLConv { + char *thousands_sep; +}; + +struct EmptyLConv {}; + +TEST(UtilTest, ThousandsSep) { + char foo[] = "foo"; + TestLConv lc = {foo}; + EXPECT_EQ("foo", fmt::internal::thousands_sep(&lc).to_string()); + EmptyLConv empty_lc; + EXPECT_EQ("", fmt::internal::thousands_sep(&empty_lc)); +} diff --git a/libs/format/test/util.h b/libs/format/test/util.h index 21d76b2d2..b7faf62ae 100644 --- a/libs/format/test/util.h +++ b/libs/format/test/util.h @@ -87,6 +87,13 @@ const Char BasicTestString::EMPTY[] = {0}; typedef BasicTestString TestString; typedef BasicTestString TestWString; +template +std::basic_ostream &operator<<( + std::basic_ostream &os, const BasicTestString &s) { + os << s.value(); + return os; +} + class Date { int year_, month_, day_; public: diff --git a/zone/map.cpp b/zone/map.cpp index 32c6564b4..c1db6086d 100644 --- a/zone/map.cpp +++ b/zone/map.cpp @@ -1,5 +1,6 @@ #include "../common/global_define.h" #include "../common/misc_functions.h" +#include "../common/compression.h" #include "map.h" #include "raycast_mesh.h" @@ -10,83 +11,6 @@ #include #include #include -#include - - -uint32 EstimateDeflateBuffer(uint32_t len) { - z_stream zstream; - memset(&zstream, 0, sizeof(zstream)); - - zstream.zalloc = Z_NULL; - zstream.zfree = Z_NULL; - zstream.opaque = Z_NULL; - if (deflateInit(&zstream, Z_FINISH) != Z_OK) - return 0; - - return deflateBound(&zstream, len); -} - -uint32_t DeflateData(const char *buffer, uint32_t len, char *out_buffer, uint32_t out_len_max) { - z_stream zstream; - memset(&zstream, 0, sizeof(zstream)); - int zerror; - - zstream.next_in = const_cast(reinterpret_cast(buffer)); - zstream.avail_in = len; - zstream.zalloc = Z_NULL; - zstream.zfree = Z_NULL; - zstream.opaque = Z_NULL; - deflateInit(&zstream, Z_FINISH); - - zstream.next_out = reinterpret_cast(out_buffer); - zstream.avail_out = out_len_max; - zerror = deflate(&zstream, Z_FINISH); - - if (zerror == Z_STREAM_END) - { - deflateEnd(&zstream); - return (uint32_t)zstream.total_out; - } - else - { - zerror = deflateEnd(&zstream); - return 0; - } -} - -uint32 InflateData(const char* buffer, uint32 len, char* out_buffer, uint32 out_len_max) { - z_stream zstream; - int zerror = 0; - int i; - - zstream.next_in = const_cast(reinterpret_cast(buffer)); - zstream.avail_in = len; - zstream.next_out = reinterpret_cast(out_buffer);; - zstream.avail_out = out_len_max; - zstream.zalloc = Z_NULL; - zstream.zfree = Z_NULL; - zstream.opaque = Z_NULL; - - i = inflateInit2(&zstream, 15); - if (i != Z_OK) { - return 0; - } - - zerror = inflate(&zstream, Z_FINISH); - if (zerror == Z_STREAM_END) { - inflateEnd(&zstream); - return zstream.total_out; - } - else { - if (zerror == -4 && zstream.msg == 0) - { - return 0; - } - - zerror = inflateEnd(&zstream); - return 0; - } -} struct Map::impl { @@ -451,7 +375,7 @@ bool Map::LoadV2(FILE *f) { std::vector buffer; buffer.resize(buffer_size); - uint32 v = InflateData(&data[0], data_size, &buffer[0], buffer_size); + uint32 v = EQEmu::InflateData(&data[0], data_size, &buffer[0], buffer_size); char *buf = &buffer[0]; uint32 vert_count; diff --git a/zone/pathfinder_interface.cpp b/zone/pathfinder_interface.cpp index 2a60ada74..1773e275f 100644 --- a/zone/pathfinder_interface.cpp +++ b/zone/pathfinder_interface.cpp @@ -10,13 +10,13 @@ IPathfinder *IPathfinder::Load(const std::string &zone) { struct stat statbuffer; std::string waypoint_path = fmt::format("maps/{0}.path", zone); std::string navmesh_path = fmt::format("maps/{0}.nav", zone); + if (stat(navmesh_path.c_str(), &statbuffer) == 0) { + return new PathfinderNavmesh(navmesh_path); + } + if (stat(waypoint_path.c_str(), &statbuffer) == 0) { return new PathfinderWaypoint(waypoint_path); } - //if (stat(waypoint_path.c_str(), &statbuffer) == 0) { - // return new PathfinderNavmesh(navmesh_path); - //} - return new PathfinderNull(); } diff --git a/zone/pathfinder_nav_mesh.cpp b/zone/pathfinder_nav_mesh.cpp index e69de29bb..d20b595bc 100644 --- a/zone/pathfinder_nav_mesh.cpp +++ b/zone/pathfinder_nav_mesh.cpp @@ -0,0 +1,268 @@ +#include +#include +#include +#include +#include +#include "pathfinder_nav_mesh.h" + +#include "zone.h" +#include "client.h" +#include "../common/compression.h" + +struct PathfinderNavmesh::Implementation +{ + dtNavMesh *nav_mesh; + dtNavMeshQuery *query; +}; + +PathfinderNavmesh::PathfinderNavmesh(const std::string &path) +{ + m_impl.reset(new Implementation()); + m_impl->nav_mesh = nullptr; + m_impl->query = nullptr; +} + +PathfinderNavmesh::~PathfinderNavmesh() +{ + if (m_impl->nav_mesh) { + dtFreeNavMesh(m_impl->nav_mesh); + } + + if (m_impl->query) { + dtFreeNavMeshQuery(m_impl->query); + } +} + +IPathfinder::IPath PathfinderNavmesh::FindRoute(const glm::vec3 &start, const glm::vec3 &end) +{ + if (!m_impl->nav_mesh || !m_impl->query) { + IPath Route; + Route.push_back(start); + Route.push_back(end); + return Route; + } + + glm::vec3 ext(15.0f, 100.0f, 15.0f); + dtQueryFilter filter; + filter.setIncludeFlags(65535U); + filter.setAreaCost(0, 1.0f); //Normal + filter.setAreaCost(0, 1.0f); //Water + filter.setAreaCost(0, 1.0f); //Lava + filter.setAreaCost(0, 1.0f); //PvP + filter.setAreaCost(0, 1.0f); //Slime + filter.setAreaCost(0, 1.0f); //Ice + filter.setAreaCost(0, 1.0f); //V Water (Frigid Water) + filter.setAreaCost(0, 1.0f); //General Area + filter.setAreaCost(0, 1.0f); //Portal + + dtPolyRef start_ref; + dtPolyRef end_ref; + + m_impl->query->findNearestPoly(&start[0], &ext[0], &filter, &start_ref, 0); + m_impl->query->findNearestPoly(&end[0], &ext[0], &filter, &end_ref, 0); + + if (!start_ref || !end_ref) { + IPath Route; + Route.push_back(start); + Route.push_back(end); + return Route; + } + + int npoly = 0; + dtPolyRef path[1024] = { 0 }; + m_impl->query->findPath(start_ref, end_ref, &start[0], &end[0], &filter, path, &npoly, 1024); + + if (npoly) { + glm::vec3 epos = end; + if (path[npoly - 1] != end_ref) + m_impl->query->closestPointOnPoly(path[npoly - 1], &end[0], &epos[0], 0); + + float straight_path[2048 * 3]; + unsigned char straight_path_flags[2048]; + int n_straight_polys; + dtPolyRef straight_path_polys[2048]; + m_impl->query->findStraightPath(&start[0], &epos[0], path, npoly, + straight_path, straight_path_flags, + straight_path_polys, &n_straight_polys, 2048, DT_STRAIGHTPATH_ALL_CROSSINGS); + + if (n_straight_polys) { + IPath Route; + + for (int i = 0; i < n_straight_polys - 1; ++i) { + glm::vec3 color(1.0f, 1.0f, 0.0f); + unsigned short flag = 0; + if (dtStatusSucceed(m_impl->nav_mesh->getPolyFlags(straight_path_polys[i], &flag))) { + if (flag & 512) { //Portal + Route.push_back(true); + } + } + + Route.push_back(glm::vec3(straight_path[i * 3], straight_path[i * 3 + 1] + 0.4f, straight_path[i * 3 + 2])); + } + + return Route; + } + + IPath Route; + Route.push_back(start); + Route.push_back(end); + return Route; + } + else { + IPath Route; + Route.push_back(start); + Route.push_back(end); + return Route; + } +} + +glm::vec3 PathfinderNavmesh::GetRandomLocation() +{ + return glm::vec3(); +} + +void PathfinderNavmesh::DebugCommand(Client *c, const Seperator *sep) +{ + if (sep->arg[1][0] == '\0' || !strcasecmp(sep->arg[1], "help")) + { + c->Message(0, "#path show: Plots a path from the user to their target."); + return; + } + + if (!strcasecmp(sep->arg[1], "show")) + { + if (c->GetTarget() != nullptr) { + auto target = c->GetTarget(); + glm::vec3 start(c->GetX(), c->GetY(), c->GetZ()); + glm::vec3 end(target->GetX(), target->GetY(), target->GetZ()); + + ShowPath(c, start, end); + } + + return; + } +} + +void PathfinderNavmesh::Load(const std::string &path) +{ + if (m_impl->nav_mesh) { + dtFreeNavMesh(m_impl->nav_mesh); + m_impl->nav_mesh = nullptr; + } + + if (m_impl->query) { + dtFreeNavMeshQuery(m_impl->query); + m_impl->query = nullptr; + } + + FILE *f = fopen(path.c_str(), "rb"); + if (f) { + char magic[9] = { 0 }; + if (fread(magic, 9, 1, f) != 1) { + fclose(f); + return; + } + + if (strncmp(magic, "EQNAVMESH", 9) != 0) + { + fclose(f); + return; + } + + uint32_t version = 0; + if (fread(&version, sizeof(uint32_t), 1, f) != 1) { + fclose(f); + return; + } + + if (version != 2U) { + fclose(f); + return; + } + + uint32_t data_size; + if (fread(&data_size, sizeof(data_size), 1, f) != 1) { + fclose(f); + return; + } + + uint32_t buffer_size; + if (fread(&buffer_size, sizeof(buffer_size), 1, f) != 1) { + fclose(f); + return; + } + + std::vector data; + data.resize(data_size); + if (fread(&data[0], data_size, 1, f) != 1) { + fclose(f); + return; + } + + std::vector buffer; + buffer.resize(buffer_size); + uint32_t v = EQEmu::InflateData(&data[0], data_size, &buffer[0], buffer_size); + fclose(f); + + char *buf = &buffer[0]; + m_impl->nav_mesh = dtAllocNavMesh(); + + uint32_t number_of_tiles = *(uint32_t*)buf; + buf += sizeof(uint32_t); + + dtNavMeshParams params = *(dtNavMeshParams*)buf; + buf += sizeof(dtNavMeshParams); + + dtStatus status = m_impl->nav_mesh->init(¶ms); + if (dtStatusFailed(status)) + { + dtFreeNavMesh(m_impl->nav_mesh); + m_impl->nav_mesh = nullptr; + return; + } + + for (unsigned int i = 0; i < number_of_tiles; ++i) + { + uint32_t tile_ref = *(uint32_t*)buf; + buf += sizeof(uint32_t); + + int32_t data_size = *(uint32_t*)buf; + buf += sizeof(uint32_t); + + if (!tile_ref || !data_size) { + dtFreeNavMesh(m_impl->nav_mesh); + m_impl->nav_mesh = nullptr; + return; + } + + unsigned char* data = (unsigned char*)dtAlloc(data_size, DT_ALLOC_PERM); + memcpy(data, buf, data_size); + buf += data_size; + + m_impl->nav_mesh->addTile(data, data_size, DT_TILE_FREE_DATA, tile_ref, 0); + } + + m_impl->query = dtAllocNavMeshQuery(); + m_impl->query->init(m_impl->nav_mesh, 32768); + } +} + +void PathfinderNavmesh::ShowPath(Client * c, const glm::vec3 & start, const glm::vec3 & end) +{ + auto path = FindRoute(start, end); + std::vector points; + + FindPerson_Point p; + for (auto &node : path) + { + if (!node.teleport) { + p.x = node.pos.x; + p.y = node.pos.y; + p.z = node.pos.z; + + points.push_back(p); + } + } + + c->SendPathPacket(points); +} diff --git a/zone/pathfinder_nav_mesh.h b/zone/pathfinder_nav_mesh.h index bec5c1b44..6229cd791 100644 --- a/zone/pathfinder_nav_mesh.h +++ b/zone/pathfinder_nav_mesh.h @@ -1,14 +1,22 @@ #pragma once #include "pathfinder_interface.h" +#include class PathfinderNavmesh : public IPathfinder { public: - PathfinderNavmesh() { } - virtual ~PathfinderNavmesh() { } + PathfinderNavmesh(const std::string &path); + virtual ~PathfinderNavmesh(); virtual IPath FindRoute(const glm::vec3 &start, const glm::vec3 &end); virtual glm::vec3 GetRandomLocation(); virtual void DebugCommand(Client *c, const Seperator *sep); + +private: + void Load(const std::string &path); + void ShowPath(Client *c, const glm::vec3 &start, const glm::vec3 &end); + + struct Implementation; + std::unique_ptr m_impl; }; \ No newline at end of file