diff options
-rw-r--r-- | dep/PackageList.txt | 2 | ||||
-rw-r--r-- | dep/cppformat/CMakeLists.txt | 6 | ||||
-rw-r--r-- | dep/cppformat/README.rst | 29 | ||||
-rw-r--r-- | dep/cppformat/cppformat/format.cc (renamed from dep/cppformat/format.cc) | 118 | ||||
-rw-r--r-- | dep/cppformat/cppformat/format.h (renamed from dep/cppformat/format.h) | 531 | ||||
-rw-r--r-- | dep/cppformat/cppformat/posix.cc (renamed from dep/cppformat/posix.cc) | 4 | ||||
-rw-r--r-- | dep/cppformat/cppformat/posix.h (renamed from dep/cppformat/posix.h) | 63 | ||||
-rw-r--r-- | src/common/Utilities/StringFormat.h | 2 | ||||
-rw-r--r-- | src/server/bnetserver/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/server/worldserver/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/tools/map_extractor/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/tools/mmaps_generator/CMakeLists.txt | 2 |
12 files changed, 463 insertions, 300 deletions
diff --git a/dep/PackageList.txt b/dep/PackageList.txt index 5ad9cef5982..7f10848aa0a 100644 --- a/dep/PackageList.txt +++ b/dep/PackageList.txt @@ -14,7 +14,7 @@ bzip2 (a freely available, patent free, high-quality data compressor) cppformat (type safe format library) https://github.com/cppformat/cppformat - Version: 5c76d107cbaf5e851bd66b6c563e4fc7c90be7ad + Version: 5174b8ca281426af604b85fdf53be8a748b33f56 G3D (a commercial-grade C++ 3D engine available as Open Source (BSD License) http://g3d.sourceforge.net/ diff --git a/dep/cppformat/CMakeLists.txt b/dep/cppformat/CMakeLists.txt index 3be3e5f6dbb..f2abb1b42d3 100644 --- a/dep/cppformat/CMakeLists.txt +++ b/dep/cppformat/CMakeLists.txt @@ -1,7 +1,7 @@ include(CheckCXXCompilerFlag) include(CheckSymbolExists) -set(FMT_SOURCES format.cc format.h) +set(FMT_SOURCES cppformat/format.cc cppformat/format.h) # Use variadic templates add_definitions(-DFMT_VARIADIC_TEMPLATES=1) @@ -20,10 +20,10 @@ endif () if (HAVE_OPEN) add_definitions(-DFMT_USE_FILE_DESCRIPTORS=1) - set(FMT_SOURCES ${FMT_SOURCES} posix.cc posix.h) + set(FMT_SOURCES ${FMT_SOURCES} cppformat/posix.cc cppformat/posix.h) endif () -add_library(format STATIC ${FMT_SOURCES}) +add_library(cppformat STATIC ${FMT_SOURCES}) if (CMAKE_COMPILER_IS_GNUCXX) set_target_properties(format PROPERTIES COMPILE_FLAGS diff --git a/dep/cppformat/README.rst b/dep/cppformat/README.rst index fb4399f0af4..e859f909466 100644 --- a/dep/cppformat/README.rst +++ b/dep/cppformat/README.rst @@ -28,9 +28,9 @@ Features * Format API with `format string syntax <http://cppformat.github.io/latest/syntax.html>`_ similar to the one used by `str.format - <http://docs.python.org/2/library/stdtypes.html#str.format>`_ in Python. + <https://docs.python.org/2/library/stdtypes.html#str.format>`_ in Python. * Safe `printf implementation - <http://cppformat.github.io/latest/reference.html#printf-formatting-functions>`_ + <http://cppformat.github.io/latest/api.html#printf-formatting-functions>`_ including the POSIX extension for positional arguments. * Support for user-defined types. * High speed: performance of the format API is close to that of @@ -103,10 +103,10 @@ An object of any user-defined type for which there is an overloaded // s == "The date is 2012-12-9" You can use the `FMT_VARIADIC -<http://cppformat.github.io/latest/reference.html#utilities>`_ +<http://cppformat.github.io/latest/api.html#utilities>`_ macro to create your own functions similar to `format -<http://cppformat.github.io/latest/reference.html#format>`_ and -`print <http://cppformat.github.io/latest/reference.html#print>`_ +<http://cppformat.github.io/latest/api.html#format>`_ and +`print <http://cppformat.github.io/latest/api.html#print>`_ which take arbitrary arguments: .. code:: c++ @@ -132,13 +132,17 @@ Projects using this library * `AMPL/MP <https://github.com/ampl/mp>`_: An open-source library for mathematical programming -* `HarpyWar/pvpgn <https://github.com/HarpyWar/pvpgn>`_: +* `HarpyWar/pvpgn <https://github.com/pvpgn/pvpgn-server>`_: Player vs Player Gaming Network with tweaks -* `KBEngine <http://www.kbengine.org/>`_: An open-source MMOG server engine +* `KBEngine <http://kbengine.org/>`_: An open-source MMOG server engine + +* `Keypirinha <http://keypirinha.com/>`_: A semantic launcher for Windows * `Lifeline <https://github.com/peter-clark/lifeline>`_: A 2D game +* `MongoDB Smasher <https://github.com/duckie/mongo_smasher>`_: A small tool to generate randomized datasets + * `PenUltima Online (POL) <http://www.polserver.com/>`_: An MMO server, compatible with most Ultima Online clients @@ -148,7 +152,7 @@ Projects using this library * `redis-cerberus <https://github.com/HunanTV/redis-cerberus>`_: A Redis cluster proxy -* `Saddy <https://code.google.com/p/saddy/>`_: +* `Saddy <https://github.com/mamontov-cpp/saddy-graphics-engine-2d>`_: Small crossplatform 2D graphic engine * `Salesforce Analytics Cloud <http://www.salesforce.com/analytics-cloud/overview/>`_: @@ -188,7 +192,7 @@ doesn't support user-defined types. Printf also has safety issues although they are mostly solved with `__attribute__ ((format (printf, ...)) <http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html>`_ in GCC. There is a POSIX extension that adds positional arguments required for -`i18n <http://en.wikipedia.org/wiki/Internationalization_and_localization>`_ +`i18n <https://en.wikipedia.org/wiki/Internationalization_and_localization>`_ to printf but it is not a part of C99 and may not be available on some platforms. @@ -376,18 +380,13 @@ C++ Format is distributed under the BSD `license The `Format String Syntax <http://cppformat.github.io/latest/syntax.html>`_ section in the documentation is based on the one from Python `string module -documentation <http://docs.python.org/3/library/string.html#module-string>`_ +documentation <https://docs.python.org/3/library/string.html#module-string>`_ adapted for the current library. For this reason the documentation is distributed under the Python Software Foundation license available in `doc/python-license.txt <https://raw.github.com/cppformat/cppformat/master/doc/python-license.txt>`_. It only applies if you distribute the documentation of C++ Format. -Links ------ - -`API changes/compatibility report <http://upstream-tracker.org/versions/cppformat.html>`_ - Acknowledgments --------------- diff --git a/dep/cppformat/format.cc b/dep/cppformat/cppformat/format.cc index 1970d53c500..daccd68f1da 100644 --- a/dep/cppformat/format.cc +++ b/dep/cppformat/cppformat/format.cc @@ -207,10 +207,15 @@ void format_error_code(fmt::Writer &out, int error_code, out.clear(); static const char SEP[] = ": "; static const char ERROR_STR[] = "error "; - fmt::internal::IntTraits<int>::MainType ec_value = error_code; // Subtract 2 to account for terminating null characters in SEP and ERROR_STR. std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2; - error_code_size += fmt::internal::count_digits(ec_value); + typedef fmt::internal::IntTraits<int>::MainType MainType; + MainType abs_value = static_cast<MainType>(error_code); + if (internal::is_negative(error_code)) { + abs_value = 0 - abs_value; + ++error_code_size; + } + error_code_size += fmt::internal::count_digits(abs_value); if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size) out << message << SEP; out << ERROR_STR << error_code; @@ -252,7 +257,7 @@ class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> { template <typename T> unsigned visit_any_int(T value) { typedef typename fmt::internal::IntTraits<T>::MainType UnsignedType; - UnsignedType width = value; + UnsignedType width = static_cast<UnsignedType>(value); if (fmt::internal::is_negative(value)) { spec_.align_ = fmt::ALIGN_LEFT; width = 0 - width; @@ -278,8 +283,21 @@ class PrecisionHandler : } }; -// Converts an integer argument to an integral type T for printf. +template <typename T, typename U> +struct is_same { + enum { value = 0 }; +}; + template <typename T> +struct is_same<T, T> { + enum { value = 1 }; +}; + +// An argument visitor that converts an integer argument to T for printf, +// if T is an integral type. If T is void, the argument is converted to +// corresponding signed or unsigned type depending on the type specifier: +// 'd' and 'i' - signed, other - unsigned) +template <typename T = void> class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> { private: fmt::internal::Arg &arg_; @@ -300,21 +318,25 @@ class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> { void visit_any_int(U value) { bool is_signed = type_ == 'd' || type_ == 'i'; using fmt::internal::Arg; - if (sizeof(T) <= sizeof(int)) { + typedef typename fmt::internal::Conditional< + is_same<T, void>::value, U, T>::type TargetType; + if (sizeof(TargetType) <= sizeof(int)) { // Extra casts are used to silence warnings. if (is_signed) { arg_.type = Arg::INT; - arg_.int_value = static_cast<int>(static_cast<T>(value)); + arg_.int_value = static_cast<int>(static_cast<TargetType>(value)); } else { arg_.type = Arg::UINT; - arg_.uint_value = static_cast<unsigned>( - static_cast<typename fmt::internal::MakeUnsigned<T>::Type>(value)); + typedef typename fmt::internal::MakeUnsigned<TargetType>::Type Unsigned; + arg_.uint_value = static_cast<unsigned>(static_cast<Unsigned>(value)); } } else { if (is_signed) { arg_.type = Arg::LONG_LONG; - arg_.long_long_value = - static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value); + // glibc's printf doesn't sign extend arguments of smaller types: + // std::printf("%lld", -42); // prints "4294967254" + // but we don't have to do the same because it's a UB. + arg_.long_long_value = static_cast<fmt::LongLong>(value); } else { arg_.type = Arg::ULONG_LONG; arg_.ulong_long_value = @@ -340,6 +362,21 @@ class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> { arg_.int_value = static_cast<char>(value); } }; + +// Write the content of w to os. +void write(std::ostream &os, fmt::Writer &w) { + const char *data = w.data(); + typedef internal::MakeUnsigned<std::streamsize>::Type UnsignedStreamSize; + UnsignedStreamSize size = w.size(); + UnsignedStreamSize max_size = + internal::to_unsigned((std::numeric_limits<std::streamsize>::max)()); + do { + UnsignedStreamSize n = size <= max_size ? size : max_size; + os.write(data, static_cast<std::streamsize>(n)); + data += n; + size -= n; + } while (size != 0); +} } // namespace namespace internal { @@ -551,27 +588,25 @@ FMT_FUNC void fmt::WindowsError::init( 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<LPWSTR>(system_message.ptr()), 0, 0)) { - UTF16ToUTF8 utf8_message; - if (utf8_message.convert(system_message.c_str()) == ERROR_SUCCESS) { - out << message << ": " << utf8_message; - return; + MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer; + buffer.resize(INLINE_BUFFER_SIZE); + for (;;) { + wchar_t *system_message = &buffer[0]; + int result = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + 0, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + system_message, static_cast<uint32_t>(buffer.size()), 0); + if (result != 0) { + UTF16ToUTF8 utf8_message; + if (utf8_message.convert(system_message) == ERROR_SUCCESS) { + out << message << ": " << utf8_message; + return; + } + break; } + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) + break; // Can't get error message, report error code instead. + buffer.resize(buffer.size() * 2); } } FMT_CATCH(...) {} fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. @@ -616,7 +651,7 @@ void fmt::internal::ArgMap<Char>::init(const ArgList &args) { return; case internal::Arg::NAMED_ARG: named_arg = static_cast<const NamedArg*>(args.values_[i].pointer); - map_.insert(Pair(named_arg->name, *named_arg)); + map_.push_back(Pair(named_arg->name, *named_arg)); break; default: /*nothing*/; @@ -628,7 +663,7 @@ void fmt::internal::ArgMap<Char>::init(const ArgList &args) { internal::Arg::Type arg_type = args.type(i); if (arg_type == internal::Arg::NAMED_ARG) { named_arg = static_cast<const NamedArg*>(args.args_[i].pointer); - map_.insert(Pair(named_arg->name, *named_arg)); + map_.push_back(Pair(named_arg->name, *named_arg)); } } for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) { @@ -637,7 +672,7 @@ void fmt::internal::ArgMap<Char>::init(const ArgList &args) { return; case internal::Arg::NAMED_ARG: named_arg = static_cast<const NamedArg*>(args.args_[i].pointer); - map_.insert(Pair(named_arg->name, *named_arg)); + map_.push_back(Pair(named_arg->name, *named_arg)); break; default: /*nothing*/; @@ -659,6 +694,7 @@ FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg( break; case Arg::NAMED_ARG: arg = *static_cast<const internal::Arg*>(arg.pointer); + break; default: /*nothing*/; } @@ -763,7 +799,7 @@ void fmt::internal::PrintfFormatter<Char>::format( if (*s == '.') { ++s; if ('0' <= *s && *s <= '9') { - spec.precision_ = parse_nonnegative_int(s); + spec.precision_ = static_cast<int>(parse_nonnegative_int(s)); } else if (*s == '*') { ++s; spec.precision_ = PrecisionHandler().visit(get_arg(s)); @@ -772,7 +808,7 @@ void fmt::internal::PrintfFormatter<Char>::format( Arg arg = get_arg(s, arg_index); if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg)) - spec.flags_ &= ~HASH_FLAG; + spec.flags_ &= ~to_unsigned<int>(HASH_FLAG); if (spec.fill_ == '0') { if (arg.type <= Arg::LAST_NUMERIC_TYPE) spec.align_ = ALIGN_NUMERIC; @@ -809,7 +845,7 @@ void fmt::internal::PrintfFormatter<Char>::format( break; default: --s; - ArgConverter<int>(arg, *s).visit(arg); + ArgConverter<void>(arg, *s).visit(arg); } // Parse type. @@ -861,10 +897,11 @@ FMT_FUNC void fmt::print(CStringRef format_str, ArgList args) { print(stdout, format_str, args); } -FMT_FUNC void fmt::print(std::ostream &os, CStringRef format_str, ArgList args) { +FMT_FUNC void fmt::print(std::ostream &os, CStringRef format_str, + ArgList args) { MemoryWriter w; w.write(format_str, args); - os.write(w.data(), w.size()); + write(os, w); } FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) { @@ -882,6 +919,13 @@ FMT_FUNC int fmt::fprintf(std::FILE *f, CStringRef format, ArgList args) { return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size); } +FMT_FUNC int fmt::fprintf(std::ostream &os, CStringRef format, ArgList args) { + MemoryWriter w; + printf(w, format, args); + write(os, w); + return static_cast<int>(w.size()); +} + #ifndef FMT_HEADER_ONLY template struct fmt::internal::BasicData<void>; diff --git a/dep/cppformat/format.h b/dep/cppformat/cppformat/format.h index a98a166091b..08bb9b5d9e8 100644 --- a/dep/cppformat/format.h +++ b/dep/cppformat/cppformat/format.h @@ -28,14 +28,6 @@ #ifndef FMT_FORMAT_H_ #define FMT_FORMAT_H_ -#if defined _MSC_VER && _MSC_VER <= 1500 -typedef unsigned int uint32_t; -typedef unsigned long long uint64_t; -typedef long long intmax_t; -#else -#include <stdint.h> -#endif - #include <cassert> #include <cmath> #include <cstdio> @@ -44,7 +36,8 @@ typedef long long intmax_t; #include <memory> #include <stdexcept> #include <string> -#include <map> +#include <vector> +#include <utility> #ifndef FMT_USE_IOSTREAMS # define FMT_USE_IOSTREAMS 1 @@ -64,40 +57,23 @@ typedef long long intmax_t; # include <iterator> #endif -#ifdef _MSC_VER -# include <intrin.h> // _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<uint32_t>(x >> 32))) - return 63 - (r + 32); +#if defined(_MSC_VER) && _MSC_VER <= 1500 +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +typedef __int64 intmax_t; +#else +#include <stdint.h> +#endif - // Scan the low 32 bits. - _BitScanReverse(&r, static_cast<uint32_t>(x)); +#if !defined(FMT_HEADER_ONLY) && defined(_WIN32) +# ifdef FMT_EXPORT +# define FMT_API __declspec(dllexport) +# elif defined(FMT_SHARED) +# define FMT_API __declspec(dllimport) # endif - return 63 - r; -} -# define FMT_BUILTIN_CLZLL(n) fmt::internal::clzll(n) -} -} +#endif +#ifndef FMT_API +# define FMT_API #endif #ifdef __GNUC__ @@ -174,21 +150,6 @@ inline uint32_t clzll(uint64_t x) { # include <utility> // for std::move #endif -// Define FMT_USE_NOEXCEPT to make C++ Format use noexcept (C++11 feature). -#ifndef FMT_USE_NOEXCEPT -# define FMT_USE_NOEXCEPT 0 -#endif - -#ifndef FMT_NOEXCEPT -# if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ - (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \ - _MSC_VER >= 1900 -# define FMT_NOEXCEPT noexcept -# else -# define FMT_NOEXCEPT throw() -# endif -#endif - // Check if exceptions are disabled. #if defined(__GNUC__) && !defined(__EXCEPTIONS) # define FMT_EXCEPTIONS 0 @@ -208,6 +169,25 @@ inline uint32_t clzll(uint64_t x) { # endif #endif +// Define FMT_USE_NOEXCEPT to make C++ Format use noexcept (C++11 feature). +#ifndef FMT_USE_NOEXCEPT +# define FMT_USE_NOEXCEPT 0 +#endif + +#ifndef FMT_NOEXCEPT +# if FMT_EXCEPTIONS +# if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ + (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \ + _MSC_VER >= 1900 +# define FMT_NOEXCEPT noexcept +# else +# define FMT_NOEXCEPT throw() +# endif +# else +# define FMT_NOEXCEPT +# endif +#endif + // A macro to disallow the copy constructor and operator= functions // This should be used in the private: declarations for a class #ifndef FMT_USE_DELETED_FUNCTIONS @@ -241,6 +221,67 @@ inline uint32_t clzll(uint64_t x) { # define FMT_ASSERT(condition, message) assert((condition) && message) #endif + +#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz) +# define FMT_BUILTIN_CLZ(n) __builtin_clz(n) +#endif + +#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll) +# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) +#endif + +// Some compilers masquerade as both MSVC and GCC-likes or +// otherwise support __builtin_clz and __builtin_clzll, so +// only define FMT_BUILTIN_CLZ using the MSVC intrinsics +// if the clz and clzll builtins are not available. +#if defined(_MSC_VER) && !defined(FMT_BUILTIN_CLZLL) +# include <intrin.h> // _BitScanReverse, _BitScanReverse64 + +namespace fmt { +namespace internal { +# pragma intrinsic(_BitScanReverse) +inline uint32_t clz(uint32_t x) { + unsigned long r = 0; + _BitScanReverse(&r, x); + + assert(x != 0); + // Static analysis complains about using uninitialized data + // "r", but the only way that can happen is if "x" is 0, + // which the callers guarantee to not happen. +# pragma warning(suppress: 6102) + return 31 - r; +} +# define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n) + +# 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<uint32_t>(x >> 32))) + return 63 - (r + 32); + + // Scan the low 32 bits. + _BitScanReverse(&r, static_cast<uint32_t>(x)); +# endif + + assert(x != 0); + // Static analysis complains about using uninitialized data + // "r", but the only way that can happen is if "x" is 0, + // which the callers guarantee to not happen. +# pragma warning(suppress: 6102) + return 63 - r; +} +# define FMT_BUILTIN_CLZLL(n) fmt::internal::clzll(n) +} +} +#endif + namespace fmt { namespace internal { struct DummyInt { @@ -396,7 +437,7 @@ class BasicStringRef { return std::basic_string<Char>(data_, size_); } - /** Returns the pointer to a C string. */ + /** Returns a pointer to the string data. */ const Char *data() const { return data_; } /** Returns the string size. */ @@ -492,6 +533,29 @@ class FormatError : public std::runtime_error { }; namespace internal { + +// MakeUnsigned<T>::Type gives an unsigned type corresponding to integer type T. +template <typename T> +struct MakeUnsigned { typedef T Type; }; + +#define FMT_SPECIALIZE_MAKE_UNSIGNED(T, U) \ + template <> \ + struct MakeUnsigned<T> { 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); + +// Casts nonnegative integer to unsigned. +template <typename Int> +inline typename MakeUnsigned<Int>::Type to_unsigned(Int value) { + FMT_ASSERT(value >= 0, "negative value"); + return static_cast<typename MakeUnsigned<Int>::Type>(value); +} + // The number of characters to store in the MemoryBuffer object itself // to avoid dynamic memory allocation. enum { INLINE_BUFFER_SIZE = 500 }; @@ -581,8 +645,7 @@ class Buffer { template <typename T> template <typename U> void Buffer<T>::append(const U *begin, const U *end) { - assert(begin <= end); - std::size_t new_size = size_ + (end - begin); + std::size_t new_size = size_ + internal::to_unsigned(end - begin); if (new_size > capacity_) grow(new_size); std::uninitialized_copy(begin, end, @@ -592,8 +655,8 @@ void Buffer<T>::append(const U *begin, const U *end) { namespace internal { -// A memory buffer for POD types with the first SIZE elements stored in -// the object itself. +// A memory buffer for trivially copyable/constructible types with the first SIZE +// elements stored in the object itself. template <typename T, std::size_t SIZE, typename Allocator = std::allocator<T> > class MemoryBuffer : private Allocator, public Buffer<T> { private: @@ -676,7 +739,7 @@ class FixedBuffer : public fmt::Buffer<Char> { FixedBuffer(Char *array, std::size_t size) : fmt::Buffer<Char>(array, size) {} protected: - void grow(std::size_t size); + FMT_API void grow(std::size_t size); }; template <typename Char> @@ -704,7 +767,7 @@ class CharTraits<char> : public BasicCharTraits<char> { // Formats a floating-point number. template <typename T> - static int format_float(char *buffer, std::size_t size, + FMT_API static int format_float(char *buffer, std::size_t size, const char *format, unsigned width, int precision, T value); }; @@ -715,7 +778,7 @@ class CharTraits<wchar_t> : public BasicCharTraits<wchar_t> { static wchar_t convert(wchar_t value) { return value; } template <typename T> - static int format_float(wchar_t *buffer, std::size_t size, + FMT_API static int format_float(wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, int precision, T value); }; @@ -754,27 +817,12 @@ struct IntTraits { TypeSelector<std::numeric_limits<T>::digits <= 32>::Type MainType; }; -// MakeUnsigned<T>::Type gives an unsigned type corresponding to integer type T. -template <typename T> -struct MakeUnsigned { typedef T Type; }; - -#define FMT_SPECIALIZE_MAKE_UNSIGNED(T, U) \ - template <> \ - struct MakeUnsigned<T> { 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); +FMT_API void report_unknown_type(char code, const char *type); // Static data is placed in this class template to allow header-only // configuration. template <typename T = void> -struct BasicData { +struct FMT_API BasicData { static const uint32_t POWERS_OF_10_32[]; static const uint64_t POWERS_OF_10_64[]; static const char DIGITS[]; @@ -782,22 +830,14 @@ struct BasicData { 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; + int t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12; + return to_unsigned(t) - (n < Data::POWERS_OF_10_64[t]) + 1; } #else // Fallback version of count_digits used when __builtin_clz is not available. @@ -820,8 +860,8 @@ inline unsigned count_digits(uint64_t n) { #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; + int t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12; + return to_unsigned(t) - (n < Data::POWERS_OF_10_32[t]) + 1; } #endif @@ -863,7 +903,7 @@ class UTF8ToUTF16 { MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer_; public: - explicit UTF8ToUTF16(StringRef s); + FMT_API 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]; } @@ -878,7 +918,7 @@ class UTF16ToUTF8 { public: UTF16ToUTF8() {} - explicit UTF16ToUTF8(WStringRef s); + FMT_API 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]; } @@ -887,15 +927,15 @@ class UTF16ToUTF8 { // 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); + FMT_API int convert(WStringRef s); }; -void format_windows_error(fmt::Writer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT; +FMT_API void format_windows_error(fmt::Writer &out, int error_code, + fmt::StringRef message) FMT_NOEXCEPT; #endif -void format_system_error(fmt::Writer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT; +FMT_API void format_system_error(fmt::Writer &out, int error_code, + fmt::StringRef message) FMT_NOEXCEPT; // A formatting argument value. struct Value { @@ -938,8 +978,8 @@ struct Value { }; }; -// A formatting argument. It is a POD type to allow storage in -// internal::MemoryBuffer. +// A formatting argument. It is a trivially copyable/constructible type to +// allow storage in internal::MemoryBuffer. struct Arg : Value { Type type; }; @@ -976,6 +1016,7 @@ template <typename T> T &get(); struct DummyStream : std::ostream { + DummyStream(); // Suppress a bogus warning in MSVC. // Hide all operator<< overloads from std::ostream. void operator<<(Null<>); }; @@ -1199,17 +1240,27 @@ class MakeValue : public Arg { static uint64_t type(const NamedArg<Char_> &) { return Arg::NAMED_ARG; } }; +template <typename Formatter> +class MakeArg : public Arg { +public: + MakeArg() { + type = Arg::NONE; + } + + template <typename T> + MakeArg(const T &value) + : Arg(MakeValue<Formatter>(value)) { + type = static_cast<Arg::Type>(MakeValue<Formatter>::type(value)); + } +}; + template <typename Char> struct NamedArg : Arg { BasicStringRef<Char> name; - typedef internal::MakeValue< BasicFormatter<Char> > MakeValue; - template <typename T> NamedArg(BasicStringRef<Char> argname, const T &value) - : Arg(MakeValue(value)), name(argname) { - type = static_cast<Arg::Type>(MakeValue::type(value)); - } + : Arg(MakeArg< BasicFormatter<Char> >(value)), name(argname) {} }; #define FMT_DISPATCH(call) static_cast<Impl*>(this)->call @@ -1631,17 +1682,22 @@ namespace internal { template <typename Char> class ArgMap { private: - typedef std::map<fmt::BasicStringRef<Char>, internal::Arg> MapType; + typedef std::vector<std::pair<fmt::BasicStringRef<Char>, internal::Arg> > MapType; typedef typename MapType::value_type Pair; MapType map_; public: - void init(const ArgList &args); + FMT_API void init(const ArgList &args); const internal::Arg* find(const fmt::BasicStringRef<Char> &name) const { - typename MapType::const_iterator it = map_.find(name); - return it != map_.end() ? &it->second : 0; + // The list is unsorted, so just return the first matching name. + for (typename MapType::const_iterator it = map_.begin(), end = map_.end(); + it != end; ++it) { + if (it->first == name) + return &it->second; + } + return 0; } }; @@ -1767,7 +1823,7 @@ class FormatterBase { int next_arg_index_; // Returns the argument with specified index. - Arg do_get_arg(unsigned arg_index, const char *&error); + FMT_API Arg do_get_arg(unsigned arg_index, const char *&error); protected: const ArgList &args() const { return args_; } @@ -1780,7 +1836,7 @@ class FormatterBase { // Returns the next argument. Arg next_arg(const char *&error) { if (next_arg_index_ >= 0) - return do_get_arg(next_arg_index_++, error); + return do_get_arg(internal::to_unsigned(next_arg_index_++), error); error = "cannot switch from manual to automatic argument indexing"; return Arg(); } @@ -1803,7 +1859,7 @@ class FormatterBase { template <typename Char> void write(BasicWriter<Char> &w, const Char *start, const Char *end) { if (start != end) - w << BasicStringRef<Char>(start, end - start); + w << BasicStringRef<Char>(start, internal::to_unsigned(end - start)); } }; @@ -1823,14 +1879,16 @@ class PrintfFormatter : private FormatterBase { public: explicit PrintfFormatter(const ArgList &args) : FormatterBase(args) {} - void format(BasicWriter<Char> &writer, BasicCStringRef<Char> format_str); + FMT_API void format(BasicWriter<Char> &writer, + BasicCStringRef<Char> format_str); }; } // namespace internal -// A formatter. +/** This template formats data and writes the output to a writer. */ template <typename CharType> class BasicFormatter : private internal::FormatterBase { public: + /** The character type for the output. */ typedef CharType Char; private: @@ -1852,13 +1910,23 @@ class BasicFormatter : private internal::FormatterBase { internal::Arg parse_arg_name(const Char *&s); public: + /** + \rst + Constructs a ``BasicFormatter`` object. References to the arguments and + the writer are stored in the formatter object so make sure they have + appropriate lifetimes. + \endrst + */ BasicFormatter(const ArgList &args, BasicWriter<Char> &w) : internal::FormatterBase(args), writer_(w) {} + /** Returns a reference to the writer associated with this formatter. */ BasicWriter<Char> &writer() { return writer_; } + /** Formats stored arguments and writes the output to the writer. */ void format(BasicCStringRef<Char> format_str); + // Formats a single argument and advances format_str, a format string pointer. const Char *format(const Char *&format_str, const internal::Arg &arg); }; @@ -1889,16 +1957,29 @@ inline uint64_t make_type(const T &arg) { return MakeValue< BasicFormatter<char> >::type(arg); } +template <unsigned N, bool/*IsPacked*/= (N < ArgList::MAX_PACKED_ARGS)> +struct ArgArray; + +template <unsigned N> +struct ArgArray<N, true/*IsPacked*/> { + typedef Value Type[N > 0 ? N : 1]; + + template <typename Formatter, typename T> + static Value make(const T &value) { + Value result = MakeValue<Formatter>(value); + // Workaround a bug in Apple LLVM version 4.2 (clang-425.0.28) of clang: + // https://github.com/cppformat/cppformat/issues/276 + (void)result.custom.format; + return result; + } +}; + template <unsigned N> -struct ArgArray { - // Computes the argument array size by adding 1 to N, which is the number of - // arguments, if N is zero, because array of zero size is invalid, or if N - // is greater than ArgList::MAX_PACKED_ARGS to accommodate for an extra - // argument that marks the end of the list. - enum { SIZE = N + (N == 0 || N >= ArgList::MAX_PACKED_ARGS ? 1 : 0) }; - - typedef typename Conditional< - (N < ArgList::MAX_PACKED_ARGS), Value, Arg>::type Type[SIZE]; +struct ArgArray<N, false/*IsPacked*/> { + typedef Arg Type[N + 1]; // +1 for the list end Arg::NONE + + template <typename Formatter, typename T> + static Arg make(const T &value) { return MakeArg<Formatter>(value); } }; #if FMT_USE_VARIADIC_TEMPLATES @@ -1907,47 +1988,6 @@ inline uint64_t make_type(const Arg &first, const Args & ... tail) { return make_type(first) | (make_type(tail...) << 4); } -inline void do_set_types(Arg *) {} - -template <typename T, typename... Args> -inline void do_set_types(Arg *args, const T &arg, const Args & ... tail) { - args->type = static_cast<Arg::Type>( - MakeValue< BasicFormatter<char> >::type(arg)); - do_set_types(args + 1, tail...); -} - -template <typename... Args> -inline void set_types(Arg *array, const Args & ... args) { - if (check(sizeof...(Args) > ArgList::MAX_PACKED_ARGS)) - do_set_types(array, args...); - array[sizeof...(Args)].type = Arg::NONE; -} - -template <typename... Args> -inline void set_types(Value *, const Args & ...) { - // Do nothing as types are passed separately from values. -} - -template <typename Formatter, typename Value> -inline void store_args(Value *) {} - -template <typename Formatter, typename Arg, typename T, typename... Args> -inline void store_args(Arg *args, const T &arg, const Args & ... tail) { - // Assign only the Value subobject of Arg and don't overwrite type (if any) - // that is assigned by set_types. - Value &value = *args; - value = MakeValue<Formatter>(arg); - store_args<Formatter>(args + 1, tail...); -} - -template <typename Formatter, typename... Args> -ArgList make_arg_list(typename ArgArray<sizeof...(Args)>::Type array, - const Args & ... args) { - if (check(sizeof...(Args) >= ArgList::MAX_PACKED_ARGS)) - set_types(array, args...); - store_args<Formatter>(array, args...); - return ArgList(make_type(args...), array); -} #else struct ArgType { @@ -1985,7 +2025,7 @@ class FormatBuf : public std::basic_streambuf<Char> { int_type overflow(int_type ch = traits_type::eof()) { if (!traits_type::eq_int_type(ch, traits_type::eof())) { - size_t size = this->pptr() - start_; + size_t size = this->size(); buffer_.resize(size); buffer_.reserve(size * 2); @@ -1997,7 +2037,7 @@ class FormatBuf : public std::basic_streambuf<Char> { } size_t size() const { - return this->pptr() - start_; + return to_unsigned(this->pptr() - start_); } }; } // namespace internal @@ -2015,18 +2055,20 @@ class FormatBuf : public std::basic_streambuf<Char> { # define FMT_VARIADIC_VOID(func, arg_type) \ template <typename... Args> \ void func(arg_type arg0, const Args & ... args) { \ - typename fmt::internal::ArgArray<sizeof...(Args)>::Type array; \ - func(arg0, fmt::internal::make_arg_list< \ - fmt::BasicFormatter<Char> >(array, args...)); \ + typedef fmt::internal::ArgArray<sizeof...(Args)> ArgArray; \ + typename ArgArray::Type array{ \ + ArgArray::template make<fmt::BasicFormatter<Char> >(args)...}; \ + func(arg0, fmt::ArgList(fmt::internal::make_type(args...), array)); \ } // Defines a variadic constructor. # define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ template <typename... Args> \ ctor(arg0_type arg0, arg1_type arg1, const Args & ... args) { \ - typename fmt::internal::ArgArray<sizeof...(Args)>::Type array; \ - func(arg0, arg1, fmt::internal::make_arg_list< \ - fmt::BasicFormatter<Char> >(array, args...)); \ + typedef fmt::internal::ArgArray<sizeof...(Args)> ArgArray; \ + typename ArgArray::Type array{ \ + ArgArray::template make<fmt::BasicFormatter<Char> >(args)...}; \ + func(arg0, arg1, fmt::ArgList(fmt::internal::make_type(args...), array)); \ } #else @@ -2207,7 +2249,8 @@ class BasicWriter { // Writes a decimal integer. template <typename Int> void write_decimal(Int value) { - typename internal::IntTraits<Int>::MainType abs_value = value; + typedef typename internal::IntTraits<Int>::MainType MainType; + MainType abs_value = static_cast<MainType>(value); if (internal::is_negative(value)) { abs_value = 0 - abs_value; *write_unsigned_decimal(abs_value, 1) = '-'; @@ -2474,9 +2517,9 @@ void BasicWriter<Char>::write_str( return; } } - std::size_t precision = spec.precision_; + std::size_t precision = static_cast<std::size_t>(spec.precision_); if (spec.precision_ >= 0 && precision < str_size) - str_size = spec.precision_; + str_size = precision; write_str(str_value, str_size, spec); } @@ -2510,7 +2553,8 @@ typename BasicWriter<Char>::CharPtr // is specified. if (prefix_size > 0 && prefix[prefix_size - 1] == '0') --prefix_size; - unsigned number_size = prefix_size + spec.precision(); + unsigned number_size = + prefix_size + internal::to_unsigned(spec.precision()); AlignSpec subspec(number_size, '0', ALIGN_NUMERIC); if (number_size >= width) return prepare_int_buffer(num_digits, subspec, prefix, prefix_size); @@ -2564,7 +2608,7 @@ template <typename T, typename Spec> void BasicWriter<Char>::write_int(T value, Spec spec) { unsigned prefix_size = 0; typedef typename internal::IntTraits<T>::MainType UnsignedType; - UnsignedType abs_value = value; + UnsignedType abs_value = static_cast<UnsignedType>(value); char prefix[4] = ""; if (internal::is_negative(value)) { prefix[0] = '-'; @@ -2643,8 +2687,7 @@ void BasicWriter<Char>::write_int(T value, Spec spec) { template <typename Char> template <typename T> -void BasicWriter<Char>::write_double( - T value, const FormatSpec &spec) { +void BasicWriter<Char>::write_double(T value, const FormatSpec &spec) { // Check type. char type = spec.type(); bool upper = false; @@ -2744,6 +2787,8 @@ void BasicWriter<Char>::write_double( // Format using snprintf. Char fill = internal::CharTraits<Char>::cast(spec.fill()); + unsigned n = 0; + Char *start = 0; for (;;) { std::size_t buffer_size = buffer_.capacity() - offset; #ifdef _MSC_VER @@ -2755,41 +2800,44 @@ void BasicWriter<Char>::write_double( buffer_size = buffer_.capacity() - offset; } #endif - Char *start = &buffer_[offset]; - int n = internal::CharTraits<Char>::format_float( + start = &buffer_[offset]; + int result = internal::CharTraits<Char>::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<unsigned>(n)) { - width = spec.width(); - CharPtr p = grow_buffer(width); - std::memmove(get(p) + (width - n) / 2, get(p), n * sizeof(Char)); - 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 (result >= 0) { + n = internal::to_unsigned(result); + if (offset + n < buffer_.capacity()) + break; // The buffer is large enough - continue with formatting. + buffer_.reserve(offset + n + 1); + } else { + // If result is negative we ask to increase the capacity by at least 1, + // but as std::vector, the buffer grows exponentially. + buffer_.reserve(buffer_.capacity() + 1); } - // 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); } + 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() > n) { + width = spec.width(); + CharPtr p = grow_buffer(width); + std::memmove(get(p) + (width - n) / 2, get(p), n * sizeof(Char)); + fill_padding(p, spec.width(), n, fill); + return; + } + if (spec.fill() != ' ' || sign) { + while (*start == ' ') + *start++ = fill; + if (sign) + *(start - 1) = sign; + } + grow_buffer(n); } /** @@ -2920,22 +2968,21 @@ void format(BasicFormatter<Char> &f, const Char *&format_str, const T &value) { output << value; BasicStringRef<Char> str(&buffer[0], format_buf.size()); - typedef internal::MakeValue< BasicFormatter<Char> > MakeValue; - internal::Arg arg = MakeValue(str); - arg.type = static_cast<internal::Arg::Type>(MakeValue::type(str)); - format_str = f.format(format_str, arg); + typedef internal::MakeArg< BasicFormatter<Char> > MakeArg; + format_str = f.format(format_str, MakeArg(str)); } // Reports a system error without throwing an exception. // Can be used to report errors from destructors. -void report_system_error(int error_code, StringRef message) FMT_NOEXCEPT; +FMT_API void report_system_error(int error_code, + StringRef message) FMT_NOEXCEPT; #if FMT_USE_WINDOWS_H /** A Windows error. */ class WindowsError : public SystemError { private: - void init(int error_code, CStringRef format_str, ArgList args); + FMT_API void init(int error_code, CStringRef format_str, ArgList args); public: /** @@ -2974,7 +3021,8 @@ class WindowsError : public SystemError { // 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; +FMT_API void report_windows_error(int error_code, + StringRef message) FMT_NOEXCEPT; #endif @@ -2986,7 +3034,7 @@ enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE }; Example: print_colored(fmt::RED, "Elapsed time: {0:.2f} seconds", 1.23); */ -void print_colored(Color c, CStringRef format, ArgList args); +FMT_API void print_colored(Color c, CStringRef format, ArgList args); /** \rst @@ -3018,7 +3066,7 @@ inline std::wstring format(WCStringRef format_str, ArgList args) { print(stderr, "Don't {}!", "panic"); \endrst */ -void print(std::FILE *f, CStringRef format_str, ArgList args); +FMT_API void print(std::FILE *f, CStringRef format_str, ArgList args); /** \rst @@ -3029,7 +3077,7 @@ void print(std::FILE *f, CStringRef format_str, ArgList args); print("Elapsed time: {0:.2f} seconds", 1.23); \endrst */ -void print(CStringRef format_str, ArgList args); +FMT_API void print(CStringRef format_str, ArgList args); template <typename Char> void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args) { @@ -3066,7 +3114,7 @@ inline std::wstring sprintf(WCStringRef format, ArgList args) { fmt::fprintf(stderr, "Don't %s!", "panic"); \endrst */ -int fprintf(std::FILE *f, CStringRef format, ArgList args); +FMT_API int fprintf(std::FILE *f, CStringRef format, ArgList args); /** \rst @@ -3132,10 +3180,10 @@ class FormatInt { 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 the number of characters written to the output buffer. */ + std::size_t size() const { + return internal::to_unsigned(buffer_ - str_ + BUFFER_SIZE - 1); + } /** Returns a pointer to the output buffer content. No terminating null @@ -3165,7 +3213,8 @@ class FormatInt { // write a terminating null character. template <typename T> inline void format_decimal(char *&buffer, T value) { - typename internal::IntTraits<T>::MainType abs_value = value; + typedef typename internal::IntTraits<T>::MainType MainType; + MainType abs_value = static_cast<MainType>(value); if (internal::is_negative(value)) { *buffer++ = '-'; abs_value = 0 - abs_value; @@ -3245,10 +3294,11 @@ void arg(WStringRef, const internal::NamedArg<Char>&) FMT_DELETED_OR_UNDEFINED; template <typename... Args> \ ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ const Args & ... args) { \ - typename fmt::internal::ArgArray<sizeof...(Args)>::Type array; \ + typedef fmt::internal::ArgArray<sizeof...(Args)> ArgArray; \ + typename ArgArray::Type array{ \ + ArgArray::template make<fmt::BasicFormatter<Char> >(args)...}; \ call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ - fmt::internal::make_arg_list< \ - fmt::BasicFormatter<Char> >(array, args...)); \ + fmt::ArgList(fmt::internal::make_type(args...), array)); \ } #else // Defines a wrapper for a function taking __VA_ARGS__ arguments @@ -3361,8 +3411,20 @@ FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef) print(cerr, "Don't {}!", "panic"); \endrst */ -void print(std::ostream &os, CStringRef format_str, ArgList args); +FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args); FMT_VARIADIC(void, print, std::ostream &, CStringRef) + +/** + \rst + Prints formatted data to the stream *os*. + + **Example**:: + + fprintf(cerr, "Don't %s!", "panic"); + \endrst + */ +FMT_API int fprintf(std::ostream &os, CStringRef format_str, ArgList args); +FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef) #endif namespace internal { @@ -3374,7 +3436,7 @@ inline bool is_name_start(Char c) { // 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 <typename Char> -int parse_nonnegative_int(const Char *&s) { +unsigned parse_nonnegative_int(const Char *&s) { assert('0' <= *s && *s <= '9'); unsigned value = 0; do { @@ -3453,7 +3515,6 @@ inline internal::Arg BasicFormatter<Char>::parse_arg_name(const Char *&s) { return arg; } -// Should be after FormatSpec template <typename Char> const Char *BasicFormatter<Char>::format( const Char *&format_str, const internal::Arg &arg) { diff --git a/dep/cppformat/posix.cc b/dep/cppformat/cppformat/posix.cc index 756281a0ebd..c6c2ae2c413 100644 --- a/dep/cppformat/posix.cc +++ b/dep/cppformat/cppformat/posix.cc @@ -173,7 +173,7 @@ std::size_t fmt::File::read(void *buffer, std::size_t count) { FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count)))); if (result < 0) throw SystemError(errno, "cannot read from file"); - return result; + return internal::to_unsigned(result); } std::size_t fmt::File::write(const void *buffer, std::size_t count) { @@ -181,7 +181,7 @@ std::size_t fmt::File::write(const void *buffer, std::size_t count) { FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count)))); if (result < 0) throw SystemError(errno, "cannot write to file"); - return result; + return internal::to_unsigned(result); } fmt::File fmt::File::dup(int fd) { diff --git a/dep/cppformat/posix.h b/dep/cppformat/cppformat/posix.h index 88bcb4f557b..bfbd3851838 100644 --- a/dep/cppformat/posix.h +++ b/dep/cppformat/cppformat/posix.h @@ -34,11 +34,17 @@ #endif #include <errno.h> -#include <fcntl.h> // for O_RDONLY +#include <fcntl.h> // for O_RDONLY +#include <locale.h> // for locale_t #include <stdio.h> +#include <stdlib.h> // for strtod_l #include <cstddef> +#ifdef __APPLE__ +# include <xlocale.h> // for LC_NUMERIC_MASK on OS X +#endif + #include "format.h" #ifndef FMT_POSIX @@ -299,7 +305,8 @@ class File { // Closes the file. void close(); - // Returns the file size. + // Returns the file size. The size has signed type for consistency with + // stat::st_size. LongLong size() const; // Attempts to read count bytes from the file into the specified buffer. @@ -331,6 +338,58 @@ class File { // Returns the memory page size. long getpagesize(); + +#if defined(LC_NUMERIC_MASK) || defined(_MSC_VER) +# define FMT_LOCALE +#endif + +#ifdef FMT_LOCALE +// A "C" numeric locale. +class Locale { + private: +# ifdef _MSC_VER + typedef _locale_t locale_t; + + enum { LC_NUMERIC_MASK = LC_NUMERIC }; + + static locale_t newlocale(int category_mask, const char *locale, locale_t) { + return _create_locale(category_mask, locale); + } + + static void freelocale(locale_t locale) { + _free_locale(locale); + } + + static double strtod_l(const char *nptr, char **endptr, _locale_t locale) { + return _strtod_l(nptr, endptr, locale); + } +# endif + + locale_t locale_; + + FMT_DISALLOW_COPY_AND_ASSIGN(Locale); + + public: + typedef locale_t Type; + + Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", NULL)) { + if (!locale_) + throw fmt::SystemError(errno, "cannot create locale"); + } + ~Locale() { freelocale(locale_); } + + Type get() const { return locale_; } + + // Converts string to floating-point number and advances str past the end + // of the parsed input. + double strtod(const char *&str) const { + char *end = 0; + double result = strtod_l(str, &end, locale_); + str = end; + return result; + } +}; +#endif // FMT_LOCALE } // namespace fmt #if !FMT_USE_RVALUE_REFERENCES diff --git a/src/common/Utilities/StringFormat.h b/src/common/Utilities/StringFormat.h index d85523bc11f..e21b1024e87 100644 --- a/src/common/Utilities/StringFormat.h +++ b/src/common/Utilities/StringFormat.h @@ -19,7 +19,7 @@ #ifndef TRINITYCORE_STRING_FORMAT_H #define TRINITYCORE_STRING_FORMAT_H -#include "format.h" +#include "cppformat/format.h" namespace Trinity { diff --git a/src/server/bnetserver/CMakeLists.txt b/src/server/bnetserver/CMakeLists.txt index 10b8e562143..3cc1d20cf5e 100644 --- a/src/server/bnetserver/CMakeLists.txt +++ b/src/server/bnetserver/CMakeLists.txt @@ -94,7 +94,7 @@ target_link_libraries(bnetserver ipc common zmqpp - format + cppformat ${MYSQL_LIBRARY} ${OPENSSL_LIBRARIES} ${ZMQ_LIBRARY} diff --git a/src/server/worldserver/CMakeLists.txt b/src/server/worldserver/CMakeLists.txt index af30600fc09..3d6a1cf3a78 100644 --- a/src/server/worldserver/CMakeLists.txt +++ b/src/server/worldserver/CMakeLists.txt @@ -151,7 +151,7 @@ target_link_libraries(worldserver gsoap Detour zmqpp - format + cppformat ${JEMALLOC_LIBRARY} ${READLINE_LIBRARY} ${TERMCAP_LIBRARY} diff --git a/src/tools/map_extractor/CMakeLists.txt b/src/tools/map_extractor/CMakeLists.txt index 32fccaa2038..25ad7c771e8 100644 --- a/src/tools/map_extractor/CMakeLists.txt +++ b/src/tools/map_extractor/CMakeLists.txt @@ -30,7 +30,7 @@ add_executable(mapextractor target_link_libraries(mapextractor casc common - format + cppformat ${BZIP2_LIBRARIES} ${ZLIB_LIBRARIES} ${Boost_LIBRARIES} diff --git a/src/tools/mmaps_generator/CMakeLists.txt b/src/tools/mmaps_generator/CMakeLists.txt index adc3410aa6e..5640ea8be5d 100644 --- a/src/tools/mmaps_generator/CMakeLists.txt +++ b/src/tools/mmaps_generator/CMakeLists.txt @@ -39,7 +39,7 @@ target_link_libraries(mmaps_generator g3dlib Recast Detour - format + cppformat ${BZIP2_LIBRARIES} ${ZLIB_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} |