Emulate variadic functions on older compilers.

This commit is contained in:
Victor Zverovich 2014-06-25 07:50:16 -07:00
parent 2f752abe97
commit ef34eb6ec2

152
format.h
View File

@ -119,6 +119,14 @@
TypeName(const TypeName&); \ TypeName(const TypeName&); \
void operator=(const TypeName&) void operator=(const TypeName&)
#ifdef __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 #if FMT_MSC_VER
# pragma warning(push) # pragma warning(push)
# pragma warning(disable: 4521) // 'class' : multiple copy constructors specified # pragma warning(disable: 4521) // 'class' : multiple copy constructors specified
@ -864,34 +872,47 @@ public:
} }
}; };
// Generates a comma-separated list by applying f to numbers 1..n. #if FMT_USE_VARIADIC_TEMPLATES
#define FMT_GEN(n, f) FMT_GEN##n(f) // Defines a variadic function returning void.
#define FMT_GEN1(f) f(1) # define FMT_VARIADIC_VOID(func, arg_type) \
#define FMT_GEN2(f) FMT_GEN1(f), f(2) template<typename... Args> \
#define FMT_GEN3(f) FMT_GEN2(f), f(3) void func(arg_type arg1, const Args & ... args) { \
#define FMT_GEN4(f) FMT_GEN3(f), f(4) const BasicArg<> \
#define FMT_GEN5(f) FMT_GEN4(f), f(5) arg_array[fmt::internal::NonZero<sizeof...(Args)>::VALUE] = {args...}; \
#define FMT_GEN6(f) FMT_GEN5(f), f(6) func(arg1, ArgList(arg_array, sizeof...(Args))); \
#define FMT_GEN7(f) FMT_GEN6(f), f(7) }
#define FMT_GEN8(f) FMT_GEN7(f), f(8) #else
#define FMT_GEN9(f) FMT_GEN8(f), f(9) // Generates a comma-separated list with results of 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_TEMPLATE_ARG(n) typename T##n
#define FMT_MAKE_ARG(n) const T##n &v##n # define FMT_MAKE_ARG(n) const T##n &v##n
#define FMT_MAKE_REF(n) MakeArg(v##n) # define FMT_MAKE_REF(n) fmt::Writer::MakeArg(v##n)
#define FMT_TEMPLATE(func_name, n) \ # define FMT_TEMPLATE(func, arg_type, n) \
template <FMT_GEN(n, FMT_MAKE_TEMPLATE_ARG)> \ template <FMT_GEN(n, FMT_MAKE_TEMPLATE_ARG)> \
inline void func_name(BasicStringRef<Char> format, FMT_GEN(n, FMT_MAKE_ARG)) { \ inline void func(arg_type arg1, FMT_GEN(n, FMT_MAKE_ARG)) { \
const fmt::internal::ArgInfo args[] = {FMT_GEN(n, FMT_MAKE_REF)}; \ const fmt::internal::ArgInfo args[] = {FMT_GEN(n, FMT_MAKE_REF)}; \
func_name(format, fmt::ArgList(args, sizeof(args) / sizeof(*args))); \ func(arg1, fmt::ArgList(args, sizeof(args) / sizeof(*args))); \
} }
// Defines a variadic function returning void. // Emulates a variadic function returning void on a pre-C++11 compiler.
#define FMT_VARIADIC_VOID(func_name) \ # define FMT_VARIADIC_VOID(func, arg_type) \
FMT_TEMPLATE(format, 1) FMT_TEMPLATE(format, 2) FMT_TEMPLATE(format, 3) \ FMT_TEMPLATE(func, arg_type, 1) FMT_TEMPLATE(func, arg_type, 2) \
FMT_TEMPLATE(format, 4) FMT_TEMPLATE(format, 5) FMT_TEMPLATE(format, 6) \ FMT_TEMPLATE(func, arg_type, 3) FMT_TEMPLATE(func, arg_type, 4) \
FMT_TEMPLATE(format, 7) FMT_TEMPLATE(format, 8) FMT_TEMPLATE(format, 9) FMT_TEMPLATE(func, arg_type, 5) FMT_TEMPLATE(func, arg_type, 6) \
FMT_TEMPLATE(func, arg_type, 7) FMT_TEMPLATE(func, arg_type, 8) \
FMT_TEMPLATE(func, arg_type, 9)
#endif
/** /**
\rst \rst
@ -1204,13 +1225,39 @@ class BasicWriter {
return std::basic_string<Char>(&buffer_[0], buffer_.size()); return std::basic_string<Char>(&buffer_[0], buffer_.size());
} }
/**
\rst
Formats a string sending the output to the writer. This function
takes variable number of arguments.
**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
*/
inline void format(BasicStringRef<Char> format, const ArgList &args) { inline void format(BasicStringRef<Char> format, const ArgList &args) {
FormatParser().Format(*this, format, args); FormatParser().Format(*this, format, args);
} }
FMT_VARIADIC_VOID(format, fmt::BasicStringRef<Char>)
inline void printf(BasicStringRef<Char> format, const ArgList &args) { inline void printf(BasicStringRef<Char> format, const ArgList &args) {
PrintfParser().Format(*this, format, args); PrintfParser().Format(*this, format, args);
} }
FMT_VARIADIC_VOID(printf, fmt::BasicStringRef<Char>)
/** /**
\rst \rst
@ -1240,47 +1287,9 @@ class BasicWriter {
BasicFormatter<Char> Format(StringRef format); BasicFormatter<Char> Format(StringRef format);
#if FMT_USE_VARIADIC_TEMPLATES #if FMT_USE_VARIADIC_TEMPLATES
/** // This function is deprecated, use Writer::format instead.
\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> template<typename... Args>
void Format(BasicStringRef<Char> format, const Args & ... args) { FMT_DEPRECATED(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 #endif
template <typename T> template <typename T>
@ -1955,6 +1964,13 @@ inline Formatter<ANSITerminalSink> PrintColored(Color c, StringRef format) {
#if FMT_USE_VARIADIC_TEMPLATES && FMT_USE_RVALUE_REFERENCES #if 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...);
}
/** /**
\rst \rst
Formats a string similarly to Python's `str.format Formats a string similarly to Python's `str.format
@ -2165,7 +2181,7 @@ inline void FormatDec(char *&buffer, T value) {
#define FMT_ADD_ARG_NAME(type, index) type arg##index #define FMT_ADD_ARG_NAME(type, index) type arg##index
#define FMT_GET_ARG_NAME(type, index) arg##index #define FMT_GET_ARG_NAME(type, index) arg##index
#define FMT_MAKE_ARG(arg, index) fmt::Writer::MakeArg(arg) #define FMT_MAKE_ARG2(arg, index) fmt::Writer::MakeArg(arg)
#define FMT_VARIADIC(return_type, func_name, ...) \ #define FMT_VARIADIC(return_type, func_name, ...) \
inline return_type func_name(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__)) { \ inline return_type func_name(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__)) { \
@ -2175,14 +2191,14 @@ inline void FormatDec(char *&buffer, T value) {
template <typename T1> \ template <typename T1> \
inline return_type func_name(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ inline return_type func_name(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \
const T1 &v1) { \ const T1 &v1) { \
const fmt::internal::ArgInfo args[] = {FMT_FOR_EACH(FMT_MAKE_ARG, v1)}; \ const fmt::internal::ArgInfo args[] = {FMT_FOR_EACH(FMT_MAKE_ARG2, v1)}; \
return func_name(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ return func_name(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \
fmt::ArgList(args, sizeof(args) / sizeof(*args))); \ fmt::ArgList(args, sizeof(args) / sizeof(*args))); \
} \ } \
template <typename T1, typename T2> \ template <typename T1, typename T2> \
inline return_type func_name(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ inline return_type func_name(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \
const T1 &v1, const T2 &v2) { \ const T1 &v1, const T2 &v2) { \
const fmt::internal::ArgInfo args[] = {FMT_FOR_EACH(FMT_MAKE_ARG, v1, v2)}; \ const fmt::internal::ArgInfo args[] = {FMT_FOR_EACH(FMT_MAKE_ARG2, v1, v2)}; \
return func_name(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ return func_name(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \
fmt::ArgList(args, sizeof(args) / sizeof(*args))); \ fmt::ArgList(args, sizeof(args) / sizeof(*args))); \
} \ } \
@ -2190,7 +2206,7 @@ inline void FormatDec(char *&buffer, T value) {
inline return_type func_name(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ inline return_type func_name(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \
const T1 &v1, const T2 &v2, const T3 &v3) { \ const T1 &v1, const T2 &v2, const T3 &v3) { \
const fmt::internal::ArgInfo args[] = { \ const fmt::internal::ArgInfo args[] = { \
FMT_FOR_EACH(FMT_MAKE_ARG, v1, v2, v3) \ FMT_FOR_EACH(FMT_MAKE_ARG2, v1, v2, v3) \
}; \ }; \
return func_name(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ return func_name(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \
fmt::ArgList(args, sizeof(args) / sizeof(*args))); \ fmt::ArgList(args, sizeof(args) / sizeof(*args))); \
@ -2199,7 +2215,7 @@ inline void FormatDec(char *&buffer, T value) {
inline return_type func_name(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ 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 T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4) { \
const fmt::internal::ArgInfo args[] = { \ const fmt::internal::ArgInfo args[] = { \
FMT_FOR_EACH(FMT_MAKE_ARG, v1, v2, v3, v4) \ FMT_FOR_EACH(FMT_MAKE_ARG2, v1, v2, v3, v4) \
}; \ }; \
return func_name(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ return func_name(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \
fmt::ArgList(args, sizeof(args) / sizeof(*args))); \ fmt::ArgList(args, sizeof(args) / sizeof(*args))); \
@ -2208,7 +2224,7 @@ inline void FormatDec(char *&buffer, T value) {
inline return_type func_name(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ 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 T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4, const T5 &v5) { \
const fmt::internal::ArgInfo args[] = { \ const fmt::internal::ArgInfo args[] = { \
FMT_FOR_EACH(FMT_MAKE_ARG, v1, v2, v3, v4, v5) \ FMT_FOR_EACH(FMT_MAKE_ARG2, v1, v2, v3, v4, v5) \
}; \ }; \
return func_name(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \ return func_name(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), \
fmt::ArgList(args, sizeof(args) / sizeof(*args))); \ fmt::ArgList(args, sizeof(args) / sizeof(*args))); \