diff --git a/LICENSE.txt b/LICENSE.txt index dd0ae3dc68..4caa17ca16 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -63,9 +63,6 @@ in particular, let us know and we can try to clarify it. /source/scriptinterface/third_party MPL 2.0 - /source/third_party/fmt - BSD - /source/third_party/encryption GPL version 2 (or later) ISC (pkcs5_pbkdf2.cpp) diff --git a/build/premake/extern_libs5.lua b/build/premake/extern_libs5.lua index 77a0ff75f9..e183fb1168 100644 --- a/build/premake/extern_libs5.lua +++ b/build/premake/extern_libs5.lua @@ -263,6 +263,51 @@ extern_lib_defs = { end end, }, + fmt = { + compile_settings = function() + if os.istarget("windows") or os.istarget("macosx") then + add_default_include_paths("fmt") + end + + -- With Linux & BSD, we assume that fmt is installed in a standard location. + -- + -- It would be nice to not assume, and to instead use pkgconfig: however that + -- requires fmt 5.3.0 or greater. + -- + -- Unfortunately (at the time of writing) only 69 out of 95 (~72.6%) of distros + -- that provide a fmt package meet this, according to + -- https://repology.org/badge/vertical-allrepos/fmt.svg?minversion=5.3 + -- + -- Whilst that might seem like a healthy majority, this does not include the 2018 + -- Long Term Support and 2019.10 releases of Ubuntu - not only popular and widely + -- used as-is, but which are also used as a base for other popular distros (e.g. + -- Mint). + -- + -- When fmt 5.3 (or better) becomes more widely used, then we can safely use the + -- following line: + -- pkgconfig.add_includes("fmt") + end, + link_settings = function() + if os.istarget("windows") or os.istarget("macosx") then + add_default_lib_paths("fmt") + end + + if os.istarget("windows") then + add_default_links({ + win_names = { "fmt" }, + dbg_suffix = "d", + no_delayload = 1, + }) + else + add_default_links({ + unix_names = { "fmt" }, + }) + + -- See comment above as to why this is commented out. + -- pkgconfig.add_links("fmt") + end + end + }, gloox = { compile_settings = function() if os.istarget("windows") then diff --git a/build/premake/premake5.lua b/build/premake/premake5.lua index 5a071f54a2..e0f636d753 100644 --- a/build/premake/premake5.lua +++ b/build/premake/premake5.lua @@ -594,6 +594,7 @@ function setup_all_libs () "spidermonkey", "enet", "boost", -- dragged in via server->simulation.h->random + "fmt", } if not _OPTIONS["without-miniupnpc"] then table.insert(extern_libs, "miniupnpc") @@ -605,6 +606,7 @@ function setup_all_libs () } extern_libs = { "boost", -- dragged in via simulation.h and scriptinterface.h + "fmt", "spidermonkey", } setup_static_lib_project("rlinterface", source_dirs, extern_libs, { no_pch = 1 }) @@ -615,6 +617,7 @@ function setup_all_libs () extern_libs = { "iconv", "boost", + "fmt", } setup_third_party_static_lib_project("tinygettext", source_dirs, extern_libs, { } ) @@ -648,7 +651,8 @@ function setup_all_libs () "icu", "iconv", "libsodium", - "tinygettext" + "tinygettext", + "fmt", } setup_static_lib_project("lobby", source_dirs, extern_libs, {}) @@ -662,6 +666,7 @@ function setup_all_libs () extern_libs = { "boost", "gloox", + "fmt", } if _OPTIONS["build-shared-glooxwrapper"] then setup_shared_lib_project("glooxwrapper", source_dirs, extern_libs, {}) @@ -677,7 +682,8 @@ function setup_all_libs () extern_libs = { "spidermonkey", "boost", - "libsodium" + "libsodium", + "fmt", } setup_static_lib_project("lobby", source_dirs, extern_libs, {}) files { source_root.."lobby/Globals.cpp" } @@ -697,6 +703,7 @@ function setup_all_libs () "boost", "opengl", "spidermonkey", + "fmt", } setup_static_lib_project("simulation2", source_dirs, extern_libs, {}) @@ -710,6 +717,7 @@ function setup_all_libs () "spidermonkey", "valgrind", "sdl", + "fmt", } setup_static_lib_project("scriptinterface", source_dirs, extern_libs, {}) @@ -728,7 +736,6 @@ function setup_all_libs () "maths/scripting", "i18n", "i18n/scripting", - "third_party/fmt", } extern_libs = { "spidermonkey", @@ -743,6 +750,7 @@ function setup_all_libs () "icu", "iconv", "libsodium", + "fmt", } if not _OPTIONS["without-audio"] then @@ -765,7 +773,8 @@ function setup_all_libs () "opengl", "sdl", -- key definitions "spidermonkey", -- for graphics/scripting - "boost" + "boost", + "fmt", } if not _OPTIONS["without-nvtt"] then table.insert(extern_libs, "nvtt") @@ -781,7 +790,8 @@ function setup_all_libs () "boost", "sdl", -- key definitions "opengl", - "spidermonkey" + "spidermonkey", + "fmt", } setup_static_lib_project("atlas", source_dirs, extern_libs, {}) @@ -803,6 +813,7 @@ function setup_all_libs () "tinygettext", "icu", "iconv", + "fmt", } if not _OPTIONS["without-audio"] then table.insert(extern_libs, "openal") @@ -836,6 +847,7 @@ function setup_all_libs () "zlib", "valgrind", "cxxtest", + "fmt", } -- CPU architecture-specific @@ -940,6 +952,7 @@ used_extern_libs = { "icu", "iconv", "libsodium", + "fmt", "valgrind", } diff --git a/libraries/LICENSE.txt b/libraries/LICENSE.txt index e9346c20ee..487b23a624 100644 --- a/libraries/LICENSE.txt +++ b/libraries/LICENSE.txt @@ -32,6 +32,9 @@ win32/ contains headers and precompiled static libs for Windows builds. win32/enet MIT + win32/fmt + MIT + win32/gloox GPL v3 diff --git a/libraries/osx/build-osx-libs.sh b/libraries/osx/build-osx-libs.sh index e46ec9f024..72087b076f 100755 --- a/libraries/osx/build-osx-libs.sh +++ b/libraries/osx/build-osx-libs.sh @@ -46,6 +46,7 @@ ICU_VERSION="icu4c-67_1" ENET_VERSION="enet-1.3.17" MINIUPNPC_VERSION="miniupnpc-2.1" SODIUM_VERSION="libsodium-1.0.18" +FMT_VERSION="7.1.3" # -------------------------------------------------------------- # Bundled with the game: # * SpiderMonkey @@ -892,6 +893,49 @@ else fi popd > /dev/null +# -------------------------------------------------------------- +echo -e "Building fmt..." + +LIB_DIRECTORY="fmt-$FMT_VERSION" +LIB_ARCHIVE="$FMT_VERSION.tar.gz" +LIB_URL="https://github.com/fmtlib/fmt/archive/" + +mkdir -p fmt +pushd fmt > /dev/null + +if [[ "$force_rebuild" = "true" ]] || [[ ! -e .already-built ]] || [[ "$(<.already-built)" != "$FMT_VERSION" ]] +then + rm -f .already-built + + download_lib $LIB_URL $LIB_ARCHIVE + + rm -rf $LIB_DIRECTORY include lib + tar -xf $LIB_ARCHIVE + pushd $LIB_DIRECTORY + + # It appears that older versions of Clang require constexpr statements to have a user-set constructor. + patch -Np1 -i ../../patches/fmt_constexpr.diff + + mkdir -p build + pushd build + + (cmake .. \ + -DFMT_TEST=False \ + -DFMT_DOC=False \ + && make fmt ${JOBS}) || die "fmt build failed" + popd + + mkdir -p ../lib + cp build/libfmt.a ../lib/ + cp -r include ../include + + popd + echo "$FMT_VERSION" > .already-built +else + already_built +fi +popd > /dev/null + # -------------------------------------------------------------------- # The following libraries are shared on different OSes and may # be customized, so we build and install them from bundled sources diff --git a/libraries/osx/patches/fmt_constexpr.diff b/libraries/osx/patches/fmt_constexpr.diff new file mode 100644 index 0000000000..3adcd84474 --- /dev/null +++ b/libraries/osx/patches/fmt_constexpr.diff @@ -0,0 +1,13 @@ +diff --git a/include/fmt/os.h b/include/fmt/os.h +index 88151006..11c3b2cc 100644 +--- a/include/fmt/os.h ++++ b/include/fmt/os.h +@@ -375,7 +375,7 @@ struct ostream_params { + }; + } // namespace detail + +-static constexpr detail::buffer_size buffer_size; ++static constexpr detail::buffer_size buffer_size{}; + + // A fast output stream which is not thread-safe. + class ostream final : private detail::buffer { diff --git a/source/graphics/SkeletonAnimDef.cpp b/source/graphics/SkeletonAnimDef.cpp index 8ed49d0a4d..2be4498d7c 100644 --- a/source/graphics/SkeletonAnimDef.cpp +++ b/source/graphics/SkeletonAnimDef.cpp @@ -24,6 +24,7 @@ #include "SkeletonAnimDef.h" #include "maths/MathUtil.h" #include "maths/Matrix3D.h" +#include "ps/CStr.h" #include "ps/FileIo.h" diff --git a/source/lib/posix/posix.h b/source/lib/posix/posix.h index c60d5e4c7a..6b7b56321a 100644 --- a/source/lib/posix/posix.h +++ b/source/lib/posix/posix.h @@ -60,8 +60,6 @@ need only be renamed (e.g. _open, _stat). #ifndef INCLUDED_POSIX #define INCLUDED_POSIX -#include // see isfinite comment below - #if OS_WIN # include "lib/sysdep/os/win/wposix/wposix.h" #endif @@ -114,18 +112,4 @@ extern wchar_t* wcsdup(const wchar_t* str); extern int wcscasecmp(const wchar_t* s1, const wchar_t* s2); #endif -// Some systems have C99 support but in C++ they provide only std::isfinite -// and not isfinite. C99 specifies that isfinite is a macro, so we can use -// #ifndef and define it if it's not there already. -// We've included above to make sure it defines that macro. -#ifndef isfinite -# if MSC_VERSION -# define isfinite _finite -# define isnan _isnan -# else -# define isfinite std::isfinite -# define isnan std::isnan -# endif -#endif - #endif // #ifndef INCLUDED_POSIX diff --git a/source/maths/Fixed.h b/source/maths/Fixed.h index 53f10799e1..b36e2a95f9 100644 --- a/source/maths/Fixed.h +++ b/source/maths/Fixed.h @@ -146,7 +146,7 @@ public: static CFixed FromFloat(float n) { - if (!isfinite(n)) + if (!std::isfinite(n)) return CFixed(0); float scaled = n * fract_pow2; return CFixed(round_away_from_zero(scaled)); @@ -154,7 +154,7 @@ public: static CFixed FromDouble(double n) { - if (!isfinite(n)) + if (!std::isfinite(n)) return CFixed(0); double scaled = n * fract_pow2; return CFixed(round_away_from_zero(scaled)); diff --git a/source/ps/CLogger.h b/source/ps/CLogger.h index ff738a9bb1..a41f984f8b 100644 --- a/source/ps/CLogger.h +++ b/source/ps/CLogger.h @@ -25,7 +25,7 @@ #include #include -#include "third_party/fmt/format.h" +#include class CLogger; extern CLogger* g_Logger; diff --git a/source/ps/FileIo.cpp b/source/ps/FileIo.cpp index 0a129c1bf8..613cf4c738 100644 --- a/source/ps/FileIo.cpp +++ b/source/ps/FileIo.cpp @@ -23,6 +23,7 @@ #include "FileIo.h" #include "ps/CLogger.h" +#include "ps/CStr.h" #include "ps/Filesystem.h" #include "lib/byte_order.h" diff --git a/source/ps/Filesystem.cpp b/source/ps/Filesystem.cpp index 79e67cc007..23e6242214 100644 --- a/source/ps/Filesystem.cpp +++ b/source/ps/Filesystem.cpp @@ -19,6 +19,7 @@ #include "Filesystem.h" #include "ps/CLogger.h" +#include "ps/CStr.h" #include "ps/Profile.h" #include "lib/res/h_mgr.h" // h_reload diff --git a/source/ps/Game.h b/source/ps/Game.h index b6c7429ec7..8316d9a41c 100644 --- a/source/ps/Game.h +++ b/source/ps/Game.h @@ -183,7 +183,7 @@ public: * clamped to 0.0f. **/ inline void SetSimRate(float simRate) - { if (isfinite(simRate)) m_SimRate = std::max(simRate, 0.0f); } + { if (std::isfinite(simRate)) m_SimRate = std::max(simRate, 0.0f); } inline float GetSimRate() const { return m_SimRate; } diff --git a/source/ps/XML/RelaxNG.cpp b/source/ps/XML/RelaxNG.cpp index 59dbd1e95e..49cb6cb7be 100644 --- a/source/ps/XML/RelaxNG.cpp +++ b/source/ps/XML/RelaxNG.cpp @@ -22,6 +22,7 @@ #include "lib/timer.h" #include "lib/utf8.h" #include "ps/CLogger.h" +#include "ps/CStr.h" #include "ps/Filesystem.h" #include diff --git a/source/ps/XML/XMLWriter.h b/source/ps/XML/XMLWriter.h index 0155d089f3..9c47dcc926 100644 --- a/source/ps/XML/XMLWriter.h +++ b/source/ps/XML/XMLWriter.h @@ -62,8 +62,8 @@ */ #include "lib/file/vfs/vfs.h" +#include "ps/CStr.h" -class CStr8; class XMBElement; class XMBFile; class XMLWriter_Element; @@ -98,7 +98,7 @@ private: bool m_PrettyPrint; - CStr8 m_Data; + CStr m_Data; int m_Indent; XMLWriter_Element* m_LastElement; }; @@ -119,7 +119,7 @@ private: friend class XMLWriter_File; XMLWriter_File* m_File; - CStr8 m_Name; + CStr m_Name; int m_Type; }; diff --git a/source/ps/tests/test_fmt.h b/source/ps/tests/test_fmt.h index aeff26018e..2c53881999 100644 --- a/source/ps/tests/test_fmt.h +++ b/source/ps/tests/test_fmt.h @@ -15,9 +15,9 @@ * along with 0 A.D. If not, see . */ -#include "lib/self_test.h" +#include -#include "third_party/fmt/format.h" +#include "lib/self_test.h" class TestFmt : public CxxTest::TestSuite { @@ -39,7 +39,7 @@ public: TS_ASSERT_EQUALS(fmt::sprintf("%f", 0.5f), "0.500000"); TS_ASSERT_EQUALS(fmt::sprintf("%.1f", 0.1111f), "0.1"); - TS_ASSERT_EQUALS(fmt::sprintf("%d", 0x100000001ULL), "1"); + TS_ASSERT_EQUALS(fmt::sprintf("%d", 0x100000001ULL), "4294967297"); if (sizeof(long) == sizeof(int32_t)) { TS_ASSERT_EQUALS(fmt::sprintf("%ld", 0x100000001ULL), "1"); diff --git a/source/scriptinterface/ScriptExceptions.cpp b/source/scriptinterface/ScriptExceptions.cpp index 4a2fb5dd3d..e4b61d1ec2 100644 --- a/source/scriptinterface/ScriptExceptions.cpp +++ b/source/scriptinterface/ScriptExceptions.cpp @@ -21,6 +21,7 @@ #include "ScriptExceptions.h" #include "ps/CLogger.h" +#include "ps/CStr.h" #include "scriptinterface/ScriptInterface.h" bool ScriptException::IsPending(const ScriptRequest& rq) diff --git a/source/third_party/fmt/format.cpp b/source/third_party/fmt/format.cpp deleted file mode 100644 index 8f53d7dcd7..0000000000 --- a/source/third_party/fmt/format.cpp +++ /dev/null @@ -1,1178 +0,0 @@ -/* - * Slightly modified version of fmt, by Wildfire Games, for 0 A.D. - * Based on fmt v1.1.0 from https://github.com/fmtlib/fmt - */ - -/* - Formatting library for C++ - - Copyright (c) 2012 - 2015, 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 "precompiled.h" - -#include "format.h" - -#include - -#include -#include -#include -#include -#include - -#ifdef _WIN32 -# ifdef __MINGW32__ -# include -# endif -# include -#endif - -using fmt::internal::Arg; - -// Check if exceptions are disabled. -#if __GNUC__ && !__EXCEPTIONS -# define FMT_EXCEPTIONS 0 -#endif -#if defined(_MSC_VER) && _MSC_VER && !_HAS_EXCEPTIONS -# define FMT_EXCEPTIONS 0 -#endif -#ifndef FMT_EXCEPTIONS -# define FMT_EXCEPTIONS 1 -#endif - -#if FMT_EXCEPTIONS -# define FMT_TRY try -# define FMT_CATCH(x) catch (x) -#else -# define FMT_TRY if (true) -# define FMT_CATCH(x) if (false) -#endif - -#ifndef FMT_THROW -# if FMT_EXCEPTIONS -# define FMT_THROW(x) throw x -# define FMT_RETURN_AFTER_THROW(x) -# else -# define FMT_THROW(x) assert(false) -# define FMT_RETURN_AFTER_THROW(x) return x -# endif -#endif - -#ifdef FMT_HEADER_ONLY -# define FMT_FUNC inline -#else -# define FMT_FUNC -#endif - -namespace { - -#ifndef _MSC_VER -# define FMT_SNPRINTF snprintf -#else // _MSC_VER - -# pragma warning(push) -# pragma warning(disable: 4127) // conditional expression is constant -# pragma warning(disable: 4702) // unreachable code -# pragma warning(disable: 4456) // hides previous local declaration - -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 - -// 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; - } -}; - -template <> -struct IntChecker { - template - static bool fits_in_int(T value) { - return value >= INT_MIN && value <= INT_MAX; - } -}; - -const char RESET_COLOR[] = "\x1b[0m"; - -typedef void (*FormatFunc)(fmt::Writer &, int, fmt::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 { - assert(buffer != 0 && buffer_size != 0); - int result = 0; -#if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE) || (defined(__ANDROID__) && __ANDROID__) - // XSI-compliant version of strerror_r. - result = strerror_r(error_code, buffer, buffer_size); - if (result != 0) - result = errno; -#elif defined(_GNU_SOURCE) && !defined(__BIONIC__) - // GNU-specific version of strerror_r. - char *message = strerror_r(error_code, buffer, buffer_size); - // If the buffer is full then the message is probably truncated. - if (message == buffer && strlen(buffer) == buffer_size - 1) - result = ERANGE; - buffer = message; -#elif defined(__MINGW32__) - errno = 0; - (void)buffer_size; - buffer = strerror(error_code); - result = errno; -#elif defined(_WIN32) - result = strerror_s(buffer, buffer_size, error_code); - // If the buffer is full then the message is probably truncated. - if (result == 0 && std::strlen(buffer) == buffer_size - 1) - result = ERANGE; -#else - result = strerror_r(error_code, buffer, buffer_size); - if (result == -1) - result = errno; // glibc versions before 2.13 return result in errno. -#endif - return result; -} - -void format_error_code(fmt::Writer &out, int error_code, - fmt::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 ERR[] = "error "; - fmt::internal::IntTraits::MainType ec_value = error_code; - // Subtract 2 to account for terminating null characters in SEP and ERR. - std::size_t error_code_size = - sizeof(SEP) + sizeof(ERR) + fmt::internal::count_digits(ec_value) - 2; - if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size) - out << message << SEP; - out << ERR << error_code; - assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE); -} - -void report_error(FormatFunc func, - int error_code, fmt::StringRef message) FMT_NOEXCEPT { - fmt::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 fmt::internal::ArgVisitor { - public: - template - bool visit_any_int(T value) { return value == 0; } -}; - -// Parses an unsigned integer advancing s to the end of the parsed input. -// This function assumes that the first character of s is a digit. -template -int parse_nonnegative_int(const Char *&s) { - assert('0' <= *s && *s <= '9'); - unsigned value = 0; - do { - unsigned new_value = value * 10 + (*s++ - '0'); - // Check if value wrapped around. - if (new_value < value) { - value = UINT_MAX; - break; - } - value = new_value; - } while ('0' <= *s && *s <= '9'); - if (value > INT_MAX) - FMT_THROW(fmt::FormatError("number is too big")); - return value; -} - -inline void require_numeric_argument(const Arg &arg, char spec) { - if (arg.type > Arg::LAST_NUMERIC_TYPE) { - std::string message = - fmt::format("format specifier '{}' requires numeric argument", spec); - FMT_THROW(fmt::FormatError(message)); - } -} - -template -void check_sign(const Char *&s, const Arg &arg) { - char sign = static_cast(*s); - require_numeric_argument(arg, sign); - if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) { - FMT_THROW(fmt::FormatError(fmt::format( - "format specifier '{}' requires signed argument", sign))); - } - ++s; -} - -// Checks if an argument is a valid printf width specifier and sets -// left alignment if it is negative. -class WidthHandler : public fmt::internal::ArgVisitor { - private: - fmt::FormatSpec &spec_; - - FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler); - - public: - explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {} - - unsigned visit_unhandled_arg() { - FMT_THROW(fmt::FormatError("width is not integer")); - FMT_RETURN_AFTER_THROW(0); - } - - template - unsigned visit_any_int(T value) { - typedef typename fmt::internal::IntTraits::MainType UnsignedType; - UnsignedType width = value; - if (fmt::internal::is_negative(value)) { - spec_.align_ = fmt::ALIGN_LEFT; - width = 0 - width; - } - if (width > INT_MAX) - FMT_THROW(fmt::FormatError("number is too big")); - return static_cast(width); - } -}; - -class PrecisionHandler : - public fmt::internal::ArgVisitor { - public: - unsigned visit_unhandled_arg() { - FMT_THROW(fmt::FormatError("precision is not integer")); - FMT_RETURN_AFTER_THROW(0); - } - - template - int visit_any_int(T value) { - if (!IntChecker::is_signed>::fits_in_int(value)) - FMT_THROW(fmt::FormatError("number is too big")); - return static_cast(value); - } -}; - -// Converts an integer argument to an integral type T for printf. -template -class ArgConverter : public fmt::internal::ArgVisitor, void> { - private: - fmt::internal::Arg &arg_; - wchar_t type_; - - FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter); - - public: - ArgConverter(fmt::internal::Arg &arg, wchar_t type) - : arg_(arg), type_(type) {} - - template - void visit_any_int(U value) { - bool is_signed = type_ == 'd' || type_ == 'i'; - using fmt::internal::Arg; - if (sizeof(T) <= 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; - arg_.uint_value = static_cast( - static_cast::Type>(value)); - } - } else { - if (is_signed) { - arg_.type = Arg::LONG_LONG; - arg_.long_long_value = - static_cast::Type>(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 fmt::internal::ArgVisitor { - private: - fmt::internal::Arg &arg_; - - FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter); - - public: - explicit CharConverter(fmt::internal::Arg &arg) : arg_(arg) {} - - template - void visit_any_int(T value) { - arg_.type = Arg::CHAR; - arg_.int_value = static_cast(value); - } -}; - -// This function template is used to prevent compile errors when handling -// incompatible string arguments, e.g. handling a wide string in a narrow -// string formatter. -template -Arg::StringValue ignore_incompatible_str(Arg::StringValue); - -template <> -inline Arg::StringValue ignore_incompatible_str( - Arg::StringValue) { return Arg::StringValue(); } - -template <> -inline Arg::StringValue ignore_incompatible_str( - Arg::StringValue s) { return s; } -} // namespace - -FMT_FUNC void fmt::SystemError::init( - int err_code, StringRef 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 ? - swprintf(buffer, size, format, value) : - swprintf(buffer, size, format, precision, value); - } - return precision < 0 ? - swprintf(buffer, size, format, width, value) : - 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) { - 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))); -} - -#ifdef _WIN32 - -FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) { - int length = MultiByteToWideChar( - CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0); - static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16"; - if (length == 0) - FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); - buffer_.resize(length); - length = MultiByteToWideChar( - CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length); - if (length == 0) - FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); -} - -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) { - int length = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, 0, 0, 0, 0); - if (length == 0) - return GetLastError(); - buffer_.resize(length); - length = WideCharToMultiByte( - CP_UTF8, 0, s.c_str(), -1, &buffer_[0], length, 0, 0); - if (length == 0) - return GetLastError(); - return 0; -} - -FMT_FUNC void fmt::WindowsError::init( - int err_code, StringRef 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()); -} - -#endif - -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(...) {} - format_error_code(out, error_code, message); -} - -#ifdef _WIN32 -FMT_FUNC void fmt::internal::format_windows_error( - fmt::Writer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT { - class String { - private: - LPWSTR str_; - - public: - String() : str_() {} - ~String() { LocalFree(str_); } - LPWSTR *ptr() { return &str_; } - LPCWSTR c_str() const { return str_; } - }; - FMT_TRY { - String system_message; - if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, - error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - reinterpret_cast(system_message.ptr()), 0, 0)) { - UTF16ToUTF8 utf8_message; - if (utf8_message.convert(system_message.c_str()) == ERROR_SUCCESS) { - out << message << ": " << utf8_message; - return; - } - } - } FMT_CATCH(...) {} - format_error_code(out, error_code, message); -} -#endif - -// An argument formatter. -template -class fmt::internal::ArgFormatter : - public fmt::internal::ArgVisitor, void> { - private: - fmt::BasicFormatter &formatter_; - fmt::BasicWriter &writer_; - fmt::FormatSpec &spec_; - const Char *format_; - - FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatter); - - public: - ArgFormatter( - fmt::BasicFormatter &f,fmt::FormatSpec &s, const Char *fmt) - : formatter_(f), writer_(f.writer()), spec_(s), format_(fmt) {} - - template - void visit_any_int(T value) { writer_.write_int(value, spec_); } - - template - void visit_any_double(T value) { writer_.write_double(value, spec_); } - - void visit_char(int value) { - if (spec_.type_ && spec_.type_ != 'c') { - spec_.flags_ |= CHAR_FLAG; - writer_.write_int(value, spec_); - return; - } - if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0) - FMT_THROW(FormatError("invalid format specifier for char")); - typedef typename fmt::BasicWriter::CharPtr CharPtr; - Char fill = static_cast(spec_.fill()); - if (spec_.precision_ == 0) { - std::fill_n(writer_.grow_buffer(spec_.width_), spec_.width_, fill); - return; - } - CharPtr out = CharPtr(); - if (spec_.width_ > 1) { - out = writer_.grow_buffer(spec_.width_); - if (spec_.align_ == fmt::ALIGN_RIGHT) { - std::fill_n(out, spec_.width_ - 1, fill); - out += spec_.width_ - 1; - } else if (spec_.align_ == fmt::ALIGN_CENTER) { - out = writer_.fill_padding(out, spec_.width_, 1, fill); - } else { - std::fill_n(out + 1, spec_.width_ - 1, fill); - } - } else { - out = writer_.grow_buffer(1); - } - *out = static_cast(value); - } - - void visit_string(Arg::StringValue value) { - writer_.write_str(value, spec_); - } - void visit_wstring(Arg::StringValue value) { - writer_.write_str(ignore_incompatible_str(value), spec_); - } - - void visit_pointer(const void *value) { - if (spec_.type_ && spec_.type_ != 'p') - fmt::internal::report_unknown_type(spec_.type_, "pointer"); - spec_.flags_ = fmt::HASH_FLAG; - spec_.type_ = 'x'; - writer_.write_int(reinterpret_cast(value), spec_); - } - - void visit_custom(Arg::CustomValue c) { - c.format(&formatter_, c.value, &format_); - } -}; - -template -void fmt::internal::FixedBuffer::grow(std::size_t) { - FMT_THROW(std::runtime_error("buffer overflow")); -} - -template -template -void fmt::BasicWriter::write_str( - const Arg::StringValue &s, const FormatSpec &spec) { - // Check if StrChar is convertible to Char. - internal::CharTraits::convert(StrChar()); - if (spec.type_ && spec.type_ != 's') - internal::report_unknown_type(spec.type_, "string"); - const StrChar *str_value = s.value; - std::size_t str_size = s.size; - if (str_size == 0) { - if (!str_value) { - Char err[] = { '(', 'n', 'u', 'l', 'l', ')' }; - write_str(err, sizeof(err)/sizeof(Char), spec); - return; - } - if (*str_value) - str_size = std::char_traits::length(str_value); - } - std::size_t precision = spec.precision_; - if (spec.precision_ >= 0 && precision < str_size) - str_size = spec.precision_; - write_str(str_value, str_size, spec); -} - -template -inline Arg fmt::BasicFormatter::parse_arg_index(const Char *&s) { - const char *error = 0; - Arg arg = *s < '0' || *s > '9' ? - next_arg(error) : get_arg(parse_nonnegative_int(s), error); - if (error) { - FMT_THROW(FormatError( - *s != '}' && *s != ':' ? "invalid format string" : error)); - } - return arg; -} - -FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg( - unsigned arg_index, const char *&error) { - Arg arg = args_[arg_index]; - if (arg.type == Arg::NONE) - error = "argument index out of range"; - return arg; -} - -inline Arg fmt::internal::FormatterBase::next_arg(const char *&error) { - if (next_arg_index_ >= 0) - return do_get_arg(next_arg_index_++, error); - error = "cannot switch from manual to automatic argument indexing"; - return Arg(); -} - -inline Arg fmt::internal::FormatterBase::get_arg( - unsigned arg_index, const char *&error) { - if (next_arg_index_ <= 0) { - next_arg_index_ = -1; - return do_get_arg(arg_index, error); - } - error = "cannot switch from automatic to manual argument indexing"; - 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) { - 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, BasicStringRef format_str, - const ArgList &args) { - const Char *start = format_str.c_str(); - set_args(args); - 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_ = 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_ &= ~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. - switch (arg.type) { - case Arg::INT: - writer.write_int(arg.int_value, spec); - break; - case Arg::UINT: - writer.write_int(arg.uint_value, spec); - break; - case Arg::LONG_LONG: - writer.write_int(arg.long_long_value, spec); - break; - case Arg::ULONG_LONG: - writer.write_int(arg.ulong_long_value, spec); - break; - case Arg::CHAR: { - if (spec.type_ && spec.type_ != 'c') - writer.write_int(arg.int_value, spec); - typedef typename BasicWriter::CharPtr CharPtr; - CharPtr out = CharPtr(); - if (spec.width_ > 1) { - Char fill = ' '; - out = writer.grow_buffer(spec.width_); - if (spec.align_ != ALIGN_LEFT) { - std::fill_n(out, spec.width_ - 1, fill); - out += spec.width_ - 1; - } else { - std::fill_n(out + 1, spec.width_ - 1, fill); - } - } else { - out = writer.grow_buffer(1); - } - *out = static_cast(arg.int_value); - break; - } - case Arg::DOUBLE: - writer.write_double(arg.double_value, spec); - break; - case Arg::LONG_DOUBLE: - writer.write_double(arg.long_double_value, spec); - break; - case Arg::CSTRING: - arg.string.size = 0; - writer.write_str(arg.string, spec); - break; - case Arg::STRING: - writer.write_str(arg.string, spec); - break; - case Arg::WSTRING: - writer.write_str(ignore_incompatible_str(arg.wstring), spec); - break; - case Arg::POINTER: - if (spec.type_ && spec.type_ != 'p') - internal::report_unknown_type(spec.type_, "pointer"); - spec.flags_= HASH_FLAG; - spec.type_ = 'x'; - writer.write_int(reinterpret_cast(arg.pointer), spec); - break; - case Arg::CUSTOM: { - if (spec.type_) - internal::report_unknown_type(spec.type_, "object"); - const void *str_format = "s"; - arg.custom.format(&writer, arg.custom.value, &str_format); - break; - } - default: - assert(false); - break; - } - } - write(writer, start, s); -} - -template -const Char *fmt::BasicFormatter::format( - const Char *&format_str, const Arg &arg) { - const Char *s = format_str; - FormatSpec spec; - if (*s == ':') { - if (arg.type == Arg::CUSTOM) { - arg.custom.format(this, arg.custom.value, &s); - return s; - } - ++s; - // Parse fill and alignment. - if (Char c = *s) { - const Char *p = s + 1; - spec.align_ = ALIGN_DEFAULT; - do { - switch (*p) { - case '<': - spec.align_ = ALIGN_LEFT; - break; - case '>': - spec.align_ = ALIGN_RIGHT; - break; - case '=': - spec.align_ = ALIGN_NUMERIC; - break; - case '^': - spec.align_ = ALIGN_CENTER; - break; - } - if (spec.align_ != ALIGN_DEFAULT) { - if (p != s) { - if (c == '}') break; - if (c == '{') - FMT_THROW(FormatError("invalid fill character '{'")); - s += 2; - spec.fill_ = c; - } else ++s; - if (spec.align_ == ALIGN_NUMERIC) - require_numeric_argument(arg, '='); - break; - } - } while (--p >= s); - } - - // Parse sign. - switch (*s) { - case '+': - check_sign(s, arg); - spec.flags_ |= SIGN_FLAG | PLUS_FLAG; - break; - case '-': - check_sign(s, arg); - spec.flags_ |= MINUS_FLAG; - break; - case ' ': - check_sign(s, arg); - spec.flags_ |= SIGN_FLAG; - break; - } - - if (*s == '#') { - require_numeric_argument(arg, '#'); - spec.flags_ |= HASH_FLAG; - ++s; - } - - // Parse width and zero flag. - if ('0' <= *s && *s <= '9') { - if (*s == '0') { - require_numeric_argument(arg, '0'); - spec.align_ = ALIGN_NUMERIC; - spec.fill_ = '0'; - } - // Zero may be parsed again as a part of the width, but it is simpler - // and more efficient than checking if the next char is a digit. - spec.width_ = parse_nonnegative_int(s); - } - - // Parse precision. - if (*s == '.') { - ++s; - spec.precision_ = 0; - if ('0' <= *s && *s <= '9') { - spec.precision_ = parse_nonnegative_int(s); - } else if (*s == '{') { - ++s; - const Arg &precision_arg = parse_arg_index(s); - if (*s++ != '}') - FMT_THROW(FormatError("invalid format string")); - ULongLong value = 0; - switch (precision_arg.type) { - case Arg::INT: - if (precision_arg.int_value < 0) - FMT_THROW(FormatError("negative precision")); - value = precision_arg.int_value; - break; - case Arg::UINT: - value = precision_arg.uint_value; - break; - case Arg::LONG_LONG: - if (precision_arg.long_long_value < 0) - FMT_THROW(FormatError("negative precision")); - value = precision_arg.long_long_value; - break; - case Arg::ULONG_LONG: - value = precision_arg.ulong_long_value; - break; - default: - FMT_THROW(FormatError("precision is not integer")); - } - if (value > INT_MAX) - FMT_THROW(FormatError("number is too big")); - spec.precision_ = static_cast(value); - } else { - FMT_THROW(FormatError("missing precision specifier")); - } - if (arg.type < Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) { - FMT_THROW(FormatError( - fmt::format("precision not allowed in {} format specifier", - arg.type == Arg::POINTER ? "pointer" : "integer"))); - } - } - - // Parse type. - if (*s != '}' && *s) - spec.type_ = static_cast(*s++); - } - - if (*s++ != '}') - FMT_THROW(FormatError("missing '}' in format string")); - start_ = s; - - // Format argument. - internal::ArgFormatter(*this, spec, s - 1).visit(arg); - return s; -} - -template -void fmt::BasicFormatter::format( - BasicStringRef format_str, const ArgList &args) { - const Char *s = start_ = format_str.c_str(); - set_args(args); - while (*s) { - Char c = *s++; - if (c != '{' && c != '}') continue; - if (*s == c) { - write(writer_, start_, s); - start_ = ++s; - continue; - } - if (c == '}') - FMT_THROW(FormatError("unmatched '}' in format string")); - write(writer_, start_, s - 1); - Arg arg = parse_arg_index(s); - s = format(s, arg); - } - write(writer_, start_, s); -} - -FMT_FUNC void fmt::report_system_error( - int error_code, fmt::StringRef message) FMT_NOEXCEPT { - report_error(internal::format_system_error, error_code, message); -} - -#ifdef _WIN32 -FMT_FUNC void fmt::report_windows_error( - int error_code, fmt::StringRef message) FMT_NOEXCEPT { - report_error(internal::format_windows_error, error_code, message); -} -#endif - -FMT_FUNC void fmt::print(std::FILE *f, StringRef format_str, ArgList args) { - MemoryWriter w; - w.write(format_str, args); - std::fwrite(w.data(), 1, w.size(), f); -} - -FMT_FUNC void fmt::print(StringRef format_str, ArgList args) { - print(stdout, format_str, args); -} - -FMT_FUNC void fmt::print(std::ostream &os, StringRef format_str, ArgList args) { - MemoryWriter w; - w.write(format_str, args); - os.write(w.data(), w.size()); -} - -FMT_FUNC void fmt::print_colored(Color c, StringRef format, ArgList args) { - char escape[] = "\x1b[30m"; - escape[3] = '0' + static_cast(c); - std::fputs(escape, stdout); - print(format, args); - std::fputs(RESET_COLOR, stdout); -} - -FMT_FUNC int fmt::fprintf(std::FILE *f, StringRef 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 - -// Explicit instantiations for char. - -template void fmt::internal::FixedBuffer::grow(std::size_t); - -template const char *fmt::BasicFormatter::format( - const char *&format_str, const fmt::internal::Arg &arg); - -template void fmt::BasicFormatter::format( - BasicStringRef format, const ArgList &args); - -template void fmt::internal::PrintfFormatter::format( - BasicWriter &writer, BasicStringRef format, const ArgList &args); - -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 const wchar_t *fmt::BasicFormatter::format( - const wchar_t *&format_str, const fmt::internal::Arg &arg); - -template void fmt::BasicFormatter::format( - BasicStringRef format, const ArgList &args); - -template void fmt::internal::PrintfFormatter::format( - BasicWriter &writer, BasicStringRef format, - const ArgList &args); - -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 - -#if defined(_MSC_VER) && _MSC_VER -# pragma warning(pop) -#endif diff --git a/source/third_party/fmt/format.h b/source/third_party/fmt/format.h deleted file mode 100644 index 3517fe0739..0000000000 --- a/source/third_party/fmt/format.h +++ /dev/null @@ -1,2662 +0,0 @@ -/* - * Slightly modified version of fmt, by Wildfire Games, for 0 A.D. - * Based on fmt v1.1.0 from https://github.com/fmtlib/fmt - */ - -/* - Formatting library for C++ - - Copyright (c) 2012 - 2015, Victor Zverovich - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FMT_FORMAT_H_ -#define FMT_FORMAT_H_ - -#include - -#include -#include -#include // for std::ptrdiff_t -#include -#include -#include -#include -#include - -#include "ps/CStr.h" - -#if defined(_SECURE_SCL) && _SECURE_SCL -# include -#endif - -#ifdef _MSC_VER -# include // _BitScanReverse, _BitScanReverse64 - -namespace fmt { -namespace internal { -# pragma intrinsic(_BitScanReverse) -inline uint32_t clz(uint32_t x) { - unsigned long r = 0; - _BitScanReverse(&r, x); - return 31 - r; -} -# define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n) - -# ifdef _WIN64 -# pragma intrinsic(_BitScanReverse64) -# endif - -inline uint32_t clzll(uint64_t x) { - unsigned long r = 0; -# ifdef _WIN64 - _BitScanReverse64(&r, x); -# else - // Scan the high 32 bits. - if (_BitScanReverse(&r, static_cast(x >> 32))) - return 63 - (r + 32); - - // Scan the low 32 bits. - _BitScanReverse(&r, static_cast(x)); -# endif - return 63 - r; -} -# define FMT_BUILTIN_CLZLL(n) fmt::internal::clzll(n) -} -} -#endif - -#ifdef __GNUC__ -# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -# define FMT_GCC_EXTENSION __extension__ -# if FMT_GCC_VERSION >= 406 -# pragma GCC diagnostic push -// Disable the warning about "long long" which is sometimes reported even -// when using __extension__. -# pragma GCC diagnostic ignored "-Wlong-long" -// Disable the warning about declaration shadowing because it affects too -// many valid cases. -# pragma GCC diagnostic ignored "-Wshadow" -# endif -# if __cplusplus >= 201103L || defined __GXX_EXPERIMENTAL_CXX0X__ -# define FMT_HAS_GXX_CXX11 1 -# endif -#else -# define FMT_GCC_EXTENSION -#endif - -#ifdef __clang__ -# pragma clang diagnostic ignored "-Wdocumentation" -#endif - -#ifdef __GNUC_LIBSTD__ -# define FMT_GNUC_LIBSTD_VERSION (__GNUC_LIBSTD__ * 100 + __GNUC_LIBSTD_MINOR__) -#endif - -#ifdef __has_feature -# define FMT_HAS_FEATURE(x) __has_feature(x) -#else -# define FMT_HAS_FEATURE(x) 0 -#endif - -#ifdef __has_builtin -# define FMT_HAS_BUILTIN(x) __has_builtin(x) -#else -# define FMT_HAS_BUILTIN(x) 0 -#endif - -#ifdef __has_cpp_attribute -# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) -#else -# define FMT_HAS_CPP_ATTRIBUTE(x) 0 -#endif - -#ifndef FMT_USE_VARIADIC_TEMPLATES -// Variadic templates are available in GCC since version 4.4 -// (http://gcc.gnu.org/projects/cxx0x.html) and in Visual C++ -// since version 2013. -# if defined(_MSC_VER) -# define FMT_USE_VARIADIC_TEMPLATES 1 -# else -# define FMT_USE_VARIADIC_TEMPLATES \ - (FMT_HAS_FEATURE(cxx_variadic_templates) || \ - (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11)) -# endif -#endif - -#ifndef FMT_USE_RVALUE_REFERENCES -// Don't use rvalue references when compiling with clang and an old libstdc++ -// as the latter doesn't provide std::move. -# if defined(FMT_GNUC_LIBSTD_VERSION) && FMT_GNUC_LIBSTD_VERSION <= 402 -# define FMT_USE_RVALUE_REFERENCES 0 -# elif defined(_MSC_VER) -# define FMT_USE_RVALUE_REFERENCES 1 -# else -# define FMT_USE_RVALUE_REFERENCES \ - (FMT_HAS_FEATURE(cxx_rvalue_references) || \ - (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11)) -# endif -#endif - -#if FMT_USE_RVALUE_REFERENCES -# include // for std::move -#endif - -// Define FMT_USE_NOEXCEPT to make C++ Format use noexcept (C++11 feature). -#if (defined(FMT_USE_NOEXCEPT) && FMT_USE_NOEXCEPT) || FMT_HAS_FEATURE(cxx_noexcept) || \ - (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) -# define FMT_NOEXCEPT noexcept -#else -# define FMT_NOEXCEPT throw() -#endif - -// A macro to disallow the copy constructor and operator= functions -// This should be used in the private: declarations for a class -#if (defined(FMT_USE_DELETED_FUNCTIONS) && FMT_USE_DELETED_FUNCTIONS) || FMT_HAS_FEATURE(cxx_deleted_functions) || \ - (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1800 -# define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&) = delete; \ - TypeName& operator=(const TypeName&) = delete -#else -# define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&); \ - TypeName& operator=(const TypeName&) -#endif - -namespace fmt { - -// Fix the warning about long long on older versions of GCC -// that don't support the diagnostic pragma. - FMT_GCC_EXTENSION typedef long long LongLong; - FMT_GCC_EXTENSION typedef unsigned long long ULongLong; - -#if FMT_USE_RVALUE_REFERENCES - using std::move; -#endif - - template - class BasicWriter; - - typedef BasicWriter Writer; - typedef BasicWriter WWriter; - - template - class BasicFormatter; - - template - void format(BasicFormatter &f, const Char *&format_str, const T &value); - -/** - \rst - A string reference. It can be constructed from a C string or - ``std::string``. - - You can use one of the following typedefs for common character types: - - +------------+-------------------------+ - | Type | Definition | - +============+=========================+ - | StringRef | BasicStringRef | - +------------+-------------------------+ - | WStringRef | BasicStringRef | - +------------+-------------------------+ - - This class is most useful as a parameter type to allow passing - different types of strings to a function, for example:: - - template - std::string format(StringRef format_str, const Args & ... args); - - format("{}", 42); - format(std::string("{}"), 42); - \endrst - */ - template - class BasicStringRef { - private: - const Char *data_; - std::size_t size_; - - public: - /** - Constructs a string reference object from a C string and a size. - */ - BasicStringRef(const Char *s, std::size_t size) : data_(s), size_(size) {} - - /** - Constructs a string reference object from a C string computing - the size with ``std::char_traits::length``. - */ - BasicStringRef(const Char *s) - : data_(s), size_(std::char_traits::length(s)) {} - - /** - Constructs a string reference from an `std::string` object. - */ - BasicStringRef(const std::basic_string &s) - : data_(s.c_str()), size_(s.size()) {} - - /** - Converts a string reference to an `std::string` object. - */ - operator std::basic_string() const { - return std::basic_string(data_, size()); - } - - /** - Returns the pointer to a C string. - */ - const Char *c_str() const { return data_; } - - /** - Returns the string size. - */ - std::size_t size() const { return size_; } - - friend bool operator==(BasicStringRef lhs, BasicStringRef rhs) { - return lhs.data_ == rhs.data_; - } - friend bool operator!=(BasicStringRef lhs, BasicStringRef rhs) { - return lhs.data_ != rhs.data_; - } - }; - - typedef BasicStringRef StringRef; - typedef BasicStringRef WStringRef; - -/** - A formatting error such as invalid format string. -*/ - class FormatError : public std::runtime_error { - public: - explicit FormatError(StringRef message) - : std::runtime_error(message.c_str()) {} - }; - - namespace internal { - -// The number of characters to store in the MemoryBuffer object itself -// to avoid dynamic memory allocation. - enum { INLINE_BUFFER_SIZE = 500 }; - -#if defined(_SECURE_SCL) && _SECURE_SCL - // Use checked iterator to avoid warnings on MSVC. -template -inline stdext::checked_array_iterator make_ptr(T *ptr, std::size_t size) { - return stdext::checked_array_iterator(ptr, size); -} -#else - template - inline T *make_ptr(T *ptr, std::size_t) { return ptr; } -#endif - -// A buffer for POD types. It supports a subset of std::vector's operations. - template - class Buffer { - private: - FMT_DISALLOW_COPY_AND_ASSIGN(Buffer); - - protected: - T *ptr_; - std::size_t size_; - std::size_t capacity_; - - Buffer(T *ptr = 0, std::size_t capacity = 0) - : ptr_(ptr), size_(0), capacity_(capacity) {} - - virtual void grow(std::size_t size) = 0; - - public: - virtual ~Buffer() {} - - // Returns the size of this buffer. - std::size_t size() const { return size_; } - - // Returns the capacity of this buffer. - std::size_t capacity() const { return capacity_; } - - // Resizes the buffer. If T is a POD type new elements are not initialized. - void resize(std::size_t new_size) { - if (new_size > capacity_) - grow(new_size); - size_ = new_size; - } - - // Reserves space to store at least capacity elements. - void reserve(std::size_t capacity) { - if (capacity > capacity_) - grow(capacity); - } - - void clear() FMT_NOEXCEPT { size_ = 0; } - - void push_back(const T &value) { - if (size_ == capacity_) - grow(size_ + 1); - ptr_[size_++] = value; - } - - // Appends data to the end of the buffer. - void append(const T *begin, const T *end); - - T &operator[](std::size_t index) { return ptr_[index]; } - const T &operator[](std::size_t index) const { return ptr_[index]; } - }; - - template - void Buffer::append(const T *begin, const T *end) { - std::ptrdiff_t num_elements = end - begin; - if (size_ + num_elements > capacity_) - grow(size_ + num_elements); - std::copy(begin, end, make_ptr(ptr_, capacity_) + size_); - size_ += num_elements; - } - -// A memory buffer for POD types with the first SIZE elements stored in -// the object itself. - template > - class MemoryBuffer : private Allocator, public Buffer { - private: - T data_[SIZE]; - - // Free memory allocated by the buffer. - void free() { - if (this->ptr_ != data_) this->deallocate(this->ptr_, this->capacity_); - } - - protected: - void grow(std::size_t size); - - public: - explicit MemoryBuffer(const Allocator &alloc = Allocator()) - : Allocator(alloc), Buffer(data_, SIZE) {} - ~MemoryBuffer() { free(); } - -#if FMT_USE_RVALUE_REFERENCES - private: - // Move data from other to this buffer. - void move(MemoryBuffer &other) { - Allocator &this_alloc = *this, &other_alloc = other; - this_alloc = std::move(other_alloc); - this->size_ = other.size_; - this->capacity_ = other.capacity_; - if (other.ptr_ == other.data_) { - this->ptr_ = data_; - std::copy(other.data_, - other.data_ + this->size_, make_ptr(data_, this->capacity_)); - } else { - this->ptr_ = other.ptr_; - // Set pointer to the inline array so that delete is not called - // when freeing. - other.ptr_ = other.data_; - } - } - - public: - MemoryBuffer(MemoryBuffer &&other) { - move(other); - } - - MemoryBuffer &operator=(MemoryBuffer &&other) { - assert(this != &other); - free(); - move(other); - return *this; - } -#endif - - // Returns a copy of the allocator associated with this buffer. - Allocator get_allocator() const { return *this; } - }; - - template - void MemoryBuffer::grow(std::size_t size) { - std::size_t new_capacity = - (std::max)(size, this->capacity_ + this->capacity_ / 2); - T *new_ptr = this->allocate(new_capacity); - // The following code doesn't throw, so the raw pointer above doesn't leak. - std::copy(this->ptr_, - this->ptr_ + this->size_, make_ptr(new_ptr, new_capacity)); - std::size_t old_capacity = this->capacity_; - T *old_ptr = this->ptr_; - this->capacity_ = new_capacity; - this->ptr_ = new_ptr; - // deallocate may throw (at least in principle), but it doesn't matter since - // the buffer already uses the new storage and will deallocate it in case - // of exception. - if (old_ptr != data_) - this->deallocate(old_ptr, old_capacity); - } - -// A fixed-size buffer. - template - class FixedBuffer : public fmt::internal::Buffer { - public: - FixedBuffer(Char *array, std::size_t size) - : fmt::internal::Buffer(array, size) {} - - protected: - void grow(std::size_t size); - }; - -#ifndef _MSC_VER -// Portable version of signbit. - inline int getsign(double x) { - // When compiled in C++11 mode signbit is no longer a macro but a function - // defined in namespace std and the macro is undefined. -# ifdef signbit - return signbit(x); -# else - return std::signbit(x); -# endif - } - -// Portable version of isinf. -# ifdef isinf - inline int isinfinity(double x) { return isinf(x); } -inline int isinfinity(long double x) { return isinf(x); } -# else - inline int isinfinity(double x) { return std::isinf(x); } - inline int isinfinity(long double x) { return std::isinf(x); } -# endif -#else - inline int getsign(double value) { - if (value < 0) return 1; - if (value == value) return 0; - int dec = 0, sign = 0; - char buffer[2]; // The buffer size must be >= 2 or _ecvt_s will fail. - _ecvt_s(buffer, sizeof(buffer), value, 0, &dec, &sign); - return sign; -} -inline int isinfinity(double x) { return !_finite(x); } -inline int isinfinity(long double x) { return !_finite(static_cast(x)); } -#endif - - template - class BasicCharTraits { - public: -#if defined(_SECURE_SCL) && _SECURE_SCL - typedef stdext::checked_array_iterator CharPtr; -#else - typedef Char *CharPtr; -#endif - }; - - template - class CharTraits; - - template <> - class CharTraits : public BasicCharTraits { - private: - // Conversion from wchar_t to char is not allowed. - static char convert(wchar_t); - - public: - static char convert(char value) { return value; } - - // Formats a floating-point number. - template - static int format_float(char *buffer, std::size_t size, - const char *format, unsigned width, int precision, T value); - }; - - template <> - class CharTraits : public BasicCharTraits { - public: - static wchar_t convert(char value) { return value; } - static wchar_t convert(wchar_t value) { return value; } - - template - static int format_float(wchar_t *buffer, std::size_t size, - const wchar_t *format, unsigned width, int precision, T value); - }; - -// Checks if a number is negative - used to avoid warnings. - template - struct SignChecker { - template - static bool is_negative(T value) { return value < 0; } - }; - - template <> - struct SignChecker { - template - static bool is_negative(T) { return false; } - }; - -// Returns true if value is negative, false otherwise. -// Same as (value < 0) but doesn't produce warnings if T is an unsigned type. - template - inline bool is_negative(T value) { - return SignChecker::is_signed>::is_negative(value); - } - -// Selects uint32_t if FitsIn32Bits is true, uint64_t otherwise. - template - struct TypeSelector { typedef uint32_t Type; }; - - template <> - struct TypeSelector { typedef uint64_t Type; }; - - template - struct IntTraits { - // Smallest of uint32_t and uint64_t that is large enough to represent - // all values of T. - typedef typename - TypeSelector::digits <= 32>::Type MainType; - }; - -// MakeUnsigned::Type gives an unsigned type corresponding to integer type T. - template - struct MakeUnsigned { typedef T Type; }; - -#define FMT_SPECIALIZE_MAKE_UNSIGNED(T, U) \ - template <> \ - struct MakeUnsigned { typedef U Type; } - - FMT_SPECIALIZE_MAKE_UNSIGNED(char, unsigned char); - FMT_SPECIALIZE_MAKE_UNSIGNED(signed char, unsigned char); - FMT_SPECIALIZE_MAKE_UNSIGNED(short, unsigned short); - FMT_SPECIALIZE_MAKE_UNSIGNED(int, unsigned); - FMT_SPECIALIZE_MAKE_UNSIGNED(long, unsigned long); - FMT_SPECIALIZE_MAKE_UNSIGNED(LongLong, ULongLong); - - void report_unknown_type(char code, const char *type); - -// Static data is placed in this class template to allow header-only -// configuration. - template - struct BasicData { - static const uint32_t POWERS_OF_10_32[]; - static const uint64_t POWERS_OF_10_64[]; - static const char DIGITS[]; - }; - - typedef BasicData<> Data; - -#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz) -# define FMT_BUILTIN_CLZ(n) __builtin_clz(n) -#endif - -#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll) -# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) -#endif - -#ifdef FMT_BUILTIN_CLZLL - // Returns the number of decimal digits in n. Leading zeros are not counted -// except for n == 0 in which case count_digits returns 1. -inline unsigned count_digits(uint64_t n) { - // Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 - // and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits. - unsigned t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12; - return t - (n < Data::POWERS_OF_10_64[t]) + 1; -} -#else -// Fallback version of count_digits used when __builtin_clz is not available. - inline unsigned count_digits(uint64_t n) { - unsigned count = 1; - for (;;) { - // Integer division is slow so do it for a group of four digits instead - // of for every digit. The idea comes from the talk by Alexandrescu - // "Three Optimization Tips for C++". See speed-test for a comparison. - if (n < 10) return count; - if (n < 100) return count + 1; - if (n < 1000) return count + 2; - if (n < 10000) return count + 3; - n /= 10000u; - count += 4; - } - } -#endif - -#ifdef FMT_BUILTIN_CLZ - // Optional version of count_digits for better performance on 32-bit platforms. -inline unsigned count_digits(uint32_t n) { - uint32_t t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12; - return t - (n < Data::POWERS_OF_10_32[t]) + 1; -} -#endif - -// Formats a decimal unsigned integer value writing into buffer. - template - inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) { - --num_digits; - while (value >= 100) { - // Integer division is slow so do it for a group of two digits instead - // of for every digit. The idea comes from the talk by Alexandrescu - // "Three Optimization Tips for C++". See speed-test for a comparison. - unsigned index = (value % 100) * 2; - value /= 100; - buffer[num_digits] = Data::DIGITS[index + 1]; - buffer[num_digits - 1] = Data::DIGITS[index]; - num_digits -= 2; - } - if (value < 10) { - *buffer = static_cast('0' + value); - return; - } - unsigned index = static_cast(value * 2); - buffer[1] = Data::DIGITS[index + 1]; - buffer[0] = Data::DIGITS[index]; - } - -#ifdef _WIN32 - // A converter from UTF-8 to UTF-16. -// It is only provided for Windows since other systems support UTF-8 natively. -class UTF8ToUTF16 { - private: - MemoryBuffer buffer_; - - public: - explicit UTF8ToUTF16(StringRef s); - operator WStringRef() const { return WStringRef(&buffer_[0], size()); } - size_t size() const { return buffer_.size() - 1; } - const wchar_t *c_str() const { return &buffer_[0]; } - std::wstring str() const { return std::wstring(&buffer_[0], size()); } -}; - -// A converter from UTF-16 to UTF-8. -// It is only provided for Windows since other systems support UTF-8 natively. -class UTF16ToUTF8 { - private: - MemoryBuffer buffer_; - - public: - UTF16ToUTF8() {} - explicit UTF16ToUTF8(WStringRef s); - operator StringRef() const { return StringRef(&buffer_[0], size()); } - size_t size() const { return buffer_.size() - 1; } - const char *c_str() const { return &buffer_[0]; } - std::string str() const { return std::string(&buffer_[0], size()); } - - // Performs conversion returning a system error code instead of - // throwing exception on conversion error. This method may still throw - // in case of memory allocation error. - int convert(WStringRef s); -}; -#endif - - void format_system_error(fmt::Writer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT; - -#ifdef _WIN32 - void format_windows_error(fmt::Writer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT; -#endif - -// Computes max(Arg, 1) at compile time. It is used to avoid errors about -// allocating an array of 0 size. - template - struct NonZero { - enum { VALUE = Arg }; - }; - - template <> - struct NonZero<0> { - enum { VALUE = 1 }; - }; - -// The value of a formatting argument. It is a POD type to allow storage in -// internal::MemoryBuffer. - struct Value { - template - struct StringValue { - const Char *value; - std::size_t size; - }; - - typedef void (*FormatFunc)( - void *formatter, const void *arg, void *format_str_ptr); - - struct CustomValue { - const void *value; - FormatFunc format; - }; - - union { - int int_value; - unsigned uint_value; - LongLong long_long_value; - ULongLong ulong_long_value; - double double_value; - long double long_double_value; - const void *pointer; - StringValue string; - StringValue sstring; - StringValue ustring; - StringValue wstring; - CustomValue custom; - }; - }; - - struct Arg : Value { - enum Type { - NONE, - // Integer types should go first, - INT, UINT, LONG_LONG, ULONG_LONG, CHAR, LAST_INTEGER_TYPE = CHAR, - // followed by floating-point types. - DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE, - CSTRING, STRING, WSTRING, POINTER, CUSTOM - }; - Type type; - }; - - template - struct None {}; - -// A helper class template to enable or disable overloads taking wide -// characters and strings in MakeValue. - template - struct WCharHelper { - typedef None Supported; - typedef T Unsupported; - }; - - template - struct WCharHelper { - typedef T Supported; - typedef None Unsupported; - }; - -// Makes a Value object from any type. - template - class MakeValue : public Value { - private: - // The following two methods are private to disallow formatting of - // arbitrary pointers. If you want to output a pointer cast it to - // "void *" or "const void *". In particular, this forbids formatting - // of "[const] volatile char *" which is printed as bool by iostreams. - // Do not implement! - template - MakeValue(const T *value); - template - MakeValue(T *value); - - // The following methods are private to disallow formatting of wide - // characters and strings into narrow strings as in - // fmt::format("{}", L"test"); - // To fix this, use a wide format string: fmt::format(L"{}", L"test"). - MakeValue(typename WCharHelper::Unsupported); - MakeValue(typename WCharHelper::Unsupported); - MakeValue(typename WCharHelper::Unsupported); - MakeValue(typename WCharHelper::Unsupported); - MakeValue(typename WCharHelper::Unsupported); - - void set_string(StringRef str) { - string.value = str.c_str(); - string.size = str.size(); - } - - void set_string(WStringRef str) { - wstring.value = str.c_str(); - wstring.size = str.size(); - } - - // Formats an argument of a custom type, such as a user-defined class. - template - static void format_custom_arg( - void *formatter, const void *arg, void *format_str_ptr) { - format(*static_cast*>(formatter), - *static_cast(format_str_ptr), - *static_cast(arg)); - } - - public: - MakeValue() {} - -#define FMT_MAKE_VALUE(Type, field, TYPE) \ - MakeValue(Type value) { field = value; } \ - static uint64_t type(Type) { return Arg::TYPE; } - - FMT_MAKE_VALUE(bool, int_value, INT) - FMT_MAKE_VALUE(short, int_value, INT) - FMT_MAKE_VALUE(unsigned short, uint_value, UINT) - FMT_MAKE_VALUE(int, int_value, INT) - FMT_MAKE_VALUE(unsigned, uint_value, UINT) - - MakeValue(long value) { - // To minimize the number of types we need to deal with, long is - // translated either to int or to long long depending on its size. - if (sizeof(long) == sizeof(int)) - int_value = static_cast(value); - else - long_long_value = value; - } - static uint64_t type(long) { - return sizeof(long) == sizeof(int) ? Arg::INT : Arg::LONG_LONG; - } - - MakeValue(unsigned long value) { - if (sizeof(unsigned long) == sizeof(unsigned)) - uint_value = static_cast(value); - else - ulong_long_value = value; - } - static uint64_t type(unsigned long) { - return sizeof(unsigned long) == sizeof(unsigned) ? - Arg::UINT : Arg::ULONG_LONG; - } - - FMT_MAKE_VALUE(LongLong, long_long_value, LONG_LONG) - FMT_MAKE_VALUE(ULongLong, ulong_long_value, ULONG_LONG) - FMT_MAKE_VALUE(float, double_value, DOUBLE) - FMT_MAKE_VALUE(double, double_value, DOUBLE) - FMT_MAKE_VALUE(long double, long_double_value, LONG_DOUBLE) - FMT_MAKE_VALUE(signed char, int_value, CHAR) - FMT_MAKE_VALUE(unsigned char, int_value, CHAR) - FMT_MAKE_VALUE(char, int_value, CHAR) - - MakeValue(typename WCharHelper::Supported value) { - int_value = value; - } - static uint64_t type(wchar_t) { return Arg::CHAR; } - -#define FMT_MAKE_STR_VALUE(Type, TYPE) \ - MakeValue(Type value) { set_string(value); } \ - static uint64_t type(Type) { return Arg::TYPE; } - - FMT_MAKE_VALUE(char *, string.value, CSTRING) - FMT_MAKE_VALUE(const char *, string.value, CSTRING) - FMT_MAKE_VALUE(const signed char *, sstring.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) - FMT_MAKE_STR_VALUE(const CStr &, STRING) - -#define FMT_MAKE_WSTR_VALUE(Type, TYPE) \ - MakeValue(typename WCharHelper::Supported value) { \ - set_string(value); \ - } \ - static uint64_t type(Type) { return Arg::TYPE; } - - FMT_MAKE_WSTR_VALUE(wchar_t *, WSTRING) - FMT_MAKE_WSTR_VALUE(const wchar_t *, WSTRING) - FMT_MAKE_WSTR_VALUE(const std::wstring &, WSTRING) - FMT_MAKE_WSTR_VALUE(WStringRef, WSTRING) - - FMT_MAKE_VALUE(void *, pointer, POINTER) - FMT_MAKE_VALUE(const void *, pointer, POINTER) - - template - MakeValue(const T &value) { - custom.value = &value; - custom.format = &format_custom_arg; - } - template - static uint64_t type(const T &) { return Arg::CUSTOM; } - }; - -#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: - Result visit_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_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_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: - assert(false); - 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::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::CHAR: - return FMT_DISPATCH(visit_char(arg.int_value)); - case Arg::CSTRING: { - Value::StringValue str = arg.string; - str.size = 0; - return FMT_DISPATCH(visit_string(str)); - } - 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("") {} - }; - - template - class ArgFormatter; - } // namespace internal - -/** - An argument list. - */ - class ArgList { - private: - uint64_t types_; - const internal::Value *values_; - - public: - // Maximum number of arguments that can be passed in ArgList. - enum { MAX_ARGS = 16 }; - - ArgList() : types_(0) {} - ArgList(ULongLong types, const internal::Value *values) - : types_(types), values_(values) {} - - /** - Returns the argument at specified index. - */ - internal::Arg operator[](unsigned index) const { - using internal::Arg; - Arg arg; - if (index >= MAX_ARGS) { - arg.type = Arg::NONE; - return arg; - } - unsigned shift = index * 4; - uint64_t mask = 0xf; - Arg::Type type = - static_cast((types_ & (mask << shift)) >> shift); - arg.type = type; - if (type != Arg::NONE) { - internal::Value &value = arg; - value = values_[index]; - } - return arg; - } - }; - - struct FormatSpec; - - namespace internal { - - class FormatterBase { - private: - ArgList args_; - int next_arg_index_; - - // Returns the argument with specified index. - Arg do_get_arg(unsigned arg_index, const char *&error); - - protected: - void set_args(const ArgList &args) { - args_ = args; - next_arg_index_ = 0; - } - - // Returns the next argument. - Arg next_arg(const char *&error); - - // Checks if manual indexing is used and returns the argument with - // specified index. - Arg get_arg(unsigned arg_index, const char *&error); - - template - void write(BasicWriter &w, const Char *start, const Char *end) { - if (start != end) - w << BasicStringRef(start, end - start); - } - }; - -// A printf formatter. - template - class PrintfFormatter : private FormatterBase { - private: - void parse_flags(FormatSpec &spec, const Char *&s); - - // Returns the argument with specified index or, if arg_index is equal - // to the maximum unsigned value, the next argument. - Arg get_arg(const Char *s, - unsigned arg_index = (std::numeric_limits::max)()); - - // Parses argument index, flags and width and returns the argument index. - unsigned parse_header(const Char *&s, FormatSpec &spec); - - public: - void format(BasicWriter &writer, - BasicStringRef format_str, const ArgList &args); - }; - } // namespace internal - -// A formatter. - template - class BasicFormatter : private internal::FormatterBase { - private: - BasicWriter &writer_; - const Char *start_; - - FMT_DISALLOW_COPY_AND_ASSIGN(BasicFormatter); - - // Parses argument index and returns corresponding argument. - internal::Arg parse_arg_index(const Char *&s); - - public: - explicit BasicFormatter(BasicWriter &w) : writer_(w) {} - - BasicWriter &writer() { return writer_; } - - void format(BasicStringRef format_str, const ArgList &args); - - const Char *format(const Char *&format_str, const internal::Arg &arg); - }; - - enum Alignment { - ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC - }; - -// Flags. - enum { - SIGN_FLAG = 1, PLUS_FLAG = 2, MINUS_FLAG = 4, HASH_FLAG = 8, - CHAR_FLAG = 0x10 // Argument has char type - used in error reporting. - }; - -// An empty format specifier. - struct EmptySpec {}; - -// A type specifier. - template - struct TypeSpec : EmptySpec { - Alignment align() const { return ALIGN_DEFAULT; } - unsigned width() const { return 0; } - int precision() const { return -1; } - bool flag(unsigned) const { return false; } - char type() const { return TYPE; } - char fill() const { return ' '; } - }; - -// A width specifier. - struct WidthSpec { - unsigned width_; - // Fill is always wchar_t and cast to char if necessary to avoid having - // two specialization of WidthSpec and its subclasses. - wchar_t fill_; - - WidthSpec(unsigned width, wchar_t fill) : width_(width), fill_(fill) {} - - unsigned width() const { return width_; } - wchar_t fill() const { return fill_; } - }; - -// An alignment specifier. - struct AlignSpec : WidthSpec { - Alignment align_; - - AlignSpec(unsigned width, wchar_t fill, Alignment align = ALIGN_DEFAULT) - : WidthSpec(width, fill), align_(align) {} - - Alignment align() const { return align_; } - - int precision() const { return -1; } - }; - -// An alignment and type specifier. - template - struct AlignTypeSpec : AlignSpec { - AlignTypeSpec(unsigned width, wchar_t fill) : AlignSpec(width, fill) {} - - bool flag(unsigned) const { return false; } - char type() const { return TYPE; } - }; - -// A full format specifier. - struct FormatSpec : AlignSpec { - unsigned flags_; - int precision_; - char type_; - - FormatSpec( - unsigned width = 0, char type = 0, wchar_t fill = ' ') - : AlignSpec(width, fill), flags_(0), precision_(-1), type_(type) {} - - bool flag(unsigned f) const { return (flags_ & f) != 0; } - int precision() const { return precision_; } - char type() const { return type_; } - }; - -// An integer format specifier. - template , typename Char = char> - class IntFormatSpec : public SpecT { - private: - T value_; - - public: - IntFormatSpec(T val, const SpecT &spec = SpecT()) - : SpecT(spec), value_(val) {} - - T value() const { return value_; } - }; - -// A string format specifier. - template - class StrFormatSpec : public AlignSpec { - private: - const T *str_; - - public: - StrFormatSpec(const T *str, unsigned width, wchar_t fill) - : AlignSpec(width, fill), str_(str) {} - - const T *str() const { return str_; } - }; - -/** - Returns an integer format specifier to format the value in base 2. - */ - IntFormatSpec > bin(int value); - -/** - Returns an integer format specifier to format the value in base 8. - */ - IntFormatSpec > oct(int value); - -/** - Returns an integer format specifier to format the value in base 16 using - lower-case letters for the digits above 9. - */ - IntFormatSpec > hex(int value); - -/** - Returns an integer formatter format specifier to format in base 16 using - upper-case letters for the digits above 9. - */ - IntFormatSpec > hexu(int value); - -/** - \rst - Returns an integer format specifier to pad the formatted argument with the - fill character to the specified width using the default (right) numeric - alignment. - - **Example**:: - - MemoryWriter out; - out << pad(hex(0xcafe), 8, '0'); - // out.str() == "0000cafe" - - \endrst - */ - template - IntFormatSpec, Char> pad( - int value, unsigned width, Char fill = ' '); - -#define FMT_DEFINE_INT_FORMATTERS(TYPE) \ -inline IntFormatSpec > bin(TYPE value) { \ - return IntFormatSpec >(value, TypeSpec<'b'>()); \ -} \ - \ -inline IntFormatSpec > oct(TYPE value) { \ - return IntFormatSpec >(value, TypeSpec<'o'>()); \ -} \ - \ -inline IntFormatSpec > hex(TYPE value) { \ - return IntFormatSpec >(value, TypeSpec<'x'>()); \ -} \ - \ -inline IntFormatSpec > hexu(TYPE value) { \ - return IntFormatSpec >(value, TypeSpec<'X'>()); \ -} \ - \ -template \ -inline IntFormatSpec > pad( \ - IntFormatSpec > f, unsigned width) { \ - return IntFormatSpec >( \ - f.value(), AlignTypeSpec(width, ' ')); \ -} \ - \ -/* For compatibility with older compilers we provide two overloads for pad, */ \ -/* one that takes a fill character and one that doesn't. In the future this */ \ -/* can be replaced with one overload making the template argument Char */ \ -/* default to char (C++11). */ \ -template \ -inline IntFormatSpec, Char> pad( \ - IntFormatSpec, Char> f, \ - unsigned width, Char fill) { \ - return IntFormatSpec, Char>( \ - f.value(), AlignTypeSpec(width, fill)); \ -} \ - \ -inline IntFormatSpec > pad( \ - TYPE value, unsigned width) { \ - return IntFormatSpec >( \ - value, AlignTypeSpec<0>(width, ' ')); \ -} \ - \ -template \ -inline IntFormatSpec, Char> pad( \ - TYPE value, unsigned width, Char fill) { \ - return IntFormatSpec, Char>( \ - value, AlignTypeSpec<0>(width, fill)); \ -} - - FMT_DEFINE_INT_FORMATTERS(int) - FMT_DEFINE_INT_FORMATTERS(long) - FMT_DEFINE_INT_FORMATTERS(unsigned) - FMT_DEFINE_INT_FORMATTERS(unsigned long) - FMT_DEFINE_INT_FORMATTERS(LongLong) - FMT_DEFINE_INT_FORMATTERS(ULongLong) - -/** - \rst - Returns a string formatter that pads the formatted argument with the fill - character to the specified width using the default (left) string alignment. - - **Example**:: - - std::string s = str(MemoryWriter() << pad("abc", 8)); - // s == "abc " - - \endrst - */ - template - inline StrFormatSpec pad( - const Char *str, unsigned width, Char fill = ' ') { - return StrFormatSpec(str, width, fill); - } - - inline StrFormatSpec pad( - const wchar_t *str, unsigned width, char fill = ' ') { - return StrFormatSpec(str, width, fill); - } - -// Generates a comma-separated list with results of applying f to -// numbers 0..n-1. -# define FMT_GEN(n, f) FMT_GEN##n(f) -# define FMT_GEN1(f) f(0) -# define FMT_GEN2(f) FMT_GEN1(f), f(1) -# define FMT_GEN3(f) FMT_GEN2(f), f(2) -# define FMT_GEN4(f) FMT_GEN3(f), f(3) -# define FMT_GEN5(f) FMT_GEN4(f), f(4) -# define FMT_GEN6(f) FMT_GEN5(f), f(5) -# define FMT_GEN7(f) FMT_GEN6(f), f(6) -# define FMT_GEN8(f) FMT_GEN7(f), f(7) -# define FMT_GEN9(f) FMT_GEN8(f), f(8) -# define FMT_GEN10(f) FMT_GEN9(f), f(9) -# define FMT_GEN11(f) FMT_GEN10(f), f(10) -# define FMT_GEN12(f) FMT_GEN11(f), f(11) -# define FMT_GEN13(f) FMT_GEN12(f), f(12) -# define FMT_GEN14(f) FMT_GEN13(f), f(13) -# define FMT_GEN15(f) FMT_GEN14(f), f(14) - - namespace internal { - inline uint64_t make_type() { return 0; } - - template - inline uint64_t make_type(const T &arg) { return MakeValue::type(arg); } - -#if FMT_USE_VARIADIC_TEMPLATES - template -inline uint64_t make_type(const Arg &first, const Args & ... tail) { - return make_type(first) | (make_type(tail...) << 4); -} -#else - - struct ArgType { - uint64_t type; - - ArgType() : type(0) {} - - template - ArgType(const T &arg) : type(make_type(arg)) {} - }; - -# define FMT_ARG_TYPE_DEFAULT(n) ArgType t##n = ArgType() - - inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { - return t0.type | (t1.type << 4) | (t2.type << 8) | (t3.type << 12) | - (t4.type << 16) | (t5.type << 20) | (t6.type << 24) | (t7.type << 28) | - (t8.type << 32) | (t9.type << 36) | (t10.type << 40) | (t11.type << 44) | - (t12.type << 48) | (t13.type << 52) | (t14.type << 56); - } -#endif - } // namespace internal - -# define FMT_MAKE_TEMPLATE_ARG(n) typename T##n -# define FMT_MAKE_ARG_TYPE(n) T##n -# define FMT_MAKE_ARG(n) const T##n &v##n -# define FMT_MAKE_REF_char(n) fmt::internal::MakeValue(v##n) -# define FMT_MAKE_REF_wchar_t(n) fmt::internal::MakeValue(v##n) - -#if FMT_USE_VARIADIC_TEMPLATES - // Defines a variadic function returning void. -# define FMT_VARIADIC_VOID(func, arg_type) \ - template \ - void func(arg_type arg1, const Args & ... args) { \ - const fmt::internal::Value values[ \ - fmt::internal::NonZero::VALUE] = { \ - fmt::internal::MakeValue(args)... \ - }; \ - func(arg1, ArgList(fmt::internal::make_type(args...), values)); \ - } - -// Defines a variadic constructor. -# define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ - template \ - ctor(arg0_type arg0, arg1_type arg1, const Args & ... args) { \ - using fmt::internal::MakeValue; \ - const fmt::internal::Value values[ \ - fmt::internal::NonZero::VALUE] = { \ - MakeValue(args)... \ - }; \ - func(arg0, arg1, ArgList(fmt::internal::make_type(args...), values)); \ - } - -#else - -# define FMT_MAKE_REF(n) fmt::internal::MakeValue(v##n) -# define FMT_MAKE_REF2(n) v##n - -// Defines a wrapper for a function taking one argument of type arg_type -// and n additional arguments of arbitrary types. -# define FMT_WRAP1(func, arg_type, n) \ - template \ - inline void func(arg_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ - const fmt::internal::Value vals[] = {FMT_GEN(n, FMT_MAKE_REF)}; \ - func(arg1, fmt::ArgList( \ - fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), vals)); \ - } - -// Emulates a variadic function returning void on a pre-C++11 compiler. -# define FMT_VARIADIC_VOID(func, arg_type) \ - inline void func(arg_type arg) { func(arg, fmt::ArgList()); } \ - FMT_WRAP1(func, arg_type, 1) FMT_WRAP1(func, arg_type, 2) \ - FMT_WRAP1(func, arg_type, 3) FMT_WRAP1(func, arg_type, 4) \ - FMT_WRAP1(func, arg_type, 5) FMT_WRAP1(func, arg_type, 6) \ - FMT_WRAP1(func, arg_type, 7) FMT_WRAP1(func, arg_type, 8) \ - FMT_WRAP1(func, arg_type, 9) FMT_WRAP1(func, arg_type, 10) - -# define FMT_CTOR(ctor, func, arg0_type, arg1_type, n) \ - template \ - ctor(arg0_type arg0, arg1_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ - const fmt::internal::Value vals[] = {FMT_GEN(n, FMT_MAKE_REF)}; \ - func(arg0, arg1, fmt::ArgList( \ - fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), vals)); \ - } - -// Emulates a variadic constructor on a pre-C++11 compiler. -# define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 1) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 2) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 3) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 4) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 5) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 6) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 7) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 8) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 9) \ - FMT_CTOR(ctor, func, arg0_type, arg1_type, 10) -#endif - -// Generates a comma-separated list with results of applying f to pairs -// (argument, index). -#define FMT_FOR_EACH1(f, x0) f(x0, 0) -#define FMT_FOR_EACH2(f, x0, x1) \ - FMT_FOR_EACH1(f, x0), f(x1, 1) -#define FMT_FOR_EACH3(f, x0, x1, x2) \ - FMT_FOR_EACH2(f, x0 ,x1), f(x2, 2) -#define FMT_FOR_EACH4(f, x0, x1, x2, x3) \ - FMT_FOR_EACH3(f, x0, x1, x2), f(x3, 3) -#define FMT_FOR_EACH5(f, x0, x1, x2, x3, x4) \ - FMT_FOR_EACH4(f, x0, x1, x2, x3), f(x4, 4) -#define FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5) \ - FMT_FOR_EACH5(f, x0, x1, x2, x3, x4), f(x5, 5) -#define FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6) \ - FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5), f(x6, 6) -#define FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7) \ - FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6), f(x7, 7) -#define FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8) \ - FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7), f(x8, 8) -#define FMT_FOR_EACH10(f, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) \ - FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8), f(x9, 9) - -/** - An error returned by an operating system or a language runtime, - for example a file opening error. -*/ - class SystemError : public internal::RuntimeError { - private: - void init(int err_code, StringRef format_str, ArgList args); - - protected: - int error_code_; - - typedef char Char; // For FMT_VARIADIC_CTOR. - - SystemError() {} - - public: - /** - \rst - Constructs a :class:`fmt::SystemError` object with the description - of the form - - .. parsed-literal:: - **: ** - - where ** is the formatted message and ** is - the system message corresponding to the error code. - *error_code* is a system error code as given by ``errno``. - If *error_code* is not a valid error code such as -1, the system message - may look like "Unknown error -1" and is platform-dependent. - - **Example**:: - - // This throws a SystemError with the description - // cannot open file 'madeup': No such file or directory - // or similar (system message may vary). - const char *filename = "madeup"; - std::FILE *file = std::fopen(filename, "r"); - if (!file) - throw fmt::SystemError(errno, "cannot open file '{}'", filename); - \endrst - */ - SystemError(int error_code, StringRef message) { - init(error_code, message, ArgList()); - } - FMT_VARIADIC_CTOR(SystemError, init, int, StringRef) - - int error_code() const { return error_code_; } - }; - -/** - \rst - This template provides operations for formatting and writing data into - a character stream. The output is stored in a buffer provided by a subclass - such as :class:`fmt::BasicMemoryWriter`. - - You can use one of the following typedefs for common character types: - - +---------+----------------------+ - | Type | Definition | - +=========+======================+ - | Writer | BasicWriter | - +---------+----------------------+ - | WWriter | BasicWriter | - +---------+----------------------+ - - \endrst - */ - template - class BasicWriter { - private: - // Output buffer. - internal::Buffer &buffer_; - - FMT_DISALLOW_COPY_AND_ASSIGN(BasicWriter); - - typedef typename internal::CharTraits::CharPtr CharPtr; - -#if defined(_SECURE_SCL) && _SECURE_SCL - // Returns pointer value. - static Char *get(CharPtr p) { return p.base(); } -#else - static Char *get(Char *p) { return p; } -#endif - - // Fills the padding around the content and returns the pointer to the - // content area. - static CharPtr fill_padding(CharPtr buffer, - unsigned total_size, std::size_t content_size, wchar_t fill); - - // Grows the buffer by n characters and returns a pointer to the newly - // allocated area. - CharPtr grow_buffer(std::size_t n) { - std::size_t size = buffer_.size(); - buffer_.resize(size + n); - return internal::make_ptr(&buffer_[size], n); - } - - // Prepare a buffer for integer formatting. - CharPtr prepare_int_buffer(unsigned num_digits, - const EmptySpec &, const char *prefix, unsigned prefix_size) { - unsigned size = prefix_size + num_digits; - CharPtr p = grow_buffer(size); - std::copy(prefix, prefix + prefix_size, p); - return p + size - 1; - } - - template - CharPtr prepare_int_buffer(unsigned num_digits, - const Spec &spec, const char *prefix, unsigned prefix_size); - - // Formats an integer. - template - void write_int(T value, Spec spec); - - // Formats a floating-point number (double or long double). - template - void write_double(T value, const FormatSpec &spec); - - // Writes a formatted string. - template - CharPtr write_str( - const StrChar *s, std::size_t size, const AlignSpec &spec); - - template - void write_str( - const internal::Arg::StringValue &str, const FormatSpec &spec); - - // This following methods are private to disallow writing wide characters - // and strings to a char stream. If you want to print a wide string as a - // pointer as std::ostream does, cast it to const void*. - // Do not implement! - void operator<<(typename internal::WCharHelper::Unsupported); - void operator<<( - typename internal::WCharHelper::Unsupported); - - // Appends floating-point length specifier to the format string. - // The second argument is only used for overload resolution. - void append_float_length(Char *&format_ptr, long double) { - *format_ptr++ = 'L'; - } - - template - void append_float_length(Char *&, T) {} - - friend class internal::ArgFormatter; - friend class internal::PrintfFormatter; - - protected: - /** - Constructs a ``BasicWriter`` object. - */ - explicit BasicWriter(internal::Buffer &b) : buffer_(b) {} - - public: - /** - Destroys a ``BasicWriter`` object. - */ - virtual ~BasicWriter() {} - - /** - Returns the total number of characters written. - */ - std::size_t size() const { return buffer_.size(); } - - /** - Returns a pointer to the output buffer content. No terminating null - character is appended. - */ - const Char *data() const FMT_NOEXCEPT { return &buffer_[0]; } - - /** - Returns a pointer to the output buffer content with terminating null - character appended. - */ - const Char *c_str() const { - std::size_t size = buffer_.size(); - buffer_.reserve(size + 1); - buffer_[size] = '\0'; - return &buffer_[0]; - } - - /** - Returns the content of the output buffer as an `std::string`. - */ - std::basic_string str() const { - return std::basic_string(&buffer_[0], buffer_.size()); - } - - /** - \rst - Writes formatted data. - - *args* is an argument list representing arbitrary arguments. - - **Example**:: - - MemoryWriter out; - out.write("Current point:\n"); - out.write("({:+f}, {:+f})", -3.14, 3.14); - - This will write the following output to the ``out`` object: - - .. code-block:: none - - Current point: - (-3.140000, +3.140000) - - The output can be accessed using :func:`data()`, :func:`c_str` or - :func:`str` methods. - - See also :ref:`syntax`. - \endrst - */ - void write(BasicStringRef format, ArgList args) { - BasicFormatter(*this).format(format, args); - } - FMT_VARIADIC_VOID(write, BasicStringRef) - - BasicWriter &operator<<(int value) { - return *this << IntFormatSpec(value); - } - BasicWriter &operator<<(unsigned value) { - return *this << IntFormatSpec(value); - } - BasicWriter &operator<<(long value) { - return *this << IntFormatSpec(value); - } - BasicWriter &operator<<(unsigned long value) { - return *this << IntFormatSpec(value); - } - BasicWriter &operator<<(LongLong value) { - return *this << IntFormatSpec(value); - } - - /** - Formats *value* and writes it to the stream. - */ - BasicWriter &operator<<(ULongLong value) { - return *this << IntFormatSpec(value); - } - - BasicWriter &operator<<(double value) { - write_double(value, FormatSpec()); - return *this; - } - - /** - Formats *value* using the general format for floating-point numbers - (``'g'``) and writes it to the stream. - */ - BasicWriter &operator<<(long double value) { - write_double(value, FormatSpec()); - return *this; - } - - /** - Writes a character to the stream. - */ - BasicWriter &operator<<(char value) { - buffer_.push_back(value); - return *this; - } - - BasicWriter &operator<<( - typename internal::WCharHelper::Supported value) { - buffer_.push_back(value); - return *this; - } - - /** - Writes *value* to the stream. - */ - BasicWriter &operator<<(fmt::BasicStringRef value) { - const Char *str = value.c_str(); - buffer_.append(str, str + value.size()); - return *this; - } - - template - BasicWriter &operator<<(IntFormatSpec spec) { - internal::CharTraits::convert(FillChar()); - write_int(spec.value(), spec); - return *this; - } - - template - BasicWriter &operator<<(const StrFormatSpec &spec) { - const StrChar *s = spec.str(); - // TODO: error if fill is not convertible to Char - write_str(s, std::char_traits::length(s), spec); - return *this; - } - - void clear() FMT_NOEXCEPT { buffer_.clear(); } - }; - - template - template - typename BasicWriter::CharPtr BasicWriter::write_str( - const StrChar *s, std::size_t size, const AlignSpec &spec) { - CharPtr out = CharPtr(); - if (spec.width() > size) { - out = grow_buffer(spec.width()); - Char fill = static_cast(spec.fill()); - if (spec.align() == ALIGN_RIGHT) { - std::fill_n(out, spec.width() - size, fill); - out += spec.width() - size; - } else if (spec.align() == ALIGN_CENTER) { - out = fill_padding(out, spec.width(), size, fill); - } else { - std::fill_n(out + size, spec.width() - size, fill); - } - } else { - out = grow_buffer(size); - } - std::copy(s, s + size, out); - return out; - } - - template - typename BasicWriter::CharPtr - BasicWriter::fill_padding( - CharPtr buffer, unsigned total_size, - std::size_t content_size, wchar_t fill) { - std::size_t padding = total_size - content_size; - std::size_t left_padding = padding / 2; - Char fill_char = static_cast(fill); - std::fill_n(buffer, left_padding, fill_char); - buffer += left_padding; - CharPtr content = buffer; - std::fill_n(buffer + content_size, padding - left_padding, fill_char); - return content; - } - - template - template - typename BasicWriter::CharPtr - BasicWriter::prepare_int_buffer( - unsigned num_digits, const Spec &spec, - const char *prefix, unsigned prefix_size) { - unsigned width = spec.width(); - Alignment align = spec.align(); - Char fill = static_cast(spec.fill()); - if (spec.precision() > static_cast(num_digits)) { - // Octal prefix '0' is counted as a digit, so ignore it if precision - // is specified. - if (prefix_size > 0 && prefix[prefix_size - 1] == '0') - --prefix_size; - unsigned number_size = prefix_size + spec.precision(); - AlignSpec subspec(number_size, '0', ALIGN_NUMERIC); - if (number_size >= width) - return prepare_int_buffer(num_digits, subspec, prefix, prefix_size); - buffer_.reserve(width); - unsigned fill_size = width - number_size; - if (align != ALIGN_LEFT) { - CharPtr p = grow_buffer(fill_size); - std::fill(p, p + fill_size, fill); - } - CharPtr result = prepare_int_buffer( - num_digits, subspec, prefix, prefix_size); - if (align == ALIGN_LEFT) { - CharPtr p = grow_buffer(fill_size); - std::fill(p, p + fill_size, fill); - } - return result; - } - unsigned size = prefix_size + num_digits; - if (width <= size) { - CharPtr p = grow_buffer(size); - std::copy(prefix, prefix + prefix_size, p); - return p + size - 1; - } - CharPtr p = grow_buffer(width); - CharPtr end = p + width; - if (align == ALIGN_LEFT) { - std::copy(prefix, prefix + prefix_size, p); - p += size; - std::fill(p, end, fill); - } else if (align == ALIGN_CENTER) { - p = fill_padding(p, width, size, fill); - std::copy(prefix, prefix + prefix_size, p); - p += size; - } else { - if (align == ALIGN_NUMERIC) { - if (prefix_size != 0) { - p = std::copy(prefix, prefix + prefix_size, p); - size -= prefix_size; - } - } else { - std::copy(prefix, prefix + prefix_size, end - size); - } - std::fill(p, end - size, fill); - p = end; - } - return p - 1; - } - - template - template - void BasicWriter::write_int(T value, Spec spec) { - unsigned prefix_size = 0; - typedef typename internal::IntTraits::MainType UnsignedType; - UnsignedType abs_value = value; - char prefix[4] = ""; - if (internal::is_negative(value)) { - prefix[0] = '-'; - ++prefix_size; - abs_value = 0 - abs_value; - } else if (spec.flag(SIGN_FLAG)) { - prefix[0] = spec.flag(PLUS_FLAG) ? '+' : ' '; - ++prefix_size; - } - switch (spec.type()) { - case 0: case 'd': { - unsigned num_digits = internal::count_digits(abs_value); - CharPtr p = prepare_int_buffer( - num_digits, spec, prefix, prefix_size) + 1 - num_digits; - internal::format_decimal(get(p), abs_value, num_digits); - break; - } - case 'x': case 'X': { - UnsignedType n = abs_value; - if (spec.flag(HASH_FLAG)) { - prefix[prefix_size++] = '0'; - prefix[prefix_size++] = spec.type(); - } - unsigned num_digits = 0; - do { - ++num_digits; - } while ((n >>= 4) != 0); - Char *p = get(prepare_int_buffer( - num_digits, spec, prefix, prefix_size)); - n = abs_value; - const char *digits = spec.type() == 'x' ? - "0123456789abcdef" : "0123456789ABCDEF"; - do { - *p-- = digits[n & 0xf]; - } while ((n >>= 4) != 0); - break; - } - case 'b': case 'B': { - UnsignedType n = abs_value; - if (spec.flag(HASH_FLAG)) { - prefix[prefix_size++] = '0'; - prefix[prefix_size++] = spec.type(); - } - unsigned num_digits = 0; - do { - ++num_digits; - } while ((n >>= 1) != 0); - Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); - n = abs_value; - do { - *p-- = '0' + (n & 1); - } while ((n >>= 1) != 0); - break; - } - case 'o': { - UnsignedType n = abs_value; - if (spec.flag(HASH_FLAG)) - prefix[prefix_size++] = '0'; - unsigned num_digits = 0; - do { - ++num_digits; - } while ((n >>= 3) != 0); - Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); - n = abs_value; - do { - *p-- = '0' + (n & 7); - } while ((n >>= 3) != 0); - break; - } - default: - internal::report_unknown_type( - spec.type(), spec.flag(CHAR_FLAG) ? "char" : "integer"); - break; - } - } - - template - template - void BasicWriter::write_double( - T value, const FormatSpec &spec) { - // Check type. - char type = spec.type(); - bool upper = false; - switch (type) { - case 0: - type = 'g'; - break; - case 'e': case 'f': case 'g': case 'a': - break; - case 'F': -#ifdef _MSC_VER - // MSVC's printf doesn't support 'F'. - type = 'f'; -#endif - // Fall through. - case 'E': case 'G': case 'A': - upper = true; - break; - default: - internal::report_unknown_type(type, "double"); - break; - } - - char sign = 0; - // Use getsign instead of value < 0 because the latter is always - // false for NaN. - if (internal::getsign(static_cast(value))) { - sign = '-'; - value = -value; - } else if (spec.flag(SIGN_FLAG)) { - sign = spec.flag(PLUS_FLAG) ? '+' : ' '; - } - - if (value != value) { - // Format NaN ourselves because sprintf's output is not consistent - // across platforms. - std::size_t nan_size = 4; - const char *nan = upper ? " NAN" : " nan"; - if (!sign) { - --nan_size; - ++nan; - } - CharPtr out = write_str(nan, nan_size, spec); - if (sign) - *out = sign; - return; - } - - if (internal::isinfinity(value)) { - // Format infinity ourselves because sprintf's output is not consistent - // across platforms. - std::size_t inf_size = 4; - const char *inf = upper ? " INF" : " inf"; - if (!sign) { - --inf_size; - ++inf; - } - CharPtr out = write_str(inf, inf_size, spec); - if (sign) - *out = sign; - return; - } - - std::size_t offset = buffer_.size(); - unsigned width = spec.width(); - if (sign) { - buffer_.reserve(buffer_.size() + (std::max)(width, 1u)); - if (width > 0) - --width; - ++offset; - } - - // Build format string. - enum { MAX_FORMAT_SIZE = 10}; // longest format: %#-*.*Lg - Char format[MAX_FORMAT_SIZE]; - Char *format_ptr = format; - *format_ptr++ = '%'; - unsigned width_for_sprintf = width; - if (spec.flag(HASH_FLAG)) - *format_ptr++ = '#'; - if (spec.align() == ALIGN_CENTER) { - width_for_sprintf = 0; - } else { - if (spec.align() == ALIGN_LEFT) - *format_ptr++ = '-'; - if (width != 0) - *format_ptr++ = '*'; - } - if (spec.precision() >= 0) { - *format_ptr++ = '.'; - *format_ptr++ = '*'; - } - - append_float_length(format_ptr, value); - *format_ptr++ = type; - *format_ptr = '\0'; - - // Format using snprintf. - Char fill = static_cast(spec.fill()); - for (;;) { - std::size_t buffer_size = buffer_.capacity() - offset; -#if defined(_MSC_VER) && _MSC_VER - // MSVC's vsnprintf_s doesn't work with zero size, so reserve - // space for at least one extra character to make the size non-zero. - // Note that the buffer's capacity will increase by more than 1. - if (buffer_size == 0) { - buffer_.reserve(offset + 1); - buffer_size = buffer_.capacity() - offset; - } -#endif - Char *start = &buffer_[offset]; - int n = internal::CharTraits::format_float( - start, buffer_size, format, width_for_sprintf, spec.precision(), value); - if (n >= 0 && offset + n < buffer_.capacity()) { - if (sign) { - if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) || - *start != ' ') { - *(start - 1) = sign; - sign = 0; - } else { - *(start - 1) = fill; - } - ++n; - } - if (spec.align() == ALIGN_CENTER && - spec.width() > static_cast(n)) { - width = spec.width(); - CharPtr p = grow_buffer(width); - std::copy(p, p + n, p + (width - n) / 2); - fill_padding(p, spec.width(), n, fill); - return; - } - if (spec.fill() != ' ' || sign) { - while (*start == ' ') - *start++ = fill; - if (sign) - *(start - 1) = sign; - } - grow_buffer(n); - return; - } - // If n is negative we ask to increase the capacity by at least 1, - // but as std::vector, the buffer grows exponentially. - buffer_.reserve(n >= 0 ? offset + n + 1 : buffer_.capacity() + 1); - } - } - -/** - \rst - This class template provides operations for formatting and writing data - into a character stream. The output is stored in a memory buffer that grows - dynamically. - - You can use one of the following typedefs for common character types - and the standard allocator: - - +---------------+-----------------------------------------------------+ - | Type | Definition | - +===============+=====================================================+ - | MemoryWriter | BasicMemoryWriter> | - +---------------+-----------------------------------------------------+ - | WMemoryWriter | BasicMemoryWriter> | - +---------------+-----------------------------------------------------+ - - **Example**:: - - MemoryWriter out; - out << "The answer is " << 42 << "\n"; - out.write("({:+f}, {:+f})", -3.14, 3.14); - - This will write the following output to the ``out`` object: - - .. code-block:: none - - The answer is 42 - (-3.140000, +3.140000) - - The output can be converted to an ``std::string`` with ``out.str()`` or - accessed as a C string with ``out.c_str()``. - \endrst - */ - template > - class BasicMemoryWriter : public BasicWriter { - private: - internal::MemoryBuffer buffer_; - - public: - explicit BasicMemoryWriter(const Allocator& alloc = Allocator()) - : BasicWriter(buffer_), buffer_(alloc) {} - -#if FMT_USE_RVALUE_REFERENCES - /** - \rst - Constructs a :class:`fmt::BasicMemoryWriter` object moving the content - of the other object to it. - \endrst - */ - BasicMemoryWriter(BasicMemoryWriter &&other) - : BasicWriter(buffer_), buffer_(std::move(other.buffer_)) { - } - - /** - \rst - Moves the content of the other ``BasicMemoryWriter`` object to this one. - \endrst - */ - BasicMemoryWriter &operator=(BasicMemoryWriter &&other) { - buffer_ = std::move(other.buffer_); - return *this; - } -#endif - }; - - typedef BasicMemoryWriter MemoryWriter; - typedef BasicMemoryWriter WMemoryWriter; - -/** - \rst - This class template provides operations for formatting and writing data - into a fixed-size array. For writing into a dynamically growing buffer - use :class:`fmt::BasicMemoryWriter`. - - Any write method will throw ``std::runtime_error`` if the output doesn't fit - into the array. - - You can use one of the following typedefs for common character types: - - +--------------+---------------------------+ - | Type | Definition | - +==============+===========================+ - | ArrayWriter | BasicArrayWriter | - +--------------+---------------------------+ - | WArrayWriter | BasicArrayWriter | - +--------------+---------------------------+ - \endrst - */ - template - class BasicArrayWriter : public BasicWriter { - private: - internal::FixedBuffer buffer_; - - public: - /** - \rst - Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the - given size. - \endrst - */ - BasicArrayWriter(Char *array, std::size_t size) - : BasicWriter(buffer_), buffer_(array, size) {} - - // FIXME: this is temporary undocumented due to a bug in Sphinx - /* - \rst - Constructs a :class:`fmt::BasicArrayWriter` object for *array* of the - size known at compile time. - \endrst - */ - template - explicit BasicArrayWriter(Char (&array)[SIZE]) - : BasicWriter(buffer_), buffer_(array, SIZE) {} - }; - - typedef BasicArrayWriter ArrayWriter; - typedef BasicArrayWriter WArrayWriter; - -// Formats a value. - template - void format(BasicFormatter &f, const Char *&format_str, const T &value) { - std::basic_ostringstream os; - os << value; - internal::Arg arg; - internal::Value &arg_value = arg; - std::basic_string str = os.str(); - arg_value = internal::MakeValue(str); - arg.type = static_cast( - internal::MakeValue::type(str)); - format_str = f.format(format_str, arg); - } - -// Reports a system error without throwing an exception. -// Can be used to report errors from destructors. - void report_system_error(int error_code, StringRef message) FMT_NOEXCEPT; - -#ifdef _WIN32 - - /** A Windows error. */ -class WindowsError : public SystemError { - private: - void init(int error_code, StringRef format_str, ArgList args); - - public: - /** - \rst - Constructs a :class:`fmt::WindowsError` object with the description - of the form - - .. parsed-literal:: - **: ** - - where ** is the formatted message and ** is the - system message corresponding to the error code. - *error_code* is a Windows error code as given by ``GetLastError``. - If *error_code* is not a valid error code such as -1, the system message - will look like "error -1". - - **Example**:: - - // This throws a WindowsError with the description - // cannot open file 'madeup': The system cannot find the file specified. - // or similar (system message may vary). - const char *filename = "madeup"; - LPOFSTRUCT of = LPOFSTRUCT(); - HFILE file = OpenFile(filename, &of, OF_READ); - if (file == HFILE_ERROR) { - throw fmt::WindowsError(GetLastError(), - "cannot open file '{}'", filename); - } - \endrst - */ - WindowsError(int error_code, StringRef message) { - init(error_code, message, ArgList()); - } - FMT_VARIADIC_CTOR(WindowsError, init, int, StringRef) -}; - -// Reports a Windows error without throwing an exception. -// Can be used to report errors from destructors. -void report_windows_error(int error_code, StringRef message) FMT_NOEXCEPT; - -#endif - - enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE }; - -/** - Formats a string and prints it to stdout using ANSI escape sequences - to specify color (experimental). - Example: - PrintColored(fmt::RED, "Elapsed time: {0:.2f} seconds") << 1.23; - */ - void print_colored(Color c, StringRef format, ArgList args); - -/** - \rst - Formats arguments and returns the result as a string. - - **Example**:: - - std::string message = format("The answer is {}", 42); - \endrst -*/ - inline std::string format(StringRef format_str, ArgList args) { - MemoryWriter w; - w.write(format_str, args); - return w.str(); - } - - inline std::wstring format(WStringRef format_str, ArgList args) { - WMemoryWriter w; - w.write(format_str, args); - return w.str(); - } - -/** - \rst - Prints formatted data to the file *f*. - - **Example**:: - - print(stderr, "Don't {}!", "panic"); - \endrst - */ - void print(std::FILE *f, StringRef format_str, ArgList args); - -/** - \rst - Prints formatted data to ``stdout``. - - **Example**:: - - print("Elapsed time: {0:.2f} seconds", 1.23); - \endrst - */ - void print(StringRef format_str, ArgList args); - -/** - \rst - Prints formatted data to the stream *os*. - - **Example**:: - - print(cerr, "Don't {}!", "panic"); - \endrst - */ - void print(std::ostream &os, StringRef format_str, ArgList args); - - template - void printf(BasicWriter &w, BasicStringRef format, ArgList args) { - internal::PrintfFormatter().format(w, format, args); - } - -/** - \rst - Formats arguments and returns the result as a string. - - **Example**:: - - std::string message = fmt::sprintf("The answer is %d", 42); - \endrst -*/ - inline std::string sprintf(StringRef format, ArgList args) { - MemoryWriter w; - printf(w, format, args); - return w.str(); - } - -/** - \rst - Prints formatted data to the file *f*. - - **Example**:: - - fmt::fprintf(stderr, "Don't %s!", "panic"); - \endrst - */ - int fprintf(std::FILE *f, StringRef format, ArgList args); - -/** - \rst - Prints formatted data to ``stdout``. - - **Example**:: - - fmt::printf("Elapsed time: %.2f seconds", 1.23); - \endrst - */ - inline int printf(StringRef format, ArgList args) { - return fprintf(stdout, format, args); - } - -/** - Fast integer formatter. - */ - class FormatInt { - private: - // Buffer should be large enough to hold all digits (digits10 + 1), - // a sign and a null character. - enum {BUFFER_SIZE = std::numeric_limits::digits10 + 3}; - mutable char buffer_[BUFFER_SIZE]; - char *str_; - - // Formats value in reverse and returns the number of digits. - char *format_decimal(ULongLong value) { - char *buffer_end = buffer_ + BUFFER_SIZE - 1; - while (value >= 100) { - // Integer division is slow so do it for a group of two digits instead - // of for every digit. The idea comes from the talk by Alexandrescu - // "Three Optimization Tips for C++". See speed-test for a comparison. - unsigned index = (value % 100) * 2; - value /= 100; - *--buffer_end = internal::Data::DIGITS[index + 1]; - *--buffer_end = internal::Data::DIGITS[index]; - } - if (value < 10) { - *--buffer_end = static_cast('0' + value); - return buffer_end; - } - unsigned index = static_cast(value * 2); - *--buffer_end = internal::Data::DIGITS[index + 1]; - *--buffer_end = internal::Data::DIGITS[index]; - return buffer_end; - } - - void FormatSigned(LongLong value) { - ULongLong abs_value = static_cast(value); - bool negative = value < 0; - if (negative) - abs_value = 0 - abs_value; - str_ = format_decimal(abs_value); - if (negative) - *--str_ = '-'; - } - - public: - explicit FormatInt(int value) { FormatSigned(value); } - explicit FormatInt(long value) { FormatSigned(value); } - explicit FormatInt(LongLong value) { FormatSigned(value); } - explicit FormatInt(unsigned value) : str_(format_decimal(value)) {} - explicit FormatInt(unsigned long value) : str_(format_decimal(value)) {} - explicit FormatInt(ULongLong value) : str_(format_decimal(value)) {} - - /** - Returns the number of characters written to the output buffer. - */ - std::size_t size() const { return buffer_ - str_ + BUFFER_SIZE - 1; } - - /** - Returns a pointer to the output buffer content. No terminating null - character is appended. - */ - const char *data() const { return str_; } - - /** - Returns a pointer to the output buffer content with terminating null - character appended. - */ - const char *c_str() const { - buffer_[BUFFER_SIZE - 1] = '\0'; - return str_; - } - - /** - Returns the content of the output buffer as an `std::string`. - */ - std::string str() const { return std::string(str_, size()); } - }; - -// Formats a decimal integer value writing into buffer and returns -// a pointer to the end of the formatted string. This function doesn't -// write a terminating null character. - template - inline void format_decimal(char *&buffer, T value) { - typename internal::IntTraits::MainType abs_value = value; - if (internal::is_negative(value)) { - *buffer++ = '-'; - abs_value = 0 - abs_value; - } - if (abs_value < 100) { - if (abs_value < 10) { - *buffer++ = static_cast('0' + abs_value); - return; - } - unsigned index = static_cast(abs_value * 2); - *buffer++ = internal::Data::DIGITS[index]; - *buffer++ = internal::Data::DIGITS[index + 1]; - return; - } - unsigned num_digits = internal::count_digits(abs_value); - internal::format_decimal(buffer, abs_value, num_digits); - buffer += num_digits; - } -} - -#if FMT_GCC_VERSION -// Use the system_header pragma to suppress warnings about variadic macros -// because suppressing -Wvariadic-macros with the diagnostic pragma doesn't -// work. It is used at the end because we want to suppress as little warnings -// as possible. -# pragma GCC system_header -#endif - -// This is used to work around VC++ bugs in handling variadic macros. -#define FMT_EXPAND(args) args - -// Returns the number of arguments. -// Based on https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s. -#define FMT_NARG(...) FMT_NARG_(__VA_ARGS__, FMT_RSEQ_N()) -#define FMT_NARG_(...) FMT_EXPAND(FMT_ARG_N(__VA_ARGS__)) -#define FMT_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N -#define FMT_RSEQ_N() 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 - -#define FMT_CONCAT(a, b) a##b -#define FMT_FOR_EACH_(N, f, ...) \ - FMT_EXPAND(FMT_CONCAT(FMT_FOR_EACH, N)(f, __VA_ARGS__)) -#define FMT_FOR_EACH(f, ...) \ - FMT_EXPAND(FMT_FOR_EACH_(FMT_NARG(__VA_ARGS__), f, __VA_ARGS__)) - -#define FMT_ADD_ARG_NAME(type, index) type arg##index -#define FMT_GET_ARG_NAME(type, index) arg##index - -#if FMT_USE_VARIADIC_TEMPLATES -# define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \ - template \ - ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ - const Args & ... args) { \ - using fmt::internal::Value; \ - const Value values[fmt::internal::NonZero::VALUE] = { \ - fmt::internal::MakeValue(args)... \ - }; \ - call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList( \ - fmt::internal::make_type(args...), values)); \ - } -#else -// Defines a wrapper for a function taking __VA_ARGS__ arguments -// and n additional arguments of arbitrary types. -# define FMT_WRAP(Char, ReturnType, func, call, n, ...) \ - template \ - inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ - FMT_GEN(n, FMT_MAKE_ARG)) { \ - const fmt::internal::Value vals[] = {FMT_GEN(n, FMT_MAKE_REF_##Char)}; \ - call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList( \ - fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), vals)); \ - } - -# define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \ - inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__)) { \ - call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList()); \ - } \ - FMT_WRAP(Char, ReturnType, func, call, 1, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 2, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 3, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 4, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 5, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 6, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 7, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 8, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 9, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 10, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 11, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 12, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 13, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 14, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 15, __VA_ARGS__) -#endif // FMT_USE_VARIADIC_TEMPLATES - -/** - \rst - Defines a variadic function with the specified return type, function name - and argument types passed as variable arguments to this macro. - - **Example**:: - - void print_error(const char *file, int line, const char *format, - fmt::ArgList args) { - fmt::print("{}: {}: ", file, line); - fmt::print(format, args); - } - FMT_VARIADIC(void, print_error, const char *, int, const char *) - - ``FMT_VARIADIC`` is used for compatibility with legacy C++ compilers that - don't implement variadic templates. You don't have to use this macro if - you don't need legacy compiler support and can use variadic templates - directly:: - - template - void print_error(const char *file, int line, const char *format, - const Args & ... args) { - fmt::print("{}: {}: ", file, line); - fmt::print(format, args...); - } - \endrst - */ -#define FMT_VARIADIC(ReturnType, func, ...) \ - FMT_VARIADIC_(char, ReturnType, func, return func, __VA_ARGS__) - -#define FMT_VARIADIC_W(ReturnType, func, ...) \ - FMT_VARIADIC_(wchar_t, ReturnType, func, return func, __VA_ARGS__) - -namespace fmt { - FMT_VARIADIC(std::string, format, StringRef) - FMT_VARIADIC_W(std::wstring, format, WStringRef) - FMT_VARIADIC(void, print, StringRef) - FMT_VARIADIC(void, print, std::FILE *, StringRef) - FMT_VARIADIC(void, print, std::ostream &, StringRef) - FMT_VARIADIC(void, print_colored, Color, StringRef) - FMT_VARIADIC(std::string, sprintf, StringRef) - FMT_VARIADIC(int, printf, StringRef) - FMT_VARIADIC(int, fprintf, std::FILE *, StringRef) -} - -// Restore warnings. -#if FMT_GCC_VERSION >= 406 -# pragma GCC diagnostic pop -#endif - -#ifdef __clang__ -# pragma clang diagnostic pop -#endif - -#ifdef FMT_HEADER_ONLY -# include "format.cc" -#endif - -#endif // FMT_FORMAT_H_ \ No newline at end of file diff --git a/source/third_party/patches/fmt.diff b/source/third_party/patches/fmt.diff deleted file mode 100644 index 7f53d3ba46..0000000000 --- a/source/third_party/patches/fmt.diff +++ /dev/null @@ -1,221 +0,0 @@ ---- format.h 2020-02-09 20:52:31.892811631 +0100 -+++ 0ad/source/third_party/fmt/format.h 2020-03-04 21:53:39.475417249 +0100 -@@ -1,4 +1,9 @@ - /* -+ * Slightly modified version of fmt, by Wildfire Games, for 0 A.D. -+ * Based on fmt v1.1.0 from https://github.com/fmtlib/fmt -+ */ -+ -+/* - Formatting library for C++ - - Copyright (c) 2012 - 2015, Victor Zverovich -@@ -37,10 +42,11 @@ - #include - #include - #include --#include - #include - --#if _SECURE_SCL -+#include "ps/CStr.h" -+ -+#if defined(_SECURE_SCL) && _SECURE_SCL - # include - #endif - -@@ -129,9 +135,13 @@ - // Variadic templates are available in GCC since version 4.4 - // (http://gcc.gnu.org/projects/cxx0x.html) and in Visual C++ - // since version 2013. -+# if defined(_MSC_VER) -+# define FMT_USE_VARIADIC_TEMPLATES 1 -+# else - # 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)) -+# endif - #endif - - #ifndef FMT_USE_RVALUE_REFERENCES -@@ -139,10 +149,12 @@ - // as the latter doesn't provide std::move. - # if defined(FMT_GNUC_LIBSTD_VERSION) && FMT_GNUC_LIBSTD_VERSION <= 402 - # define FMT_USE_RVALUE_REFERENCES 0 -+# elif defined(_MSC_VER) -+# define FMT_USE_RVALUE_REFERENCES 1 - # 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)) - # endif - #endif - -@@ -151,7 +163,7 @@ - #endif - - // Define FMT_USE_NOEXCEPT to make C++ Format use noexcept (C++11 feature). --#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ -+#if (defined(FMT_USE_NOEXCEPT) && FMT_USE_NOEXCEPT) || FMT_HAS_FEATURE(cxx_noexcept) || \ - (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) - # define FMT_NOEXCEPT noexcept - #else -@@ -160,7 +172,7 @@ - - // A macro to disallow the copy constructor and operator= functions - // This should be used in the private: declarations for a class --#if FMT_USE_DELETED_FUNCTIONS || FMT_HAS_FEATURE(cxx_deleted_functions) || \ -+#if (defined(FMT_USE_DELETED_FUNCTIONS) && FMT_USE_DELETED_FUNCTIONS) || FMT_HAS_FEATURE(cxx_deleted_functions) || \ - (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1800 - # define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&) = delete; \ -@@ -287,7 +299,7 @@ - // to avoid dynamic memory allocation. - enum { INLINE_BUFFER_SIZE = 500 }; - --#if _SECURE_SCL -+#if defined(_SECURE_SCL) && _SECURE_SCL - // Use checked iterator to avoid warnings on MSVC. - template - inline stdext::checked_array_iterator make_ptr(T *ptr, std::size_t size) { -@@ -483,7 +495,7 @@ - template - class BasicCharTraits { - public: --#if _SECURE_SCL -+#if defined(_SECURE_SCL) && _SECURE_SCL - typedef stdext::checked_array_iterator CharPtr; - #else - typedef Char *CharPtr; -@@ -869,6 +881,7 @@ - FMT_MAKE_VALUE(const unsigned char *, ustring.value, CSTRING) - FMT_MAKE_STR_VALUE(const std::string &, STRING) - FMT_MAKE_STR_VALUE(StringRef, STRING) -+ FMT_MAKE_STR_VALUE(const CStr &, STRING) - - #define FMT_MAKE_WSTR_VALUE(Type, TYPE) \ - MakeValue(typename WCharHelper::Supported value) { \ -@@ -1567,7 +1580,7 @@ - - typedef typename internal::CharTraits::CharPtr CharPtr; - --#if _SECURE_SCL -+#if defined(_SECURE_SCL) && _SECURE_SCL - // Returns pointer value. - static Char *get(CharPtr p) { return p.base(); } - #else -@@ -2074,7 +2087,7 @@ - Char fill = static_cast(spec.fill()); - for (;;) { - std::size_t buffer_size = buffer_.capacity() - offset; --#if _MSC_VER -+#if defined(_MSC_VER) && _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. ---- format.cpp 2020-02-09 20:52:10.936425878 +0100 -+++ 0ad/source/third_party/fmt/format.cpp 2020-03-04 21:36:15.755684084 +0100 -@@ -1,4 +1,9 @@ - /* -+ * Slightly modified version of fmt, by Wildfire Games, for 0 A.D. -+ * Based on fmt v1.1.0 from https://github.com/fmtlib/fmt -+ */ -+ -+/* - Formatting library for C++ - - Copyright (c) 2012 - 2015, Victor Zverovich -@@ -24,6 +29,7 @@ - (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 "precompiled.h" - - #include "format.h" - -@@ -48,7 +54,7 @@ - #if __GNUC__ && !__EXCEPTIONS - # define FMT_EXCEPTIONS 0 - #endif --#if _MSC_VER && !_HAS_EXCEPTIONS -+#if defined(_MSC_VER) && _MSC_VER && !_HAS_EXCEPTIONS - # define FMT_EXCEPTIONS 0 - #endif - #ifndef FMT_EXCEPTIONS -@@ -79,17 +85,17 @@ - # define FMT_FUNC - #endif - --#if _MSC_VER --# pragma warning(push) --# pragma warning(disable: 4127) // conditional expression is constant --# pragma warning(disable: 4702) // unreachable code --#endif -- - namespace { - - #ifndef _MSC_VER - # define FMT_SNPRINTF snprintf - #else // _MSC_VER -+ -+# pragma warning(push) -+# pragma warning(disable: 4127) // conditional expression is constant -+# pragma warning(disable: 4702) // unreachable code -+# pragma warning(disable: 4456) // hides previous local declaration -+ - inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) { - va_list args; - va_start(args, format); -@@ -136,24 +142,24 @@ - int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT { - assert(buffer != 0 && buffer_size != 0); - int result = 0; --#if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE) || __ANDROID__ -+#if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE) || (defined(__ANDROID__) && __ANDROID__) - // XSI-compliant version of strerror_r. - result = strerror_r(error_code, buffer, buffer_size); - if (result != 0) - result = errno; --#elif _GNU_SOURCE -+#elif defined(_GNU_SOURCE) && !defined(__BIONIC__) - // GNU-specific version of strerror_r. - char *message = strerror_r(error_code, buffer, buffer_size); - // If the buffer is full then the message is probably truncated. - if (message == buffer && strlen(buffer) == buffer_size - 1) - result = ERANGE; - buffer = message; --#elif __MINGW32__ -+#elif defined(__MINGW32__) - errno = 0; - (void)buffer_size; - buffer = strerror(error_code); - result = errno; --#elif _WIN32 -+#elif defined(_WIN32) - result = strerror_s(buffer, buffer_size, error_code); - // If the buffer is full then the message is probably truncated. - if (result == 0 && std::strlen(buffer) == buffer_size - 1) -@@ -627,8 +633,11 @@ - const StrChar *str_value = s.value; - std::size_t str_size = s.size; - if (str_size == 0) { -- if (!str_value) -- FMT_THROW(FormatError("string pointer is null")); -+ if (!str_value) { -+ Char err[] = { '(', 'n', 'u', 'l', 'l', ')' }; -+ write_str(err, sizeof(err)/sizeof(Char), spec); -+ return; -+ } - if (*str_value) - str_size = std::char_traits::length(str_value); - } -@@ -1164,6 +1173,6 @@ - - #endif // FMT_HEADER_ONLY - --#if _MSC_VER -+#if defined(_MSC_VER) && _MSC_VER - # pragma warning(pop) - #endif