diff --git a/CMakeLists.txt b/CMakeLists.txt index 92fbf2b5..2ac29fa0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -142,8 +142,8 @@ function(add_headers VAR) endfunction() # Define the fmt library, its includes and the needed defines. -add_headers(FMT_HEADERS core.h format.h format-inl.h locale.h ostream.h printf.h - time.h ranges.h) +add_headers(FMT_HEADERS core.h format.h format-inl.h ostream.h printf.h time.h + ranges.h) set(FMT_SOURCES src/format.cc) if (HAVE_OPEN) add_headers(FMT_HEADERS posix.h) diff --git a/ChangeLog.rst b/ChangeLog.rst index 8cd24414..eb5c5b5d 100644 --- a/ChangeLog.rst +++ b/ChangeLog.rst @@ -1,5 +1,5 @@ -5.0.0 - TBD ------------ +5.0.0 - 2018-05-21 +------------------ * Added a requirement for partial C++11 support, most importantly variadic templates and type traits, and dropped ``FMT_VARIADIC_*`` emulation macros. @@ -12,18 +12,40 @@ of the library for standardization in `P0645R2 Text Formatting `_. -* Implemented ``constexpr`` parsing of format strings. +* Implemented ``constexpr`` parsing of format strings and `compile-time format + string checks + `_. For + example + + .. code:: c++ + + #include + + std::string s = format(fmt("{:d}"), "foo"); + + gives a compile-time error because ``d`` is an invalid specifier for strings + (`godbolt `__):: + + ... + :4:19: note: in instantiation of function template specialization 'fmt::v5::format' requested here + std::string s = format(fmt("{:d}"), "foo"); + ^ + format.h:1337:13: note: non-constexpr function 'on_error' cannot be used in a constant expression + handler.on_error("invalid type specifier"); + + Compile-time checks require relaxed ``constexpr`` (C++14 feature) support. If + the latter is not available, checks will be performed at runtime. * Separated format string parsing and formatting in the extension API to enable compile-time format string processing. For example .. code:: c++ - struct S {}; + struct Answer {}; namespace fmt { template <> - struct formatter { + struct formatter { constexpr auto parse(parse_context& ctx) { auto it = ctx.begin(); spec = *it; @@ -33,7 +55,7 @@ } template - auto format(S, FormatContext& ctx) { + auto format(Answer, FormatContext& ctx) { return spec == 's' ? format_to(ctx.begin(), "{}", "fourty-two") : format_to(ctx.begin(), "{}", 42); @@ -43,10 +65,10 @@ }; } - std::string s = format(fmt("{:x}"), S()); + std::string s = format(fmt("{:x}"), Answer()); - will give a compile-time error due to invalid format specifier (`godbolt - `_):: + gives a compile-time error due to invalid format specifier (`godbolt + `__):: ... :12:45: error: expression '' is not a constant expression @@ -63,9 +85,20 @@ std::vector out; fmt::format_to(std::back_inserter(out), "{}", 42); +* Added the `format_to_n + `_ + function that restricts the output to the specified number of characters + (`#298 `_): + + .. code:: c++ + + char out[4]; + fmt::format_to_n(out, sizeof(out), "{}", 12345); + // out == "1234" (without terminating '\0') + * Added the `formatted_size - `_ function for - computing output size: + `_ + function for computing the output size: .. code:: c++ @@ -101,6 +134,11 @@ vreport_error(format, fmt::make_format_args(args...)); } +* Added the ``make_printf_args`` function for capturing ``printf`` arguments ( + `#687 `_, + `#694 `_). + Thanks `@Kronuz (Germán Méndez Bravo) `_. + * Added prefix ``v`` to non-variadic functions taking ``format_args`` to distinguish them from variadic ones: @@ -111,6 +149,34 @@ template std::string format(string_view format_str, const Args & ... args); +* Added experimental support for formatting ranges, containers and tuple-like + types in ``fmt/ranges.h`` (`#735 `_): + + .. code:: c++ + + #include + + std::vector v = {1, 2, 3}; + fmt::print("{}", v); // prints {1, 2, 3} + + Thanks `@Remotion (Remo) `_. + +* Implemented ``wchar_t`` date and time formatting + (`#712 `_): + + .. code:: c++ + + #include + + std::time_t t = std::time(nullptr); + auto s = fmt::format(L"The date is {:%Y-%m-%d}.", *std::localtime(&t)); + + Thanks `@DanielaE (Daniela Engert) `_. + +* Provided more wide string overloads + (`#724 `_). + Thanks `@DanielaE (Daniela Engert) `_. + * Switched from a custom null-terminated string view class to ``string_view`` in the format API and provided ``fmt::string_view`` which implements a subset of ``std::string_view`` API for pre-C++17 systems. @@ -126,7 +192,7 @@ fmt::print("{}", std::experimental::string_view("foo")); Thanks `@virgiliofornazin (Virgilio Alexandre Fornazin) - `_. + `__. * Allowed mixing named and automatic arguments: @@ -141,30 +207,48 @@ * Disallowed formatting of multibyte strings into a wide character target (`#606 `_). -* Added a section describing `the use of header-only target with CMake - `_ to the docs - (`#515 `_). - Thanks `@ibell (Ian Bell) `_. - -* Added a `note about errno `_ to the - documentation ( +* Improved documentation ( + `#515 `_, `#614 `_, - `#617 `_). - Thanks `@mihaitodor (Mihai Todor) `_. + `#617 `_, + `#661 `_, + `#680 `_). + Thanks `@ibell (Ian Bell) `_, + `@mihaitodor (Mihai Todor) `_, and + `@johnthagen `_. * Implemented more efficient handling of large number of format arguments. +* Introduced an inline namespace for symbol versioning. + +* Added debug postfix ``d`` to the ``fmt`` library name + (`#636 `_). + * Removed unnecessary ``fmt/`` prefix in includes (`#397 `_). Thanks `@chronoxor (Ivan Shynkarenka) `_. -* Renamed ``CHAR_WIDTH`` to ``CHAR_SIZE`` to avoid collision with ISO/IEC TS - 18661-1:2014 macro. +* Moved ``fmt/*.h`` to ``include/fmt/*.h`` to prevent irrelevant files and + directories appearing on the include search paths when fmt is used as a + subproject and moved source files to the ``src`` directory. + +* Added qmake project file ``support/fmt.pro`` + (`#641 `_). + Thanks `@cowo78 (Giuseppe Corbelli) `_. + +* Added Gradle build file ``support/build.gradle`` + (`#649 `_). + Thanks `@luncliff (Park DongHa) `_. + +* Removed ``FMT_CPPFORMAT`` CMake option. * Fixed a name conflict with the macro ``CHAR_WIDTH`` in glibc (`#616 `_). Thanks `@aroig (Abdó Roig-Maranges) `_. +* Fixed handling of nested braces in ``fmt::join`` + (`#638 `_). + * Added ``SOURCELINK_SUFFIX`` for compatibility with Sphinx 1.5 (`#497 `_). Thanks `@ginggs (Graham Inggs) `_. @@ -173,6 +257,95 @@ (`#626 `_). Thanks `@aroig (Abdó Roig-Maranges) `_. +* Fixed various compiler warnings ( + `#640 `_, + `#656 `_, + `#679 `_, + `#681 `_, + `#705 `__, + `#715 `_, + `#717 `_, + `#720 `_, + `#723 `_, + `#726 `_, + `#730 `_, + `#739 `_). + Thanks `@peterbell10 `_, + `@LarsGullik `_, + `@foonathan (Jonathan Müller) `_, + `@eliaskosunen (Elias Kosunen) `_, + `@christianparpart (Christian Parpart) `_, + `@DanielaE (Daniela Engert) `_, + and `@mwinterb `_. + +* Worked around an MSVC bug and fixed several warnings + (`#653 `_). + Thanks `@alabuzhev (Alex Alabuzhev) `_. + +* Worked around GCC bug 67371 + (`#682 `_). + +* Fixed compilation with ``-fno-exceptions`` + (`#655 `_). + Thanks `@chenxiaolong (Andrew Gunnerson) `_. + +* Made ``constexpr remove_prefix`` gcc version check tighter + (`#648 `_). + +* Renamed internal type enum constants to prevent collision with poorly written + C libraries (`#644 `_). + +* Added detection of ``wostream operator<<`` + (`#650 `_). + +* Fixed compilation on OpenBSD + (`#660 `_). + Thanks `@hubslave `_. + +* Fixed compilation on FreeBSD 12 + (`#732 `_). + Thanks `@dankm `_. + +* Fixed compilation when there is a mismatch between ``-std`` options between + the library and user code + (`#664 `_). + +* Fixed compilation with GCC 7 and ``-std=c++11`` + (`#734 `_). + +* Improved generated binary code on GCC 7 and older + (`#668 `_). + +* Fixed handling of numeric alignment with no width + (`#675 `_). + +* Fixed handling of empty strings in UTF8/16 converters + (`#676 `_). + Thanks `@vgalka-sl (Vasili Galka) `_. + +* Fixed formatting of an empty ``string_view`` + (`#689 `_). + +* Fixed detection of ``string_view`` on libc++ + (`#686 `_). + +* Fixed DLL issues (`#696 `_). + Thanks `@sebkoenig `_. + +* Fixed compile checks for mixing narrow and wide strings + (`#690 `_). + +* Disabled unsafe implicit conversion to ``std::string`` + (`#729 `_). + +* Fixed handling of reused format specs (as in ``fmt::join``) for pointers + (`#725 `_). + Thanks `@mwinterb `_. + +* Fixed installation of ``fmt/ranges.h`` + (`#738 `_). + Thanks `@sv1990 `_. + 4.1.0 - 2017-12-20 ------------------ @@ -234,7 +407,7 @@ `@thelostt (Mário Feroldi) `_, and `@Manu343726 (Manu Sánchez) `_. -* Improved CMake: Used GNUInstallDirs to set installation location +* Improved CMake: Used ``GNUInstallDirs`` to set installation location (`#610 `_) and fixed warnings (`#536 `_ and `#556 `_). @@ -340,7 +513,6 @@ (`#494 `_, `#499 `_, `#483 `_, - `#519 `_, `#485 `_, `#482 `_, `#475 `_, diff --git a/doc/api.rst b/doc/api.rst index 0eeab744..8bf71c57 100644 --- a/doc/api.rst +++ b/doc/api.rst @@ -164,6 +164,10 @@ Utilities System errors ------------- +fmt does not use ``errno`` to communicate errors to the user, but it may call +system functions which set ``errno``. Users should not make any assumptions about +the value of ``errno`` being preserved by library functions. + .. doxygenclass:: fmt::system_error :members: diff --git a/doc/build.py b/doc/build.py index cfa52b0d..ef45ebc4 100755 --- a/doc/build.py +++ b/doc/build.py @@ -6,7 +6,7 @@ import errno, os, shutil, sys, tempfile from subprocess import check_call, check_output, CalledProcessError, Popen, PIPE from distutils.version import LooseVersion -versions = ['1.0.0', '1.1.0', '2.0.0', '3.0.2', '4.0.0', '4.1.0'] +versions = ['1.0.0', '1.1.0', '2.0.0', '3.0.2', '4.0.0', '4.1.0', '5.0.0'] def pip_install(package, commit=None, **kwargs): "Install package using pip." diff --git a/doc/index.rst b/doc/index.rst index ac463062..17d6b4bb 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -2,8 +2,7 @@ Overview ======== **fmt** (formerly cppformat) is an open-source formatting library. -It can be used as a safe alternative to printf or as a fast -alternative to C++ IOStreams. +It can be used as a fast and safe alternative to printf and IOStreams. .. raw:: html @@ -30,9 +29,9 @@ in Python: .. code:: c++ - fmt::format("The answer is {}", 42); + fmt::format("The answer is {}.", 42); -The ``fmt::format`` function returns a string "The answer is 42". You can use +The ``fmt::format`` function returns a string "The answer is 42.". You can use ``fmt::memory_buffer`` to avoid constructing ``std::string``: .. code:: c++ @@ -94,19 +93,25 @@ Safety ------ The library is fully type safe, automatic memory management prevents buffer -overflow, errors in format strings are reported using exceptions. For example, -the code +overflow, errors in format strings are reported using exceptions or at compile +tim. For example, the code .. code:: c++ fmt::format("The answer is {:d}", "forty-two"); -throws a ``format_error`` exception with description -"unknown format code 'd' for string", because the argument -``"forty-two"`` is a string while the format code ``d`` -only applies to integers. +throws a ``format_error`` exception with description "unknown format code 'd' for +string", because the argument ``"forty-two"`` is a string while the format code +``d`` only applies to integers, while -Where possible, errors are caught at compile time. For example, the code +.. code:: c++ + + format(fmt("The answer is {:d}"), "forty-two"); + +reports a compile-time error for the same reason on compilers that support +relaxed ``constexpr``. + +The following code .. code:: c++ @@ -124,16 +129,10 @@ its numeric value being written to the stream (i.e. 1070 instead of letter 'ю' which is represented by ``L'\x42e'`` if we use Unicode) which is rarely what is needed. -Note that fmt does not use the value of the ``errno`` global to communicate -errors to the user, but it may call system functions which set ``errno``. Since -fmt does not attempt to preserve the value of ``errno``, users should not make -any assumptions about it and always set it to ``0`` before making any system -calls that convey error information via ``errno``. - Compact binary code ------------------- -Each call to a formatting function results in a compact binary code. For example +The library is designed to produce compact per-call compiled code. For example (`godbolt `_), .. code:: c++ @@ -167,33 +166,19 @@ compiles to just Portability ----------- -The library is highly portable. Here is an incomplete list of operating systems -and compilers where it has been tested and known to work: +The library is highly portable and relies only on a small set of C++11 features: -* 64-bit (amd64) GNU/Linux with GCC 4.4.3, - `4.6.3 `_, 4.7.2, 4.8.1, and Intel C++ - Compiler (ICC) 14.0.2 +* variadic templates +* type traits +* rvalue references +* decltype +* trailing return types +* deleted functions -* 32-bit (i386) GNU/Linux with GCC 4.4.3, 4.6.3 - -* Mac OS X with GCC 4.2.1 and Clang 4.2, 5.1.0 - -* 64-bit Windows with Visual C++ 2010, 2013 and - `2015 `_ - -* 32-bit Windows with Visual C++ 2010 - -Although the library uses C++11 features when available, it also works with -older compilers and standard library implementations. The only thing to keep in -mind for C++98 portability: - -* Variadic templates: minimum GCC 4.4, Clang 2.9 or VS2013. This feature allows - the Format API to accept an unlimited number of arguments. With older - compilers the maximum is 15. - -* User-defined literals: minimum GCC 4.7, Clang 3.1 or VS2015. The suffixes - ``_format`` and ``_a`` are functionally equivalent to the functions - ``fmt::format`` and ``fmt::arg``. +These are available since GCC 4.4, Clang 2.9 and MSVC 18.0 (2013). For older +compilers use fmt `version 4.x +`_ which continues to be +maintained and only requires C++98. The output of all formatting functions is consistent across platforms. In particular, formatting a floating-point infinity always gives ``inf`` while the @@ -211,7 +196,7 @@ Ease of Use ----------- fmt has a small self-contained code base with the core library consisting of -a single header file and a single source file and no external dependencies. +just three header files and no external dependencies. A permissive BSD `license `_ allows using the library both in open-source and commercial projects. diff --git a/include/fmt/core.h b/include/fmt/core.h index 50bf6b00..55fddfbd 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -627,7 +627,8 @@ FMT_MAKE_VALUE(pointer_type, std::nullptr_t, const void*) // formatting of "[const] volatile char *" which is printed as bool by // iostreams. template -typed_value make_value(const T *) { +typename std::enable_if::value>::type + make_value(const T *) { static_assert(!sizeof(T), "formatting of non-void pointers is disallowed"); } @@ -640,8 +641,9 @@ inline typename std::enable_if< template inline typename std::enable_if< !convert_to_int::value && - !std::is_convertible>::value && - !std::is_convertible>::value, + !std::is_convertible>::value, + // Implicit conversion to std::string is not handled here because it's + // unsafe: https://github.com/fmtlib/fmt/issues/729 typed_value>::type make_value(const T &val) { return val; } @@ -1250,12 +1252,12 @@ inline std::string format(string_view format_str, const Args & ... args) { // This should be just // return vformat(format_str, make_format_args(args...)); // but gcc has trouble optimizing the latter, so break it down. - format_arg_store as(args...); + format_arg_store as{args...}; return vformat(format_str, as); } template inline std::wstring format(wstring_view format_str, const Args & ... args) { - format_arg_store as(args...); + format_arg_store as{args...}; return vformat(format_str, as); } @@ -1296,7 +1298,7 @@ FMT_API void vprint(wstring_view format_str, wformat_args args); */ template inline void print(string_view format_str, const Args & ... args) { - format_arg_store as(args...); + format_arg_store as{args...}; vprint(format_str, as); } diff --git a/include/fmt/format-inl.h b/include/fmt/format-inl.h index e9b495cb..c43b8868 100644 --- a/include/fmt/format-inl.h +++ b/include/fmt/format-inl.h @@ -9,7 +9,6 @@ #define FMT_FORMAT_INL_H_ #include "format.h" -#include "locale.h" #include @@ -19,6 +18,7 @@ #include #include #include // for std::ptrdiff_t +#include #if defined(_WIN32) && defined(__MINGW32__) # include @@ -104,14 +104,14 @@ int safe_strerror( int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT { FMT_ASSERT(buffer != FMT_NULL && buffer_size != 0, "invalid buffer"); - class StrError { + class dispatcher { private: int error_code_; char *&buffer_; std::size_t buffer_size_; // A noop assignment operator to avoid bogus warnings. - void operator=(const StrError &) {} + void operator=(const dispatcher &) {} // Handle the result of XSI-compliant version of strerror_r. int handle(int result) { @@ -148,14 +148,14 @@ int safe_strerror( } public: - StrError(int err_code, char *&buf, std::size_t buf_size) + dispatcher(int err_code, char *&buf, std::size_t buf_size) : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {} int run() { return handle(strerror_r(error_code_, buffer_, buffer_size_)); } }; - return StrError(error_code, buffer, buffer_size).run(); + return dispatcher(error_code, buffer, buffer_size).run(); } void format_error_code(internal::buffer &out, int error_code, @@ -196,6 +196,15 @@ void report_error(FormatFunc func, int error_code, } } // namespace +class locale { + private: + std::locale locale_; + + public: + explicit locale(std::locale loc = std::locale()) : locale_(loc) {} + std::locale get() { return locale_; } +}; + template FMT_FUNC Char internal::thousands_sep(locale_provider *lp) { std::locale loc = lp ? lp->locale().get() : std::locale(); diff --git a/include/fmt/format.h b/include/fmt/format.h index fcbfcc71..07c16694 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -2249,7 +2249,9 @@ void handle_dynamic_spec( /** The default argument formatter. */ template class arg_formatter: - public internal::function, public internal::arg_formatter_base { + public internal::function< + typename internal::arg_formatter_base::iterator>, + public internal::arg_formatter_base { private: typedef typename Range::value_type char_type; typedef internal::arg_formatter_base base; @@ -2985,7 +2987,7 @@ FMT_API void report_windows_error(int error_code, #endif /** Fast integer formatter. */ -class FormatInt { +class format_int { private: // Buffer should be large enough to hold all digits (digits10 + 1), // a sign and a null character. @@ -3026,12 +3028,12 @@ class FormatInt { } public: - explicit FormatInt(int value) { format_signed(value); } - explicit FormatInt(long value) { format_signed(value); } - explicit FormatInt(long long value) { format_signed(value); } - explicit FormatInt(unsigned value) : str_(format_decimal(value)) {} - explicit FormatInt(unsigned long value) : str_(format_decimal(value)) {} - explicit FormatInt(unsigned long long value) : str_(format_decimal(value)) {} + explicit format_int(int value) { format_signed(value); } + explicit format_int(long value) { format_signed(value); } + explicit format_int(long long value) { format_signed(value); } + explicit format_int(unsigned value) : str_(format_decimal(value)) {} + explicit format_int(unsigned long value) : str_(format_decimal(value)) {} + explicit format_int(unsigned long long value) : str_(format_decimal(value)) {} /** Returns the number of characters written to the output buffer. */ std::size_t size() const { @@ -3658,7 +3660,7 @@ FMT_END_NAMESPACE #include // A compile-time error because 'd' is an invalid specifier for strings. - std::string s = fmt::format(fmt("{:d}"), "foo"); + std::string s = format(fmt("{:d}"), "foo"); \endrst */ # define fmt(s) FMT_STRING(s) diff --git a/include/fmt/locale.h b/include/fmt/locale.h deleted file mode 100644 index a6a4b748..00000000 --- a/include/fmt/locale.h +++ /dev/null @@ -1,25 +0,0 @@ -// Formatting library for C++ - locale support -// -// Copyright (c) 2012 - 2016, Victor Zverovich -// All rights reserved. -// -// For the license information refer to format.h. - -#ifndef FMT_LOCALE_H_ -#define FMT_LOCALE_H_ - -#include "format.h" -#include - -FMT_BEGIN_NAMESPACE -class locale { - private: - std::locale locale_; - - public: - explicit locale(std::locale loc = std::locale()) : locale_(loc) {} - std::locale get() { return locale_; } -}; -FMT_END_NAMESPACE - -#endif // FMT_LOCALE_ diff --git a/include/fmt/ostream.h b/include/fmt/ostream.h index 32e9a9c1..cdb39047 100644 --- a/include/fmt/ostream.h +++ b/include/fmt/ostream.h @@ -15,7 +15,7 @@ FMT_BEGIN_NAMESPACE namespace internal { template -class FormatBuf : public std::basic_streambuf { +class formatbuf : public std::basic_streambuf { private: typedef typename std::basic_streambuf::int_type int_type; typedef typename std::basic_streambuf::traits_type traits_type; @@ -23,7 +23,7 @@ class FormatBuf : public std::basic_streambuf { basic_buffer &buffer_; public: - FormatBuf(basic_buffer &buffer) : buffer_(buffer) {} + formatbuf(basic_buffer &buffer) : buffer_(buffer) {} protected: // The put-area is actually always empty. This makes the implementation @@ -53,10 +53,10 @@ struct test_stream : std::basic_ostream { void operator<<(null); }; -// Disable conversion to int if T has an overloaded operator<< which is a free -// function (not a member of std::ostream). +// Checks if T has an overloaded operator<< which is a free function (not a +// member of std::ostream). template -class convert_to_int { +class is_streamable { private: template static decltype( @@ -69,7 +69,16 @@ class convert_to_int { typedef decltype(test(0)) result; public: - static const bool value = !result::value; + static const bool value = result::value; +}; + +// Disable conversion to int if T has an overloaded operator<< which is a free +// function (not a member of std::ostream). +template +class convert_to_int { + public: + static const bool value = + convert_to_int::value && !is_streamable::value; }; // Write the content of buf to os. @@ -90,7 +99,7 @@ void write(std::basic_ostream &os, basic_buffer &buf) { template void format_value(basic_buffer &buffer, const T &value) { - internal::FormatBuf format_buf(buffer); + internal::formatbuf format_buf(buffer); std::basic_ostream output(&format_buf); output.exceptions(std::ios_base::failbit | std::ios_base::badbit); output << value; @@ -106,8 +115,7 @@ struct format_enum struct formatter::type, T>::value>::type> + typename std::enable_if::value>::type> : formatter, Char> { template @@ -140,22 +148,13 @@ inline void vprint(std::basic_ostream &os, template inline void print(std::ostream &os, string_view format_str, const Args & ... args) { -#if FMT_GCC_VERSION && FMT_GCC_VERSION <= 440 - // Fix gcc's bugged template deduction vprint(os, format_str, make_format_args(args...)); -#else - vprint(os, format_str, make_format_args(args...)); -#endif } template inline void print(std::wostream &os, wstring_view format_str, const Args & ... args) { -#if FMT_GCC_VERSION && FMT_GCC_VERSION <= 440 vprint(os, format_str, make_format_args(args...)); -#else - vprint(os, format_str, make_format_args(args...)); -#endif } FMT_END_NAMESPACE diff --git a/include/fmt/posix.h b/include/fmt/posix.h index 67f5b91f..8682d716 100644 --- a/include/fmt/posix.h +++ b/include/fmt/posix.h @@ -113,31 +113,31 @@ typedef basic_cstring_view cstring_view; typedef basic_cstring_view wcstring_view; // An error code. -class ErrorCode { +class error_code { private: int value_; public: - explicit ErrorCode(int value = 0) FMT_NOEXCEPT : value_(value) {} + explicit error_code(int value = 0) FMT_NOEXCEPT : value_(value) {} int get() const FMT_NOEXCEPT { return value_; } }; // A buffered file. -class BufferedFile { +class buffered_file { private: FILE *file_; - friend class File; + friend class file; - explicit BufferedFile(FILE *f) : file_(f) {} + explicit buffered_file(FILE *f) : file_(f) {} public: - // Constructs a BufferedFile object which doesn't represent any file. - BufferedFile() FMT_NOEXCEPT : file_(FMT_NULL) {} + // Constructs a buffered_file object which doesn't represent any file. + buffered_file() FMT_NOEXCEPT : file_(FMT_NULL) {} // Destroys the object closing the file it represents if any. - FMT_API ~BufferedFile() FMT_DTOR_NOEXCEPT; + FMT_API ~buffered_file() FMT_DTOR_NOEXCEPT; #if !FMT_USE_RVALUE_REFERENCES // Emulate a move constructor and a move assignment operator if rvalue @@ -152,22 +152,22 @@ class BufferedFile { public: // A "move constructor" for moving from a temporary. - BufferedFile(Proxy p) FMT_NOEXCEPT : file_(p.file) {} + buffered_file(Proxy p) FMT_NOEXCEPT : file_(p.file) {} // A "move constructor" for moving from an lvalue. - BufferedFile(BufferedFile &f) FMT_NOEXCEPT : file_(f.file_) { + buffered_file(buffered_file &f) FMT_NOEXCEPT : file_(f.file_) { f.file_ = FMT_NULL; } // A "move assignment operator" for moving from a temporary. - BufferedFile &operator=(Proxy p) { + buffered_file &operator=(Proxy p) { close(); file_ = p.file; return *this; } // A "move assignment operator" for moving from an lvalue. - BufferedFile &operator=(BufferedFile &other) { + buffered_file &operator=(buffered_file &other) { close(); file_ = other.file_; other.file_ = FMT_NULL; @@ -175,7 +175,7 @@ public: } // Returns a proxy object for moving from a temporary: - // BufferedFile file = BufferedFile(...); + // buffered_file file = buffered_file(...); operator Proxy() FMT_NOEXCEPT { Proxy p = {file_}; file_ = FMT_NULL; @@ -184,14 +184,14 @@ public: #else private: - FMT_DISALLOW_COPY_AND_ASSIGN(BufferedFile); + FMT_DISALLOW_COPY_AND_ASSIGN(buffered_file); public: - BufferedFile(BufferedFile &&other) FMT_NOEXCEPT : file_(other.file_) { + buffered_file(buffered_file &&other) FMT_NOEXCEPT : file_(other.file_) { other.file_ = FMT_NULL; } - BufferedFile& operator=(BufferedFile &&other) { + buffered_file& operator=(buffered_file &&other) { close(); file_ = other.file_; other.file_ = FMT_NULL; @@ -200,7 +200,7 @@ public: #endif // Opens a file. - FMT_API BufferedFile(cstring_view filename, cstring_view mode); + FMT_API buffered_file(cstring_view filename, cstring_view mode); // Closes the file. FMT_API void close(); @@ -222,18 +222,18 @@ public: } }; -// A file. Closed file is represented by a File object with descriptor -1. +// A file. Closed file is represented by a file object with descriptor -1. // Methods that are not declared with FMT_NOEXCEPT may throw // fmt::system_error in case of failure. Note that some errors such as // closing the file multiple times will cause a crash on Windows rather // than an exception. You can get standard behavior by overriding the // invalid parameter handler with _set_invalid_parameter_handler. -class File { +class file { private: int fd_; // File descriptor. - // Constructs a File object with a given descriptor. - explicit File(int fd) : fd_(fd) {} + // Constructs a file object with a given descriptor. + explicit file(int fd) : fd_(fd) {} public: // Possible values for the oflag argument to the constructor. @@ -243,11 +243,11 @@ class File { RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing. }; - // Constructs a File object which doesn't represent any file. - File() FMT_NOEXCEPT : fd_(-1) {} + // Constructs a file object which doesn't represent any file. + file() FMT_NOEXCEPT : fd_(-1) {} - // Opens a file and constructs a File object representing this file. - FMT_API File(cstring_view path, int oflag); + // Opens a file and constructs a file object representing this file. + FMT_API file(cstring_view path, int oflag); #if !FMT_USE_RVALUE_REFERENCES // Emulate a move constructor and a move assignment operator if rvalue @@ -262,22 +262,22 @@ class File { public: // A "move constructor" for moving from a temporary. - File(Proxy p) FMT_NOEXCEPT : fd_(p.fd) {} + file(Proxy p) FMT_NOEXCEPT : fd_(p.fd) {} // A "move constructor" for moving from an lvalue. - File(File &other) FMT_NOEXCEPT : fd_(other.fd_) { + file(file &other) FMT_NOEXCEPT : fd_(other.fd_) { other.fd_ = -1; } // A "move assignment operator" for moving from a temporary. - File &operator=(Proxy p) { + file &operator=(Proxy p) { close(); fd_ = p.fd; return *this; } // A "move assignment operator" for moving from an lvalue. - File &operator=(File &other) { + file &operator=(file &other) { close(); fd_ = other.fd_; other.fd_ = -1; @@ -285,7 +285,7 @@ class File { } // Returns a proxy object for moving from a temporary: - // File file = File(...); + // file f = file(...); operator Proxy() FMT_NOEXCEPT { Proxy p = {fd_}; fd_ = -1; @@ -294,14 +294,14 @@ class File { #else private: - FMT_DISALLOW_COPY_AND_ASSIGN(File); + FMT_DISALLOW_COPY_AND_ASSIGN(file); public: - File(File &&other) FMT_NOEXCEPT : fd_(other.fd_) { + file(file &&other) FMT_NOEXCEPT : fd_(other.fd_) { other.fd_ = -1; } - File& operator=(File &&other) { + file& operator=(file &&other) { close(); fd_ = other.fd_; other.fd_ = -1; @@ -310,7 +310,7 @@ class File { #endif // Destroys the object closing the file it represents if any. - FMT_API ~File() FMT_DTOR_NOEXCEPT; + FMT_API ~file() FMT_DTOR_NOEXCEPT; // Returns the file descriptor. int descriptor() const FMT_NOEXCEPT { return fd_; } @@ -330,7 +330,7 @@ class File { // Duplicates a file descriptor with the dup function and returns // the duplicate as a file object. - FMT_API static File dup(int fd); + FMT_API static file dup(int fd); // Makes fd be the copy of this file descriptor, closing fd first if // necessary. @@ -338,15 +338,15 @@ class File { // Makes fd be the copy of this file descriptor, closing fd first if // necessary. - FMT_API void dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT; + FMT_API void dup2(int fd, error_code &ec) FMT_NOEXCEPT; // Creates a pipe setting up read_end and write_end file objects for reading // and writing respectively. - FMT_API static void pipe(File &read_end, File &write_end); + FMT_API static void pipe(file &read_end, file &write_end); - // Creates a BufferedFile object associated with this file and detaches - // this File object from the file. - FMT_API BufferedFile fdopen(const char *mode); + // Creates a buffered_file object associated with this file and detaches + // this file object from the file. + FMT_API buffered_file fdopen(const char *mode); }; // Returns the memory page size. @@ -409,8 +409,8 @@ FMT_END_NAMESPACE #if !FMT_USE_RVALUE_REFERENCES namespace std { // For compatibility with C++98. -inline fmt::BufferedFile &move(fmt::BufferedFile &f) { return f; } -inline fmt::File &move(fmt::File &f) { return f; } +inline fmt::buffered_file &move(fmt::buffered_file &f) { return f; } +inline fmt::file &move(fmt::file &f) { return f; } } #endif diff --git a/include/fmt/printf.h b/include/fmt/printf.h index db1a0d73..fb69d5b1 100644 --- a/include/fmt/printf.h +++ b/include/fmt/printf.h @@ -213,7 +213,9 @@ class basic_printf_context; */ template class printf_arg_formatter: - public internal::function, public internal::arg_formatter_base { + public internal::function< + typename internal::arg_formatter_base::iterator>, + public internal::arg_formatter_base { private: typedef typename Range::value_type char_type; typedef decltype(internal::declval().begin()) iterator; @@ -625,12 +627,7 @@ template inline int fprintf(std::FILE *f, string_view format_str, const Args & ... args) { auto vargs = make_format_args< typename printf_context::type>(args...); -#if FMT_GCC_VERSION && FMT_GCC_VERSION <= 440 - // Fix gcc's bugged template deduction return vfprintf(f, format_str, vargs); -#else - return vfprintf(f, format_str, vargs); -#endif } template diff --git a/include/fmt/ranges.h b/include/fmt/ranges.h index e5dc63f7..d946eb36 100644 --- a/include/fmt/ranges.h +++ b/include/fmt/ranges.h @@ -34,18 +34,20 @@ template struct formatting_range : formatting_base { static FMT_CONSTEXPR_DECL const std::size_t range_length_limit = FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the range. - Char prefix = '{'; - Char delimiter = ','; - Char postfix = '}'; + Char prefix; + Char delimiter; + Char postfix; + formatting_range() : prefix('{'), delimiter(','), postfix('}') {} static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true; static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false; }; template struct formatting_tuple : formatting_base { - Char prefix = '('; - Char delimiter = ','; - Char postfix = ')'; + Char prefix; + Char delimiter; + Char postfix; + formatting_tuple() : prefix('('), delimiter(','), postfix(')') {} static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true; static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false; }; @@ -54,9 +56,8 @@ namespace internal { template void copy(const RangeT &range, OutputIterator out) { - for (const auto &it : range) { - *out++ = it; - } + for (auto it = range.begin(), end = range.end(); it != end; ++it) + *out++ = *it; } template @@ -83,7 +84,7 @@ class is_like_std_string { public: static FMT_CONSTEXPR_DECL const bool value = - !std::is_void(nullptr))>::value; + !std::is_void(FMT_NULL))>::value; }; template @@ -95,8 +96,8 @@ struct is_range_ : std::false_type {}; template struct is_range_().begin()), - decltype(std::declval().end())>, + conditional_helper().begin()), + decltype(internal::declval().end())>, void>::type> : std::true_type {}; template @@ -111,13 +112,13 @@ class is_tuple_like_ { template static auto check(U *p) -> decltype(std::tuple_size::value, - std::declval::type>(), int()); + internal::declval::type>(), int()); template static void check(...); public: static FMT_CONSTEXPR_DECL const bool value = - !std::is_void(nullptr))>::value; + !std::is_void(FMT_NULL))>::value; }; template @@ -125,6 +126,7 @@ struct is_tuple_like { static FMT_CONSTEXPR_DECL const bool value = is_tuple_like_::value && !is_range_::value; }; +} // namespace internal // Check for integer_sequence #if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1910 @@ -213,6 +215,7 @@ struct formatter struct formatter< RangeT, Char, @@ -226,11 +229,12 @@ struct formatter< RangeT, Char, } template - auto format(const RangeT &values, FormatContext &ctx) -> decltype(ctx.out()) { + typename FormatContext::iterator format( + const RangeT &values, FormatContext &ctx) { auto out = ctx.out(); internal::copy(formatting.prefix, out); std::size_t i = 0; - for (const auto &it : values) { + for (auto it = values.begin(), end = values.end(); it != end; ++it) { if (i > 0) { if (formatting.add_prepostfix_space) { *out++ = ' '; @@ -238,9 +242,9 @@ struct formatter< RangeT, Char, internal::copy(formatting.delimiter, out); } if (formatting.add_delimiter_spaces && i > 0) { - format_to(out, " {}", it); + format_to(out, " {}", *it); } else { - format_to(out, "{}", it); + format_to(out, "{}", *it); } if (++i > formatting.range_length_limit) { format_to(out, " ... "); diff --git a/include/fmt/time.h b/include/fmt/time.h index 7ca967f6..515452a4 100644 --- a/include/fmt/time.h +++ b/include/fmt/time.h @@ -22,11 +22,11 @@ inline null<> gmtime_s(...) { return null<>(); } // Thread-safe replacement for std::localtime inline std::tm localtime(std::time_t time) { - struct LocalTime { + struct dispatcher { std::time_t time_; std::tm tm_; - LocalTime(std::time_t t): time_(t) {} + dispatcher(std::time_t t): time_(t) {} bool run() { using namespace fmt::internal; @@ -49,7 +49,7 @@ inline std::tm localtime(std::time_t time) { return tm != FMT_NULL; } }; - LocalTime lt(time); + dispatcher lt(time); if (lt.run()) return lt.tm_; // Too big time values may be unsupported. @@ -58,11 +58,11 @@ inline std::tm localtime(std::time_t time) { // Thread-safe replacement for std::gmtime inline std::tm gmtime(std::time_t time) { - struct GMTime { + struct dispatcher { std::time_t time_; std::tm tm_; - GMTime(std::time_t t): time_(t) {} + dispatcher(std::time_t t): time_(t) {} bool run() { using namespace fmt::internal; @@ -84,7 +84,7 @@ inline std::tm gmtime(std::time_t time) { return tm != FMT_NULL; } }; - GMTime gt(time); + dispatcher gt(time); if (gt.run()) return gt.tm_; // Too big time values may be unsupported. @@ -92,11 +92,13 @@ inline std::tm gmtime(std::time_t time) { } namespace internal { -inline std::size_t strftime(char *str, std::size_t count, const char *format, const std::tm *time) { +inline std::size_t strftime(char *str, std::size_t count, const char *format, + const std::tm *time) { return std::strftime(str, count, format, time); } -inline std::size_t strftime(wchar_t *str, std::size_t count, const wchar_t *format, const std::tm *time) { +inline std::size_t strftime(wchar_t *str, std::size_t count, + const wchar_t *format, const std::tm *time) { return std::wcsftime(str, count, format, time); } } @@ -124,7 +126,8 @@ struct formatter { std::size_t start = buf.size(); for (;;) { std::size_t size = buf.capacity() - start; - std::size_t count = internal::strftime(&buf[start], size, &tm_format[0], &tm); + std::size_t count = + internal::strftime(&buf[start], size, &tm_format[0], &tm); if (count != 0) { buf.resize(start + count); break; diff --git a/src/posix.cc b/src/posix.cc index 452d49f5..296da232 100644 --- a/src/posix.cc +++ b/src/posix.cc @@ -66,19 +66,19 @@ inline std::size_t convert_rwcount(std::size_t count) { return count; } FMT_BEGIN_NAMESPACE -BufferedFile::~BufferedFile() FMT_NOEXCEPT { +buffered_file::~buffered_file() FMT_NOEXCEPT { if (file_ && FMT_SYSTEM(fclose(file_)) != 0) report_system_error(errno, "cannot close file"); } -BufferedFile::BufferedFile(cstring_view filename, cstring_view mode) { +buffered_file::buffered_file(cstring_view filename, cstring_view mode) { FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), FMT_NULL); if (!file_) FMT_THROW(system_error(errno, "cannot open file {}", filename.c_str())); } -void BufferedFile::close() { +void buffered_file::close() { if (!file_) return; int result = FMT_SYSTEM(fclose(file_)); @@ -90,14 +90,14 @@ void BufferedFile::close() { // A macro used to prevent expansion of fileno on broken versions of MinGW. #define FMT_ARGS -int BufferedFile::fileno() const { +int buffered_file::fileno() const { int fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_)); if (fd == -1) FMT_THROW(system_error(errno, "cannot get file descriptor")); return fd; } -File::File(cstring_view path, int oflag) { +file::file(cstring_view path, int oflag) { int mode = S_IRUSR | S_IWUSR; #if defined(_WIN32) && !defined(__MINGW32__) fd_ = -1; @@ -109,14 +109,14 @@ File::File(cstring_view path, int oflag) { FMT_THROW(system_error(errno, "cannot open file {}", path.c_str())); } -File::~File() FMT_NOEXCEPT { +file::~file() FMT_NOEXCEPT { // Don't retry close in case of EINTR! // See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0) report_system_error(errno, "cannot close file"); } -void File::close() { +void file::close() { if (fd_ == -1) return; // Don't retry close in case of EINTR! @@ -127,7 +127,7 @@ void File::close() { FMT_THROW(system_error(errno, "cannot close file")); } -long long File::size() const { +long long file::size() const { #ifdef _WIN32 // Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT // is less than 0x0500 as is the case with some default MinGW builds. @@ -148,12 +148,12 @@ long long File::size() const { if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1) FMT_THROW(system_error(errno, "cannot get file attributes")); static_assert(sizeof(long long) >= sizeof(file_stat.st_size), - "return type of File::size is not large enough"); + "return type of file::size is not large enough"); return file_stat.st_size; #endif } -std::size_t File::read(void *buffer, std::size_t count) { +std::size_t file::read(void *buffer, std::size_t count) { RWResult result = 0; FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count)))); if (result < 0) @@ -161,7 +161,7 @@ std::size_t File::read(void *buffer, std::size_t count) { return internal::to_unsigned(result); } -std::size_t File::write(const void *buffer, std::size_t count) { +std::size_t file::write(const void *buffer, std::size_t count) { RWResult result = 0; FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count)))); if (result < 0) @@ -169,16 +169,16 @@ std::size_t File::write(const void *buffer, std::size_t count) { return internal::to_unsigned(result); } -File File::dup(int fd) { +file file::dup(int fd) { // Don't retry as dup doesn't return EINTR. // http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html int new_fd = FMT_POSIX_CALL(dup(fd)); if (new_fd == -1) FMT_THROW(system_error(errno, "cannot duplicate file descriptor {}", fd)); - return File(new_fd); + return file(new_fd); } -void File::dup2(int fd) { +void file::dup2(int fd) { int result = 0; FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); if (result == -1) { @@ -187,14 +187,14 @@ void File::dup2(int fd) { } } -void File::dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT { +void file::dup2(int fd, error_code &ec) FMT_NOEXCEPT { int result = 0; FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd))); if (result == -1) - ec = ErrorCode(errno); + ec = error_code(errno); } -void File::pipe(File &read_end, File &write_end) { +void file::pipe(file &read_end, file &write_end) { // Close the descriptors first to make sure that assignments don't throw // and there are no leaks. read_end.close(); @@ -213,19 +213,19 @@ void File::pipe(File &read_end, File &write_end) { FMT_THROW(system_error(errno, "cannot create pipe")); // The following assignments don't throw because read_fd and write_fd // are closed. - read_end = File(fds[0]); - write_end = File(fds[1]); + read_end = file(fds[0]); + write_end = file(fds[1]); } -BufferedFile File::fdopen(const char *mode) { +buffered_file file::fdopen(const char *mode) { // Don't retry as fdopen doesn't return EINTR. FILE *f = FMT_POSIX_CALL(fdopen(fd_, mode)); if (!f) FMT_THROW(system_error(errno, "cannot associate stream with file descriptor")); - BufferedFile file(f); + buffered_file bf(f); fd_ = -1; - return file; + return bf; } long getpagesize() { diff --git a/test/compile-test/CMakeLists.txt b/test/compile-test/CMakeLists.txt index 38038ede..dda1fb96 100644 --- a/test/compile-test/CMakeLists.txt +++ b/test/compile-test/CMakeLists.txt @@ -9,8 +9,7 @@ set(CMAKE_REQUIRED_FLAGS ${CPP14_FLAG}) function (generate_source result fragment) set(${result} " #define FMT_HEADER_ONLY 1 - #include \"fmt/posix.h\" - #include \"fmt/ostream.h\" + #include \"fmt/format.h\" int main() { ${fragment} } @@ -58,6 +57,14 @@ expect_compile_error("fmt::format(\"{}\", L\"foo\");") # mixing UTF-8 with UTF-16/32 can result in an invalid output. expect_compile_error("fmt::format(L\"{}\", \"foo\");") +# Formatting a wide string with a narrow format string is forbidden. +expect_compile_error(" + struct S { + operator std::string() const { return std::string(); } + }; + fmt::format(\"{}\", S()); +") + # Make sure that compiler features detected in the header # match the features detected in CMake. if (SUPPORTS_USER_DEFINED_LITERALS) diff --git a/test/format-test.cc b/test/format-test.cc index 4a6533f5..0044390e 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1072,16 +1072,6 @@ TEST(FormatterTest, FormatStdStringView) { } #endif -struct ConvertibleToString { - std::string s; - ConvertibleToString() : s("foo") {} - operator const std::string &() const { return s; } -}; - -TEST(FormatterTest, FormatConvertibleToString) { - EXPECT_EQ("foo", format("{}", ConvertibleToString())); -} - struct ConvertibleToStringView { operator fmt::string_view() const { return "foo"; } }; @@ -1217,23 +1207,23 @@ TEST(FormatterTest, Examples) { } TEST(FormatIntTest, Data) { - fmt::FormatInt format_int(42); + fmt::format_int format_int(42); EXPECT_EQ("42", std::string(format_int.data(), format_int.size())); } TEST(FormatIntTest, FormatInt) { - EXPECT_EQ("42", fmt::FormatInt(42).str()); - EXPECT_EQ(2u, fmt::FormatInt(42).size()); - EXPECT_EQ("-42", fmt::FormatInt(-42).str()); - EXPECT_EQ(3u, fmt::FormatInt(-42).size()); - EXPECT_EQ("42", fmt::FormatInt(42ul).str()); - EXPECT_EQ("-42", fmt::FormatInt(-42l).str()); - EXPECT_EQ("42", fmt::FormatInt(42ull).str()); - EXPECT_EQ("-42", fmt::FormatInt(-42ll).str()); + EXPECT_EQ("42", fmt::format_int(42).str()); + EXPECT_EQ(2u, fmt::format_int(42).size()); + EXPECT_EQ("-42", fmt::format_int(-42).str()); + EXPECT_EQ(3u, fmt::format_int(-42).size()); + EXPECT_EQ("42", fmt::format_int(42ul).str()); + EXPECT_EQ("-42", fmt::format_int(-42l).str()); + EXPECT_EQ("42", fmt::format_int(42ull).str()); + EXPECT_EQ("-42", fmt::format_int(-42ll).str()); std::ostringstream os; os << std::numeric_limits::max(); EXPECT_EQ(os.str(), - fmt::FormatInt(std::numeric_limits::max()).str()); + fmt::format_int(std::numeric_limits::max()).str()); } template @@ -1404,7 +1394,8 @@ TEST(FormatTest, FixedEnum) { typedef fmt::back_insert_range buffer_range; class mock_arg_formatter: - public fmt::internal::function, + public fmt::internal::function< + fmt::internal::arg_formatter_base::iterator>, public fmt::internal::arg_formatter_base { private: MOCK_METHOD1(call, void (int value)); diff --git a/test/gtest-extra-test.cc b/test/gtest-extra-test.cc index 2043f549..8e42d8e2 100644 --- a/test/gtest-extra-test.cc +++ b/test/gtest-extra-test.cc @@ -306,20 +306,20 @@ TEST(UtilTest, FormatSystemError) { #if FMT_USE_FILE_DESCRIPTORS -using fmt::BufferedFile; -using fmt::ErrorCode; -using fmt::File; +using fmt::buffered_file; +using fmt::error_code; +using fmt::file; TEST(ErrorCodeTest, Ctor) { - EXPECT_EQ(0, ErrorCode().get()); - EXPECT_EQ(42, ErrorCode(42).get()); + EXPECT_EQ(0, error_code().get()); + EXPECT_EQ(42, error_code(42).get()); } TEST(OutputRedirectTest, ScopedRedirect) { - File read_end, write_end; - File::pipe(read_end, write_end); + file read_end, write_end; + file::pipe(read_end, write_end); { - BufferedFile file(write_end.fdopen("w")); + buffered_file file(write_end.fdopen("w")); std::fprintf(file.get(), "[[["); { OutputRedirect redir(file.get()); @@ -332,11 +332,11 @@ TEST(OutputRedirectTest, ScopedRedirect) { // Test that OutputRedirect handles errors in flush correctly. TEST(OutputRedirectTest, FlushErrorInCtor) { - File read_end, write_end; - File::pipe(read_end, write_end); + file read_end, write_end; + file::pipe(read_end, write_end); int write_fd = write_end.descriptor(); - File write_copy = write_end.dup(write_fd); - BufferedFile f = write_end.fdopen("w"); + file write_copy = write_end.dup(write_fd); + buffered_file f = write_end.fdopen("w"); // Put a character in a file buffer. EXPECT_EQ('x', fputc('x', f.get())); FMT_POSIX(close(write_fd)); @@ -348,9 +348,9 @@ TEST(OutputRedirectTest, FlushErrorInCtor) { } TEST(OutputRedirectTest, DupErrorInCtor) { - BufferedFile f = open_buffered_file(); + buffered_file f = open_buffered_file(); int fd = (f.fileno)(); - File copy = File::dup(fd); + file copy = file::dup(fd); FMT_POSIX(close(fd)); scoped_ptr redir; EXPECT_SYSTEM_ERROR_NOASSERT(redir.reset(new OutputRedirect(f.get())), @@ -359,26 +359,26 @@ TEST(OutputRedirectTest, DupErrorInCtor) { } TEST(OutputRedirectTest, RestoreAndRead) { - File read_end, write_end; - File::pipe(read_end, write_end); - BufferedFile file(write_end.fdopen("w")); + file read_end, write_end; + file::pipe(read_end, write_end); + buffered_file file(write_end.fdopen("w")); std::fprintf(file.get(), "[[["); OutputRedirect redir(file.get()); std::fprintf(file.get(), "censored"); EXPECT_EQ("censored", sanitize(redir.restore_and_read())); EXPECT_EQ("", sanitize(redir.restore_and_read())); std::fprintf(file.get(), "]]]"); - file = BufferedFile(); + file = buffered_file(); EXPECT_READ(read_end, "[[[]]]"); } // Test that OutputRedirect handles errors in flush correctly. TEST(OutputRedirectTest, FlushErrorInRestoreAndRead) { - File read_end, write_end; - File::pipe(read_end, write_end); + file read_end, write_end; + file::pipe(read_end, write_end); int write_fd = write_end.descriptor(); - File write_copy = write_end.dup(write_fd); - BufferedFile f = write_end.fdopen("w"); + file write_copy = write_end.dup(write_fd); + buffered_file f = write_end.fdopen("w"); OutputRedirect redir(f.get()); // Put a character in a file buffer. EXPECT_EQ('x', fputc('x', f.get())); @@ -389,11 +389,11 @@ TEST(OutputRedirectTest, FlushErrorInRestoreAndRead) { } TEST(OutputRedirectTest, ErrorInDtor) { - File read_end, write_end; - File::pipe(read_end, write_end); + file read_end, write_end; + file::pipe(read_end, write_end); int write_fd = write_end.descriptor(); - File write_copy = write_end.dup(write_fd); - BufferedFile f = write_end.fdopen("w"); + file write_copy = write_end.dup(write_fd); + buffered_file f = write_end.fdopen("w"); scoped_ptr redir(new OutputRedirect(f.get())); // Put a character in a file buffer. EXPECT_EQ('x', fputc('x', f.get())); @@ -405,7 +405,7 @@ TEST(OutputRedirectTest, ErrorInDtor) { FMT_POSIX(close(write_fd)); SUPPRESS_ASSERT(redir.reset()); }, format_system_error(EBADF, "cannot flush stream")); - write_copy.dup2(write_fd); // "undo" close or dtor of BufferedFile will fail + write_copy.dup2(write_fd); // "undo" close or dtor of buffered_file will fail } #endif // FMT_USE_FILE_DESCRIPTORS diff --git a/test/gtest-extra.cc b/test/gtest-extra.cc index 21a7ea97..2c4c34a7 100644 --- a/test/gtest-extra.cc +++ b/test/gtest-extra.cc @@ -9,7 +9,7 @@ #if FMT_USE_FILE_DESCRIPTORS -using fmt::File; +using fmt::file; void OutputRedirect::flush() { #if EOF != -1 @@ -30,14 +30,14 @@ void OutputRedirect::restore() { original_.close(); } -OutputRedirect::OutputRedirect(FILE *file) : file_(file) { +OutputRedirect::OutputRedirect(FILE *f) : file_(f) { flush(); - int fd = FMT_POSIX(fileno(file)); - // Create a File object referring to the original file. - original_ = File::dup(fd); + int fd = FMT_POSIX(fileno(f)); + // Create a file object referring to the original file. + original_ = file::dup(fd); // Create a pipe. - File write_end; - File::pipe(read_end_, write_end); + file write_end; + file::pipe(read_end_, write_end); // Connect the passed FILE object to the write end of the pipe. write_end.dup2(fd); } @@ -69,7 +69,7 @@ std::string OutputRedirect::restore_and_read() { return content; } -std::string read(File &f, std::size_t count) { +std::string read(file &f, std::size_t count) { std::string buffer(count, '\0'); std::size_t n = 0, offset = 0; do { diff --git a/test/gtest-extra.h b/test/gtest-extra.h index 198d9b1e..db0323d2 100644 --- a/test/gtest-extra.h +++ b/test/gtest-extra.h @@ -74,8 +74,8 @@ std::string format_system_error(int error_code, fmt::string_view message); class OutputRedirect { private: FILE *file_; - fmt::File original_; // Original file passed to redirector. - fmt::File read_end_; // Read end of the pipe where the output is redirected. + fmt::file original_; // Original file passed to redirector. + fmt::file read_end_; // Read end of the pipe where the output is redirected. GTEST_DISALLOW_COPY_AND_ASSIGN_(OutputRedirect); @@ -145,7 +145,7 @@ class SuppressAssert { EXPECT_SYSTEM_ERROR(SUPPRESS_ASSERT(statement), error_code, message) // Attempts to read count characters from a file. -std::string read(fmt::File &f, std::size_t count); +std::string read(fmt::file &f, std::size_t count); #define EXPECT_READ(file, expected_content) \ EXPECT_EQ(expected_content, read(file, std::strlen(expected_content))) diff --git a/test/ostream-test.cc b/test/ostream-test.cc index bdb81651..ffc2f8b2 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -158,3 +158,8 @@ TEST(OStreamTest, WriteToOStreamMaxSize) { } while (size != 0); fmt::internal::write(os, buffer); } + +TEST(OStreamTest, Join) { + int v[3] = {1, 2, 3}; + EXPECT_EQ("1, 2, 3", fmt::format("{}", fmt::join(v, v + 3, ", "))); +} diff --git a/test/posix-mock-test.cc b/test/posix-mock-test.cc index b724a6ac..f69313c3 100644 --- a/test/posix-mock-test.cc +++ b/test/posix-mock-test.cc @@ -25,9 +25,9 @@ #include "gtest-extra.h" #include "util.h" -using fmt::BufferedFile; -using fmt::ErrorCode; -using fmt::File; +using fmt::buffered_file; +using fmt::error_code; +using fmt::file; using testing::internal::scoped_ptr; using testing::_; @@ -194,7 +194,7 @@ int (test::fileno)(FILE *stream) { #endif void write_file(fmt::cstring_view filename, fmt::string_view content) { - fmt::BufferedFile f(filename, "w"); + fmt::buffered_file f(filename, "w"); f.print("{}", content); } @@ -214,8 +214,8 @@ TEST(UtilTest, GetPageSize) { TEST(FileTest, OpenRetry) { write_file("test", "there must be something here"); - scoped_ptr f; - EXPECT_RETRY(f.reset(new File("test", File::RDONLY)), + scoped_ptr f; + EXPECT_RETRY(f.reset(new file("test", file::RDONLY)), open, "cannot open file test"); #ifndef _WIN32 char c = 0; @@ -224,9 +224,9 @@ TEST(FileTest, OpenRetry) { } TEST(FileTest, CloseNoRetryInDtor) { - File read_end, write_end; - File::pipe(read_end, write_end); - scoped_ptr f(new File(std::move(read_end))); + file read_end, write_end; + file::pipe(read_end, write_end); + scoped_ptr f(new file(std::move(read_end))); int saved_close_count = 0; EXPECT_WRITE(stderr, { close_count = 1; @@ -238,8 +238,8 @@ TEST(FileTest, CloseNoRetryInDtor) { } TEST(FileTest, CloseNoRetry) { - File read_end, write_end; - File::pipe(read_end, write_end); + file read_end, write_end; + file::pipe(read_end, write_end); close_count = 1; EXPECT_SYSTEM_ERROR(read_end.close(), EINTR, "cannot close file"); EXPECT_EQ(2, close_count); @@ -249,7 +249,7 @@ TEST(FileTest, CloseNoRetry) { TEST(FileTest, Size) { std::string content = "top secret, destroy before reading"; write_file("test", content); - File f("test", File::RDONLY); + file f("test", file::RDONLY); EXPECT_GE(f.size(), 0); EXPECT_EQ(content.size(), static_cast(f.size())); #ifdef _WIN32 @@ -267,7 +267,7 @@ TEST(FileTest, Size) { TEST(FileTest, MaxSize) { write_file("test", ""); - File f("test", File::RDONLY); + file f("test", file::RDONLY); fstat_sim = MAX_SIZE; EXPECT_GE(f.size(), 0); EXPECT_EQ(max_file_size(), f.size()); @@ -275,8 +275,8 @@ TEST(FileTest, MaxSize) { } TEST(FileTest, ReadRetry) { - File read_end, write_end; - File::pipe(read_end, write_end); + file read_end, write_end; + file::pipe(read_end, write_end); enum { SIZE = 4 }; write_end.write("test", SIZE); write_end.close(); @@ -288,8 +288,8 @@ TEST(FileTest, ReadRetry) { } TEST(FileTest, WriteRetry) { - File read_end, write_end; - File::pipe(read_end, write_end); + file read_end, write_end; + file::pipe(read_end, write_end); enum { SIZE = 4 }; std::size_t count = 0; EXPECT_RETRY(count = write_end.write("test", SIZE), @@ -306,8 +306,8 @@ TEST(FileTest, WriteRetry) { #ifdef _WIN32 TEST(FileTest, ConvertReadCount) { - File read_end, write_end; - File::pipe(read_end, write_end); + file read_end, write_end; + file::pipe(read_end, write_end); char c; std::size_t size = UINT_MAX; if (sizeof(unsigned) != sizeof(std::size_t)) @@ -320,8 +320,8 @@ TEST(FileTest, ConvertReadCount) { } TEST(FileTest, ConvertWriteCount) { - File read_end, write_end; - File::pipe(read_end, write_end); + file read_end, write_end; + file::pipe(read_end, write_end); char c; std::size_t size = UINT_MAX; if (sizeof(unsigned) != sizeof(std::size_t)) @@ -337,14 +337,14 @@ TEST(FileTest, ConvertWriteCount) { TEST(FileTest, DupNoRetry) { int stdout_fd = FMT_POSIX(fileno(stdout)); dup_count = 1; - EXPECT_SYSTEM_ERROR(File::dup(stdout_fd), EINTR, + EXPECT_SYSTEM_ERROR(file::dup(stdout_fd), EINTR, fmt::format("cannot duplicate file descriptor {}", stdout_fd)); dup_count = 0; } TEST(FileTest, Dup2Retry) { int stdout_fd = FMT_POSIX(fileno(stdout)); - File f1 = File::dup(stdout_fd), f2 = File::dup(stdout_fd); + file f1 = file::dup(stdout_fd), f2 = file::dup(stdout_fd); EXPECT_RETRY(f1.dup2(f2.descriptor()), dup2, fmt::format("cannot duplicate file descriptor {} to {}", f1.descriptor(), f2.descriptor())); @@ -352,8 +352,8 @@ TEST(FileTest, Dup2Retry) { TEST(FileTest, Dup2NoExceptRetry) { int stdout_fd = FMT_POSIX(fileno(stdout)); - File f1 = File::dup(stdout_fd), f2 = File::dup(stdout_fd); - ErrorCode ec; + file f1 = file::dup(stdout_fd), f2 = file::dup(stdout_fd); + error_code ec; dup2_count = 1; f1.dup2(f2.descriptor(), ec); #ifndef _WIN32 @@ -365,16 +365,16 @@ TEST(FileTest, Dup2NoExceptRetry) { } TEST(FileTest, PipeNoRetry) { - File read_end, write_end; + file read_end, write_end; pipe_count = 1; EXPECT_SYSTEM_ERROR( - File::pipe(read_end, write_end), EINTR, "cannot create pipe"); + file::pipe(read_end, write_end), EINTR, "cannot create pipe"); pipe_count = 0; } TEST(FileTest, FdopenNoRetry) { - File read_end, write_end; - File::pipe(read_end, write_end); + file read_end, write_end; + file::pipe(read_end, write_end); fdopen_count = 1; EXPECT_SYSTEM_ERROR(read_end.fdopen("r"), EINTR, "cannot associate stream with file descriptor"); @@ -383,8 +383,8 @@ TEST(FileTest, FdopenNoRetry) { TEST(BufferedFileTest, OpenRetry) { write_file("test", "there must be something here"); - scoped_ptr f; - EXPECT_RETRY(f.reset(new BufferedFile("test", "r")), + scoped_ptr f; + EXPECT_RETRY(f.reset(new buffered_file("test", "r")), fopen, "cannot open file test"); #ifndef _WIN32 char c = 0; @@ -394,9 +394,9 @@ TEST(BufferedFileTest, OpenRetry) { } TEST(BufferedFileTest, CloseNoRetryInDtor) { - File read_end, write_end; - File::pipe(read_end, write_end); - scoped_ptr f(new BufferedFile(read_end.fdopen("r"))); + file read_end, write_end; + file::pipe(read_end, write_end); + scoped_ptr f(new buffered_file(read_end.fdopen("r"))); int saved_fclose_count = 0; EXPECT_WRITE(stderr, { fclose_count = 1; @@ -408,9 +408,9 @@ TEST(BufferedFileTest, CloseNoRetryInDtor) { } TEST(BufferedFileTest, CloseNoRetry) { - File read_end, write_end; - File::pipe(read_end, write_end); - BufferedFile f = read_end.fdopen("r"); + file read_end, write_end; + file::pipe(read_end, write_end); + buffered_file f = read_end.fdopen("r"); fclose_count = 1; EXPECT_SYSTEM_ERROR(f.close(), EINTR, "cannot close file"); EXPECT_EQ(2, fclose_count); @@ -418,9 +418,9 @@ TEST(BufferedFileTest, CloseNoRetry) { } TEST(BufferedFileTest, FilenoNoRetry) { - File read_end, write_end; - File::pipe(read_end, write_end); - BufferedFile f = read_end.fdopen("r"); + file read_end, write_end; + file::pipe(read_end, write_end); + buffered_file f = read_end.fdopen("r"); fileno_count = 1; EXPECT_SYSTEM_ERROR((f.fileno)(), EINTR, "cannot get file descriptor"); EXPECT_EQ(2, fileno_count); diff --git a/test/posix-test.cc b/test/posix-test.cc index 6e0d08c6..6f65ec38 100644 --- a/test/posix-test.cc +++ b/test/posix-test.cc @@ -16,9 +16,9 @@ # undef fileno #endif -using fmt::BufferedFile; -using fmt::ErrorCode; -using fmt::File; +using fmt::buffered_file; +using fmt::error_code; +using fmt::file; using testing::internal::scoped_ptr; @@ -36,16 +36,16 @@ bool isclosed(int fd) { } // Opens a file for reading. -File open_file() { - File read_end, write_end; - File::pipe(read_end, write_end); +file open_file() { + file read_end, write_end; + file::pipe(read_end, write_end); write_end.write(FILE_CONTENT, std::strlen(FILE_CONTENT)); write_end.close(); return read_end; } // Attempts to write a string to a file. -void write(File &f, fmt::string_view s) { +void write(file &f, fmt::string_view s) { std::size_t num_chars_left = s.size(); const char *ptr = s.data(); do { @@ -58,32 +58,32 @@ void write(File &f, fmt::string_view s) { } TEST(BufferedFileTest, DefaultCtor) { - BufferedFile f; + buffered_file f; EXPECT_TRUE(f.get() == 0); } TEST(BufferedFileTest, MoveCtor) { - BufferedFile bf = open_buffered_file(); + buffered_file bf = open_buffered_file(); FILE *fp = bf.get(); EXPECT_TRUE(fp != 0); - BufferedFile bf2(std::move(bf)); + buffered_file bf2(std::move(bf)); EXPECT_EQ(fp, bf2.get()); EXPECT_TRUE(bf.get() == 0); } TEST(BufferedFileTest, MoveAssignment) { - BufferedFile bf = open_buffered_file(); + buffered_file bf = open_buffered_file(); FILE *fp = bf.get(); EXPECT_TRUE(fp != 0); - BufferedFile bf2; + buffered_file bf2; bf2 = std::move(bf); EXPECT_EQ(fp, bf2.get()); EXPECT_TRUE(bf.get() == 0); } TEST(BufferedFileTest, MoveAssignmentClosesFile) { - BufferedFile bf = open_buffered_file(); - BufferedFile bf2 = open_buffered_file(); + buffered_file bf = open_buffered_file(); + buffered_file bf2 = open_buffered_file(); int old_fd = bf2.fileno(); bf2 = std::move(bf); EXPECT_TRUE(isclosed(old_fd)); @@ -91,19 +91,19 @@ TEST(BufferedFileTest, MoveAssignmentClosesFile) { TEST(BufferedFileTest, MoveFromTemporaryInCtor) { FILE *fp = 0; - BufferedFile f(open_buffered_file(&fp)); + buffered_file f(open_buffered_file(&fp)); EXPECT_EQ(fp, f.get()); } TEST(BufferedFileTest, MoveFromTemporaryInAssignment) { FILE *fp = 0; - BufferedFile f; + buffered_file f; f = open_buffered_file(&fp); EXPECT_EQ(fp, f.get()); } TEST(BufferedFileTest, MoveFromTemporaryInAssignmentClosesFile) { - BufferedFile f = open_buffered_file(); + buffered_file f = open_buffered_file(); int old_fd = f.fileno(); f = open_buffered_file(); EXPECT_TRUE(isclosed(old_fd)); @@ -112,14 +112,14 @@ TEST(BufferedFileTest, MoveFromTemporaryInAssignmentClosesFile) { TEST(BufferedFileTest, CloseFileInDtor) { int fd = 0; { - BufferedFile f = open_buffered_file(); + buffered_file f = open_buffered_file(); fd = f.fileno(); } EXPECT_TRUE(isclosed(fd)); } TEST(BufferedFileTest, CloseErrorInDtor) { - scoped_ptr f(new BufferedFile(open_buffered_file())); + scoped_ptr f(new buffered_file(open_buffered_file())); EXPECT_WRITE(stderr, { // The close function must be called inside EXPECT_WRITE, otherwise // the system may recycle closed file descriptor when redirecting the @@ -131,7 +131,7 @@ TEST(BufferedFileTest, CloseErrorInDtor) { } TEST(BufferedFileTest, Close) { - BufferedFile f = open_buffered_file(); + buffered_file f = open_buffered_file(); int fd = f.fileno(); f.close(); EXPECT_TRUE(f.get() == 0); @@ -139,14 +139,14 @@ TEST(BufferedFileTest, Close) { } TEST(BufferedFileTest, CloseError) { - BufferedFile f = open_buffered_file(); + buffered_file f = open_buffered_file(); FMT_POSIX(close(f.fileno())); EXPECT_SYSTEM_ERROR_NOASSERT(f.close(), EBADF, "cannot close file"); EXPECT_TRUE(f.get() == 0); } TEST(BufferedFileTest, Fileno) { - BufferedFile f; + buffered_file f; #ifndef __COVERITY__ // fileno on a null FILE pointer either crashes or returns an error. // Disable Coverity because this is intentional. @@ -160,12 +160,12 @@ TEST(BufferedFileTest, Fileno) { #endif f = open_buffered_file(); EXPECT_TRUE(f.fileno() != -1); - File copy = File::dup(f.fileno()); + file copy = file::dup(f.fileno()); EXPECT_READ(copy, FILE_CONTENT); } TEST(FileTest, DefaultCtor) { - File f; + file f; EXPECT_EQ(-1, f.descriptor()); } @@ -173,64 +173,64 @@ TEST(FileTest, OpenBufferedFileInCtor) { FILE *fp = safe_fopen("test-file", "w"); std::fputs(FILE_CONTENT, fp); std::fclose(fp); - File f("test-file", File::RDONLY); + file f("test-file", file::RDONLY); ASSERT_TRUE(isopen(f.descriptor())); } TEST(FileTest, OpenBufferedFileError) { - EXPECT_SYSTEM_ERROR(File("nonexistent", File::RDONLY), + EXPECT_SYSTEM_ERROR(file("nonexistent", file::RDONLY), ENOENT, "cannot open file nonexistent"); } TEST(FileTest, MoveCtor) { - File f = open_file(); + file f = open_file(); int fd = f.descriptor(); EXPECT_NE(-1, fd); - File f2(std::move(f)); + file f2(std::move(f)); EXPECT_EQ(fd, f2.descriptor()); EXPECT_EQ(-1, f.descriptor()); } TEST(FileTest, MoveAssignment) { - File f = open_file(); + file f = open_file(); int fd = f.descriptor(); EXPECT_NE(-1, fd); - File f2; + file f2; f2 = std::move(f); EXPECT_EQ(fd, f2.descriptor()); EXPECT_EQ(-1, f.descriptor()); } TEST(FileTest, MoveAssignmentClosesFile) { - File f = open_file(); - File f2 = open_file(); + file f = open_file(); + file f2 = open_file(); int old_fd = f2.descriptor(); f2 = std::move(f); EXPECT_TRUE(isclosed(old_fd)); } -File OpenBufferedFile(int &fd) { - File f = open_file(); +file OpenBufferedFile(int &fd) { + file f = open_file(); fd = f.descriptor(); return f; } TEST(FileTest, MoveFromTemporaryInCtor) { int fd = 0xdead; - File f(OpenBufferedFile(fd)); + file f(OpenBufferedFile(fd)); EXPECT_EQ(fd, f.descriptor()); } TEST(FileTest, MoveFromTemporaryInAssignment) { int fd = 0xdead; - File f; + file f; f = OpenBufferedFile(fd); EXPECT_EQ(fd, f.descriptor()); } TEST(FileTest, MoveFromTemporaryInAssignmentClosesFile) { int fd = 0xdead; - File f = open_file(); + file f = open_file(); int old_fd = f.descriptor(); f = OpenBufferedFile(fd); EXPECT_TRUE(isclosed(old_fd)); @@ -239,14 +239,14 @@ TEST(FileTest, MoveFromTemporaryInAssignmentClosesFile) { TEST(FileTest, CloseFileInDtor) { int fd = 0; { - File f = open_file(); + file f = open_file(); fd = f.descriptor(); } EXPECT_TRUE(isclosed(fd)); } TEST(FileTest, CloseErrorInDtor) { - scoped_ptr f(new File(open_file())); + scoped_ptr f(new file(open_file())); EXPECT_WRITE(stderr, { // The close function must be called inside EXPECT_WRITE, otherwise // the system may recycle closed file descriptor when redirecting the @@ -258,7 +258,7 @@ TEST(FileTest, CloseErrorInDtor) { } TEST(FileTest, Close) { - File f = open_file(); + file f = open_file(); int fd = f.descriptor(); f.close(); EXPECT_EQ(-1, f.descriptor()); @@ -266,19 +266,19 @@ TEST(FileTest, Close) { } TEST(FileTest, CloseError) { - File f = open_file(); + file f = open_file(); FMT_POSIX(close(f.descriptor())); EXPECT_SYSTEM_ERROR_NOASSERT(f.close(), EBADF, "cannot close file"); EXPECT_EQ(-1, f.descriptor()); } TEST(FileTest, Read) { - File f = open_file(); + file f = open_file(); EXPECT_READ(f, FILE_CONTENT); } TEST(FileTest, ReadError) { - File f("test-file", File::WRONLY); + file f("test-file", file::WRONLY); char buf; // We intentionally read from a file opened in the write-only mode to // cause error. @@ -286,23 +286,23 @@ TEST(FileTest, ReadError) { } TEST(FileTest, Write) { - File read_end, write_end; - File::pipe(read_end, write_end); + file read_end, write_end; + file::pipe(read_end, write_end); write(write_end, "test"); write_end.close(); EXPECT_READ(read_end, "test"); } TEST(FileTest, WriteError) { - File f("test-file", File::RDONLY); + file f("test-file", file::RDONLY); // We intentionally write to a file opened in the read-only mode to // cause error. EXPECT_SYSTEM_ERROR(f.write(" ", 1), EBADF, "cannot write to file"); } TEST(FileTest, Dup) { - File f = open_file(); - File copy = File::dup(f.descriptor()); + file f = open_file(); + file copy = file::dup(f.descriptor()); EXPECT_NE(f.descriptor(), copy.descriptor()); EXPECT_EQ(FILE_CONTENT, read(copy, std::strlen(FILE_CONTENT))); } @@ -310,29 +310,29 @@ TEST(FileTest, Dup) { #ifndef __COVERITY__ TEST(FileTest, DupError) { int value = -1; - EXPECT_SYSTEM_ERROR_NOASSERT(File::dup(value), + EXPECT_SYSTEM_ERROR_NOASSERT(file::dup(value), EBADF, "cannot duplicate file descriptor -1"); } #endif TEST(FileTest, Dup2) { - File f = open_file(); - File copy = open_file(); + file f = open_file(); + file copy = open_file(); f.dup2(copy.descriptor()); EXPECT_NE(f.descriptor(), copy.descriptor()); EXPECT_READ(copy, FILE_CONTENT); } TEST(FileTest, Dup2Error) { - File f = open_file(); + file f = open_file(); EXPECT_SYSTEM_ERROR_NOASSERT(f.dup2(-1), EBADF, fmt::format("cannot duplicate file descriptor {} to -1", f.descriptor())); } TEST(FileTest, Dup2NoExcept) { - File f = open_file(); - File copy = open_file(); - ErrorCode ec; + file f = open_file(); + file copy = open_file(); + error_code ec; f.dup2(copy.descriptor(), ec); EXPECT_EQ(0, ec.get()); EXPECT_NE(f.descriptor(), copy.descriptor()); @@ -340,15 +340,15 @@ TEST(FileTest, Dup2NoExcept) { } TEST(FileTest, Dup2NoExceptError) { - File f = open_file(); - ErrorCode ec; + file f = open_file(); + error_code ec; SUPPRESS_ASSERT(f.dup2(-1, ec)); EXPECT_EQ(EBADF, ec.get()); } TEST(FileTest, Pipe) { - File read_end, write_end; - File::pipe(read_end, write_end); + file read_end, write_end; + file::pipe(read_end, write_end); EXPECT_NE(-1, read_end.descriptor()); EXPECT_NE(-1, write_end.descriptor()); write(write_end, "test"); @@ -356,14 +356,14 @@ TEST(FileTest, Pipe) { } TEST(FileTest, Fdopen) { - File read_end, write_end; - File::pipe(read_end, write_end); + file read_end, write_end; + file::pipe(read_end, write_end); int read_fd = read_end.descriptor(); EXPECT_EQ(read_fd, FMT_POSIX(fileno(read_end.fdopen("r").get()))); } TEST(FileTest, FdopenError) { - File f; + file f; EXPECT_SYSTEM_ERROR_NOASSERT( f.fdopen("r"), EBADF, "cannot associate stream with file descriptor"); } diff --git a/test/printf-test.cc b/test/printf-test.cc index 3f877898..c15a3201 100644 --- a/test/printf-test.cc +++ b/test/printf-test.cc @@ -478,8 +478,8 @@ TEST(PrintfTest, Examples) { } TEST(PrintfTest, PrintfError) { - fmt::File read_end, write_end; - fmt::File::pipe(read_end, write_end); + fmt::file read_end, write_end; + fmt::file::pipe(read_end, write_end); int result = fmt::fprintf(read_end.fdopen("r").get(), "test"); EXPECT_LT(result, 0); } diff --git a/test/ranges-test.cc b/test/ranges-test.cc index 76c37a11..c27833f2 100644 --- a/test/ranges-test.cc +++ b/test/ranges-test.cc @@ -30,6 +30,7 @@ TEST(RangesTest, FormatVector2) { EXPECT_EQ("{{1, 2}, {3, 5}, {7, 11}}", ivf); } +#if FMT_USE_INTEGER_SEQUENCE TEST(RangesTest, FormatMap) { std::map simap{{"one", 1}, {"two", 2}}; EXPECT_EQ("{(one, 1), (two, 2)}", fmt::format("{}", simap)); @@ -46,7 +47,7 @@ TEST(RangesTest, FormatTuple) { EXPECT_EQ("(42, 3.14159, this is tuple)", fmt::format("{}", tu1)); } -/// check if 'if constexpr' is supported. +/// Check if 'if constexpr' is supported. #if (__cplusplus > 201402L) || \ (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910) @@ -86,3 +87,4 @@ TEST(RangesTest, FormatStruct) { #endif // (__cplusplus > 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG > // 201402L && _MSC_VER >= 1910) +#endif // FMT_USE_INTEGER_SEQUENCE diff --git a/test/util-test.cc b/test/util-test.cc index b22aa0ed..d0fdefec 100644 --- a/test/util-test.cc +++ b/test/util-test.cc @@ -17,7 +17,6 @@ # include #endif -#include "fmt/locale.h" #include "gmock/gmock.h" #include "gtest-extra.h" #include "mock-allocator.h" @@ -397,13 +396,14 @@ TEST(FixedBufferTest, BufferOverflow) { EXPECT_THROW_MSG(buffer.resize(11), std::runtime_error, "buffer overflow"); } +struct uint32_pair { + uint32_t u[2]; +}; + TEST(UtilTest, BitCast) { - struct S { - uint32_t u[2]; - }; - auto s = fmt::internal::bit_cast(uint64_t(42)); + auto s = fmt::internal::bit_cast(uint64_t{42}); EXPECT_EQ(fmt::internal::bit_cast(s), 42ull); - s = fmt::internal::bit_cast(uint64_t(~0ull)); + s = fmt::internal::bit_cast(uint64_t(~0ull)); EXPECT_EQ(fmt::internal::bit_cast(s), ~0ull); } diff --git a/test/util.cc b/test/util.cc index 17837414..12270bcc 100644 --- a/test/util.cc +++ b/test/util.cc @@ -32,12 +32,12 @@ std::string get_system_error(int error_code) { const char *const FILE_CONTENT = "Don't panic!"; -fmt::BufferedFile open_buffered_file(FILE **fp) { - fmt::File read_end, write_end; - fmt::File::pipe(read_end, write_end); +fmt::buffered_file open_buffered_file(FILE **fp) { + fmt::file read_end, write_end; + fmt::file::pipe(read_end, write_end); write_end.write(FILE_CONTENT, std::strlen(FILE_CONTENT)); write_end.close(); - fmt::BufferedFile f = read_end.fdopen("r"); + fmt::buffered_file f = read_end.fdopen("r"); if (fp) *fp = f.get(); return f; diff --git a/test/util.h b/test/util.h index 16aae737..a4440bb0 100644 --- a/test/util.h +++ b/test/util.h @@ -35,7 +35,7 @@ std::string get_system_error(int error_code); extern const char *const FILE_CONTENT; // Opens a buffered file for reading. -fmt::BufferedFile open_buffered_file(FILE **fp = 0); +fmt::buffered_file open_buffered_file(FILE **fp = 0); inline FILE *safe_fopen(const char *filename, const char *mode) { #if defined(_WIN32) && !defined(__MINGW32__)