diff --git a/dep/CMakeLists.txt b/dep/CMakeLists.txt index 86fdd8f38ad..1a02ca3ec5c 100644 --- a/dep/CMakeLists.txt +++ b/dep/CMakeLists.txt @@ -24,7 +24,7 @@ if(SERVERS OR TOOLS) add_subdirectory(zlib) add_subdirectory(g3dlite) add_subdirectory(recastnavigation) - add_subdirectory(cppformat) + add_subdirectory(fmt) add_subdirectory(SFMT) add_subdirectory(utf8cpp) add_subdirectory(valgrind) diff --git a/dep/PackageList.txt b/dep/PackageList.txt index 574c27d2042..43416499c21 100644 --- a/dep/PackageList.txt +++ b/dep/PackageList.txt @@ -14,7 +14,7 @@ bzip2 (a freely available, patent free, high-quality data compressor) cppformat (type safe format library) https://github.com/cppformat/cppformat - Version: 5174b8ca281426af604b85fdf53be8a748b33f56 + Version: 3.0.1 7fa8f8fa48b0903deab5bb42e6760477173ac485 efws (Entropia File System Watcher - crossplatform file system watcher) https://bitbucket.org/SpartanJ/efsw diff --git a/dep/cppformat/CMakeLists.txt b/dep/fmt/CMakeLists.txt similarity index 66% rename from dep/cppformat/CMakeLists.txt rename to dep/fmt/CMakeLists.txt index 1cbff49b871..6d25fb49791 100644 --- a/dep/cppformat/CMakeLists.txt +++ b/dep/fmt/CMakeLists.txt @@ -16,22 +16,25 @@ else () endif () set(FMT_SOURCES - ${CMAKE_CURRENT_SOURCE_DIR}/cppformat/format.h - ${CMAKE_CURRENT_SOURCE_DIR}/cppformat/format.cc) + ${CMAKE_CURRENT_SOURCE_DIR}/fmt/format.h + ${CMAKE_CURRENT_SOURCE_DIR}/fmt/format.cc + ${CMAKE_CURRENT_SOURCE_DIR}/fmt/ostream.h + ${CMAKE_CURRENT_SOURCE_DIR}/fmt/ostream.cc + ${CMAKE_CURRENT_SOURCE_DIR}/fmt/time.h) if (HAVE_OPEN) set(FMT_SOURCES ${FMT_SOURCES} - ${CMAKE_CURRENT_SOURCE_DIR}/cppformat/posix.h - ${CMAKE_CURRENT_SOURCE_DIR}/cppformat/posix.cc) + ${CMAKE_CURRENT_SOURCE_DIR}/fmt/posix.h + ${CMAKE_CURRENT_SOURCE_DIR}/fmt/posix.cc) endif() -add_library(cppformat STATIC ${FMT_SOURCES}) +add_library(fmt STATIC ${FMT_SOURCES}) -target_include_directories(cppformat +target_include_directories(fmt PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) -set_target_properties(cppformat +set_target_properties(fmt PROPERTIES FOLDER "dep") diff --git a/dep/cppformat/ChangeLog.rst b/dep/fmt/ChangeLog.rst similarity index 50% rename from dep/cppformat/ChangeLog.rst rename to dep/fmt/ChangeLog.rst index d2a77f8712f..f4df68b6a12 100644 --- a/dep/cppformat/ChangeLog.rst +++ b/dep/fmt/ChangeLog.rst @@ -1,3 +1,232 @@ +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 +------------------ + +* The project has been renamed from C++ Format (cppformat) to fmt for + consistency with the used namespace and macro prefix + (`#307 `_). + Library headers are now located in the ``fmt`` directory: + + .. code:: c++ + + #include "fmt/format.h" + + Including ``format.h`` from the ``cppformat`` directory is deprecated + but works via a proxy header which will be removed in the next major version. + + The documentation is now available at http://fmtlib.net. + +* Added support for `strftime `_-like + `date and time formatting `_ + (`#283 `_): + + .. code:: c++ + + #include "fmt/time.h" + + std::time_t t = std::time(nullptr); + // Prints "The date is 2016-04-29." (with the current date) + fmt::print("The date is {:%Y-%m-%d}.", *std::localtime(&t)); + +* ``std::ostream`` support including formatting of user-defined types that provide + overloaded ``operator<<`` has been moved to ``fmt/ostream.h``: + + .. code:: c++ + + #include "fmt/ostream.h" + + class Date { + int year_, month_, day_; + public: + Date(int year, int month, int day) : year_(year), month_(month), day_(day) {} + + friend std::ostream &operator<<(std::ostream &os, const Date &d) { + return os << d.year_ << '-' << d.month_ << '-' << d.day_; + } + }; + + std::string s = fmt::format("The date is {}", Date(2012, 12, 9)); + // s == "The date is 2012-12-9" + +* Added support for `custom argument formatters + `_ + (`#235 `_). + +* Added support for locale-specific integer formatting with the ``n`` specifier + (`#305 `_): + + .. code:: c++ + + std::setlocale(LC_ALL, "en_US.utf8"); + fmt::print("cppformat: {:n}\n", 1234567); // prints 1,234,567 + +* Sign is now preserved when formatting an integer with an incorrect ``printf`` + format specifier (`#265 `_): + + .. code:: c++ + + fmt::printf("%lld", -42); // prints -42 + + Note that it would be an undefined behavior in ``std::printf``. + +* Length modifiers such as ``ll`` are now optional in printf formatting + functions and the correct type is determined automatically + (`#255 `_): + + .. code:: c++ + + fmt::printf("%d", std::numeric_limits::max()); + + Note that it would be an undefined behavior in ``std::printf``. + +* Added initial support for custom formatters + (`#231 `_). + +* Fixed detection of user-defined literal support on Intel C++ compiler + (`#311 `_, + `#312 `_). + Thanks to `@dean0x7d (Dean Moldovan) `_ and + `@speth (Ray Speth) `_. + +* Reduced compile time + (`#243 `_, + `#249 `_, + `#317 `_): + + .. image:: https://cloud.githubusercontent.com/assets/4831417/11614060/ + b9e826d2-9c36-11e5-8666-d4131bf503ef.png + + .. image:: https://cloud.githubusercontent.com/assets/4831417/11614080/ + 6ac903cc-9c37-11e5-8165-26df6efae364.png + + Thanks to `@dean0x7d (Dean Moldovan) `_. + +* Compile test fixes (`#313 `_). + Thanks to `@dean0x7d (Dean Moldovan) `_. + +* Documentation fixes (`#239 `_, + `#248 `_, + `#252 `_, + `#258 `_, + `#260 `_, + `#301 `_, + `#309 `_). + Thanks to `@ReadmeCritic `_ + `@Gachapen (Magnus Bjerke Vik) `_ and + `@jwilk (Jakub Wilk) `_. + +* Fixed compiler and sanitizer warnings ( + `#244 `_, + `#256 `_, + `#259 `_, + `#263 `_, + `#274 `_, + `#277 `_, + `#286 `_, + `#291 `_, + `#296 `_, + `#308 `_) + Thanks to `@mwinterb `_, + `@pweiskircher (Patrik Weiskircher) `_, + `@Naios `_. + +* Improved compatibility with Windows Store apps + (`#280 `_, + `#285 `_) + Thanks to `@mwinterb `_. + +* Added tests of compatibility with older C++ standards + (`#273 `_). + Thanks to `@niosHD `_. + +* Fixed Android build (`#271 `_). + Thanks to `@newnon `_. + +* Changed ``ArgMap`` to be backed by a vector instead of a map. + (`#261 `_, + `#262 `_). + Thanks to `@mwinterb `_. + +* Added ``fprintf`` overload that writes to a ``std::ostream`` + (`#251 `_). + Thanks to `nickhutchinson (Nicholas Hutchinson) `_. + +* Export symbols when building a Windows DLL + (`#245 `_). + Thanks to `macdems (Maciek Dems) `_. + +* Fixed compilation on Cygwin (`#304 `_). + +* Implemented a workaround for a bug in Apple LLVM version 4.2 of clang + (`#276 `_). + +* Implemented a workaround for Google Test bug + `#705 `_ on gcc 6 + (`#268 `_). + Thanks to `octoploid `_. + +* Removed Biicode support because the latter has been discontinued. + +2.1.1 - 2016-04-11 +------------------ + +* The install location for generated CMake files is now configurable via + the ``FMT_CMAKE_DIR`` CMake variable + (`#299 `_). + Thanks to `@niosHD `_. + +* Documentation fixes (`#252 `_). + +2.1.0 - 2016-03-21 +------------------ + +* Project layout and build system improvements + (`#267 `_): + + * The code have been moved to the ``cppformat`` directory. + Including ``format.h`` from the top-level directory is deprecated + but works via a proxy header which will be removed in the next + major version. + + * C++ Format CMake targets now have proper interface definitions. + + * Installed version of the library now supports the header-only + configuration. + + * Targets ``doc``, ``install``, and ``test`` are now disabled if C++ Format + is included as a CMake subproject. They can be enabled by setting + ``FMT_DOC``, ``FMT_INSTALL``, and ``FMT_TEST`` in the parent project. + + Thanks to `@niosHD `_. + +2.0.1 - 2016-03-13 +------------------ + +* Improved CMake find and package support + (`#264 `_). + Thanks to `@niosHD `_. + +* Fix compile error with Android NDK and mingw32 + (`#241 `_). + Thanks to `@Gachapen (Magnus Bjerke Vik) `_. + +* Documentation fixes + (`#248 `_, + `#260 `_). + 2.0.0 - 2015-12-01 ------------------ @@ -5,9 +234,9 @@ General ~~~~~~~ * [Breaking] Named arguments - (`#169 `_, - `#173 `_, - `#174 `_): + (`#169 `_, + `#173 `_, + `#174 `_): .. code:: c++ @@ -16,9 +245,9 @@ General Thanks to `@jamboree `_. * [Experimental] User-defined literals for format and named arguments - (`#204 `_, - `#206 `_, - `#207 `_): + (`#204 `_, + `#206 `_, + `#207 `_): .. code:: c++ @@ -29,11 +258,11 @@ General * [Breaking] Formatting of more than 16 arguments is now supported when using variadic templates - (`#141 `_). + (`#141 `_). Thanks to `@Shauren `_. * Runtime width specification - (`#168 `_): + (`#168 `_): .. code:: c++ @@ -43,10 +272,10 @@ General * [Breaking] Enums are now formatted with an overloaded ``std::ostream`` insertion operator (``operator<<``) if available - (`#232 `_). + (`#232 `_). * [Breaking] Changed default ``bool`` format to textual, "true" or "false" - (`#170 `_): + (`#170 `_): .. code:: c++ @@ -60,7 +289,7 @@ General * ``fmt::printf`` and ``fmt::sprintf`` now support formatting of ``bool`` with the ``%s`` specifier giving textual output, "true" or "false" - (`#223 `_): + (`#223 `_): .. code:: c++ @@ -69,10 +298,10 @@ General Thanks to `@LarsGullik `_. * [Breaking] ``signed char`` and ``unsigned char`` are now formatted as integers by default - (`#217 `_). + (`#217 `_). * [Breaking] Pointers to C strings can now be formatted with the ``p`` specifier - (`#223 `_): + (`#223 `_): .. code:: c++ @@ -82,12 +311,12 @@ General * [Breaking] ``fmt::printf`` and ``fmt::sprintf`` now print null pointers as ``(nil)`` and null strings as ``(null)`` for consistency with glibc - (`#226 `_). + (`#226 `_). Thanks to `@LarsGullik `_. * [Breaking] ``fmt::(s)printf`` now supports formatting of objects of user-defined types that provide an overloaded ``std::ostream`` insertion operator (``operator<<``) - (`#201 `_): + (`#201 `_): .. code:: c++ @@ -95,15 +324,15 @@ General * [Breaking] The ``Buffer`` template is now part of the public API and can be used to implement custom memory buffers - (`#140 `_). + (`#140 `_). Thanks to `@polyvertex (Jean-Charles Lefebvre) `_. * [Breaking] Improved compatibility between ``BasicStringRef`` and `std::experimental::basic_string_view `_ - (`#100 `_, - `#159 `_, - `#183 `_): + (`#100 `_, + `#159 `_, + `#183 `_): - Comparison operators now compare string content, not pointers - ``BasicStringRef::c_str`` replaced by ``BasicStringRef::data`` @@ -113,40 +342,40 @@ General ``BasicCStringRef``. * Dependency on pthreads introduced by Google Test is now optional - (`#185 `_). + (`#185 `_). * New CMake options ``FMT_DOC``, ``FMT_INSTALL`` and ``FMT_TEST`` to control generation of ``doc``, ``install`` and ``test`` targets respectively, on by default - (`#197 `_, - `#198 `_, - `#200 `_). + (`#197 `_, + `#198 `_, + `#200 `_). Thanks to `@maddinat0r (Alex Martin) `_. * ``noexcept`` is now used when compiling with MSVC2015 - (`#215 `_). + (`#215 `_). Thanks to `@dmkrepo (Dmitriy) `_. * Added an option to disable use of ``windows.h`` when ``FMT_USE_WINDOWS_H`` is defined as 0 before including ``format.h`` - (`#171 `_). + (`#171 `_). Thanks to `@alfps (Alf P. Steinbach) `_. * [Breaking] ``windows.h`` is now included with ``NOMINMAX`` unless ``FMT_WIN_MINMAX`` is defined. This is done to prevent breaking code using ``std::min`` and ``std::max`` and only affects the header-only configuration - (`#152 `_, - `#153 `_, - `#154 `_). + (`#152 `_, + `#153 `_, + `#154 `_). Thanks to `@DevO2012 `_. * Improved support for custom character types - (`#171 `_). + (`#171 `_). Thanks to `@alfps (Alf P. Steinbach) `_. * Added an option to disable use of IOStreams when ``FMT_USE_IOSTREAMS`` is defined as 0 before including ``format.h`` - (`#205 `_, - `#208 `_). + (`#205 `_, + `#208 `_). Thanks to `@JodiTheTigger `_. * Improved detection of ``isnan``, ``isinf`` and ``signbit``. @@ -155,31 +384,31 @@ Optimization ~~~~~~~~~~~~ * Made formatting of user-defined types more efficient with a custom stream buffer - (`#92 `_, - `#230 `_). + (`#92 `_, + `#230 `_). Thanks to `@NotImplemented `_. * Further improved performance of ``fmt::Writer`` on integer formatting and fixed a minor regression. Now it is ~7% faster than ``karma::generate`` on Karma's benchmark - (`#186 `_). + (`#186 `_). * [Breaking] Reduced `compiled code size - `_ - (`#143 `_, - `#149 `_). + `_ + (`#143 `_, + `#149 `_). Distribution ~~~~~~~~~~~~ * [Breaking] Headers are now installed in ``${CMAKE_INSTALL_PREFIX}/include/cppformat`` - (`#178 `_). + (`#178 `_). Thanks to `@jackyf (Eugene V. Lyubimkin) `_. * [Breaking] Changed the library name from ``format`` to ``cppformat`` for consistency with the project name and to avoid potential conflicts - (`#178 `_). + (`#178 `_). Thanks to `@jackyf (Eugene V. Lyubimkin) `_. * C++ Format is now available in `Debian `_ GNU/Linux @@ -187,7 +416,7 @@ Distribution `sid `_) and derived distributions such as `Ubuntu `_ 15.10 and later - (`#155 `_):: + (`#155 `_):: $ sudo apt-get install libcppformat1-dev @@ -197,7 +426,7 @@ Distribution are now available. Thanks to Dave Johansen. * C++ Format can now be installed via `Homebrew `_ on OS X - (`#157 `_):: + (`#157 `_):: $ brew install cppformat @@ -208,47 +437,47 @@ Documentation * Migrated from ReadTheDocs to GitHub Pages for better responsiveness and reliability - (`#128 `_). + (`#128 `_). New documentation address is http://cppformat.github.io/. * Added `Building the documentation - `_ + `_ section to the documentation. * Documentation build script is now compatible with Python 3 and newer pip versions. - (`#189 `_, - `#209 `_). + (`#189 `_, + `#209 `_). Thanks to `@JodiTheTigger `_ and `@xentec `_. * Documentation fixes and improvements - (`#36 `_, - `#75 `_, - `#125 `_, - `#160 `_, - `#161 `_, - `#162 `_, - `#165 `_, - `#210 `_). + (`#36 `_, + `#75 `_, + `#125 `_, + `#160 `_, + `#161 `_, + `#162 `_, + `#165 `_, + `#210 `_). Thanks to `@syohex (Syohei YOSHIDA) `_ and bug reporters. * Fixed out-of-tree documentation build - (`#177 `_). + (`#177 `_). Thanks to `@jackyf (Eugene V. Lyubimkin) `_. Fixes ~~~~~ * Fixed ``initializer_list`` detection - (`#136 `_). + (`#136 `_). Thanks to `@Gachapen (Magnus Bjerke Vik) `_. * [Breaking] Fixed formatting of enums with numeric format specifiers in ``fmt::(s)printf`` - (`#131 `_, - `#139 `_): + (`#131 `_, + `#139 `_): .. code:: c++ @@ -258,51 +487,53 @@ Fixes Thanks to `@Naios `_. * Improved compatibility with old versions of MinGW - (`#129 `_, - `#130 `_, - `#132 `_). + (`#129 `_, + `#130 `_, + `#132 `_). Thanks to `@cstamford (Christopher Stamford) `_. * Fixed a compile error on MSVC with disabled exceptions - (`#144 `_). + (`#144 `_). * Added a workaround for broken implementation of variadic templates in MSVC2012 - (`#148 `_). + (`#148 `_). * Placed the anonymous namespace within ``fmt`` namespace for the header-only configuration - (`#171 `_). + (`#171 `_). Thanks to `@alfps (Alf P. Steinbach) `_. * Fixed issues reported by Coverity Scan - (`#187 `_, - `#192 `_). + (`#187 `_, + `#192 `_). * Implemented a workaround for a name lookup bug in MSVC2010 - (`#188 `_). + (`#188 `_). * Fixed compiler warnings - (`#95 `_, - `#96 `_, - `#114 `_, - `#135 `_, - `#142 `_, - `#145 `_, - `#146 `_, - `#158 `_, - `#163 `_, - `#175 `_, - `#190 `_, - `#191 `_, - `#194 `_, - `#196 `_, - `#216 `_, - `#218 `_, - `#220 `_, - `#229 `_, - `#233 `_, - `#234 `_, - `#236 `_). + (`#95 `_, + `#96 `_, + `#114 `_, + `#135 `_, + `#142 `_, + `#145 `_, + `#146 `_, + `#158 `_, + `#163 `_, + `#175 `_, + `#190 `_, + `#191 `_, + `#194 `_, + `#196 `_, + `#216 `_, + `#218 `_, + `#220 `_, + `#229 `_, + `#233 `_, + `#234 `_, + `#236 `_, + `#281 `_, + `#289 `_). Thanks to `@seanmiddleditch (Sean Middleditch) `_, `@dixlorenz (Dix Lorenz) `_, `@CarterLi (李通洲) `_, @@ -319,36 +550,36 @@ Fixes * Fixed portability issues (mostly causing test failures) on ARM, ppc64, ppc64le, s390x and SunOS 5.11 i386 ( - `#138 `_, - `#179 `_, - `#180 `_, - `#202 `_, - `#225 `_, + `#138 `_, + `#179 `_, + `#180 `_, + `#202 `_, + `#225 `_, `Red Hat Bugzilla Bug 1260297 `_). Thanks to `@Naios `_, `@jackyf (Eugene V. Lyubimkin) `_ and Dave Johansen. * Fixed a name conflict with macro ``free`` defined in ``crtdbg.h`` when ``_CRTDBG_MAP_ALLOC`` is set - (`#211 `_). + (`#211 `_). * Fixed shared library build on OS X - (`#212 `_). + (`#212 `_). Thanks to `@dean0x7d (Dean Moldovan) `_. * Fixed an overload conflict on MSVC when ``/Zc:wchar_t-`` option is specified - (`#214 `_). + (`#214 `_). Thanks to `@slavanap (Vyacheslav Napadovsky) `_. * Improved compatibility with MSVC 2008 - (`#236 `_). + (`#236 `_). Thanks to `@Jopie64 (Johan) `_. * Improved compatibility with bcc32 - (`#227 `_). + (`#227 `_). * Fixed ``static_assert`` detection on Clang - (`#228 `_). + (`#228 `_). Thanks to `@dean0x7d (Dean Moldovan) `_. 1.1.0 - 2015-03-06 @@ -356,8 +587,8 @@ Fixes * Added ``BasicArrayWriter``, a class template that provides operations for formatting and writing data into a fixed-size array - (`#105 `_ and - `#122 `_): + (`#105 `_ and + `#122 `_): .. code:: c++ @@ -369,58 +600,58 @@ Fixes `_ to the list of notable projects using C++ Format. * C++ Format now uses MSVC intrinsics for better formatting performance - (`#115 `_, - `#116 `_, - `#118 `_ and - `#121 `_). + (`#115 `_, + `#116 `_, + `#118 `_ and + `#121 `_). Previously these optimizations where only used on GCC and Clang. Thanks to `@CarterLi `_ and `@objectx `_. -* CMake install target (`#119 `_). +* CMake install target (`#119 `_). Thanks to `@TrentHouliston `_. You can now install C++ Format with ``make install`` command. * Improved `Biicode `_ support - (`#98 `_ and - `#104 `_). Thanks to + (`#98 `_ and + `#104 `_). Thanks to `@MariadeAnton `_ and `@franramirez688 `_. -* Improved support for bulding with `Android NDK +* Improved support for building with `Android NDK `_ - (`#107 `_). + (`#107 `_). Thanks to `@newnon `_. - The `android-ndk-example `_ + The `android-ndk-example `_ repository provides and example of using C++ Format with Android NDK: - .. image:: https://raw.githubusercontent.com/cppformat/android-ndk-example/ + .. image:: https://raw.githubusercontent.com/fmtlib/android-ndk-example/ master/screenshot.png * Improved documentation of ``SystemError`` and ``WindowsError`` - (`#54 `_). + (`#54 `_). * Various code improvements - (`#110 `_, - `#111 `_ - `#112 `_). + (`#110 `_, + `#111 `_ + `#112 `_). Thanks to `@CarterLi `_. * Improved compile-time errors when formatting wide into narrow strings - (`#117 `_). + (`#117 `_). * Fixed ``BasicWriter::write`` without formatting arguments when C++11 support - is disabled (`#109 `_). + is disabled (`#109 `_). * Fixed header-only build on OS X with GCC 4.9 - (`#124 `_). + (`#124 `_). -* Fixed packaging issues (`#94 `_). +* Fixed packaging issues (`#94 `_). -* Added `changelog `_ - (`#103 `_). +* Added `changelog `_ + (`#103 `_). 1.0.0 - 2015-02-05 ------------------ @@ -435,29 +666,29 @@ Fixes * Compute string length in the constructor of ``BasicStringRef`` instead of the ``size`` method - (`#79 `_). + (`#79 `_). This eliminates size computation for string literals on reasonable optimizing compilers. * Fix formatting of types with overloaded ``operator <<`` for ``std::wostream`` - (`#86 `_): + (`#86 `_): .. code:: c++ fmt::format(L"The date is {0}", Date(2012, 12, 9)); * Fix linkage of tests on Arch Linux - (`#89 `_). + (`#89 `_). * Allow precision specifier for non-float arguments - (`#90 `_): + (`#90 `_): .. code:: c++ fmt::print("{:.3}\n", "Carpet"); // prints "Car" * Fix build on Android NDK - (`#93 `_) + (`#93 `_) * Improvements to documentation build procedure. @@ -498,17 +729,17 @@ Fixes This doesn't affect the formatting API. * Support for custom memory allocators - (`#69 `_) + (`#69 `_) * Formatting functions now accept `signed char` and `unsigned char` strings as - arguments (`#73 `_): + arguments (`#73 `_): .. code:: c++ auto s = format("GLSL version: {}", glGetString(GL_VERSION)); * Reduced code bloat. According to the new `benchmark results - `_, + `_, cppformat is close to ``printf`` and by the order of magnitude better than Boost Format in terms of compiled code size. @@ -538,7 +769,7 @@ Fixes fmt::printf("%1$s, %3$d %2$s", weekday, month, day); * Arguments of ``char`` type can now be formatted as integers - (Issue `#55 `_): + (Issue `#55 `_): .. code:: c++ @@ -574,7 +805,7 @@ Fixes Apart from a more natural syntax, this also improves performance as there is no need to construct temporary formatter objects and control arguments' - lifetimes. Because the wrapper functions are very ligthweight, this doesn't + lifetimes. Because the wrapper functions are very lightweight, this doesn't cause code bloat even in pre-C++11 mode. * Simplified common case of formatting an ``std::string``. Now it requires a @@ -607,7 +838,7 @@ Fixes Now all public functions are lowercase following the standard library conventions. Previously it was a combination of lowercase and CapitalizedWords. - Issue `#50 `_. + Issue `#50 `_. * Old functions are marked as deprecated and will be removed in the next release. diff --git a/dep/cppformat/LICENSE.rst b/dep/fmt/LICENSE.rst similarity index 96% rename from dep/cppformat/LICENSE.rst rename to dep/fmt/LICENSE.rst index b1c96ca02c8..eb6be6503e9 100644 --- a/dep/cppformat/LICENSE.rst +++ b/dep/fmt/LICENSE.rst @@ -1,4 +1,4 @@ -Copyright (c) 2012 - 2015, Victor Zverovich +Copyright (c) 2012 - 2016, Victor Zverovich All rights reserved. diff --git a/dep/cppformat/README.rst b/dep/fmt/README.rst similarity index 82% rename from dep/cppformat/README.rst rename to dep/fmt/README.rst index e859f909466..846d0eb0979 100644 --- a/dep/cppformat/README.rst +++ b/dep/fmt/README.rst @@ -1,62 +1,64 @@ -C++ Format -========== +{fmt} +===== -.. image:: https://travis-ci.org/cppformat/cppformat.png?branch=master - :target: https://travis-ci.org/cppformat/cppformat +.. image:: https://travis-ci.org/fmtlib/fmt.png?branch=master + :target: https://travis-ci.org/fmtlib/fmt -.. image:: https://ci.appveyor.com/api/projects/status/qk0bhyhqp1ekpat8 - :target: https://ci.appveyor.com/project/vitaut/cppformat +.. image:: https://ci.appveyor.com/api/projects/status/ehjkiefde6gucy1v + :target: https://ci.appveyor.com/project/vitaut/fmt .. image:: https://badges.gitter.im/Join%20Chat.svg - :alt: Join the chat at https://gitter.im/cppformat/cppformat - :target: https://gitter.im/cppformat/cppformat?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge + :alt: Join the chat at https://gitter.im/fmtlib/fmt + :target: https://gitter.im/fmtlib/fmt -C++ Format is an open-source formatting library for C++. +**fmt** is an open-source formatting library for C++. It can be used as a safe alternative to printf or as a fast alternative to IOStreams. -`Documentation `_ +`Documentation `_ 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 - `_ + `_ similar to the one used by `str.format `_ in Python. * Safe `printf implementation - `_ + `_ including the POSIX extension for positional arguments. * Support for user-defined types. * High speed: performance of the format API is close to that of glibc's `printf `_ - and better than 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 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 - `_. + `_. * Safety: the library is fully type safe, errors in format strings are reported using exceptions, automatic memory management prevents buffer overflow errors. * Ease of use: small self-contained code base, no external dependencies, permissive BSD `license - `_ -* `Portability `_ with consistent output + `_ +* `Portability `_ with consistent output across platforms and support for older compilers. * Clean warning-free codebase even on high warning levels (-Wall -Wextra -pedantic). * Support for wide strings. * Optional header-only configuration enabled with the ``FMT_HEADER_ONLY`` macro. -See the `documentation `_ for more details. +See the `documentation `_ for more details. Examples -------- @@ -75,7 +77,7 @@ Arguments can be accessed by position and arguments' indices can be repeated: std::string s = fmt::format("{0}{1}{0}", "abra", "cad"); // s == "abracadabra" -C++ Format can be used as a safe portable replacement for ``itoa``: +fmt can be used as a safe portable replacement for ``itoa``: .. code:: c++ @@ -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: @@ -103,10 +107,10 @@ An object of any user-defined type for which there is an overloaded // s == "The date is 2012-12-9" You can use the `FMT_VARIADIC -`_ +`_ macro to create your own functions similar to `format -`_ and -`print `_ +`_ and +`print `_ which take arbitrary arguments: .. code:: c++ @@ -132,6 +136,8 @@ Projects using this library * `AMPL/MP `_: An open-source library for mathematical programming +* `CUAUV `_: Cornell University's autonomous underwater vehicle + * `HarpyWar/pvpgn `_: Player vs Player Gaming Network with tweaks @@ -158,6 +164,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 @@ -170,7 +182,7 @@ Projects using this library If you are aware of other projects using this library, please let me know by `email `_ or by submitting an -`issue `_. +`issue `_. Motivation ---------- @@ -281,14 +293,14 @@ The following speed tests results were generated by building runs. In the test, the format string ``"%0.10f:%04d:%+g:%s:%p:%c:%%\n"`` or equivalent is filled 2000000 times with output sent to ``/dev/null``; for further details see the `source -`_. +`_. ================= ============= =========== Library Method Run Time, s ================= ============= =========== EGLIBC 2.19 printf 1.30 libstdc++ 4.8.2 std::ostream 1.85 -C++ Format 1.0 fmt::print 1.42 +fmt 1.0 fmt::print 1.42 tinyformat 2.0.1 tfm::printf 2.25 Boost Format 1.54 boost::format 9.94 ================= ============= =========== @@ -297,7 +309,7 @@ As you can see ``boost::format`` is much slower than the alternative methods; th is confirmed by `other tests `_. Tinyformat is quite good coming close to IOStreams. Unfortunately tinyformat cannot be faster than the IOStreams because it uses them internally. -Performance of cppformat is close to that of printf, being `faster than printf on integer +Performance of fmt is close to that of printf, being `faster than printf on integer formatting `_, but slower on floating-point formatting which dominates this benchmark. @@ -305,8 +317,8 @@ Compile time and code bloat ~~~~~~~~~~~~~~~~~~~~~~~~~~~ The script `bloat-test.py -`_ -from `format-benchmark `_ +`_ +from `format-benchmark `_ tests compile time and code bloat for nontrivial projects. It generates 100 translation units and uses ``printf()`` or its alternative five times in each to simulate a medium sized project. The resulting @@ -320,12 +332,12 @@ Method Compile Time, s Executable size, KiB Stripped size, KiB ============ =============== ==================== ================== printf 2.6 41 30 IOStreams 19.4 92 70 -C++ Format 46.8 46 34 +fmt 46.8 46 34 tinyformat 64.6 418 386 Boost Format 222.8 990 923 ============ =============== ==================== ================== -As you can see, C++ Format has two times less overhead in terms of resulting +As you can see, fmt has two times less overhead in terms of resulting code size compared to IOStreams and comes pretty close to ``printf``. Boost Format has by far the largest overheads. @@ -336,12 +348,12 @@ Method Compile Time, s Executable size, KiB Stripped size, KiB ============ =============== ==================== ================== printf 2.1 41 30 IOStreams 19.7 86 62 -C++ Format 47.9 108 86 +fmt 47.9 108 86 tinyformat 27.7 234 190 Boost Format 122.6 884 763 ============ =============== ==================== ================== -``libc``, ``libstdc++`` and ``libformat`` are all linked as shared +``libc``, ``libstdc++`` and ``libfmt`` are all linked as shared libraries to compare formatting function overhead only. Boost Format and tinyformat are header-only libraries so they don't provide any linkage options. @@ -352,14 +364,14 @@ Running the tests Please refer to `Building the library`__ for the instructions on how to build the library and run the unit tests. -__ http://cppformat.github.io/latest/usage.html#building-the-library +__ http://fmtlib.net/latest/usage.html#building-the-library Benchmarks reside in a separate repository, -`format-benchmarks `_, +`format-benchmarks `_, so to run the benchmarks you first need to clone this repository and generate Makefiles with CMake:: - $ git clone --recursive https://github.com/cppformat/format-benchmark.git + $ git clone --recursive https://github.com/fmtlib/format-benchmark.git $ cd format-benchmark $ cmake . @@ -374,18 +386,18 @@ or the bloat test:: License ------- -C++ Format is distributed under the BSD `license -`_. +fmt is distributed under the BSD `license +`_. The `Format String Syntax -`_ +`_ section in the documentation is based on the one from Python `string module documentation `_ adapted for the current library. For this reason the documentation is distributed under the Python Software Foundation license available in `doc/python-license.txt -`_. -It only applies if you distribute the documentation of C++ Format. +`_. +It only applies if you distribute the documentation of fmt. Acknowledgments --------------- diff --git a/dep/cppformat/cppformat/format.cc b/dep/fmt/cppformat/format.cc similarity index 100% rename from dep/cppformat/cppformat/format.cc rename to dep/fmt/cppformat/format.cc diff --git a/dep/fmt/cppformat/format.h b/dep/fmt/cppformat/format.h new file mode 100644 index 00000000000..3fbf86b894c --- /dev/null +++ b/dep/fmt/cppformat/format.h @@ -0,0 +1,2 @@ +#include "../fmt/format.h" +#warning Including cppformat/format.h is deprecated. Include fmt/format.h instead. diff --git a/dep/cppformat/cppformat/posix.cc b/dep/fmt/cppformat/posix.cc similarity index 100% rename from dep/cppformat/cppformat/posix.cc rename to dep/fmt/cppformat/posix.cc diff --git a/dep/fmt/cppformat/posix.h b/dep/fmt/cppformat/posix.h new file mode 100644 index 00000000000..97b6fadcdea --- /dev/null +++ b/dep/fmt/cppformat/posix.h @@ -0,0 +1,2 @@ +#include "../fmt/posix.h" +#warning Including cppformat/posix.h is deprecated. Include fmt/posix.h instead. diff --git a/dep/fmt/fmt/format.cc b/dep/fmt/fmt/format.cc new file mode 100644 index 00000000000..2bd774e4408 --- /dev/null +++ b/dep/fmt/fmt/format.cc @@ -0,0 +1,940 @@ +/* + Formatting library for C++ + + Copyright (c) 2012 - 2016, Victor Zverovich + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "format.h" + +#include + +#include +#include +#include +#include +#include +#include // for std::ptrdiff_t + +#if defined(_WIN32) && defined(__MINGW32__) +# include +#endif + +#if FMT_USE_WINDOWS_H +# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX) +# include +# else +# define NOMINMAX +# include +# undef NOMINMAX +# endif +#endif + +using fmt::internal::Arg; + +#if FMT_EXCEPTIONS +# define FMT_TRY try +# define FMT_CATCH(x) catch (x) +#else +# define FMT_TRY if (true) +# define FMT_CATCH(x) if (false) +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4127) // conditional expression is constant +# pragma warning(disable: 4702) // unreachable code +// Disable deprecation warning for strerror. The latter is not called but +// MSVC fails to detect it. +# pragma warning(disable: 4996) +#endif + +// Dummy implementations of strerror_r and strerror_s called if corresponding +// system functions are not available. +static inline fmt::internal::Null<> strerror_r(int, char *, ...) { + return fmt::internal::Null<>(); +} +static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) { + return fmt::internal::Null<>(); +} + +namespace fmt { + +FMT_FUNC internal::RuntimeError::~RuntimeError() throw() {} +FMT_FUNC FormatError::~FormatError() throw() {} +FMT_FUNC SystemError::~SystemError() throw() {} + +namespace { + +#ifndef _MSC_VER +# define FMT_SNPRINTF snprintf +#else // _MSC_VER +inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) { + va_list args; + va_start(args, format); + int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args); + va_end(args); + return result; +} +# define FMT_SNPRINTF fmt_snprintf +#endif // _MSC_VER + +#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) +# define FMT_SWPRINTF snwprintf +#else +# define FMT_SWPRINTF swprintf +#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) + +// 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); + +// Portable thread-safe version of strerror. +// Sets buffer to point to a string describing the error code. +// This can be either a pointer to a string stored in buffer, +// or a pointer to some static immutable string. +// Returns one of the following values: +// 0 - success +// ERANGE - buffer is not large enough to store the error message +// other - failure +// Buffer should be at least of size 1. +int safe_strerror( + int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT { + FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer"); + + class StrError { + private: + int error_code_; + char *&buffer_; + std::size_t buffer_size_; + + // A noop assignment operator to avoid bogus warnings. + void operator=(const StrError &) {} + + // Handle the result of XSI-compliant version of strerror_r. + int handle(int result) { + // glibc versions before 2.13 return result in errno. + return result == -1 ? errno : result; + } + + // Handle the result of GNU-specific version of strerror_r. + int handle(char *message) { + // If the buffer is full then the message is probably truncated. + if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1) + return ERANGE; + buffer_ = message; + return 0; + } + + // Handle the case when strerror_r is not available. + int handle(internal::Null<>) { + return fallback(strerror_s(buffer_, buffer_size_, error_code_)); + } + + // Fallback to strerror_s when strerror_r is not available. + int fallback(int result) { + // If the buffer is full then the message is probably truncated. + return result == 0 && strlen(buffer_) == buffer_size_ - 1 ? + ERANGE : result; + } + + // Fallback to strerror if strerror_r and strerror_s are not available. + int fallback(internal::Null<>) { + errno = 0; + buffer_ = strerror(error_code_); + return errno; + } + + public: + StrError(int err_code, char *&buf, std::size_t buf_size) + : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {} + + int run() { + strerror_r(0, 0, ""); // Suppress a warning about unused strerror_r. + return handle(strerror_r(error_code_, buffer_, buffer_size_)); + } + }; + return StrError(error_code, buffer, buffer_size).run(); +} + +void format_error_code(Writer &out, int error_code, + StringRef message) FMT_NOEXCEPT { + // Report error code making sure that the output fits into + // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential + // bad_alloc. + out.clear(); + static const char SEP[] = ": "; + static const char ERROR_STR[] = "error "; + // Subtract 2 to account for terminating null characters in SEP and ERROR_STR. + std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2; + typedef internal::IntTraits::MainType MainType; + MainType abs_value = static_cast(error_code); + if (internal::is_negative(error_code)) { + abs_value = 0 - abs_value; + ++error_code_size; + } + error_code_size += internal::count_digits(abs_value); + if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size) + out << message << SEP; + out << ERROR_STR << error_code; + assert(out.size() <= internal::INLINE_BUFFER_SIZE); +} + +void report_error(FormatFunc func, int error_code, + StringRef message) FMT_NOEXCEPT { + MemoryWriter full_message; + func(full_message, error_code, message); + // Use Writer::data instead of Writer::c_str to avoid potential memory + // allocation. + std::fwrite(full_message.data(), full_message.size(), 1, stderr); + std::fputc('\n', stderr); +} + +// 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( + 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)); + std::runtime_error &base = *this; + base = std::runtime_error(w.str()); +} + +template +int fmt::internal::CharTraits::format_float( + char *buffer, std::size_t size, const char *format, + unsigned width, int precision, T value) { + if (width == 0) { + return precision < 0 ? + FMT_SNPRINTF(buffer, size, format, value) : + FMT_SNPRINTF(buffer, size, format, precision, value); + } + return precision < 0 ? + FMT_SNPRINTF(buffer, size, format, width, value) : + FMT_SNPRINTF(buffer, size, format, width, precision, value); +} + +template +int fmt::internal::CharTraits::format_float( + wchar_t *buffer, std::size_t size, const wchar_t *format, + unsigned width, int precision, T value) { + if (width == 0) { + return precision < 0 ? + FMT_SWPRINTF(buffer, size, format, value) : + FMT_SWPRINTF(buffer, size, format, precision, value); + } + return precision < 0 ? + FMT_SWPRINTF(buffer, size, format, width, value) : + FMT_SWPRINTF(buffer, size, format, width, precision, value); +} + +template +const char fmt::internal::BasicData::DIGITS[] = + "0001020304050607080910111213141516171819" + "2021222324252627282930313233343536373839" + "4041424344454647484950515253545556575859" + "6061626364656667686970717273747576777879" + "8081828384858687888990919293949596979899"; + +#define FMT_POWERS_OF_10(factor) \ + factor * 10, \ + factor * 100, \ + factor * 1000, \ + factor * 10000, \ + factor * 100000, \ + factor * 1000000, \ + factor * 10000000, \ + factor * 100000000, \ + factor * 1000000000 + +template +const uint32_t fmt::internal::BasicData::POWERS_OF_10_32[] = { + 0, FMT_POWERS_OF_10(1) +}; + +template +const uint64_t fmt::internal::BasicData::POWERS_OF_10_64[] = { + 0, + FMT_POWERS_OF_10(1), + FMT_POWERS_OF_10(fmt::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 +}; + +FMT_FUNC void fmt::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(fmt::FormatError( + fmt::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) { + 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); + if (length == 0) + FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); + buffer_.resize(length + 1); + length = MultiByteToWideChar( + CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length); + if (length == 0) + FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); + buffer_[length] = 0; +} + +FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::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) { + 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); + if (length == 0) + return GetLastError(); + buffer_.resize(length + 1); + length = WideCharToMultiByte( + CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, 0, 0); + if (length == 0) + return GetLastError(); + buffer_[length] = 0; + return 0; +} + +FMT_FUNC void fmt::WindowsError::init( + int err_code, CStringRef format_str, ArgList args) { + error_code_ = err_code; + MemoryWriter w; + internal::format_windows_error(w, err_code, format(format_str, args)); + std::runtime_error &base = *this; + base = std::runtime_error(w.str()); +} + +FMT_FUNC void fmt::internal::format_windows_error( + fmt::Writer &out, int error_code, + fmt::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); + if (result != 0) { + UTF16ToUTF8 utf8_message; + if (utf8_message.convert(system_message) == ERROR_SUCCESS) { + out << message << ": " << utf8_message; + return; + } + break; + } + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) + break; // Can't get error message, report error code instead. + buffer.resize(buffer.size() * 2); + } + } FMT_CATCH(...) {} + fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. +} + +#endif // FMT_USE_WINDOWS_H + +FMT_FUNC void fmt::internal::format_system_error( + fmt::Writer &out, int error_code, + fmt::StringRef message) FMT_NOEXCEPT { + FMT_TRY { + MemoryBuffer buffer; + buffer.resize(INLINE_BUFFER_SIZE); + for (;;) { + char *system_message = &buffer[0]; + int result = safe_strerror(error_code, system_message, buffer.size()); + if (result == 0) { + out << message << ": " << system_message; + return; + } + if (result != ERANGE) + break; // Can't get error message, report error code instead. + buffer.resize(buffer.size() * 2); + } + } FMT_CATCH(...) {} + fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. +} + +template +void fmt::internal::ArgMap::init(const ArgList &args) { + if (!map_.empty()) + return; + typedef internal::NamedArg NamedArg; + const NamedArg *named_arg = 0; + bool use_values = + args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE; + if (use_values) { + for (unsigned i = 0;/*nothing*/; ++i) { + internal::Arg::Type arg_type = args.type(i); + switch (arg_type) { + case internal::Arg::NONE: + return; + case internal::Arg::NAMED_ARG: + named_arg = static_cast(args.values_[i].pointer); + map_.push_back(Pair(named_arg->name, *named_arg)); + break; + default: + /*nothing*/; + } + } + return; + } + for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) { + internal::Arg::Type arg_type = args.type(i); + if (arg_type == internal::Arg::NAMED_ARG) { + named_arg = static_cast(args.args_[i].pointer); + map_.push_back(Pair(named_arg->name, *named_arg)); + } + } + for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) { + switch (args.args_[i].type) { + case internal::Arg::NONE: + return; + case internal::Arg::NAMED_ARG: + named_arg = static_cast(args.args_[i].pointer); + map_.push_back(Pair(named_arg->name, *named_arg)); + break; + default: + /*nothing*/; + } + } +} + +template +void fmt::internal::FixedBuffer::grow(std::size_t) { + FMT_THROW(std::runtime_error("buffer overflow")); +} + +FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg( + unsigned arg_index, const char *&error) { + Arg arg = args_[arg_index]; + switch (arg.type) { + case Arg::NONE: + error = "argument index out of range"; + break; + case Arg::NAMED_ARG: + arg = *static_cast(arg.pointer); + break; + default: + /*nothing*/; + } + 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( + int error_code, fmt::StringRef message) FMT_NOEXCEPT { + // 'fmt::' is for bcc32. + fmt::report_error(internal::format_system_error, error_code, message); +} + +#if FMT_USE_WINDOWS_H +FMT_FUNC void fmt::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); +} +#endif + +FMT_FUNC void fmt::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) { + print(stdout, format_str, args); +} + +FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) { + char escape[] = "\x1b[30m"; + escape[3] = static_cast('0' + c); + std::fputs(escape, stdout); + print(format, args); + std::fputs(RESET_COLOR, stdout); +} + +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; + +// Explicit instantiations for char. + +template void fmt::internal::FixedBuffer::grow(std::size_t); + +template void fmt::internal::ArgMap::init(const fmt::ArgList &args); + +template void fmt::internal::PrintfFormatter::format( + BasicWriter &writer, CStringRef format); + +template int fmt::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( + 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 fmt::internal::ArgMap::init(const fmt::ArgList &args); + +template void fmt::internal::PrintfFormatter::format( + BasicWriter &writer, WCStringRef format); + +template int fmt::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( + wchar_t *buffer, std::size_t size, const wchar_t *format, + unsigned width, int precision, long double value); + +#endif // FMT_HEADER_ONLY + +#ifdef _MSC_VER +# pragma warning(pop) +#endif diff --git a/dep/cppformat/cppformat/format.h b/dep/fmt/fmt/format.h similarity index 90% rename from dep/cppformat/cppformat/format.h rename to dep/fmt/fmt/format.h index 08bb9b5d9e8..f8ce147cb38 100644 --- a/dep/cppformat/cppformat/format.h +++ b/dep/fmt/fmt/format.h @@ -1,7 +1,7 @@ /* Formatting library for C++ - Copyright (c) 2012 - 2015, Victor Zverovich + Copyright (c) 2012 - 2016, Victor Zverovich All rights reserved. Redistribution and use in source and binary forms, with or without @@ -29,6 +29,7 @@ #define FMT_FORMAT_H_ #include +#include #include #include #include @@ -39,14 +40,6 @@ #include #include -#ifndef FMT_USE_IOSTREAMS -# define FMT_USE_IOSTREAMS 1 -#endif - -#if FMT_USE_IOSTREAMS -# include -#endif - #ifdef _SECURE_SCL # define FMT_SECURE_SCL _SECURE_SCL #else @@ -57,7 +50,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; @@ -98,9 +97,16 @@ typedef __int64 intmax_t; # define FMT_GCC_EXTENSION #endif -#if defined(__clang__) && !defined(__INTEL_COMPILER) +#if defined(__INTEL_COMPILER) +# define FMT_ICC_VERSION __INTEL_COMPILER +#elif defined(__ICL) +# define FMT_ICC_VERSION __ICL +#endif + +#if defined(__clang__) && !defined(FMT_ICC_VERSION) # 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__ @@ -131,7 +137,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 @@ -142,7 +148,7 @@ 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 @@ -154,7 +160,7 @@ typedef __int64 intmax_t; #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 @@ -169,7 +175,7 @@ typedef __int64 intmax_t; # endif #endif -// Define FMT_USE_NOEXCEPT to make C++ Format use noexcept (C++11 feature). +// Define FMT_USE_NOEXCEPT to make fmt use noexcept (C++11 feature). #ifndef FMT_USE_NOEXCEPT # define FMT_USE_NOEXCEPT 0 #endif @@ -178,7 +184,7 @@ typedef __int64 intmax_t; # if FMT_EXCEPTIONS # if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \ - _MSC_VER >= 1900 + FMT_MSC_VER >= 1900 # define FMT_NOEXCEPT noexcept # else # define FMT_NOEXCEPT throw() @@ -188,6 +194,17 @@ typedef __int64 intmax_t; # endif #endif +#ifndef FMT_OVERRIDE +# if 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 + + // 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 @@ -195,7 +212,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; \ @@ -211,17 +228,18 @@ typedef __int64 intmax_t; // All compilers which support UDLs also support variadic templates. This // makes the fmt::literals implementation easier. However, an explicit check // for variadic templates is added here just in case. +// For Intel's compiler both it and the system gcc/msc must support UDLs. # 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_ASSERT # define FMT_ASSERT(condition, message) assert((condition) && message) #endif - #if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz) # define FMT_BUILTIN_CLZ(n) __builtin_clz(n) #endif @@ -230,11 +248,11 @@ typedef __int64 intmax_t; # 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) # include // _BitScanReverse, _BitScanReverse64 namespace fmt { @@ -246,7 +264,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 +290,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; @@ -302,7 +320,7 @@ inline DummyInt _isnan(...) { return DummyInt(); } // 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 @@ -321,8 +339,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)); @@ -332,8 +350,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; @@ -342,7 +360,7 @@ 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(int))) return signbit(x) != 0; if (x < 0) return true; if (!isnotanumber(x)) return false; @@ -372,10 +390,11 @@ typedef BasicWriter Writer; typedef BasicWriter WWriter; template -class BasicFormatter; +class ArgFormatter; -template -void format(BasicFormatter &f, const Char *&format_str, const T &value); +template > +class BasicFormatter; /** \rst @@ -523,13 +542,12 @@ 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() throw(); }; namespace internal { @@ -655,8 +673,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: @@ -668,7 +686,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()) @@ -828,6 +846,16 @@ struct FMT_API BasicData { static const char DIGITS[]; }; +#ifndef FMT_USE_EXTERN_TEMPLATES +// Clang doesn't have a feature check for extern templates so we check +// for variadic templates which were introduced in the same version. +# define FMT_USE_EXTERN_TEMPLATES (__clang__ && FMT_USE_VARIADIC_TEMPLATES) +#endif + +#if FMT_USE_EXTERN_TEMPLATES && !defined(FMT_HEADER_ONLY) +extern template struct BasicData; +#endif + typedef BasicData<> Data; #ifdef FMT_BUILTIN_CLZLL @@ -865,9 +893,39 @@ inline unsigned count_digits(uint32_t n) { } #endif +// A functor that doesn't add a thousands separator. +struct NoThousandsSep { + template + void operator()(Char *) {} +}; + +// A functor that adds a thousands separator. +class ThousandsSep { + private: + fmt::StringRef sep_; + + // Index of a decimal digit with the least significant digit having index 0. + unsigned digit_index_; + + public: + explicit ThousandsSep(fmt::StringRef sep) : sep_(sep), digit_index_(0) {} + + template + void operator()(Char *&buffer) { + if (++digit_index_ % 3 != 0) + return; + buffer -= sep_.size(); + std::uninitialized_copy(sep_.data(), sep_.data() + sep_.size(), + internal::make_ptr(buffer, sep_.size())); + } +}; + // Formats a decimal unsigned integer value writing into buffer. -template -inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) { +// thousands_sep is a functor that is called after writing each char to +// add a thousands separator if necessary. +template +inline void format_decimal(Char *buffer, UInt value, unsigned num_digits, + ThousandsSep thousands_sep) { buffer += num_digits; while (value >= 100) { // Integer division is slow so do it for a group of two digits instead @@ -876,7 +934,9 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) { unsigned index = static_cast((value % 100) * 2); value /= 100; *--buffer = Data::DIGITS[index + 1]; + thousands_sep(buffer); *--buffer = Data::DIGITS[index]; + thousands_sep(buffer); } if (value < 10) { *--buffer = static_cast('0' + value); @@ -884,9 +944,15 @@ 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()); +} + #ifndef _WIN32 # define FMT_USE_WINDOWS_H 0 #elif !defined(FMT_USE_WINDOWS_H) @@ -1007,33 +1073,16 @@ struct WCharHelper { typedef char Yes[1]; typedef char No[2]; -// These are non-members to workaround an overload resolution bug in bcc32. -Yes &convert(fmt::ULongLong); -Yes &convert(std::ostream &); -No &convert(...); - template T &get(); -struct DummyStream : std::ostream { - DummyStream(); // Suppress a bogus warning in MSVC. - // Hide all operator<< overloads from std::ostream. - void operator<<(Null<>); -}; - -No &operator<<(std::ostream &, int); +// These are non-members to workaround an overload resolution bug in bcc32. +Yes &convert(fmt::ULongLong); +No &convert(...); template struct ConvertToIntImpl { - enum { value = false }; -}; - -template -struct ConvertToIntImpl { - // Convert to int only if T doesn't have an overloaded operator<<. - enum { - value = sizeof(convert(get() << get())) == sizeof(No) - }; + enum { value = ENABLE_CONVERSION }; }; template @@ -1083,6 +1132,21 @@ struct Not { enum { value = 0 }; }; template<> struct Not { enum { value = 1 }; }; +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 ""; } + // Makes an Arg object from any type. template class MakeValue : public Arg { @@ -1104,7 +1168,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); @@ -1150,7 +1214,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; @@ -1160,7 +1224,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; @@ -1192,7 +1256,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) @@ -1246,7 +1312,7 @@ public: MakeArg() { type = Arg::NONE; } - + template MakeArg(const T &value) : Arg(MakeValue(value)) { @@ -1263,126 +1329,10 @@ struct NamedArg : Arg { : Arg(MakeArg< BasicFormatter >(value)), name(argname) {} }; -#define FMT_DISPATCH(call) static_cast(this)->call - -// An argument visitor. -// To use ArgVisitor define a subclass that implements some or all of the -// visit methods with the same signatures as the methods in ArgVisitor, -// for example, visit_int(int). -// Specify the subclass name as the Impl template parameter. Then calling -// ArgVisitor::visit for some argument will dispatch to a visit method -// specific to the argument type. For example, if the argument type is -// double then visit_double(double) method of a subclass will be called. -// If the subclass doesn't contain a method with this signature, then -// a corresponding method of ArgVisitor will be called. -// -// Example: -// class MyArgVisitor : public ArgVisitor { -// public: -// void visit_int(int value) { print("{}", value); } -// void visit_double(double value) { print("{}", value ); } -// }; -// -// ArgVisitor uses the curiously recurring template pattern: -// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern -template -class ArgVisitor { - public: - void report_unhandled_arg() {} - - Result visit_unhandled_arg() { - FMT_DISPATCH(report_unhandled_arg()); - return Result(); - } - - Result visit_int(int value) { - return FMT_DISPATCH(visit_any_int(value)); - } - Result visit_long_long(LongLong value) { - return FMT_DISPATCH(visit_any_int(value)); - } - Result visit_uint(unsigned value) { - return FMT_DISPATCH(visit_any_int(value)); - } - Result visit_ulong_long(ULongLong value) { - return FMT_DISPATCH(visit_any_int(value)); - } - Result visit_bool(bool value) { - return FMT_DISPATCH(visit_any_int(value)); - } - Result visit_char(int value) { - return FMT_DISPATCH(visit_any_int(value)); - } - template - Result visit_any_int(T) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - Result visit_double(double value) { - return FMT_DISPATCH(visit_any_double(value)); - } - Result visit_long_double(long double value) { - return FMT_DISPATCH(visit_any_double(value)); - } - template - Result visit_any_double(T) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - Result visit_cstring(const char *) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - Result visit_string(Arg::StringValue) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - Result visit_wstring(Arg::StringValue) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - Result visit_pointer(const void *) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - Result visit_custom(Arg::CustomValue) { - return FMT_DISPATCH(visit_unhandled_arg()); - } - - Result visit(const Arg &arg) { - switch (arg.type) { - default: - FMT_ASSERT(false, "invalid argument type"); - return Result(); - case Arg::INT: - return FMT_DISPATCH(visit_int(arg.int_value)); - case Arg::UINT: - return FMT_DISPATCH(visit_uint(arg.uint_value)); - case Arg::LONG_LONG: - return FMT_DISPATCH(visit_long_long(arg.long_long_value)); - case Arg::ULONG_LONG: - return FMT_DISPATCH(visit_ulong_long(arg.ulong_long_value)); - case Arg::BOOL: - return FMT_DISPATCH(visit_bool(arg.int_value != 0)); - case Arg::CHAR: - return FMT_DISPATCH(visit_char(arg.int_value)); - case Arg::DOUBLE: - return FMT_DISPATCH(visit_double(arg.double_value)); - case Arg::LONG_DOUBLE: - return FMT_DISPATCH(visit_long_double(arg.long_double_value)); - case Arg::CSTRING: - return FMT_DISPATCH(visit_cstring(arg.string.value)); - case Arg::STRING: - return FMT_DISPATCH(visit_string(arg.string)); - case Arg::WSTRING: - return FMT_DISPATCH(visit_wstring(arg.wstring)); - case Arg::POINTER: - return FMT_DISPATCH(visit_pointer(arg.pointer)); - case Arg::CUSTOM: - return FMT_DISPATCH(visit_custom(arg.custom)); - } - } -}; - class RuntimeError : public std::runtime_error { protected: RuntimeError() : std::runtime_error("") {} + ~RuntimeError() throw(); }; template @@ -1456,6 +1406,167 @@ class ArgList { } }; +#define FMT_DISPATCH(call) static_cast(this)->call + +/** + \rst + An argument visitor based on the `curiously recurring template pattern + `_. + + To use `~fmt::ArgVisitor` define a subclass that implements some or all of the + visit methods with the same signatures as the methods in `~fmt::ArgVisitor`, + for example, `~fmt::ArgVisitor::visit_int()`. + Pass the subclass as the *Impl* template parameter. Then calling + `~fmt::ArgVisitor::visit` for some argument will dispatch to a visit method + specific to the argument type. For example, if the argument type is + ``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass + will be called. If the subclass doesn't contain a method with this signature, + then a corresponding method of `~fmt::ArgVisitor` will be called. + + **Example**:: + + class MyArgVisitor : public fmt::ArgVisitor { + public: + void visit_int(int value) { fmt::print("{}", value); } + void visit_double(double value) { fmt::print("{}", value ); } + }; + \endrst + */ +template +class ArgVisitor { + private: + typedef internal::Arg Arg; + + public: + void report_unhandled_arg() {} + + Result visit_unhandled_arg() { + FMT_DISPATCH(report_unhandled_arg()); + return Result(); + } + + /** Visits an ``int`` argument. **/ + Result visit_int(int value) { + return FMT_DISPATCH(visit_any_int(value)); + } + + /** Visits a ``long long`` argument. **/ + Result visit_long_long(LongLong value) { + return FMT_DISPATCH(visit_any_int(value)); + } + + /** Visits an ``unsigned`` argument. **/ + Result visit_uint(unsigned value) { + return FMT_DISPATCH(visit_any_int(value)); + } + + /** Visits an ``unsigned long long`` argument. **/ + Result visit_ulong_long(ULongLong value) { + return FMT_DISPATCH(visit_any_int(value)); + } + + /** Visits a ``bool`` argument. **/ + Result visit_bool(bool value) { + return FMT_DISPATCH(visit_any_int(value)); + } + + /** Visits a ``char`` or ``wchar_t`` argument. **/ + Result visit_char(int value) { + return FMT_DISPATCH(visit_any_int(value)); + } + + /** Visits an argument of any integral type. **/ + template + Result visit_any_int(T) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + + /** Visits a ``double`` argument. **/ + Result visit_double(double value) { + return FMT_DISPATCH(visit_any_double(value)); + } + + /** Visits a ``long double`` argument. **/ + Result visit_long_double(long double value) { + return FMT_DISPATCH(visit_any_double(value)); + } + + /** Visits a ``double`` or ``long double`` argument. **/ + template + Result visit_any_double(T) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + + /** Visits a null-terminated C string (``const char *``) argument. **/ + Result visit_cstring(const char *) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + + /** Visits a string argument. **/ + Result visit_string(Arg::StringValue) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + + /** Visits a wide string argument. **/ + Result visit_wstring(Arg::StringValue) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + + /** Visits a pointer argument. **/ + Result visit_pointer(const void *) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + + /** Visits an argument of a custom (user-defined) type. **/ + Result visit_custom(Arg::CustomValue) { + return FMT_DISPATCH(visit_unhandled_arg()); + } + + /** + \rst + Visits an argument dispatching to the appropriate visit method based on + the argument type. For example, if the argument type is ``double`` then + the `~fmt::ArgVisitor::visit_double()` method of the *Impl* class will be + called. + \endrst + */ + Result visit(const Arg &arg) { + switch (arg.type) { + case Arg::NONE: + case Arg::NAMED_ARG: + FMT_ASSERT(false, "invalid argument type"); + break; + case Arg::INT: + return FMT_DISPATCH(visit_int(arg.int_value)); + case Arg::UINT: + return FMT_DISPATCH(visit_uint(arg.uint_value)); + case Arg::LONG_LONG: + return FMT_DISPATCH(visit_long_long(arg.long_long_value)); + case Arg::ULONG_LONG: + return FMT_DISPATCH(visit_ulong_long(arg.ulong_long_value)); + case Arg::BOOL: + return FMT_DISPATCH(visit_bool(arg.int_value != 0)); + case Arg::CHAR: + return FMT_DISPATCH(visit_char(arg.int_value)); + case Arg::DOUBLE: + return FMT_DISPATCH(visit_double(arg.double_value)); + case Arg::LONG_DOUBLE: + return FMT_DISPATCH(visit_long_double(arg.long_double_value)); + case Arg::CSTRING: + return FMT_DISPATCH(visit_cstring(arg.string.value)); + case Arg::STRING: + return FMT_DISPATCH(visit_string(arg.string)); + case Arg::WSTRING: + return FMT_DISPATCH(visit_wstring(arg.wstring)); + case Arg::POINTER: + return FMT_DISPATCH(visit_pointer(arg.pointer)); + case Arg::CUSTOM: + return FMT_DISPATCH(visit_custom(arg.custom)); + } + return Result(); + } +}; + enum Alignment { ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC }; @@ -1682,7 +1793,8 @@ namespace internal { template class ArgMap { private: - typedef std::vector, internal::Arg> > MapType; + typedef std::vector< + std::pair, internal::Arg> > MapType; typedef typename MapType::value_type Pair; MapType map_; @@ -1757,21 +1869,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); } @@ -1799,24 +1911,6 @@ class ArgFormatterBase : public ArgVisitor { } }; -// An argument formatter. -template -class BasicArgFormatter : - public ArgFormatterBase, Char> { - private: - BasicFormatter &formatter_; - const Char *format_; - - public: - BasicArgFormatter(BasicFormatter &f, FormatSpec &s, const Char *fmt) - : ArgFormatterBase, Char>(f.writer(), s), - formatter_(f), format_(fmt) {} - - void visit_custom(Arg::CustomValue c) { - c.format(&formatter_, c.value, &format_); - } -}; - class FormatterBase { private: ArgList args_; @@ -1884,8 +1978,61 @@ class PrintfFormatter : private FormatterBase { }; } // namespace internal +/** + \rst + An argument formatter based on the `curiously recurring template pattern + `_. + + To use `~fmt::BasicArgFormatter` define a subclass that implements some or + all of the visit methods with the same signatures as the methods in + `~fmt::ArgVisitor`, for example, `~fmt::ArgVisitor::visit_int()`. + Pass the subclass as the *Impl* template parameter. When a formatting + function processes an argument, it will dispatch to a visit method + specific to the argument type. For example, if the argument type is + ``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass + will be called. If the subclass doesn't contain a method with this signature, + then a corresponding method of `~fmt::BasicArgFormatter` or its superclass + will be called. + \endrst + */ +template +class BasicArgFormatter : public internal::ArgFormatterBase { + private: + BasicFormatter &formatter_; + const Char *format_; + + public: + /** + \rst + Constructs an argument formatter object. + *formatter* is a reference to the main formatter object, *spec* contains + format specifier information for standard argument types, and *fmt* points + to the part of the format string being parsed for custom argument types. + \endrst + */ + BasicArgFormatter(BasicFormatter &formatter, + FormatSpec &spec, const Char *fmt) + : internal::ArgFormatterBase(formatter.writer(), spec), + formatter_(formatter), format_(fmt) {} + + /** Formats argument of a custom (user-defined) type. */ + void visit_custom(internal::Arg::CustomValue c) { + c.format(&formatter_, c.value, &format_); + } +}; + +/** The default argument formatter. */ +template +class ArgFormatter : public BasicArgFormatter, Char> { + public: + /** Constructs an argument formatter object. */ + ArgFormatter(BasicFormatter &formatter, + FormatSpec &spec, const Char *fmt) + : BasicArgFormatter, Char>(formatter, spec, fmt) {} +}; + /** This template formats data and writes the output to a writer. */ -template +template class BasicFormatter : private internal::FormatterBase { public: /** The character type for the output. */ @@ -1963,14 +2110,18 @@ struct ArgArray; template struct ArgArray { typedef Value Type[N > 0 ? N : 1]; - + template static Value make(const T &value) { +#ifdef __clang__ Value result = MakeValue(value); // Workaround a bug in Apple LLVM version 4.2 (clang-425.0.28) of clang: - // https://github.com/cppformat/cppformat/issues/276 + // https://github.com/fmtlib/fmt/issues/276 (void)result.custom.format; return result; +#else + return MakeValue(value); +#endif } }; @@ -2008,38 +2159,6 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { (t12.type << 48) | (t13.type << 52) | (t14.type << 56); } #endif - -template -class FormatBuf : public std::basic_streambuf { - private: - typedef typename std::basic_streambuf::int_type int_type; - typedef typename std::basic_streambuf::traits_type traits_type; - - Buffer &buffer_; - Char *start_; - - public: - FormatBuf(Buffer &buffer) : buffer_(buffer), start_(&buffer[0]) { - this->setp(start_, start_ + buffer_.capacity()); - } - - int_type overflow(int_type ch = traits_type::eof()) { - if (!traits_type::eq_int_type(ch, traits_type::eof())) { - size_t size = this->size(); - buffer_.resize(size); - buffer_.reserve(size * 2); - - start_ = &buffer_[0]; - start_[size] = traits_type::to_char_type(ch); - this->setp(start_+ size + 1, start_ + size * 2); - } - return ch; - } - - size_t size() const { - return to_unsigned(this->pptr() - start_); - } -}; } // namespace internal # define FMT_MAKE_TEMPLATE_ARG(n) typename T##n @@ -2186,6 +2305,8 @@ class SystemError : public internal::RuntimeError { } FMT_VARIADIC_CTOR(SystemError, init, int, CStringRef) + ~SystemError() throw(); + int error_code() const { return error_code_; } }; @@ -2476,6 +2597,8 @@ class BasicWriter { } void clear() FMT_NOEXCEPT { buffer_.clear(); } + + Buffer &buffer() FMT_NOEXCEPT { return buffer_; } }; template @@ -2514,7 +2637,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_); @@ -2621,9 +2743,8 @@ void BasicWriter::write_int(T value, Spec spec) { switch (spec.type()) { case 0: case 'd': { unsigned num_digits = internal::count_digits(abs_value); - CharPtr p = prepare_int_buffer( - num_digits, spec, prefix, prefix_size) + 1 - num_digits; - internal::format_decimal(get(p), abs_value, num_digits); + CharPtr p = prepare_int_buffer(num_digits, spec, prefix, prefix_size) + 1; + internal::format_decimal(get(p), abs_value, 0); break; } case 'x': case 'X': { @@ -2678,6 +2799,18 @@ void BasicWriter::write_int(T value, Spec spec) { } while ((n >>= 3) != 0); break; } + case 'n': { + unsigned num_digits = internal::count_digits(abs_value); + fmt::StringRef sep = ""; +#ifndef ANDROID + sep = internal::thousands_sep(std::localeconv()); +#endif + unsigned size = static_cast( + num_digits + sep.size() * ((num_digits - 1) / 3)); + CharPtr p = prepare_int_buffer(size, spec, prefix, prefix_size) + 1; + internal::format_decimal(get(p), abs_value, 0, internal::ThousandsSep(sep)); + break; + } default: internal::report_unknown_type( spec.type(), spec.flag(CHAR_FLAG) ? "char" : "integer"); @@ -2698,7 +2831,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 @@ -2791,7 +2924,7 @@ void BasicWriter::write_double(T value, const FormatSpec &spec) { Char *start = 0; 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. @@ -2958,20 +3091,6 @@ class BasicArrayWriter : public BasicWriter { typedef BasicArrayWriter ArrayWriter; typedef BasicArrayWriter WArrayWriter; -// Formats a value. -template -void format(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()); - typedef internal::MakeArg< BasicFormatter > MakeArg; - format_str = f.format(format_str, MakeArg(str)); -} - // Reports a system error without throwing an exception. // Can be used to report errors from destructors. FMT_API void report_system_error(int error_code, @@ -3401,32 +3520,6 @@ FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef) FMT_VARIADIC(int, printf, CStringRef) FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef) -#if FMT_USE_IOSTREAMS -/** - \rst - Prints formatted data to the stream *os*. - - **Example**:: - - print(cerr, "Don't {}!", "panic"); - \endrst - */ -FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args); -FMT_VARIADIC(void, print, std::ostream &, CStringRef) - -/** - \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) -#endif - namespace internal { template inline bool is_name_start(Char c) { @@ -3475,9 +3568,9 @@ void check_sign(const Char *&s, const Arg &arg) { } } // namespace internal -template -inline internal::Arg BasicFormatter::get_arg( - BasicStringRef arg_name, const char *&error) { +template +inline internal::Arg BasicFormatter::get_arg( + BasicStringRef arg_name, const char *&error) { if (check_no_auto_index(error)) { map_.init(args()); const internal::Arg *arg = map_.find(arg_name); @@ -3488,8 +3581,8 @@ inline internal::Arg BasicFormatter::get_arg( return internal::Arg(); } -template -inline internal::Arg BasicFormatter::parse_arg_index(const Char *&s) { +template +inline internal::Arg BasicFormatter::parse_arg_index(const Char *&s) { const char *error = 0; internal::Arg arg = *s < '0' || *s > '9' ? next_arg(error) : get_arg(internal::parse_nonnegative_int(s), error); @@ -3500,8 +3593,8 @@ inline internal::Arg BasicFormatter::parse_arg_index(const Char *&s) { return arg; } -template -inline internal::Arg BasicFormatter::parse_arg_name(const Char *&s) { +template +inline internal::Arg BasicFormatter::parse_arg_name(const Char *&s) { assert(internal::is_name_start(*s)); const Char *start = s; Char c; @@ -3515,8 +3608,8 @@ inline internal::Arg BasicFormatter::parse_arg_name(const Char *&s) { return arg; } -template -const Char *BasicFormatter::format( +template +const Char *BasicFormatter::format( const Char *&format_str, const internal::Arg &arg) { using internal::Arg; const Char *s = format_str; @@ -3681,12 +3774,12 @@ const Char *BasicFormatter::format( FMT_THROW(FormatError("missing '}' in format string")); // Format argument. - internal::BasicArgFormatter(*this, spec, s - 1).visit(arg); + ArgFormatter(*this, spec, s - 1).visit(arg); return s; } -template -void BasicFormatter::format(BasicCStringRef format_str) { +template +void BasicFormatter::format(BasicCStringRef format_str) { const Char *s = format_str.c_str(); const Char *start = s; while (*s) { @@ -3776,12 +3869,15 @@ operator"" _a(const wchar_t *s, std::size_t) { return {s}; } # pragma GCC diagnostic pop #endif -#if defined(__clang__) && !defined(__INTEL_COMPILER) +#if defined(__clang__) && !defined(FMT_ICC_VERSION) # pragma clang diagnostic pop #endif #ifdef FMT_HEADER_ONLY +# define FMT_FUNC inline # include "format.cc" +#else +# define FMT_FUNC #endif #endif // FMT_FORMAT_H_ diff --git a/dep/fmt/fmt/ostream.cc b/dep/fmt/fmt/ostream.cc new file mode 100644 index 00000000000..bcb67fe1577 --- /dev/null +++ b/dep/fmt/fmt/ostream.cc @@ -0,0 +1,43 @@ +/* + Formatting library for C++ - std::ostream support + + Copyright (c) 2012 - 2016, Victor Zverovich + All rights reserved. + + For the license information refer to format.h. + */ + +#include "ostream.h" + +namespace fmt { + +namespace { +// Write the content of w to os. +void write(std::ostream &os, Writer &w) { + const char *data = w.data(); + typedef internal::MakeUnsigned::Type UnsignedStreamSize; + UnsignedStreamSize size = w.size(); + UnsignedStreamSize max_size = + internal::to_unsigned((std::numeric_limits::max)()); + do { + UnsignedStreamSize n = size <= max_size ? size : max_size; + os.write(data, static_cast(n)); + data += n; + size -= n; + } while (size != 0); +} +} + +FMT_FUNC void print(std::ostream &os, CStringRef format_str, ArgList args) { + MemoryWriter w; + w.write(format_str, args); + 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()); +} +} // namespace fmt diff --git a/dep/fmt/fmt/ostream.h b/dep/fmt/fmt/ostream.h new file mode 100644 index 00000000000..29483c1bcbd --- /dev/null +++ b/dep/fmt/fmt/ostream.h @@ -0,0 +1,115 @@ +/* + Formatting library for C++ - std::ostream support + + Copyright (c) 2012 - 2016, Victor Zverovich + All rights reserved. + + For the license information refer to format.h. + */ + +#ifndef FMT_OSTREAM_H_ +#define FMT_OSTREAM_H_ + +#include "format.h" +#include + +namespace fmt { + +namespace internal { + +template +class FormatBuf : public std::basic_streambuf { + private: + typedef typename std::basic_streambuf::int_type int_type; + typedef typename std::basic_streambuf::traits_type traits_type; + + Buffer &buffer_; + Char *start_; + + public: + FormatBuf(Buffer &buffer) : buffer_(buffer), start_(&buffer[0]) { + this->setp(start_, start_ + buffer_.capacity()); + } + + 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); + + start_ = &buffer_[0]; + start_[buf_size] = traits_type::to_char_type(ch); + this->setp(start_+ buf_size + 1, start_ + buf_size * 2); + } + return ch; + } + + size_t size() const { + return to_unsigned(this->pptr() - start_); + } +}; + +Yes &convert(std::ostream &); + +struct DummyStream : std::ostream { + DummyStream(); // Suppress a bogus warning in MSVC. + // Hide all operator<< overloads from std::ostream. + void operator<<(Null<>); +}; + +No &operator<<(std::ostream &, int); + +template +struct ConvertToIntImpl { + // Convert to int only if T doesn't have an overloaded operator<<. + enum { + value = sizeof(convert(get() << get())) == sizeof(No) + }; +}; +} // namespace internal + +// Formats a value. +template +void format(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()); + typedef internal::MakeArg< BasicFormatter > MakeArg; + format_str = f.format(format_str, MakeArg(str)); +} + +/** + \rst + Prints formatted data to the stream *os*. + + **Example**:: + + print(cerr, "Don't {}!", "panic"); + \endrst + */ +FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args); +FMT_VARIADIC(void, print, std::ostream &, CStringRef) + +/** + \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 +# include "ostream.cc" +#endif + +#endif // FMT_OSTREAM_H_ diff --git a/dep/fmt/fmt/posix.cc b/dep/fmt/fmt/posix.cc new file mode 100644 index 00000000000..76eb7f05eb8 --- /dev/null +++ b/dep/fmt/fmt/posix.cc @@ -0,0 +1,238 @@ +/* + A C++ interface to POSIX functions. + + Copyright (c) 2012 - 2016, Victor Zverovich + All rights reserved. + + For the license information refer to format.h. + */ + +// Disable bogus MSVC warnings. +#ifndef _CRT_SECURE_NO_WARNINGS +# define _CRT_SECURE_NO_WARNINGS +#endif + +#include "posix.h" + +#include +#include +#include + +#ifndef _WIN32 +# include +#else +# include +# include + +# define O_CREAT _O_CREAT +# define O_TRUNC _O_TRUNC + +# ifndef S_IRUSR +# define S_IRUSR _S_IREAD +# endif + +# ifndef S_IWUSR +# define S_IWUSR _S_IWRITE +# endif + +# ifdef __MINGW32__ +# define _SH_DENYNO 0x40 +# endif + +#endif // _WIN32 + +#ifdef fileno +# undef fileno +#endif + +namespace { +#ifdef _WIN32 +// Return type of read and write functions. +typedef int RWResult; + +// On Windows the count argument to read and write is unsigned, so convert +// it from size_t preventing integer overflow. +inline unsigned convert_rwcount(std::size_t count) { + return count <= UINT_MAX ? static_cast(count) : UINT_MAX; +} +#else +// Return type of read and write functions. +typedef ssize_t RWResult; + +inline std::size_t convert_rwcount(std::size_t count) { return count; } +#endif +} + +fmt::BufferedFile::~BufferedFile() FMT_NOEXCEPT { + if (file_ && FMT_SYSTEM(fclose(file_)) != 0) + fmt::report_system_error(errno, "cannot close file"); +} + +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_) + FMT_THROW(SystemError(errno, "cannot open file {}", filename)); +} + +void fmt::BufferedFile::close() { + if (!file_) + return; + int result = FMT_SYSTEM(fclose(file_)); + file_ = 0; + if (result != 0) + FMT_THROW(SystemError(errno, "cannot close file")); +} + +// A macro used to prevent expansion of fileno on broken versions of MinGW. +#define FMT_ARGS + +int fmt::BufferedFile::fileno() const { + int fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_)); + if (fd == -1) + FMT_THROW(SystemError(errno, "cannot get file descriptor")); + return fd; +} + +fmt::File::File(fmt::CStringRef path, int oflag) { + int mode = S_IRUSR | S_IWUSR; +#if defined(_WIN32) && !defined(__MINGW32__) + fd_ = -1; + FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode)); +#else + FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode))); +#endif + if (fd_ == -1) + FMT_THROW(SystemError(errno, "cannot open file {}", path)); +} + +fmt::File::~File() FMT_NOEXCEPT { + // Don't retry close in case of EINTR! + // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html + if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0) + fmt::report_system_error(errno, "cannot close file"); +} + +void fmt::File::close() { + if (fd_ == -1) + return; + // Don't retry close in case of EINTR! + // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html + int result = FMT_POSIX_CALL(close(fd_)); + fd_ = -1; + if (result != 0) + FMT_THROW(SystemError(errno, "cannot close file")); +} + +fmt::LongLong fmt::File::size() const { +#ifdef _WIN32 + // Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT + // is less than 0x0500 as is the case with some default MinGW builds. + // Both functions support large file sizes. + DWORD size_upper = 0; + HANDLE handle = reinterpret_cast(_get_osfhandle(fd_)); + DWORD size_lower = FMT_SYSTEM(GetFileSize(handle, &size_upper)); + if (size_lower == INVALID_FILE_SIZE) { + DWORD error = GetLastError(); + if (error != NO_ERROR) + FMT_THROW(WindowsError(GetLastError(), "cannot get file size")); + } + fmt::ULongLong long_size = size_upper; + return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower; +#else + typedef struct stat Stat; + Stat file_stat = Stat(); + if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1) + 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; +#endif +} + +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) + FMT_THROW(SystemError(errno, "cannot read from file")); + return internal::to_unsigned(result); +} + +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) + FMT_THROW(SystemError(errno, "cannot write to file")); + return internal::to_unsigned(result); +} + +fmt::File fmt::File::dup(int fd) { + // Don't retry as dup doesn't return EINTR. + // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html + int new_fd = FMT_POSIX_CALL(dup(fd)); + if (new_fd == -1) + FMT_THROW(SystemError(errno, "cannot duplicate file descriptor {}", fd)); + return File(new_fd); +} + +void fmt::File::dup2(int fd) { + int result = 0; + FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); + if (result == -1) { + FMT_THROW(SystemError(errno, + "cannot duplicate file descriptor {} to {}", fd_, fd)); + } +} + +void fmt::File::dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT { + int result = 0; + FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); + if (result == -1) + ec = ErrorCode(errno); +} + +void fmt::File::pipe(File &read_end, File &write_end) { + // Close the descriptors first to make sure that assignments don't throw + // and there are no leaks. + read_end.close(); + write_end.close(); + int fds[2] = {}; +#ifdef _WIN32 + // Make the default pipe capacity same as on Linux 2.6.11+. + enum { DEFAULT_CAPACITY = 65536 }; + int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY)); +#else + // Don't retry as the pipe function doesn't return EINTR. + // http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html + int result = FMT_POSIX_CALL(pipe(fds)); +#endif + if (result != 0) + 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]); + write_end = File(fds[1]); +} + +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) + FMT_THROW(SystemError(errno, "cannot associate stream with file descriptor")); + BufferedFile file(f); + fd_ = -1; + return file; +} + +long fmt::getpagesize() { +#ifdef _WIN32 + SYSTEM_INFO si; + GetSystemInfo(&si); + return si.dwPageSize; +#else + long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE)); + if (size < 0) + FMT_THROW(SystemError(errno, "cannot get memory page size")); + return size; +#endif +} diff --git a/dep/cppformat/cppformat/posix.h b/dep/fmt/fmt/posix.h similarity index 85% rename from dep/cppformat/cppformat/posix.h rename to dep/fmt/fmt/posix.h index bfbd3851838..be1286c425d 100644 --- a/dep/cppformat/cppformat/posix.h +++ b/dep/fmt/fmt/posix.h @@ -1,34 +1,16 @@ /* A C++ interface to POSIX functions. - Copyright (c) 2014 - 2015, 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 @@ -145,7 +127,7 @@ public: // A "move constructor" for moving from a temporary. BufferedFile(Proxy p) FMT_NOEXCEPT : file_(p.file) {} - // A "move constructor" for for moving from an lvalue. + // A "move constructor" for moving from an lvalue. BufferedFile(BufferedFile &f) FMT_NOEXCEPT : file_(f.file_) { f.file_ = 0; } @@ -251,7 +233,7 @@ class File { // A "move constructor" for moving from a temporary. File(Proxy p) FMT_NOEXCEPT : fd_(p.fd) {} - // A "move constructor" for for moving from an lvalue. + // A "move constructor" for moving from an lvalue. File(File &other) FMT_NOEXCEPT : fd_(other.fd_) { other.fd_ = -1; } @@ -339,7 +321,8 @@ class File { // 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 @@ -374,7 +357,7 @@ class Locale { Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", NULL)) { if (!locale_) - throw fmt::SystemError(errno, "cannot create locale"); + FMT_THROW(fmt::SystemError(errno, "cannot create locale")); } ~Locale() { freelocale(locale_); } diff --git a/dep/fmt/fmt/time.h b/dep/fmt/fmt/time.h new file mode 100644 index 00000000000..10225c03ef8 --- /dev/null +++ b/dep/fmt/fmt/time.h @@ -0,0 +1,53 @@ +/* + Formatting library for C++ - time formatting + + Copyright (c) 2012 - 2016, Victor Zverovich + All rights reserved. + + For the license information refer to format.h. + */ + +#ifndef FMT_TIME_H_ +#define FMT_TIME_H_ + +#include "format.h" +#include + +namespace fmt { +template +void format(BasicFormatter &f, + const char *&format_str, const std::tm &tm) { + if (*format_str == ':') + ++format_str; + const char *end = format_str; + while (*end && *end != '}') + ++end; + if (*end != '}') + FMT_THROW(FormatError("missing '}' in format string")); + internal::MemoryBuffer format; + format.append(format_str, end + 1); + format[format.size() - 1] = '\0'; + Buffer &buffer = f.writer().buffer(); + std::size_t start = buffer.size(); + for (;;) { + std::size_t size = buffer.capacity() - start; + std::size_t count = std::strftime(&buffer[start], size, &format[0], &tm); + if (count != 0) { + buffer.resize(start + count); + break; + } + if (size >= format.size() * 256) { + // If the buffer is 256 times larger than the format string, assume + // that `strftime` gives an empty result. There doesn't seem to be a + // better way to distinguish the two cases: + // https://github.com/fmtlib/fmt/issues/367 + break; + } + const std::size_t MIN_GROWTH = 10; + buffer.reserve(buffer.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH)); + } + format_str = end + 1; +} +} + +#endif // FMT_TIME_H_ diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 0428738f2dd..6855ac871da 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -63,7 +63,7 @@ target_include_directories(common target_link_libraries(common PUBLIC boost - cppformat + fmt g3dlib Detour sfmt diff --git a/src/common/Utilities/StringFormat.h b/src/common/Utilities/StringFormat.h index e21b1024e87..6f101a78ef1 100644 --- a/src/common/Utilities/StringFormat.h +++ b/src/common/Utilities/StringFormat.h @@ -19,7 +19,7 @@ #ifndef TRINITYCORE_STRING_FORMAT_H #define TRINITYCORE_STRING_FORMAT_H -#include "cppformat/format.h" +#include "fmt/format.h" namespace Trinity {