diff --git a/src/common/format.cpp b/src/common/format.cpp index 3f5d808..566a010 100644 --- a/src/common/format.cpp +++ b/src/common/format.cpp @@ -116,10 +116,37 @@ void ReportError(FormatFunc func, std::fputc('\n', stderr); } catch (...) {} } + +const fmt::internal::ArgInfo DUMMY_ARG = {fmt::internal::ArgInfo::INT, 0}; + +fmt::ULongLong GetIntValue(const fmt::internal::ArgInfo &arg) { + typedef fmt::internal::ArgInfo Arg; + switch (arg.type) { + case Arg::INT: + return arg.int_value; + case Arg::UINT: + return arg.uint_value; + case Arg::LONG_LONG: + return arg.long_long_value; + case Arg::ULONG_LONG: + return arg.ulong_long_value; + default: + return -1; + } +} } // namespace int fmt::internal::SignBitNoInline(double value) { return SignBit(value); } +void fmt::SystemError::init( + int error_code, StringRef format_str, const ArgList &args) { + error_code_ = error_code; + Writer w; + internal::FormatSystemErrorMessage(w, error_code, format(format_str, args)); + std::runtime_error &base = *this; + base = std::runtime_error(w.str()); +} + template <typename T> int fmt::internal::CharTraits<char>::FormatFloat( char *buffer, std::size_t size, const char *format, @@ -178,12 +205,12 @@ const uint64_t fmt::internal::POWERS_OF_10_64[] = { void fmt::internal::ReportUnknownType(char code, const char *type) { if (std::isprint(static_cast<unsigned char>(code))) { - throw fmt::FormatError(fmt::str( - fmt::Format("unknown format code '{}' for {}") << code << type)); + throw fmt::FormatError( + fmt::format("unknown format code '{}' for {}", code, type)); } throw fmt::FormatError( - fmt::str(fmt::Format("unknown format code '\\x{:02x}' for {}") - << static_cast<unsigned>(code) << type)); + fmt::format("unknown format code '\\x{:02x}' for {}", + static_cast<unsigned>(code), type)); } #ifdef _WIN32 @@ -193,17 +220,17 @@ fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) { CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0); static const char ERROR[] = "cannot convert string from UTF-8 to UTF-16"; if (length == 0) - ThrowWinError(GetLastError(), ERROR); + throw WindowsError(GetLastError(), ERROR); buffer_.resize(length); length = MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length); if (length == 0) - ThrowWinError(GetLastError(), ERROR); + throw WindowsError(GetLastError(), ERROR); } fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) { if (int error_code = Convert(s)) { - ThrowWinError(GetLastError(), + throw WindowsError(GetLastError(), "cannot convert string from UTF-16 to UTF-8"); } } @@ -220,6 +247,15 @@ int fmt::internal::UTF16ToUTF8::Convert(fmt::WStringRef s) { return 0; } +void fmt::WindowsError::init( + int error_code, StringRef format_str, const ArgList &args) { + error_code_ = error_code; + Writer w; + internal::FormatWinErrorMessage(w, error_code, format(format_str, args)); + std::runtime_error &base = *this; + base = std::runtime_error(w.str()); +} + #endif int fmt::internal::StrError( @@ -289,7 +325,7 @@ void fmt::internal::FormatWinErrorMessage( reinterpret_cast<LPWSTR>(system_message.ptr()), 0, 0)) { UTF16ToUTF8 utf8_message; if (!utf8_message.Convert(system_message.c_str())) { - out << message << ": " << c_str(utf8_message); + out << message << ": " << utf8_message; return; } } @@ -332,10 +368,6 @@ int fmt::internal::ParseNonnegativeInt( return value; } -template <typename Char> -const typename fmt::internal::ArgInfo - fmt::BasicWriter<Char>::DUMMY_ARG = {fmt::internal::ArgInfo::INT, 0}; - // Fills the padding around the content and returns the pointer to the // content area. template <typename Char> @@ -397,7 +429,7 @@ void fmt::BasicWriter<Char>::FormatDouble(T value, const FormatSpec &spec) { --size; ++nan; } - CharPtr out = FormatString(nan, size, spec); + CharPtr out = write_str(nan, size, spec); if (sign) *out = sign; return; @@ -412,7 +444,7 @@ void fmt::BasicWriter<Char>::FormatDouble(T value, const FormatSpec &spec) { --size; ++inf; } - CharPtr out = FormatString(inf, size, spec); + CharPtr out = write_str(inf, size, spec); if (sign) *out = sign; return; @@ -502,26 +534,10 @@ void fmt::BasicWriter<Char>::FormatDouble(T value, const FormatSpec &spec) { } } -template <typename Char> -fmt::ULongLong fmt::BasicWriter<Char>::GetIntValue(const Arg &arg) { - switch (arg.type) { - case Arg::INT: - return arg.int_value; - case Arg::UINT: - return arg.uint_value; - case Arg::LONG_LONG: - return arg.long_long_value; - case Arg::ULONG_LONG: - return arg.ulong_long_value; - default: - return -1; - } -} - template <typename Char> template <typename StringChar> -void fmt::BasicWriter<Char>::FormatString( - const Arg::StringValue<StringChar> &str, const FormatSpec &spec) { +void fmt::BasicWriter<Char>::write_str( + const internal::StringValue<StringChar> &str, const FormatSpec &spec) { if (spec.type_ && spec.type_ != 's') internal::ReportUnknownType(spec.type_, "string"); const StringChar *s = str.value; @@ -532,7 +548,7 @@ void fmt::BasicWriter<Char>::FormatString( if (*s) size = std::char_traits<StringChar>::length(s); } - FormatString(s, size, spec); + write_str(s, size, spec); } template <typename Char> @@ -569,17 +585,17 @@ void fmt::BasicWriter<Char>::FormatParser::CheckSign( char sign = static_cast<char>(*s); if (arg.type > Arg::LAST_NUMERIC_TYPE) { report_error_(s, - fmt::Format("format specifier '{}' requires numeric argument") << sign); + fmt::format("format specifier '{}' requires numeric argument", sign).c_str()); } if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) { report_error_(s, - fmt::Format("format specifier '{}' requires signed argument") << sign); + fmt::format("format specifier '{}' requires signed argument", sign).c_str()); } ++s; } template <typename Char> -void fmt::BasicWriter<Char>::PrintfParser::ParseFlags( +void fmt::internal::PrintfParser<Char>::ParseFlags( FormatSpec &spec, const Char *&s) { for (;;) { switch (*s++) { @@ -606,7 +622,7 @@ void fmt::BasicWriter<Char>::PrintfParser::ParseFlags( } template <typename Char> -unsigned fmt::BasicWriter<Char>::PrintfParser::ParseHeader( +unsigned fmt::internal::PrintfParser<Char>::ParseHeader( const Char *&s, FormatSpec &spec, const char *&error) { unsigned arg_index = UINT_MAX; Char c = *s; @@ -672,8 +688,8 @@ unsigned fmt::BasicWriter<Char>::PrintfParser::ParseHeader( // TODO: move to a base class that doesn't depend on template argument template <typename Char> -const typename fmt::BasicWriter<Char>::Arg - &fmt::BasicWriter<Char>::PrintfParser::HandleArgIndex( +const fmt::internal::ArgInfo + &fmt::internal::PrintfParser<Char>::HandleArgIndex( unsigned arg_index, const char *&error) { if (arg_index != UINT_MAX) { if (next_arg_index_ <= 0) { @@ -695,7 +711,7 @@ const typename fmt::BasicWriter<Char>::Arg } template <typename Char> -void fmt::BasicWriter<Char>::PrintfParser::Format( +void fmt::internal::PrintfParser<Char>::Format( BasicWriter<Char> &writer, BasicStringRef<Char> format, const ArgList &args) { const Char *start = format.c_str(); @@ -739,7 +755,7 @@ void fmt::BasicWriter<Char>::PrintfParser::Format( ++s; const Arg &arg = HandleArgIndex(UINT_MAX, error); if (arg.type <= Arg::LAST_INTEGER_TYPE) - spec.precision_ = GetIntValue(arg); + spec.precision_ = static_cast<int>(GetIntValue(arg)); // TODO: check for overflow else if (!error) error = "precision is not integer"; } @@ -821,10 +837,10 @@ void fmt::BasicWriter<Char>::PrintfParser::Format( break; } case Arg::STRING: - writer.FormatString(arg.string, spec); + writer.write_str(arg.string, spec); break; case Arg::WSTRING: - writer.FormatString(arg.wstring, spec); + writer.write_str(internal::CharTraits<Char>::convert(arg.wstring), spec); break; case Arg::POINTER: if (spec.type_ && spec.type_ != 'p') @@ -1045,10 +1061,10 @@ void fmt::BasicWriter<Char>::FormatParser::Format( break; } case Arg::STRING: - writer.FormatString(arg.string, spec); + writer.write_str(arg.string, spec); break; case Arg::WSTRING: - writer.FormatString(arg.wstring, spec); + writer.write_str(internal::CharTraits<Char>::convert(arg.wstring), spec); break; case Arg::POINTER: if (spec.type_ && spec.type_ != 'p') @@ -1070,12 +1086,6 @@ void fmt::BasicWriter<Char>::FormatParser::Format( writer.buffer_.append(start, s); } -void fmt::SystemErrorSink::operator()(const fmt::Writer &w) const { - Writer message; - internal::FormatSystemErrorMessage(message, error_code_, w.c_str()); - throw SystemError(message.c_str(), error_code_); -} - void fmt::ReportSystemError( int error_code, fmt::StringRef message) FMT_NOEXCEPT(true) { // FIXME: FormatSystemErrorMessage may throw @@ -1084,9 +1094,7 @@ void fmt::ReportSystemError( #ifdef _WIN32 void fmt::WinErrorSink::operator()(const Writer &w) const { - Writer message; - internal::FormatWinErrorMessage(message, error_code_, w.c_str()); - throw SystemError(message.c_str(), error_code_); + throw WindowsError(error_code_, w.c_str()); } void fmt::ReportWinError( @@ -1105,6 +1113,24 @@ void fmt::ANSITerminalSink::operator()( std::fputs(RESET_COLOR, file_); } +void fmt::print(StringRef format, const ArgList &args) { + Writer w; + w.write(format, args); + std::fwrite(w.data(), 1, w.size(), stdout); +} + +void fmt::print(std::FILE *f, StringRef format, const ArgList &args) { + Writer w; + w.write(format, args); + std::fwrite(w.data(), 1, w.size(), f); +} + +void fmt::printf(StringRef format, const ArgList &args) { + Writer w; + printf(w, format, args); + std::fwrite(w.data(), 1, w.size(), stdout); +} + // Explicit instantiations for char. template fmt::BasicWriter<char>::CharPtr @@ -1114,7 +1140,7 @@ template fmt::BasicWriter<char>::CharPtr template void fmt::BasicWriter<char>::FormatParser::Format( BasicWriter<char> &writer, BasicStringRef<char> format, const ArgList &args); -template void fmt::BasicWriter<char>::PrintfParser::Format( +template void fmt::internal::PrintfParser<char>::Format( BasicWriter<char> &writer, BasicStringRef<char> format, const ArgList &args); // Explicit instantiations for wchar_t. @@ -1127,7 +1153,7 @@ template void fmt::BasicWriter<wchar_t>::FormatParser::Format( BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format, const ArgList &args); -template void fmt::BasicWriter<wchar_t>::PrintfParser::Format( +template void fmt::internal::PrintfParser<wchar_t>::Format( BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format, const ArgList &args); diff --git a/src/common/format.h b/src/common/format.h index 9e6eae8..c418258 100644 --- a/src/common/format.h +++ b/src/common/format.h @@ -119,6 +119,16 @@ TypeName(const TypeName&); \ void operator=(const TypeName&) +#ifdef FMT_DEPRECATED +// Do nothing. +#elif defined(__GNUC__) +# define FMT_DEPRECATED(func) func __attribute__((deprecated)) +#elif defined(_MSC_VER) +# define FMT_DEPRECATED(func) __declspec(deprecated) func +#else +# define FMT_DEPRECATED(func) func +#endif + #if FMT_MSC_VER # pragma warning(push) # pragma warning(disable: 4521) // 'class' : multiple copy constructors specified @@ -131,6 +141,10 @@ namespace fmt { FMT_GCC_EXTENSION typedef long long LongLong; FMT_GCC_EXTENSION typedef unsigned long long ULongLong; +#if FMT_USE_RVALUE_REFERENCES +using std::move; +#endif + template <typename Char> class BasicWriter; @@ -144,15 +158,27 @@ struct FormatSpec; /** \rst - A string reference. It can be constructed from a C string, ``std::string`` - or as a result of a formatting operation. It is most useful as a parameter - type to allow passing different types of strings in a function, for example:: + A string reference. It can be constructed from a C string or + ``std::string``. + + You can use one of the following typedefs for common character types: - Formatter<> Format(StringRef format); + +------------+-------------------------+ + | Type | Definition | + +============+=========================+ + | StringRef | BasicStringRef<char> | + +------------+-------------------------+ + | WStringRef | BasicStringRef<wchar_t> | + +------------+-------------------------+ - Format("{}") << 42; - Format(std::string("{}")) << 42; - Format(Format("{{}}")) << 42; + This class is most useful as a parameter type to allow passing + different types of strings to a function, for example:: + + template<typename... Args> + Writer format(StringRef format, const Args & ... args); + + format("{}", 42); + format(std::string("{}"), 42); \endrst */ template <typename Char> @@ -242,8 +268,14 @@ class Array { if (ptr_ != data_) delete [] ptr_; } + FMT_DISALLOW_COPY_AND_ASSIGN(Array); + + public: + Array() : size_(0), capacity_(SIZE), ptr_(data_) {} + ~Array() { Free(); } + // Move data from other to this array. - void Move(Array &other) { + void move(Array &other) { size_ = other.size_; capacity_ = other.capacity_; if (other.ptr_ == other.data_) { @@ -257,21 +289,15 @@ class Array { } } - FMT_DISALLOW_COPY_AND_ASSIGN(Array); - - public: - Array() : size_(0), capacity_(SIZE), ptr_(data_) {} - ~Array() { Free(); } - #if FMT_USE_RVALUE_REFERENCES Array(Array &&other) { - Move(other); + move(other); } Array& operator=(Array &&other) { assert(this != &other); Free(); - Move(other); + move(other); return *this; } #endif @@ -329,6 +355,12 @@ void Array<T, SIZE>::append(const T *begin, const T *end) { size_ += num_elements; } +template <typename Char> +struct StringValue { + const Char *value; + std::size_t size; +}; + template <typename Char> class CharTraits; @@ -353,6 +385,11 @@ class CharTraits<char> : public BasicCharTraits<char> { static char ConvertChar(char value) { return value; } + static StringValue<char> convert(StringValue<wchar_t>) { + StringValue<char> s = {"", 0}; + return s; + } + template <typename T> static int FormatFloat(char *buffer, std::size_t size, const char *format, unsigned width, int precision, T value); @@ -366,6 +403,8 @@ class CharTraits<wchar_t> : public BasicCharTraits<wchar_t> { static wchar_t ConvertChar(char value) { return value; } static wchar_t ConvertChar(wchar_t value) { return value; } + static StringValue<wchar_t> convert(StringValue<wchar_t> s) { return s; } + template <typename T> static int FormatFloat(wchar_t *buffer, std::size_t size, const wchar_t *format, unsigned width, int precision, T value); @@ -492,6 +531,7 @@ class UTF8ToUTF16 { explicit UTF8ToUTF16(StringRef s); operator WStringRef() const { return WStringRef(&buffer_[0], size()); } size_t size() const { return buffer_.size() - 1; } + std::wstring str() const { return std::wstring(&buffer_[0], size()); } }; // A converter from UTF-16 to UTF-8. @@ -505,6 +545,7 @@ class UTF16ToUTF8 { explicit UTF16ToUTF8(WStringRef s); operator StringRef() const { return StringRef(&buffer_[0], size()); } size_t size() const { return buffer_.size() - 1; } + std::string str() const { return std::string(&buffer_[0], size()); } // Performs conversion returning a system error code instead of // throwing exception on error. @@ -577,12 +618,6 @@ struct ArgInfo { }; Type type; - template <typename Char> - struct StringValue { - const Char *value; - std::size_t size; - }; - typedef void (*FormatFunc)( void *writer, const void *arg, const FormatSpec &spec); @@ -604,22 +639,171 @@ struct ArgInfo { CustomValue custom; }; }; + +// An argument action that does nothing. +struct NullArgAction { + void operator()() const {} +}; + +// A wrapper around a format argument. +template <typename Char, typename Action = internal::NullArgAction> +class BasicArg : public Action, public internal::ArgInfo { + private: + // This method is private to disallow formatting of arbitrary pointers. + // If you want to output a pointer cast it to const void*. Do not implement! + template <typename T> + BasicArg(const T *value); + + // This method is private to disallow formatting of arbitrary pointers. + // If you want to output a pointer cast it to void*. Do not implement! + template <typename T> + BasicArg(T *value); + + public: + using internal::ArgInfo::type; + + BasicArg() {} + // TODO: unsigned char & signed char + BasicArg(short value) { type = INT; int_value = value; } + BasicArg(unsigned short value) { type = UINT; uint_value = value; } + BasicArg(int value) { type = INT; int_value = value; } + BasicArg(unsigned value) { type = UINT; uint_value = value; } + BasicArg(long value) { + if (sizeof(long) == sizeof(int)) { + type = INT; + int_value = static_cast<int>(value); + } else { + type = LONG_LONG; + long_long_value = value; + } + } + BasicArg(unsigned long value) { + if (sizeof(unsigned long) == sizeof(unsigned)) { + type = UINT; + uint_value = static_cast<unsigned>(value); + } else { + type = ULONG_LONG; + ulong_long_value = value; + } + } + BasicArg(LongLong value) { type = LONG_LONG; long_long_value = value; } + BasicArg(ULongLong value) { type = ULONG_LONG; ulong_long_value = value; } + BasicArg(float value) { type = DOUBLE; double_value = value; } + BasicArg(double value) { type = DOUBLE; double_value = value; } + BasicArg(long double value) { type = LONG_DOUBLE; long_double_value = value; } + BasicArg(char value) { type = CHAR; int_value = value; } + BasicArg(wchar_t value) { + type = CHAR; + int_value = internal::CharTraits<Char>::ConvertChar(value); + } + + BasicArg(const char *value) { + type = STRING; + string.value = value; + string.size = 0; + } + + BasicArg(const wchar_t *value) { + type = WSTRING; + wstring.value = value; + wstring.size = 0; + } + + BasicArg(Char *value) { + type = STRING; + string.value = value; + string.size = 0; + } + + BasicArg(const void *value) { type = POINTER; pointer_value = value; + } + BasicArg(void *value) { type = POINTER; pointer_value = value; } + + BasicArg(const std::basic_string<Char> &value) { + type = STRING; + string.value = value.c_str(); + string.size = value.size(); + } + + BasicArg(BasicStringRef<Char> value) { + type = STRING; + string.value = value.c_str(); + string.size = value.size(); + } + + template <typename T> + BasicArg(const T &value) { + type = CUSTOM; + custom.value = &value; + custom.format = &internal::FormatCustomArg<Char, T>; + } + + // The destructor is declared noexcept(false) because the action may throw + // an exception. + ~BasicArg() FMT_NOEXCEPT(false) { + // Invoke the action. + (*this)(); + } +}; + +template <typename Char, typename T> +inline ArgInfo make_arg(const T &arg) { return BasicArg<Char>(arg); } + +class SystemErrorBase : public std::runtime_error { +public: + SystemErrorBase() : std::runtime_error("") {} +}; } // namespace internal /** - An error returned by an operating system or a language runtime, - for example a file opening error. + An argument list. */ -class SystemError : public std::runtime_error { +class ArgList { private: - int error_code_; + const internal::ArgInfo *args_; + std::size_t size_; + +public: + ArgList() : size_(0) {} + ArgList(const internal::ArgInfo *args, std::size_t size) + : args_(args), size_(size) {} + + /** + Returns the list size (the number of arguments). + */ + std::size_t size() const { return size_; } + + /** + Returns the argument at specified index. + */ + const internal::ArgInfo &operator[](std::size_t index) const { + return args_[index]; + } +}; + +namespace internal { +// Printf format string parser. +template <typename Char> +class PrintfParser { + private: + ArgList args_; + int next_arg_index_; + + typedef ArgInfo Arg; + + void ParseFlags(FormatSpec &spec, const Char *&s); + + // Parses argument index, flags and width and returns the parsed + // argument index. + unsigned ParseHeader(const Char *&s, FormatSpec &spec, const char *&error); + + const ArgInfo &HandleArgIndex(unsigned arg_index, const char *&error); public: - SystemError(StringRef message, int error_code) - : std::runtime_error(message), error_code_(error_code) {} - - int error_code() const { return error_code_; } + void Format(BasicWriter<Char> &writer, + BasicStringRef<Char> format, const ArgList &args); }; +} // namespace internal enum Alignment { ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC @@ -847,51 +1031,140 @@ inline StrFormatSpec<wchar_t> pad( return StrFormatSpec<wchar_t>(str, width, fill); } -class ArgList { - private: - const internal::ArgInfo *args_; - std::size_t size_; +// Generates a comma-separated list with results of applying f to numbers 0..n-1. +# define FMT_GEN(n, f) FMT_GEN##n(f) +# define FMT_GEN1(f) f(0) +# define FMT_GEN2(f) FMT_GEN1(f), f(1) +# define FMT_GEN3(f) FMT_GEN2(f), f(2) +# define FMT_GEN4(f) FMT_GEN3(f), f(3) +# define FMT_GEN5(f) FMT_GEN4(f), f(4) +# define FMT_GEN6(f) FMT_GEN5(f), f(5) +# define FMT_GEN7(f) FMT_GEN6(f), f(6) +# define FMT_GEN8(f) FMT_GEN7(f), f(7) +# define FMT_GEN9(f) FMT_GEN8(f), f(8) +# define FMT_GEN10(f) FMT_GEN9(f), f(9) -public: - ArgList() : size_(0) {} - ArgList(const internal::ArgInfo *args, std::size_t size) - : args_(args), size_(size) {} - - std::size_t size() const { return size_; } - - const internal::ArgInfo &operator[](std::size_t index) const { - return args_[index]; - } -}; - -// Generates a comma-separated list by applying f to numbers 1..n. -#define FMT_GEN(n, f) FMT_GEN##n(f) -#define FMT_GEN1(f) f(1) -#define FMT_GEN2(f) FMT_GEN1(f), f(2) -#define FMT_GEN3(f) FMT_GEN2(f), f(3) -#define FMT_GEN4(f) FMT_GEN3(f), f(4) -#define FMT_GEN5(f) FMT_GEN4(f), f(5) -#define FMT_GEN6(f) FMT_GEN5(f), f(6) -#define FMT_GEN7(f) FMT_GEN6(f), f(7) -#define FMT_GEN8(f) FMT_GEN7(f), f(8) -#define FMT_GEN9(f) FMT_GEN8(f), f(9) - -#define FMT_MAKE_TEMPLATE_ARG(n) typename T##n -#define FMT_MAKE_ARG(n) const T##n &v##n -#define FMT_MAKE_REF(n) MakeArg(v##n) - -#define FMT_TEMPLATE(func_name, n) \ - template <FMT_GEN(n, FMT_MAKE_TEMPLATE_ARG)> \ - inline void func_name(BasicStringRef<Char> format, FMT_GEN(n, FMT_MAKE_ARG)) { \ - const fmt::internal::ArgInfo args[] = {FMT_GEN(n, FMT_MAKE_REF)}; \ - func_name(format, fmt::ArgList(args, sizeof(args) / sizeof(*args))); \ - } +# define FMT_MAKE_TEMPLATE_ARG(n) typename T##n +# define FMT_MAKE_ARG(n) const T##n &v##n +# define FMT_MAKE_REF_char(n) fmt::internal::make_arg<char>(v##n) +# define FMT_MAKE_REF_wchar_t(n) fmt::internal::make_arg<wchar_t>(v##n) +#if FMT_USE_VARIADIC_TEMPLATES // Defines a variadic function returning void. -#define FMT_VARIADIC_VOID(func_name) \ - FMT_TEMPLATE(format, 1) FMT_TEMPLATE(format, 2) FMT_TEMPLATE(format, 3) \ - FMT_TEMPLATE(format, 4) FMT_TEMPLATE(format, 5) FMT_TEMPLATE(format, 6) \ - FMT_TEMPLATE(format, 7) FMT_TEMPLATE(format, 8) FMT_TEMPLATE(format, 9) +# define FMT_VARIADIC_VOID(func, arg_type) \ + template<typename... Args> \ + void func(arg_type arg1, const Args & ... args) { \ + const internal::ArgInfo arg_array[fmt::internal::NonZero<sizeof...(Args)>::VALUE] = { \ + fmt::internal::make_arg<Char>(args)... \ + }; \ + func(arg1, ArgList(arg_array, sizeof...(Args))); \ + } + +// 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) { \ + const internal::ArgInfo arg_array[fmt::internal::NonZero<sizeof...(Args)>::VALUE] = { \ + fmt::internal::make_arg<Char>(args)... \ + }; \ + func(arg0, arg1, ArgList(arg_array, sizeof...(Args))); \ + } + +#else + +# define FMT_MAKE_REF(n) fmt::internal::make_arg<Char>(v##n) +// Defines a wrapper for a function taking one argument of type arg_type +// and n additional arguments of arbitrary types. +# define FMT_WRAP1(func, arg_type, n) \ + template <FMT_GEN(n, FMT_MAKE_TEMPLATE_ARG)> \ + inline void func(arg_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ + const fmt::internal::ArgInfo args[] = {FMT_GEN(n, FMT_MAKE_REF)}; \ + func(arg1, fmt::ArgList(args, sizeof(args) / sizeof(*args))); \ + } + +// Emulates a variadic function returning void on a pre-C++11 compiler. +# define FMT_VARIADIC_VOID(func, arg_type) \ + FMT_WRAP1(func, arg_type, 1) FMT_WRAP1(func, arg_type, 2) \ + FMT_WRAP1(func, arg_type, 3) FMT_WRAP1(func, arg_type, 4) \ + FMT_WRAP1(func, arg_type, 5) FMT_WRAP1(func, arg_type, 6) \ + FMT_WRAP1(func, arg_type, 7) FMT_WRAP1(func, arg_type, 8) \ + FMT_WRAP1(func, arg_type, 9) FMT_WRAP1(func, arg_type, 10) + +# define FMT_CTOR(ctor, func, arg0_type, arg1_type, n) \ + template <FMT_GEN(n, FMT_MAKE_TEMPLATE_ARG)> \ + ctor(arg0_type arg0, arg1_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \ + const fmt::internal::ArgInfo args[] = {FMT_GEN(n, FMT_MAKE_REF)}; \ + func(arg0, arg1, fmt::ArgList(args, sizeof(args) / sizeof(*args))); \ + } + +// Emulates a variadic function returning void on a pre-C++11 compiler. +# define FMT_VARIADIC_CTOR(ctor, func, arg0_type, arg1_type) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 1) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 2) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 3) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 4) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 5) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 6) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 7) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 8) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 9) \ + FMT_CTOR(ctor, func, arg0_type, arg1_type, 10) +#endif + +// Generates a comma-separated list with results of applying f to pairs +// (argument, index). +#define FMT_FOR_EACH1(f, x0) f(x0, 0) +#define FMT_FOR_EACH2(f, x0, x1) \ + FMT_FOR_EACH1(f, x0), f(x1, 1) +#define FMT_FOR_EACH3(f, x0, x1, x2) \ + FMT_FOR_EACH2(f, x0 ,x1), f(x2, 2) +#define FMT_FOR_EACH4(f, x0, x1, x2, x3) \ + FMT_FOR_EACH3(f, x0, x1, x2), f(x3, 3) +#define FMT_FOR_EACH5(f, x0, x1, x2, x3, x4) \ + FMT_FOR_EACH4(f, x0, x1, x2, x3), f(x4, 4) +#define FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5) \ + FMT_FOR_EACH5(f, x0, x1, x2, x3, x4), f(x5, 5) +#define FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6) \ + FMT_FOR_EACH6(f, x0, x1, x2, x3, x4, x5), f(x6, 6) +#define FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7) \ + FMT_FOR_EACH7(f, x0, x1, x2, x3, x4, x5, x6), f(x7, 7) +#define FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8) \ + FMT_FOR_EACH8(f, x0, x1, x2, x3, x4, x5, x6, x7), f(x8, 8) +#define FMT_FOR_EACH10(f, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) \ + FMT_FOR_EACH9(f, x0, x1, x2, x3, x4, x5, x6, x7, x8), f(x9, 9) + +/** +An error returned by an operating system or a language runtime, +for example a file opening error. +*/ +class SystemError : public internal::SystemErrorBase { + private: + void init(int error_code, StringRef format_str, const ArgList &args); + + protected: + int error_code_; + + typedef char Char; // For FMT_VARIADIC_CTOR. + + SystemError() {} + + public: + /** + \rst + Constructs a :cpp:class:`fmt::SystemError` object with the description + of the form "*<message>*: *<system-message>*", where *<message>* is the + formatted message and *<system-message>* is the system message corresponding + to the error code. + *error_code* is a system error code as given by ``errno``. + \endrst + */ + SystemError(int error_code, StringRef message) { + init(error_code, message, ArgList()); + } + FMT_VARIADIC_CTOR(SystemError, init, int, StringRef) + + int error_code() const { return error_code_; } +}; /** \rst @@ -913,7 +1186,7 @@ public: Writer out; out << "The answer is " << 42 << "\n"; - out.Format("({:+f}, {:+f})") << -3.14 << 3.14; + out.write("({:+f}, {:+f})", -3.14, 3.14); This will write the following output to the ``out`` object: @@ -930,7 +1203,8 @@ template <typename Char> class BasicWriter { private: // Output buffer. - mutable internal::Array<Char, internal::INLINE_BUFFER_SIZE> buffer_; + typedef internal::Array<Char, internal::INLINE_BUFFER_SIZE> Buffer; + mutable Buffer buffer_; // Make BasicFormatter a friend so that it can access ArgInfo and Arg. friend class BasicFormatter<Char>; @@ -939,8 +1213,6 @@ class BasicWriter { typedef internal::ArgInfo Arg; - static const Arg DUMMY_ARG; - #if _SECURE_SCL static Char *GetBase(CharPtr p) { return p.base(); } #else @@ -979,14 +1251,14 @@ class BasicWriter { template <typename T> void FormatDouble(T value, const FormatSpec &spec); - // Formats a string. + // Writes a formatted string. template <typename StringChar> - CharPtr FormatString( + CharPtr write_str( const StringChar *s, std::size_t size, const AlignSpec &spec); template <typename StringChar> - void FormatString( - const Arg::StringValue<StringChar> &str, const FormatSpec &spec); + void write_str( + const internal::StringValue<StringChar> &str, const FormatSpec &spec); // This method is private to disallow writing a wide string to a // char stream and vice versa. If you want to print a wide string @@ -994,128 +1266,6 @@ class BasicWriter { // Do not implement! void operator<<(typename internal::CharTraits<Char>::UnsupportedStrType); - static ULongLong GetIntValue(const Arg &arg); - - // An argument action that does nothing. - struct NullArgAction { - void operator()() const {} - }; - - // A wrapper around a format argument. - template <typename Action = NullArgAction> - class BasicArg : public Action, public Arg { - private: - // This method is private to disallow formatting of arbitrary pointers. - // If you want to output a pointer cast it to const void*. Do not implement! - template <typename T> - BasicArg(const T *value); - - // This method is private to disallow formatting of arbitrary pointers. - // If you want to output a pointer cast it to void*. Do not implement! - template <typename T> - BasicArg(T *value); - - public: - using Arg::type; - - BasicArg() {} - // TODO: unsigned char & signed char - BasicArg(short value) { type = Arg::INT; Arg::int_value = value; } - BasicArg(unsigned short value) { - type = Arg::UINT; - Arg::uint_value = value; - } - BasicArg(int value) { type = Arg::INT; Arg::int_value = value; } - BasicArg(unsigned value) { type = Arg::UINT; Arg::uint_value = value; } - BasicArg(long value) { - if (sizeof(long) == sizeof(int)) { - type = Arg::INT; - Arg::int_value = static_cast<int>(value); - } else { - type = Arg::LONG_LONG; - Arg::long_long_value = value; - } - } - BasicArg(unsigned long value) { - if (sizeof(unsigned long) == sizeof(unsigned)) { - type = Arg::UINT; - Arg::uint_value = static_cast<unsigned>(value); - } else { - type = Arg::ULONG_LONG; - Arg::ulong_long_value = value; - } - } - BasicArg(LongLong value) { - type = Arg::LONG_LONG; - Arg::long_long_value = value; - } - BasicArg(ULongLong value) { - type = Arg::ULONG_LONG; - Arg::ulong_long_value = value; - } - BasicArg(float value) { type = Arg::DOUBLE; Arg::double_value = value; } - BasicArg(double value) { type = Arg::DOUBLE; Arg::double_value = value; } - BasicArg(long double value) { - type = Arg::LONG_DOUBLE; - Arg::long_double_value = value; - } - BasicArg(char value) { type = Arg::CHAR; Arg::int_value = value; } - BasicArg(wchar_t value) { - type = Arg::CHAR; - Arg::int_value = internal::CharTraits<Char>::ConvertChar(value); - } - - BasicArg(const char *value) { - type = Arg::STRING; - Arg::string.value = value; - Arg::string.size = 0; - } - - BasicArg(const wchar_t *value) { - type = Arg::WSTRING; - Arg::wstring.value = value; - Arg::wstring.size = 0; - } - - BasicArg(Char *value) { - type = Arg::STRING; - Arg::string.value = value; - Arg::string.size = 0; - } - - BasicArg(const void *value) { - type = Arg::POINTER; - Arg::pointer_value = value; - } - BasicArg(void *value) { type = Arg::POINTER; Arg::pointer_value = value; } - - BasicArg(const std::basic_string<Char> &value) { - type = Arg::STRING; - Arg::string.value = value.c_str(); - Arg::string.size = value.size(); - } - - BasicArg(BasicStringRef<Char> value) { - type = Arg::STRING; - Arg::string.value = value.c_str(); - Arg::string.size = value.size(); - } - - template <typename T> - BasicArg(const T &value) { - type = Arg::CUSTOM; - Arg::custom.value = &value; - Arg::custom.format = &internal::FormatCustomArg<Char, T>; - } - - // The destructor is declared noexcept(false) because the action may throw - // an exception. - ~BasicArg() FMT_NOEXCEPT(false) { - // Invoke the action. - (*this)(); - } - }; - // Format string parser. class FormatParser { private: @@ -1133,24 +1283,7 @@ class BasicWriter { BasicStringRef<Char> format, const ArgList &args); }; - // Printf format string parser. - class PrintfParser { - private: - ArgList args_; - int next_arg_index_; - - void ParseFlags(FormatSpec &spec, const Char *&s); - - // Parses argument index, flags and width and returns the parsed - // argument index. - unsigned ParseHeader(const Char *&s, FormatSpec &spec, const char *&error); - - const Arg &HandleArgIndex(unsigned arg_index, const char *&error); - - public: - void Format(BasicWriter<Char> &writer, - BasicStringRef<Char> format, const ArgList &args); - }; + friend class internal::PrintfParser<Char>; public: /** @@ -1204,88 +1337,41 @@ class BasicWriter { return std::basic_string<Char>(&buffer_[0], buffer_.size()); } - inline void format(BasicStringRef<Char> format, const ArgList &args) { + /** + \rst + Writes formatted data. + + *args* is an argument list representing arbitrary arguments. + + **Example**:: + + Writer out; + out.write("Current point:\n"); + out.write("({:+f}, {:+f})", -3.14, 3.14); + + This will write the following output to the ``out`` object: + + .. code-block:: none + + Current point: + (-3.140000, +3.140000) + + The output can be accessed using :meth:`data`, :meth:`c_str` or :meth:`str` + methods. + + See also `Format String Syntax`_. + \endrst + */ + inline void write(BasicStringRef<Char> format, const ArgList &args) { FormatParser().Format(*this, format, args); } + FMT_VARIADIC_VOID(write, fmt::BasicStringRef<Char>) - inline void printf(BasicStringRef<Char> format, const ArgList &args) { - PrintfParser().Format(*this, format, args); + friend void printf(BasicWriter<Char> &w, + BasicStringRef<Char> format, const ArgList &args) { + internal::PrintfParser<Char>().Format(w, format, args); } - /** - \rst - Formats a string sending the output to the writer. Arguments are - accepted through the returned :cpp:class:`fmt::BasicFormatter` object - using operator ``<<``. - - **Example**:: - - Writer out; - out.Format("Current point:\n"); - out.Format("({:+f}, {:+f})") << -3.14 << 3.14; - - This will write the following output to the ``out`` object: - - .. code-block:: none - - Current point: - (-3.140000, +3.140000) - - The output can be accessed using :meth:`data`, :meth:`c_str` or :meth:`str` - methods. - - See also `Format String Syntax`_. - \endrst - */ - BasicFormatter<Char> Format(StringRef format); - -#if FMT_USE_VARIADIC_TEMPLATES - /** - \rst - Formats a string sending the output to the writer. - - This version of the Format method uses C++11 features such as - variadic templates and rvalue references. For C++98 version, see - the overload taking a single ``StringRef`` argument above. - - **Example**:: - - Writer out; - out.Format("Current point:\n"); - out.Format("({:+f}, {:+f})", -3.14, 3.14); - - This will write the following output to the ``out`` object: - - .. code-block:: none - - Current point: - (-3.140000, +3.140000) - - The output can be accessed using :meth:`data`, :meth:`c_str` or :meth:`str` - methods. - - See also `Format String Syntax`_. - \endrst - */ - template<typename... Args> - void Format(BasicStringRef<Char> format, const Args & ... args) { - BasicArg<> arg_array[] = {args...}; - this->format(format, ArgList(arg_array, sizeof...(Args))); - } - - template<typename... Args> - void printf(BasicStringRef<Char> format, const Args & ... args) { - BasicArg<> arg_array[internal::NonZero<sizeof...(Args)>::VALUE] = {args...}; - this->printf(format, ArgList(arg_array, sizeof...(Args))); - } - -#else - FMT_VARIADIC_VOID(format) -#endif - - template <typename T> - static Arg MakeArg(const T &arg) { return BasicArg<>(arg); } - BasicWriter &operator<<(int value) { return *this << IntFormatSpec<int>(value); } @@ -1356,22 +1442,44 @@ class BasicWriter { template <typename StringChar> BasicWriter &operator<<(const StrFormatSpec<StringChar> &spec) { const StringChar *s = spec.str(); - FormatString(s, std::char_traits<Char>::length(s), spec); + write_str(s, std::char_traits<Char>::length(s), spec); return *this; } - void Write(const std::basic_string<Char> &s, const FormatSpec &spec) { - FormatString(s.data(), s.size(), spec); + void write_str(const std::basic_string<Char> &s, const FormatSpec &spec) { + write_str(s.data(), s.size(), spec); } - void Clear() { - buffer_.clear(); - } + void clear() { buffer_.clear(); } + +#if !defined(FMT_NO_DEPRECATED) + FMT_DEPRECATED(BasicFormatter<Char> Format(StringRef format)); + +#if FMT_USE_VARIADIC_TEMPLATES + // This function is deprecated. Use Writer::write instead. + template<typename... Args> + FMT_DEPRECATED(void Format(BasicStringRef<Char> format, const Args & ... args)); +#endif + + // This function is deprecated. Use Writer::write instead. + FMT_DEPRECATED(void Write(const std::basic_string<Char> &s, const FormatSpec &spec)); + + // This function is deprecated. Use Writer::clear instead. + FMT_DEPRECATED(void Clear()); +#endif }; +template <typename Char> +inline void BasicWriter<Char>::Write(const std::basic_string<Char> &s, const FormatSpec &spec) { + write(s, spec); +} + +template <typename Char> +inline void BasicWriter<Char>::Clear() { clear(); } + template <typename Char> template <typename StringChar> -typename BasicWriter<Char>::CharPtr BasicWriter<Char>::FormatString( +typename BasicWriter<Char>::CharPtr BasicWriter<Char>::write_str( const StringChar *s, std::size_t size, const AlignSpec &spec) { CharPtr out = CharPtr(); if (spec.width() > size) { @@ -1400,6 +1508,7 @@ typename fmt::BasicWriter<Char>::CharPtr const char *prefix, unsigned prefix_size) { unsigned width = spec.width(); Alignment align = spec.align(); + Char fill = static_cast<Char>(spec.fill()); if (spec.precision() > static_cast<int>(num_digits)) { // Octal prefix '0' is counted as a digit, so ignore it if precision // is specified. @@ -1413,12 +1522,12 @@ typename fmt::BasicWriter<Char>::CharPtr unsigned fill_size = width - number_size; if (align != ALIGN_LEFT) { CharPtr p = GrowBuffer(fill_size); - std::fill(p, p + fill_size, spec.fill()); + std::fill(p, p + fill_size, fill); } CharPtr result = PrepareBufferForInt(num_digits, subspec, prefix, prefix_size); if (align == ALIGN_LEFT) { CharPtr p = GrowBuffer(fill_size); - std::fill(p, p + fill_size, spec.fill()); + std::fill(p, p + fill_size, fill); } return result; } @@ -1431,7 +1540,6 @@ typename fmt::BasicWriter<Char>::CharPtr CharPtr p = GrowBuffer(width); CharPtr end = p + width; // TODO: error if fill is not convertible to Char - Char fill = static_cast<Char>(spec.fill()); if (align == ALIGN_LEFT) { std::copy(prefix, prefix + prefix_size, p); p += size; @@ -1545,17 +1653,17 @@ BasicFormatter<Char> BasicWriter<Char>::Format(StringRef format) { // The default formatting function. template <typename Char, typename T> -void Format(BasicWriter<Char> &w, const FormatSpec &spec, const T &value) { +void format(BasicWriter<Char> &w, const FormatSpec &spec, const T &value) { std::basic_ostringstream<Char> os; os << value; - w.Write(os.str(), spec); + w.write_str(os.str(), spec); } namespace internal { // Formats an argument of a custom type, such as a user-defined class. template <typename Char, typename T> void FormatCustomArg(void *writer, const void *arg, const FormatSpec &spec) { - Format(*static_cast<BasicWriter<Char>*>(writer), + format(*static_cast<BasicWriter<Char>*>(writer), spec, *static_cast<const T*>(arg)); } } @@ -1596,7 +1704,7 @@ class BasicFormatter { }; typedef typename internal::ArgInfo ArgInfo; - typedef typename BasicWriter<Char>::template BasicArg<ArgAction> Arg; + typedef internal::BasicArg<Char, ArgAction> Arg; enum { NUM_INLINE_ARGS = 10 }; internal::Array<ArgInfo, NUM_INLINE_ARGS> args_; // Format arguments. @@ -1622,7 +1730,7 @@ class BasicFormatter { if (!format_) return; const Char *format = format_; format_ = 0; - writer_->format(format, ArgList(&args_[0], args_.size())); + writer_->write(format, ArgList(&args_[0], args_.size())); } public: @@ -1654,70 +1762,64 @@ class BasicFormatter { } }; +template <typename Char> +FMT_DEPRECATED(std::basic_string<Char> str(const BasicWriter<Char> &f)); + +// This function is deprecated. Use BasicWriter::str() instead. template <typename Char> inline std::basic_string<Char> str(const BasicWriter<Char> &f) { return f.str(); } +template <typename Char> +FMT_DEPRECATED(const Char *c_str(const BasicWriter<Char> &f)); + +// This function is deprecated. Use BasicWriter::c_str() instead. template <typename Char> inline const Char *c_str(const BasicWriter<Char> &f) { return f.c_str(); } +FMT_DEPRECATED(std::string str(StringRef s)); + /** Converts a string reference to `std::string`. */ +// This function is deprecated. Use StringRef::c_str() instead. inline std::string str(StringRef s) { return std::string(s.c_str(), s.size()); } +FMT_DEPRECATED(const char *c_str(StringRef s)); + /** Returns the pointer to a C string. */ +// This function is deprecated. Use StringRef::c_str() instead. inline const char *c_str(StringRef s) { return s.c_str(); } +FMT_DEPRECATED(std::wstring str(WStringRef s)); + +// This function is deprecated. Use WStringRef::c_str() instead. inline std::wstring str(WStringRef s) { return std::wstring(s.c_str(), s.size()); } +FMT_DEPRECATED(const wchar_t *c_str(WStringRef s)); + +// This function is deprecated. Use WStringRef::c_str() instead. inline const wchar_t *c_str(WStringRef s) { return s.c_str(); } -/** - A sink that discards all output written to it. - */ +// This class is deprecated. Use variadic functions instead of sinks. class NullSink { public: - /** Discards the output. */ template <typename Char> void operator()(const BasicWriter<Char> &) const {} }; -/** - \rst - A formatter that sends output to a sink. Objects of this class normally - exist only as temporaries returned by one of the formatting functions. - You can use this class to create your own functions similar to - :cpp:func:`fmt::Format()`. - - **Example**:: - - struct ErrorSink { - void operator()(const fmt::Writer &w) const { - fmt::Print("Error: {}\n") << w.str(); - } - }; - - // Formats an error message and prints it to stdout. - fmt::Formatter<ErrorSink> ReportError(const char *format) { - fmt::Formatter f<ErrorSink>(format); - return f; - } - - ReportError("File not found: {}") << path; - \endrst - */ +// This class is deprecated. Use variadic functions instead. template <typename Sink = NullSink, typename Char = char> class Formatter : private Sink, public BasicFormatter<Char> { private: @@ -1727,47 +1829,17 @@ class Formatter : private Sink, public BasicFormatter<Char> { FMT_DISALLOW_COPY_AND_ASSIGN(Formatter); public: - /** - \rst - Constructs a formatter with a format string and a sink. - The sink should be an unary function object that takes a const - reference to :cpp:class:`fmt::BasicWriter`, representing the - formatting output, as an argument. See :cpp:class:`fmt::NullSink` - and :cpp:class:`fmt::FileSink` for examples of sink classes. - \endrst - */ explicit Formatter(BasicStringRef<Char> format, Sink s = Sink()) : Sink(s), BasicFormatter<Char>(writer_, format.c_str()), inactive_(false) { } - /** - \rst - A "move" constructor. Constructs a formatter transferring the format - string from other to this object. This constructor is used to return - a formatter object from a formatting function since the copy constructor - taking a const reference is disabled to prevent misuse of the API. - It is not implemented as a move constructor for compatibility with - pre-C++11 compilers, but should be treated as such. - - **Example**:: - - fmt::Formatter<> Format(fmt::StringRef format) { - fmt::Formatter<> f(format); - return f; - } - \endrst - */ Formatter(Formatter &other) : Sink(other), BasicFormatter<Char>(writer_, other.TakeFormatString()), inactive_(false) { other.inactive_ = true; } - /** - Performs the formatting, sends the output to the sink and destroys - the object. - */ ~Formatter() FMT_NOEXCEPT(false) { if (!inactive_) { this->CompleteFormatting(); @@ -1776,41 +1848,22 @@ class Formatter : private Sink, public BasicFormatter<Char> { } }; -/** - \rst - Formats a string similarly to Python's `str.format - <http://docs.python.org/3/library/stdtypes.html#str.format>`__ function. - Returns a temporary :cpp:class:`fmt::Formatter` object that accepts arguments - via operator ``<<``. - - *format* is a format string that contains literal text and replacement - fields surrounded by braces ``{}``. The formatter object replaces the - fields with formatted arguments and stores the output in a memory buffer. - The content of the buffer can be converted to ``std::string`` with - :cpp:func:`fmt::str()` or accessed as a C string with - :cpp:func:`fmt::c_str()`. - - **Example**:: - - std::string message = str(Format("The answer is {}") << 42); - - See also `Format String Syntax`_. - \endrst - */ +#if !defined(FMT_NO_DEPRECATED) +// This function is deprecated. Use fmt::format instead. +FMT_DEPRECATED(Formatter<> Format(StringRef format)); inline Formatter<> Format(StringRef format) { Formatter<> f(format); return f; } +// This function is deprecated. Use fmt::format instead. +Formatter<NullSink, wchar_t> FMT_DEPRECATED(Format(WStringRef format)); inline Formatter<NullSink, wchar_t> Format(WStringRef format) { Formatter<NullSink, wchar_t> f(format); return f; } -/** - A sink that gets the error message corresponding to a system error code - as given by errno and throws SystemError. - */ +// This class is deprecated. Use variadic functions instead of sinks. class SystemErrorSink { private: int error_code_; @@ -1818,18 +1871,16 @@ class SystemErrorSink { public: explicit SystemErrorSink(int error_code) : error_code_(error_code) {} - void operator()(const Writer &w) const; + void operator()(const Writer &w) const { + throw SystemError(error_code_, "{}", w.c_str()); + } }; +#endif -/** - \rst - Formats a message and throws :cpp:class:`fmt::SystemError` with - the description of the form "*<message>*: *<system-message>*", - where *<message>* is the formatted message and *<system-message>* - is the system message corresponding to the error code. - *error_code* is a system error code as given by ``errno``. - \endrst - */ +FMT_DEPRECATED(Formatter<SystemErrorSink> ThrowSystemError( + int error_code, StringRef format)); + +// This function is deprecated. Use fmt::SystemError instead. inline Formatter<SystemErrorSink> ThrowSystemError( int error_code, StringRef format) { Formatter<SystemErrorSink> f(format, SystemErrorSink(error_code)); @@ -1842,10 +1893,7 @@ void ReportSystemError(int error_code, StringRef message) FMT_NOEXCEPT(true); #ifdef _WIN32 -/** - A sink that gets the error message corresponding to a Windows error code - as given by GetLastError and throws SystemError. - */ +// This class is deprecated. Use variadic functions instead of sinks. class WinErrorSink { private: int error_code_; @@ -1857,16 +1905,31 @@ class WinErrorSink { }; /** - \rst - Formats a message and throws :cpp:class:`fmt::SystemError` with - the description of the form "*<message>*: *<system-message>*", - where *<message>* is the formatted message and *<system-message>* - is the system message corresponding to the error code. - *error_code* is a Windows error code as given by ``GetLastError``. + A Windows error. +*/ +class WindowsError : public SystemError { + private: + void init(int error_code, StringRef format_str, const ArgList &args); - This function is only available on Windows. - \endrst - */ + public: + /** + \rst + Constructs a :cpp:class:`fmt::WindowsError` object with the description + of the form "*<message>*: *<system-message>*", where *<message>* is the + formatted message and *<system-message>* is the system message corresponding + to the error code. + *error_code* is a Windows error code as given by ``GetLastError``. + \endrst + */ + WindowsError(int error_code, StringRef message) { + init(error_code, message, ArgList()); + } + FMT_VARIADIC_CTOR(WindowsError, init, int, StringRef) +}; + +FMT_DEPRECATED(Formatter<WinErrorSink> ThrowWinError(int error_code, StringRef format)); + +// This function is deprecated. Use WindowsError instead. inline Formatter<WinErrorSink> ThrowWinError(int error_code, StringRef format) { Formatter<WinErrorSink> f(format, WinErrorSink(error_code)); return f; @@ -1878,7 +1941,7 @@ void ReportWinError(int error_code, StringRef message) FMT_NOEXCEPT(true); #endif -/** A sink that writes output to a file. */ +// This class is deprecated. Use variadic functions instead of sinks. class FileSink { private: std::FILE *file_; @@ -1886,36 +1949,17 @@ class FileSink { public: explicit FileSink(std::FILE *f) : file_(f) {} - /** Writes the output to a file. */ void operator()(const BasicWriter<char> &w) const { if (std::fwrite(w.data(), w.size(), 1, file_) == 0) - ThrowSystemError(errno, "cannot write to file"); + throw SystemError(errno, "cannot write to file"); } }; -/** - \rst - Formats a string and writes the result to ``stdout``. - - **Example**:: - - Print("Elapsed time: {0:.2f} seconds") << 1.23; - \endrst - */ inline Formatter<FileSink> Print(StringRef format) { Formatter<FileSink> f(format, FileSink(stdout)); return f; } -/** - \rst - Formats a string and writes the result to a file. - - **Example**:: - - Print(stderr, "Don't {}!") << "panic"; - \endrst - */ inline Formatter<FileSink> Print(std::FILE *file, StringRef format) { Formatter<FileSink> f(format, FileSink(file)); return f; @@ -1923,10 +1967,7 @@ inline Formatter<FileSink> Print(std::FILE *file, StringRef format) { enum Color { BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE }; -/** - A sink that writes output to a terminal using ANSI escape sequences - to specify color. - */ +// This class is deprecated. Use variadic functions instead of sinks. class ANSITerminalSink { private: std::FILE *file_; @@ -1935,10 +1976,6 @@ class ANSITerminalSink { public: ANSITerminalSink(std::FILE *f, Color c) : file_(f), color_(c) {} - /** - Writes the output to a terminal using ANSI escape sequences to - specify color. - */ void operator()(const BasicWriter<char> &w) const; }; @@ -1953,32 +1990,80 @@ inline Formatter<ANSITerminalSink> PrintColored(Color c, StringRef format) { return f; } -#if FMT_USE_VARIADIC_TEMPLATES && FMT_USE_RVALUE_REFERENCES - /** \rst Formats a string similarly to Python's `str.format <http://docs.python.org/3/library/stdtypes.html#str.format>`__ function - and returns an :cpp:class:`fmt::BasicWriter` object containing the output. + and returns the result as a string. - This version of the Format function uses C++11 features such as - variadic templates and rvalue references. For C++98 version, see - the :cpp:func:`fmt::Format()` overload above. - - *format* is a format string that contains literal text and replacement - fields surrounded by braces ``{}``. The formatter object replaces the - fields with formatted arguments and stores the output in a memory buffer. - The content of the buffer can be converted to ``std::string`` with - :cpp:func:`fmt::str()` or accessed as a C string with - :cpp:func:`fmt::c_str()`. + *format_str* is a format string that contains literal text and replacement + fields surrounded by braces ``{}``. The fields are replaced with formatted + arguments in the resulting string. + + *args* is an argument list representing arbitrary arguments. **Example**:: - std::string message = str(Format("The answer is {}", 42)); + std::string message = format("The answer is {}", 42); See also `Format String Syntax`_. \endrst +*/ +inline std::string format(StringRef format_str, const ArgList &args) { + Writer w; + w.write(format_str, args); + return w.str(); +} + +inline std::wstring format(WStringRef format, const ArgList &args) { + WWriter w; + w.write(format, args); + return w.str(); +} + +/** + \rst + Prints formatted data to ``stdout``. + + **Example**:: + + print("Elapsed time: {0:.2f} seconds", 1.23); + \endrst */ +void print(StringRef format, const ArgList &args); + +/** + \rst + Prints formatted data to a file. + + **Example**:: + + print(stderr, "Don't {}!", "panic"); + \endrst + */ +void print(std::FILE *f, StringRef format, const ArgList &args); + +inline std::string sprintf(StringRef format, const ArgList &args) { + Writer w; + printf(w, format, args); + return w.str(); +} + +void printf(StringRef format, const ArgList &args); + +#if !defined(FMT_NO_DEPRECATED) && FMT_USE_VARIADIC_TEMPLATES && FMT_USE_RVALUE_REFERENCES + +template <typename Char> +template<typename... Args> +void BasicWriter<Char>::Format( + BasicStringRef<Char> format, const Args & ... args) { + this->format(format, args...); +} + +// This function is deprecated. Use fmt::format instead. +template<typename... Args> +FMT_DEPRECATED(Writer Format(StringRef format, const Args & ... args)); + template<typename... Args> inline Writer Format(StringRef format, const Args & ... args) { Writer w; @@ -1986,6 +2071,10 @@ inline Writer Format(StringRef format, const Args & ... args) { return std::move(w); } +// This function is deprecated. Use fmt::format instead. +template<typename... Args> +FMT_DEPRECATED(WWriter Format(WStringRef format, const Args & ... args)); + template<typename... Args> inline WWriter Format(WStringRef format, const Args & ... args) { WWriter w; @@ -1993,13 +2082,21 @@ inline WWriter Format(WStringRef format, const Args & ... args) { return std::move(w); } +// This function is deprecated. Use fmt::print instead. +template<typename... Args> +FMT_DEPRECATED(void Print(StringRef format, const Args & ... args)); + template<typename... Args> void Print(StringRef format, const Args & ... args) { Writer w; - w.Format(format, args...); + w.write(format, args...); std::fwrite(w.data(), 1, w.size(), stdout); } +// This function is deprecated. Use fmt::print instead. +template<typename... Args> +FMT_DEPRECATED(void Print(std::FILE *f, StringRef format, const Args & ... args)); + template<typename... Args> void Print(std::FILE *f, StringRef format, const Args & ... args) { Writer w; @@ -2007,20 +2104,6 @@ void Print(std::FILE *f, StringRef format, const Args & ... args) { std::fwrite(w.data(), 1, w.size(), f); } -template<typename... Args> -inline Writer sprintf(StringRef format, const Args & ... args) { - Writer w; - w.printf(format, args...); - return std::move(w); -} - -template<typename... Args> -void printf(StringRef format, const Args & ... args) { - Writer w; - w.printf(format, args...); - std::fwrite(w.data(), 1, w.size(), stdout); -} - #endif // FMT_USE_VARIADIC_TEMPLATES && FMT_USE_RVALUE_REFERENCES /** @@ -2129,91 +2212,104 @@ inline void FormatDec(char *&buffer, T value) { #if FMT_GCC_VERSION // Use the system_header pragma to suppress warnings about variadic macros // because suppressing -Wvariadic-macros with the diagnostic pragma doesn't work. +// It is used at the end because we want to suppress as little warnings as +// possible. # pragma GCC system_header #endif -#define FMT_CONCATENATE(arg1, arg2) FMT_CONCATENATE1(arg1, arg2) -#define FMT_CONCATENATE1(arg1, arg2) FMT_CONCATENATE2(arg1, arg2) -#define FMT_CONCATENATE2(arg1, arg2) arg1##arg2 - +// This is used to work around VC++ bugs in handling variadic macros. #define FMT_EXPAND(args) args -#define FMT_FOR_EACH_1(func, x, ...) func(x, 1) -#define FMT_FOR_EACH_2(func, x, ...) \ - func(x, 2), FMT_EXPAND(FMT_FOR_EACH_1(func, __VA_ARGS__)) -#define FMT_FOR_EACH_3(func, x, ...) \ - func(x, 3), FMT_EXPAND(FMT_FOR_EACH_2(func, __VA_ARGS__)) -#define FMT_FOR_EACH_4(func, x, ...) \ - func(x, 4), FMT_EXPAND(FMT_FOR_EACH_3(func, __VA_ARGS__)) -#define FMT_FOR_EACH_5(func, x, ...) \ - func(x, 5), FMT_EXPAND(FMT_FOR_EACH_4(func, __VA_ARGS__)) -#define FMT_FOR_EACH_6(func, x, ...) \ - func(x, 6), FMT_EXPAND(FMT_FOR_EACH_5(func, __VA_ARGS__)) -#define FMT_FOR_EACH_7(func, x, ...) \ - func(x, 7), FMT_EXPAND(FMT_FOR_EACH_6(func, __VA_ARGS__)) -#define FMT_FOR_EACH_8(func, x, ...) \ - func(x, 8), FMT_EXPAND(FMT_FOR_EACH_7(func, __VA_ARGS__)) -#define FMT_FOR_EACH_NARG(...) FMT_FOR_EACH_NARG_(__VA_ARGS__, FMT_FOR_EACH_RSEQ_N()) -#define FMT_FOR_EACH_NARG_(...) FMT_EXPAND(FMT_FOR_EACH_ARG_N(__VA_ARGS__)) -#define FMT_FOR_EACH_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N -#define FMT_FOR_EACH_RSEQ_N() 8, 7, 6, 5, 4, 3, 2, 1, 0 +// Returns the number of arguments. +// Based on https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s. +#define FMT_NARG(...) FMT_NARG_(__VA_ARGS__, FMT_RSEQ_N()) +#define FMT_NARG_(...) FMT_EXPAND(FMT_ARG_N(__VA_ARGS__)) +#define FMT_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N +#define FMT_RSEQ_N() 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 -#define FMT_FOR_EACH_(N, func, ...) \ - FMT_CONCATENATE(FMT_FOR_EACH_, N)(func, __VA_ARGS__) -#define FMT_FOR_EACH(func, ...) \ - FMT_EXPAND(FMT_FOR_EACH_(FMT_FOR_EACH_NARG(__VA_ARGS__), func, __VA_ARGS__)) +#define FMT_CONCAT(a, b) a##b +#define FMT_FOR_EACH_(N, f, ...) \ + FMT_EXPAND(FMT_CONCAT(FMT_FOR_EACH, N)(f, __VA_ARGS__)) +#define FMT_FOR_EACH(f, ...) \ + FMT_EXPAND(FMT_FOR_EACH_(FMT_NARG(__VA_ARGS__), f, __VA_ARGS__)) #define FMT_ADD_ARG_NAME(type, index) type arg##index #define FMT_GET_ARG_NAME(type, index) arg##index -#define FMT_MAKE_ARG(arg, index) fmt::Writer::MakeArg(arg) -#define FMT_VARIADIC(return_type, func_name, ...) \ - inline return_type func_name(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__)) { \ - return func_name(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ - fmt::ArgList()); \ - } \ - template <typename T1> \ - inline return_type func_name(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ - const T1 &v1) { \ - const fmt::internal::ArgInfo args[] = {FMT_FOR_EACH(FMT_MAKE_ARG, v1)}; \ - return func_name(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ - fmt::ArgList(args, sizeof(args) / sizeof(*args))); \ - } \ - template <typename T1, typename T2> \ - inline return_type func_name(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ - const T1 &v1, const T2 &v2) { \ - const fmt::internal::ArgInfo args[] = {FMT_FOR_EACH(FMT_MAKE_ARG, v1, v2)}; \ - return func_name(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ - fmt::ArgList(args, sizeof(args) / sizeof(*args))); \ - } \ - template <typename T1, typename T2, typename T3> \ - inline return_type func_name(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ - const T1 &v1, const T2 &v2, const T3 &v3) { \ - const fmt::internal::ArgInfo args[] = { \ - FMT_FOR_EACH(FMT_MAKE_ARG, v1, v2, v3) \ +#if FMT_USE_VARIADIC_TEMPLATES + +# define FMT_VARIADIC_(Char, ReturnType, func, ...) \ + template<typename... Args> \ + ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ + const Args & ... args) { \ + enum {N = fmt::internal::NonZero<sizeof...(Args)>::VALUE}; \ + const fmt::internal::ArgInfo array[N] = { \ + fmt::internal::make_arg<Char>(args)... \ }; \ - return func_name(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ - fmt::ArgList(args, sizeof(args) / sizeof(*args))); \ - } \ - template <typename T1, typename T2, typename T3, typename T4> \ - inline return_type func_name(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ - const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4) { \ - const fmt::internal::ArgInfo args[] = { \ - FMT_FOR_EACH(FMT_MAKE_ARG, v1, v2, v3, v4) \ - }; \ - return func_name(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ - fmt::ArgList(args, sizeof(args) / sizeof(*args))); \ - } \ - template <typename T1, typename T2, typename T3, typename T4, typename T5> \ - inline return_type func_name(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ - const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5) { \ - const fmt::internal::ArgInfo args[] = { \ - FMT_FOR_EACH(FMT_MAKE_ARG, v1, v2, v3, v4, v5) \ - }; \ - return func_name(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ + return func(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ + fmt::ArgList(array, sizeof...(Args))); \ + } + +#else + +// Defines a wrapper for a function taking __VA_ARGS__ arguments +// and n additional arguments of arbitrary types. +# define FMT_WRAP(Char, ReturnType, func, n, ...) \ + template <FMT_GEN(n, FMT_MAKE_TEMPLATE_ARG)> \ + inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ + FMT_GEN(n, FMT_MAKE_ARG)) { \ + const fmt::internal::ArgInfo args[] = {FMT_GEN(n, FMT_MAKE_REF_##Char)}; \ + return func(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ fmt::ArgList(args, sizeof(args) / sizeof(*args))); \ } +# define FMT_VARIADIC_(Char, ReturnType, func, ...) \ + inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__)) { \ + return func(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList()); \ + } \ + FMT_WRAP(Char, ReturnType, func, 1, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, 2, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, 3, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, 4, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, 5, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, 6, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, 7, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, 8, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, 9, __VA_ARGS__) \ + FMT_WRAP(Char, ReturnType, func, 10, __VA_ARGS__) + +#endif // FMT_USE_VARIADIC_TEMPLATES + +/** + \rst + Defines a variadic function with the specified return type, function name + and argument types passed as variable arguments to this macro. + + **Example**:: + + void print_error(const char *file, int line, const char *format, + const fmt::ArgList &args) { + fmt::print("{}: {}: ", file, line); + fmt::print(format, args); + } + FMT_VARIADIC(void, print_error, const char *, int, const char *) + \endrst + */ +#define FMT_VARIADIC(ReturnType, func, ...) \ + FMT_VARIADIC_(char, ReturnType, func, __VA_ARGS__) + +#define FMT_VARIADIC_W(ReturnType, func, ...) \ + FMT_VARIADIC_(wchar_t, ReturnType, func, __VA_ARGS__) + +namespace fmt { +FMT_VARIADIC(std::string, format, StringRef) +FMT_VARIADIC_W(std::wstring, format, WStringRef) +FMT_VARIADIC(void, print, StringRef) +FMT_VARIADIC(void, print, std::FILE *, StringRef) +FMT_VARIADIC(std::string, sprintf, StringRef) +FMT_VARIADIC(void, printf, StringRef) +} + // Restore warnings. #if FMT_GCC_VERSION >= 406 # pragma GCC diagnostic pop