mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-30 10:47:35 +02:00
Don't inherit basic_format_arg from internal::Value
This commit is contained in:
528
fmt/format.h
528
fmt/format.h
@ -989,146 +989,27 @@ FMT_API void format_windows_error(fmt::Writer &out, int error_code,
|
|||||||
fmt::StringRef message) FMT_NOEXCEPT;
|
fmt::StringRef message) FMT_NOEXCEPT;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum Type {
|
template<bool B, class T = void>
|
||||||
NONE, NAMED_ARG,
|
struct EnableIf {};
|
||||||
// Integer types should go first,
|
|
||||||
INT, UINT, LONG_LONG, ULONG_LONG, BOOL, CHAR, LAST_INTEGER_TYPE = CHAR,
|
|
||||||
// followed by floating-point types.
|
|
||||||
DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE,
|
|
||||||
CSTRING, STRING, TSTRING, POINTER, CUSTOM
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Char>
|
template<class T>
|
||||||
struct StringValue {
|
struct EnableIf<true, T> { typedef T type; };
|
||||||
const Char *value;
|
|
||||||
std::size_t size;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef void (*FormatFunc)(void *writer, const void *arg, void *ctx);
|
template<bool B, class T, class F>
|
||||||
|
struct Conditional { typedef T type; };
|
||||||
|
|
||||||
struct CustomValue {
|
template<class T, class F>
|
||||||
const void *value;
|
struct Conditional<false, T, F> { typedef F type; };
|
||||||
FormatFunc format;
|
|
||||||
};
|
|
||||||
|
|
||||||
// A formatting argument value.
|
// For bcc32 which doesn't understand ! in template arguments.
|
||||||
template <typename Char>
|
template <bool>
|
||||||
struct Value {
|
struct Not { enum { value = 0 }; };
|
||||||
union {
|
|
||||||
int int_value;
|
|
||||||
unsigned uint_value;
|
|
||||||
LongLong long_long_value;
|
|
||||||
ULongLong ulong_long_value;
|
|
||||||
double double_value;
|
|
||||||
long double long_double_value;
|
|
||||||
const void *pointer;
|
|
||||||
StringValue<char> string;
|
|
||||||
StringValue<signed char> sstring;
|
|
||||||
StringValue<unsigned char> ustring;
|
|
||||||
StringValue<Char> tstring;
|
|
||||||
CustomValue custom;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Char>
|
template <>
|
||||||
class ArgMap;
|
struct Not<false> { enum { value = 1 }; };
|
||||||
} // namespace internal
|
|
||||||
|
|
||||||
template <typename Context, typename Char>
|
template <typename T>
|
||||||
class basic_format_args;
|
struct False { enum { value = 0 }; };
|
||||||
|
|
||||||
// A formatting argument. It is a trivially copyable/constructible type to
|
|
||||||
// allow storage in internal::MemoryBuffer.
|
|
||||||
template <typename Char>
|
|
||||||
class basic_format_arg : public internal::Value<Char> {
|
|
||||||
protected:
|
|
||||||
internal::Type type_;
|
|
||||||
|
|
||||||
template <typename Visitor, typename CharType>
|
|
||||||
friend typename std::result_of<Visitor(int)>::type
|
|
||||||
visit(Visitor &&vis, basic_format_arg<CharType> arg);
|
|
||||||
|
|
||||||
template <typename Context, typename CharType>
|
|
||||||
friend class basic_format_args;
|
|
||||||
|
|
||||||
template <typename CharType>
|
|
||||||
friend class internal::ArgMap;
|
|
||||||
|
|
||||||
void check_type() const {
|
|
||||||
FMT_ASSERT(type_ > internal::NAMED_ARG, "invalid argument type");
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit operator bool() const noexcept { return type_ != internal::NONE; }
|
|
||||||
|
|
||||||
bool is_integral() const {
|
|
||||||
check_type();
|
|
||||||
return type_ <= internal::LAST_INTEGER_TYPE;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_numeric() const {
|
|
||||||
check_type();
|
|
||||||
return type_ <= internal::LAST_NUMERIC_TYPE;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_pointer() const {
|
|
||||||
check_type();
|
|
||||||
return type_ == internal::POINTER;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef basic_format_arg<char> format_arg;
|
|
||||||
typedef basic_format_arg<wchar_t> wformat_arg;
|
|
||||||
|
|
||||||
/**
|
|
||||||
\rst
|
|
||||||
Visits an argument dispatching to the appropriate visit method based on
|
|
||||||
the argument type. For example, if the argument type is ``double`` then
|
|
||||||
``vis(value)`` will be called with the value of type ``double``.
|
|
||||||
\endrst
|
|
||||||
*/
|
|
||||||
template <typename Visitor, typename Char>
|
|
||||||
typename std::result_of<Visitor(int)>::type
|
|
||||||
visit(Visitor &&vis, basic_format_arg<Char> arg) {
|
|
||||||
switch (arg.type_) {
|
|
||||||
case internal::NONE:
|
|
||||||
case internal::NAMED_ARG:
|
|
||||||
FMT_ASSERT(false, "invalid argument type");
|
|
||||||
break;
|
|
||||||
case internal::INT:
|
|
||||||
return vis(arg.int_value);
|
|
||||||
case internal::UINT:
|
|
||||||
return vis(arg.uint_value);
|
|
||||||
case internal::LONG_LONG:
|
|
||||||
return vis(arg.long_long_value);
|
|
||||||
case internal::ULONG_LONG:
|
|
||||||
return vis(arg.ulong_long_value);
|
|
||||||
case internal::BOOL:
|
|
||||||
return vis(arg.int_value != 0);
|
|
||||||
case internal::CHAR:
|
|
||||||
return vis(static_cast<Char>(arg.int_value));
|
|
||||||
case internal::DOUBLE:
|
|
||||||
return vis(arg.double_value);
|
|
||||||
case internal::LONG_DOUBLE:
|
|
||||||
return vis(arg.long_double_value);
|
|
||||||
case internal::CSTRING:
|
|
||||||
return vis(arg.string.value);
|
|
||||||
case internal::STRING:
|
|
||||||
return vis(StringRef(arg.string.value, arg.string.size));
|
|
||||||
case internal::TSTRING:
|
|
||||||
return vis(BasicStringRef<Char>(arg.tstring.value, arg.tstring.size));
|
|
||||||
case internal::POINTER:
|
|
||||||
return vis(arg.pointer);
|
|
||||||
case internal::CUSTOM:
|
|
||||||
return vis(arg.custom);
|
|
||||||
}
|
|
||||||
return typename std::result_of<Visitor(int)>::type();
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace internal {
|
|
||||||
|
|
||||||
template <typename Char>
|
|
||||||
struct NamedArg;
|
|
||||||
|
|
||||||
template <typename T = void>
|
template <typename T = void>
|
||||||
struct Null {};
|
struct Null {};
|
||||||
@ -1190,71 +1071,49 @@ FMT_DISABLE_CONVERSION_TO_INT(float);
|
|||||||
FMT_DISABLE_CONVERSION_TO_INT(double);
|
FMT_DISABLE_CONVERSION_TO_INT(double);
|
||||||
FMT_DISABLE_CONVERSION_TO_INT(long double);
|
FMT_DISABLE_CONVERSION_TO_INT(long double);
|
||||||
|
|
||||||
template<bool B, class T = void>
|
enum Type {
|
||||||
struct EnableIf {};
|
NONE, NAMED_ARG,
|
||||||
|
// Integer types should go first,
|
||||||
template<class T>
|
INT, UINT, LONG_LONG, ULONG_LONG, BOOL, CHAR, LAST_INTEGER_TYPE = CHAR,
|
||||||
struct EnableIf<true, T> { typedef T type; };
|
// followed by floating-point types.
|
||||||
|
DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE,
|
||||||
template<bool B, class T, class F>
|
CSTRING, STRING, TSTRING, POINTER, CUSTOM
|
||||||
struct Conditional { typedef T type; };
|
|
||||||
|
|
||||||
template<class T, class F>
|
|
||||||
struct Conditional<false, T, F> { typedef F type; };
|
|
||||||
|
|
||||||
// For bcc32 which doesn't understand ! in template arguments.
|
|
||||||
template <bool>
|
|
||||||
struct Not { enum { value = 0 }; };
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct Not<false> { enum { value = 1 }; };
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct False { enum { value = 0 }; };
|
|
||||||
|
|
||||||
template <typename T, T> struct LConvCheck {
|
|
||||||
LConvCheck(int) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns the thousands separator for the current locale.
|
template <typename Char>
|
||||||
// We check if ``lconv`` contains ``thousands_sep`` because on Android
|
struct StringValue {
|
||||||
// ``lconv`` is stubbed as an empty struct.
|
const Char *value;
|
||||||
template <typename LConv>
|
std::size_t size;
|
||||||
inline StringRef thousands_sep(
|
};
|
||||||
LConv *lc, LConvCheck<char *LConv::*, &LConv::thousands_sep> = 0) {
|
|
||||||
return lc->thousands_sep;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline fmt::StringRef thousands_sep(...) { return ""; }
|
typedef void (*FormatFunc)(void *writer, const void *arg, void *ctx);
|
||||||
|
|
||||||
#define FMT_CONCAT(a, b) a##b
|
struct CustomValue {
|
||||||
|
const void *value;
|
||||||
|
FormatFunc format;
|
||||||
|
};
|
||||||
|
|
||||||
#if FMT_GCC_VERSION >= 407
|
// A formatting argument value.
|
||||||
# define FMT_UNUSED __attribute__((unused))
|
template <typename Char>
|
||||||
#else
|
struct Value {
|
||||||
# define FMT_UNUSED
|
union {
|
||||||
#endif
|
int int_value;
|
||||||
|
unsigned uint_value;
|
||||||
|
LongLong long_long_value;
|
||||||
|
ULongLong ulong_long_value;
|
||||||
|
double double_value;
|
||||||
|
long double long_double_value;
|
||||||
|
const void *pointer;
|
||||||
|
StringValue<char> string;
|
||||||
|
StringValue<signed char> sstring;
|
||||||
|
StringValue<unsigned char> ustring;
|
||||||
|
StringValue<Char> tstring;
|
||||||
|
CustomValue custom;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
#ifndef FMT_USE_STATIC_ASSERT
|
template <typename Char>
|
||||||
# define FMT_USE_STATIC_ASSERT 0
|
struct NamedArg;
|
||||||
#endif
|
|
||||||
|
|
||||||
#if FMT_USE_STATIC_ASSERT || FMT_HAS_FEATURE(cxx_static_assert) || \
|
|
||||||
(FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600
|
|
||||||
# define FMT_STATIC_ASSERT(cond, message) static_assert(cond, message)
|
|
||||||
#else
|
|
||||||
# define FMT_CONCAT_(a, b) FMT_CONCAT(a, b)
|
|
||||||
# define FMT_STATIC_ASSERT(cond, message) \
|
|
||||||
typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template <typename Formatter, typename T, typename Char>
|
|
||||||
void format_value(BasicWriter<Char> &, const T &, Formatter &, const Char *) {
|
|
||||||
FMT_STATIC_ASSERT(False<T>::value,
|
|
||||||
"Cannot format argument. To enable the use of ostream "
|
|
||||||
"operator<< include fmt/ostream.h. Otherwise provide "
|
|
||||||
"an overload of format_arg.");
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct IsNamedArg : std::false_type {};
|
struct IsNamedArg : std::false_type {};
|
||||||
@ -1264,81 +1123,57 @@ struct IsNamedArg< NamedArg<Char> > : std::true_type {};
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr Type gettype() {
|
constexpr Type gettype() {
|
||||||
typedef format_arg Arg;
|
|
||||||
return IsNamedArg<T>::value ?
|
return IsNamedArg<T>::value ?
|
||||||
internal::NAMED_ARG :
|
NAMED_ARG : (ConvertToInt<T>::value ? INT : CUSTOM);
|
||||||
(ConvertToInt<T>::value ? internal::INT : internal::CUSTOM);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <> constexpr Type gettype<bool>() { return internal::BOOL; }
|
template <> constexpr Type gettype<bool>() { return BOOL; }
|
||||||
template <> constexpr Type gettype<short>() { return internal::INT; }
|
template <> constexpr Type gettype<short>() { return INT; }
|
||||||
template <> constexpr Type gettype<unsigned short>() {
|
template <> constexpr Type gettype<unsigned short>() { return UINT; }
|
||||||
return internal::UINT;
|
template <> constexpr Type gettype<int>() { return INT; }
|
||||||
}
|
template <> constexpr Type gettype<unsigned>() { return UINT; }
|
||||||
template <> constexpr Type gettype<int>() { return internal::INT; }
|
|
||||||
template <> constexpr Type gettype<unsigned>() { return internal::UINT; }
|
|
||||||
template <> constexpr Type gettype<long>() {
|
template <> constexpr Type gettype<long>() {
|
||||||
return sizeof(long) == sizeof(int) ? internal::INT : internal::LONG_LONG;
|
return sizeof(long) == sizeof(int) ? INT : LONG_LONG;
|
||||||
}
|
}
|
||||||
template <> constexpr Type gettype<unsigned long>() {
|
template <> constexpr Type gettype<unsigned long>() {
|
||||||
return sizeof(unsigned long) == sizeof(unsigned) ?
|
return sizeof(unsigned long) == sizeof(unsigned) ?
|
||||||
internal::UINT : internal::ULONG_LONG;
|
UINT : ULONG_LONG;
|
||||||
}
|
}
|
||||||
template <> constexpr Type gettype<LongLong>() { return internal::LONG_LONG; }
|
template <> constexpr Type gettype<LongLong>() { return LONG_LONG; }
|
||||||
template <> constexpr Type gettype<ULongLong>() {
|
template <> constexpr Type gettype<ULongLong>() { return ULONG_LONG; }
|
||||||
return internal::ULONG_LONG;
|
template <> constexpr Type gettype<float>() { return DOUBLE; }
|
||||||
}
|
template <> constexpr Type gettype<double>() { return DOUBLE; }
|
||||||
template <> constexpr Type gettype<float>() { return internal::DOUBLE; }
|
template <> constexpr Type gettype<long double>() { return LONG_DOUBLE; }
|
||||||
template <> constexpr Type gettype<double>() { return internal::DOUBLE; }
|
template <> constexpr Type gettype<signed char>() { return INT; }
|
||||||
template <> constexpr Type gettype<long double>() {
|
template <> constexpr Type gettype<unsigned char>() { return UINT; }
|
||||||
return internal::LONG_DOUBLE;
|
template <> constexpr Type gettype<char>() { return CHAR; }
|
||||||
}
|
|
||||||
template <> constexpr Type gettype<signed char>() { return internal::INT; }
|
|
||||||
template <> constexpr Type gettype<unsigned char>() { return internal::UINT; }
|
|
||||||
template <> constexpr Type gettype<char>() { return internal::CHAR; }
|
|
||||||
|
|
||||||
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
|
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
|
||||||
template <> constexpr Type gettype<wchar_t>() { return internal::CHAR; }
|
template <> constexpr Type gettype<wchar_t>() { return CHAR; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <> constexpr Type gettype<char *>() { return internal::CSTRING; }
|
template <> constexpr Type gettype<char *>() { return CSTRING; }
|
||||||
template <> constexpr Type gettype<const char *>() {
|
template <> constexpr Type gettype<const char *>() { return CSTRING; }
|
||||||
return internal::CSTRING;
|
template <> constexpr Type gettype<signed char *>() { return CSTRING; }
|
||||||
}
|
template <> constexpr Type gettype<const signed char *>() { return CSTRING; }
|
||||||
template <> constexpr Type gettype<signed char *>() {
|
template <> constexpr Type gettype<unsigned char *>() { return CSTRING; }
|
||||||
return internal::CSTRING;
|
template <> constexpr Type gettype<const unsigned char *>() { return CSTRING; }
|
||||||
}
|
template <> constexpr Type gettype<std::string>() { return STRING; }
|
||||||
template <> constexpr Type gettype<const signed char *>() {
|
template <> constexpr Type gettype<StringRef>() { return STRING; }
|
||||||
return internal::CSTRING;
|
template <> constexpr Type gettype<CStringRef>() { return CSTRING; }
|
||||||
}
|
template <> constexpr Type gettype<wchar_t *>() { return TSTRING; }
|
||||||
template <> constexpr Type gettype<unsigned char *>() {
|
template <> constexpr Type gettype<const wchar_t *>() { return TSTRING; }
|
||||||
return internal::CSTRING;
|
template <> constexpr Type gettype<std::wstring>() { return TSTRING; }
|
||||||
}
|
template <> constexpr Type gettype<WStringRef>() { return TSTRING; }
|
||||||
template <> constexpr Type gettype<const unsigned char *>() {
|
template <> constexpr Type gettype<void *>() { return POINTER; }
|
||||||
return internal::CSTRING;
|
template <> constexpr Type gettype<const void *>() { return POINTER; }
|
||||||
}
|
|
||||||
template <> constexpr Type gettype<std::string>() { return internal::STRING; }
|
|
||||||
template <> constexpr Type gettype<StringRef>() { return internal::STRING; }
|
|
||||||
template <> constexpr Type gettype<CStringRef>() { return internal::CSTRING; }
|
|
||||||
template <> constexpr Type gettype<wchar_t *>() { return internal::TSTRING; }
|
|
||||||
template <> constexpr Type gettype<const wchar_t *>() {
|
|
||||||
return internal::TSTRING;
|
|
||||||
}
|
|
||||||
template <> constexpr Type gettype<std::wstring>() {
|
|
||||||
return internal::TSTRING;
|
|
||||||
}
|
|
||||||
template <> constexpr Type gettype<WStringRef>() { return internal::TSTRING; }
|
|
||||||
template <> constexpr Type gettype<void *>() { return internal::POINTER; }
|
|
||||||
template <> constexpr Type gettype<const void *>() {
|
|
||||||
return internal::POINTER;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
constexpr Type type() { return gettype<typename std::decay<T>::type>(); }
|
constexpr Type type() { return gettype<typename std::decay<T>::type>(); }
|
||||||
|
|
||||||
// Makes a format_arg object from any type.
|
// Makes a format_arg object from any type.
|
||||||
template <typename Context>
|
template <typename Context>
|
||||||
class MakeValue : public basic_format_arg<typename Context::char_type> {
|
class MakeValue : public Value<typename Context::char_type> {
|
||||||
public:
|
public:
|
||||||
typedef typename Context::char_type Char;
|
typedef typename Context::char_type Char;
|
||||||
|
|
||||||
@ -1492,20 +1327,165 @@ class MakeValue : public basic_format_arg<typename Context::char_type> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
class ArgMap;
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
template <typename Context, typename Char>
|
||||||
|
class basic_format_args;
|
||||||
|
|
||||||
|
// A formatting argument. It is a trivially copyable/constructible type to
|
||||||
|
// allow storage in internal::MemoryBuffer.
|
||||||
|
template <typename Char>
|
||||||
|
class basic_format_arg {
|
||||||
|
protected:
|
||||||
|
internal::Value<Char> value_;
|
||||||
|
internal::Type type_;
|
||||||
|
|
||||||
|
template <typename Visitor, typename CharType>
|
||||||
|
friend typename std::result_of<Visitor(int)>::type
|
||||||
|
visit(Visitor &&vis, basic_format_arg<CharType> arg);
|
||||||
|
|
||||||
|
template <typename Context, typename CharType>
|
||||||
|
friend class basic_format_args;
|
||||||
|
|
||||||
|
template <typename CharType>
|
||||||
|
friend class internal::ArgMap;
|
||||||
|
|
||||||
|
void check_type() const {
|
||||||
|
FMT_ASSERT(type_ > internal::NAMED_ARG, "invalid argument type");
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
basic_format_arg() : type_(internal::NONE) {}
|
||||||
|
|
||||||
|
explicit operator bool() const noexcept { return type_ != internal::NONE; }
|
||||||
|
|
||||||
|
bool is_integral() const {
|
||||||
|
check_type();
|
||||||
|
return type_ <= internal::LAST_INTEGER_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_numeric() const {
|
||||||
|
check_type();
|
||||||
|
return type_ <= internal::LAST_NUMERIC_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_pointer() const {
|
||||||
|
check_type();
|
||||||
|
return type_ == internal::POINTER;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef basic_format_arg<char> format_arg;
|
||||||
|
typedef basic_format_arg<wchar_t> wformat_arg;
|
||||||
|
|
||||||
|
/**
|
||||||
|
\rst
|
||||||
|
Visits an argument dispatching to the appropriate visit method based on
|
||||||
|
the argument type. For example, if the argument type is ``double`` then
|
||||||
|
``vis(value)`` will be called with the value of type ``double``.
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
|
template <typename Visitor, typename Char>
|
||||||
|
typename std::result_of<Visitor(int)>::type
|
||||||
|
visit(Visitor &&vis, basic_format_arg<Char> arg) {
|
||||||
|
switch (arg.type_) {
|
||||||
|
case internal::NONE:
|
||||||
|
case internal::NAMED_ARG:
|
||||||
|
FMT_ASSERT(false, "invalid argument type");
|
||||||
|
break;
|
||||||
|
case internal::INT:
|
||||||
|
return vis(arg.value_.int_value);
|
||||||
|
case internal::UINT:
|
||||||
|
return vis(arg.value_.uint_value);
|
||||||
|
case internal::LONG_LONG:
|
||||||
|
return vis(arg.value_.long_long_value);
|
||||||
|
case internal::ULONG_LONG:
|
||||||
|
return vis(arg.value_.ulong_long_value);
|
||||||
|
case internal::BOOL:
|
||||||
|
return vis(arg.value_.int_value != 0);
|
||||||
|
case internal::CHAR:
|
||||||
|
return vis(static_cast<Char>(arg.value_.int_value));
|
||||||
|
case internal::DOUBLE:
|
||||||
|
return vis(arg.value_.double_value);
|
||||||
|
case internal::LONG_DOUBLE:
|
||||||
|
return vis(arg.value_.long_double_value);
|
||||||
|
case internal::CSTRING:
|
||||||
|
return vis(arg.value_.string.value);
|
||||||
|
case internal::STRING:
|
||||||
|
return vis(StringRef(arg.value_.string.value, arg.value_.string.size));
|
||||||
|
case internal::TSTRING:
|
||||||
|
return vis(BasicStringRef<Char>(
|
||||||
|
arg.value_.tstring.value, arg.value_.tstring.size));
|
||||||
|
case internal::POINTER:
|
||||||
|
return vis(arg.value_.pointer);
|
||||||
|
case internal::CUSTOM:
|
||||||
|
return vis(arg.value_.custom);
|
||||||
|
}
|
||||||
|
return typename std::result_of<Visitor(int)>::type();
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
template <typename Context>
|
template <typename Context>
|
||||||
class MakeArg : public basic_format_arg<typename Context::char_type> {
|
class MakeArg : public basic_format_arg<typename Context::char_type> {
|
||||||
public:
|
public:
|
||||||
MakeArg() {
|
MakeArg() {
|
||||||
this->type_ = internal::NONE;
|
this->type_ = internal::NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
MakeArg(const T &value)
|
MakeArg(const T &value) {
|
||||||
: basic_format_arg<typename Context::char_type>(MakeValue<Context>(value)) {
|
this->value_ = internal::MakeValue<Context>(value);
|
||||||
this->type_ = internal::type<T>();
|
this->type_ = internal::type<T>();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T, T> struct LConvCheck {
|
||||||
|
LConvCheck(int) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns the thousands separator for the current locale.
|
||||||
|
// We check if ``lconv`` contains ``thousands_sep`` because on Android
|
||||||
|
// ``lconv`` is stubbed as an empty struct.
|
||||||
|
template <typename LConv>
|
||||||
|
inline StringRef thousands_sep(
|
||||||
|
LConv *lc, LConvCheck<char *LConv::*, &LConv::thousands_sep> = 0) {
|
||||||
|
return lc->thousands_sep;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fmt::StringRef thousands_sep(...) { return ""; }
|
||||||
|
|
||||||
|
#define FMT_CONCAT(a, b) a##b
|
||||||
|
|
||||||
|
#if FMT_GCC_VERSION >= 407
|
||||||
|
# define FMT_UNUSED __attribute__((unused))
|
||||||
|
#else
|
||||||
|
# define FMT_UNUSED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FMT_USE_STATIC_ASSERT
|
||||||
|
# define FMT_USE_STATIC_ASSERT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if FMT_USE_STATIC_ASSERT || FMT_HAS_FEATURE(cxx_static_assert) || \
|
||||||
|
(FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600
|
||||||
|
# define FMT_STATIC_ASSERT(cond, message) static_assert(cond, message)
|
||||||
|
#else
|
||||||
|
# define FMT_CONCAT_(a, b) FMT_CONCAT(a, b)
|
||||||
|
# define FMT_STATIC_ASSERT(cond, message) \
|
||||||
|
typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename Formatter, typename T, typename Char>
|
||||||
|
void format_value(BasicWriter<Char> &, const T &, Formatter &, const Char *) {
|
||||||
|
FMT_STATIC_ASSERT(False<T>::value,
|
||||||
|
"Cannot format argument. To enable the use of ostream "
|
||||||
|
"operator<< include fmt/ostream.h. Otherwise provide "
|
||||||
|
"an overload of format_arg.");
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
struct NamedArg : basic_format_arg<Char> {
|
struct NamedArg : basic_format_arg<Char> {
|
||||||
BasicStringRef<Char> name;
|
BasicStringRef<Char> name;
|
||||||
@ -1532,27 +1512,39 @@ constexpr uint64_t make_type<void>() { return 0; }
|
|||||||
|
|
||||||
// Maximum number of arguments with packed types.
|
// Maximum number of arguments with packed types.
|
||||||
enum { MAX_PACKED_ARGS = 16 };
|
enum { MAX_PACKED_ARGS = 16 };
|
||||||
|
|
||||||
|
template <bool PACKED, typename Context, typename T>
|
||||||
|
inline typename std::enable_if<PACKED, Value<typename Context::char_type>>::type
|
||||||
|
make_arg(const T& value) {
|
||||||
|
return MakeValue<Context>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <bool PACKED, typename Context, typename T>
|
||||||
|
inline typename std::enable_if<!PACKED, format_arg>::type
|
||||||
|
make_arg(const T& value) {
|
||||||
|
return MakeArg<Context>(value);
|
||||||
|
}
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
template <typename Context, typename ...Args>
|
template <typename Context, typename ...Args>
|
||||||
class format_arg_store {
|
class format_arg_store {
|
||||||
private:
|
private:
|
||||||
static const size_t NUM_ARGS = sizeof...(Args);
|
static const size_t NUM_ARGS = sizeof...(Args);
|
||||||
static const bool IS_PACKED = NUM_ARGS < internal::MAX_PACKED_ARGS;
|
static const bool PACKED = NUM_ARGS < internal::MAX_PACKED_ARGS;
|
||||||
|
|
||||||
typedef typename Context::char_type char_type;
|
typedef typename Context::char_type char_type;
|
||||||
|
|
||||||
typedef typename std::conditional<IS_PACKED,
|
typedef typename std::conditional<PACKED,
|
||||||
internal::Value<char_type>, basic_format_arg<char_type>>::type value_type;
|
internal::Value<char_type>, basic_format_arg<char_type>>::type value_type;
|
||||||
|
|
||||||
// If the arguments are not packed, add one more element to mark the end.
|
// If the arguments are not packed, add one more element to mark the end.
|
||||||
std::array<value_type, NUM_ARGS + (IS_PACKED ? 0 : 1)> data_;
|
std::array<value_type, NUM_ARGS + (PACKED ? 0 : 1)> data_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const uint64_t TYPES = internal::make_type<Args..., void>();
|
static const uint64_t TYPES = internal::make_type<Args..., void>();
|
||||||
|
|
||||||
format_arg_store(const Args &... args)
|
format_arg_store(const Args &... args)
|
||||||
: data_{{internal::MakeArg<Context>(args)...}} {}
|
: data_{{internal::make_arg<PACKED, Context>(args)...}} {}
|
||||||
|
|
||||||
const value_type *data() const { return data_.data(); }
|
const value_type *data() const { return data_.data(); }
|
||||||
};
|
};
|
||||||
@ -1607,9 +1599,9 @@ class basic_format_args {
|
|||||||
bool use_values = type(internal::MAX_PACKED_ARGS - 1) == internal::NONE;
|
bool use_values = type(internal::MAX_PACKED_ARGS - 1) == internal::NONE;
|
||||||
if (index < internal::MAX_PACKED_ARGS) {
|
if (index < internal::MAX_PACKED_ARGS) {
|
||||||
typename internal::Type arg_type = type(index);
|
typename internal::Type arg_type = type(index);
|
||||||
internal::Value<Char> &val = arg;
|
internal::Value<Char> &val = arg.value_;
|
||||||
if (arg_type != internal::NONE)
|
if (arg_type != internal::NONE)
|
||||||
val = use_values ? values_[index] : args_[index];
|
val = use_values ? values_[index] : args_[index].value_;
|
||||||
arg.type_ = arg_type;
|
arg.type_ = arg_type;
|
||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
@ -1639,7 +1631,7 @@ class basic_format_args {
|
|||||||
format_arg operator[](size_type index) const {
|
format_arg operator[](size_type index) const {
|
||||||
format_arg arg = get(index);
|
format_arg arg = get(index);
|
||||||
return arg.type_ == internal::NAMED_ARG ?
|
return arg.type_ == internal::NAMED_ARG ?
|
||||||
*static_cast<const format_arg*>(arg.pointer) : arg;
|
*static_cast<const format_arg*>(arg.value_.pointer) : arg;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1922,7 +1914,7 @@ void ArgMap<Char>::init(const basic_format_args<Context, Char> &args) {
|
|||||||
for (unsigned i = 0; i != MAX_PACKED_ARGS; ++i) {
|
for (unsigned i = 0; i != MAX_PACKED_ARGS; ++i) {
|
||||||
internal::Type arg_type = args.type(i);
|
internal::Type arg_type = args.type(i);
|
||||||
if (arg_type == internal::NAMED_ARG) {
|
if (arg_type == internal::NAMED_ARG) {
|
||||||
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
|
named_arg = static_cast<const NamedArg*>(args.args_[i].value_.pointer);
|
||||||
map_.push_back(Pair(named_arg->name, *named_arg));
|
map_.push_back(Pair(named_arg->name, *named_arg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1931,7 +1923,7 @@ void ArgMap<Char>::init(const basic_format_args<Context, Char> &args) {
|
|||||||
case internal::NONE:
|
case internal::NONE:
|
||||||
return;
|
return;
|
||||||
case internal::NAMED_ARG:
|
case internal::NAMED_ARG:
|
||||||
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
|
named_arg = static_cast<const NamedArg*>(args.args_[i].value_.pointer);
|
||||||
map_.push_back(Pair(named_arg->name, *named_arg));
|
map_.push_back(Pair(named_arg->name, *named_arg));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -3497,7 +3489,7 @@ void do_format_arg(BasicWriter<Char> &writer, const basic_format_arg<Char> &arg,
|
|||||||
spec.fill_ = c;
|
spec.fill_ = c;
|
||||||
} else ++s;
|
} else ++s;
|
||||||
if (spec.align_ == ALIGN_NUMERIC)
|
if (spec.align_ == ALIGN_NUMERIC)
|
||||||
require_numeric_argument(arg, '=');
|
internal::require_numeric_argument(arg, '=');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while (--p >= s);
|
} while (--p >= s);
|
||||||
@ -3506,28 +3498,28 @@ void do_format_arg(BasicWriter<Char> &writer, const basic_format_arg<Char> &arg,
|
|||||||
// Parse sign.
|
// Parse sign.
|
||||||
switch (*s) {
|
switch (*s) {
|
||||||
case '+':
|
case '+':
|
||||||
check_sign(s, arg);
|
internal::check_sign(s, arg);
|
||||||
spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
|
spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
|
||||||
break;
|
break;
|
||||||
case '-':
|
case '-':
|
||||||
check_sign(s, arg);
|
internal::check_sign(s, arg);
|
||||||
spec.flags_ |= MINUS_FLAG;
|
spec.flags_ |= MINUS_FLAG;
|
||||||
break;
|
break;
|
||||||
case ' ':
|
case ' ':
|
||||||
check_sign(s, arg);
|
internal::check_sign(s, arg);
|
||||||
spec.flags_ |= SIGN_FLAG;
|
spec.flags_ |= SIGN_FLAG;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*s == '#') {
|
if (*s == '#') {
|
||||||
require_numeric_argument(arg, '#');
|
internal::require_numeric_argument(arg, '#');
|
||||||
spec.flags_ |= HASH_FLAG;
|
spec.flags_ |= HASH_FLAG;
|
||||||
++s;
|
++s;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse zero flag.
|
// Parse zero flag.
|
||||||
if (*s == '0') {
|
if (*s == '0') {
|
||||||
require_numeric_argument(arg, '0');
|
internal::require_numeric_argument(arg, '0');
|
||||||
spec.align_ = ALIGN_NUMERIC;
|
spec.align_ = ALIGN_NUMERIC;
|
||||||
spec.fill_ = '0';
|
spec.fill_ = '0';
|
||||||
++s;
|
++s;
|
||||||
|
@ -424,7 +424,7 @@ void format_value(fmt::Writer &, const Test &, CustomFormatter &ctx) {
|
|||||||
|
|
||||||
TEST(UtilTest, MakeValueWithCustomFormatter) {
|
TEST(UtilTest, MakeValueWithCustomFormatter) {
|
||||||
::Test t;
|
::Test t;
|
||||||
format_arg arg = fmt::internal::MakeValue<CustomFormatter>(t);
|
fmt::internal::Value<char> arg = fmt::internal::MakeValue<CustomFormatter>(t);
|
||||||
CustomFormatter ctx = {false};
|
CustomFormatter ctx = {false};
|
||||||
fmt::MemoryWriter w;
|
fmt::MemoryWriter w;
|
||||||
arg.custom.format(&w, &t, &ctx);
|
arg.custom.format(&w, &t, &ctx);
|
||||||
|
Reference in New Issue
Block a user