Move ArgInfo to internal namespace and add ArgList.

This commit is contained in:
Victor Zverovich 2014-06-24 07:54:26 -07:00
parent 8d4535e76c
commit ea99bfb902
2 changed files with 244 additions and 203 deletions

190
format.cc
View File

@ -331,8 +331,8 @@ int fmt::internal::ParseNonnegativeInt(
} }
template <typename Char> template <typename Char>
const typename fmt::BasicWriter<Char>::ArgInfo const typename fmt::internal::ArgInfo
fmt::BasicWriter<Char>::DUMMY_ARG = {fmt::BasicWriter<Char>::INT, 0}; fmt::BasicWriter<Char>::DUMMY_ARG = {fmt::internal::ArgInfo::INT, 0};
// Fills the padding around the content and returns the pointer to the // Fills the padding around the content and returns the pointer to the
// content area. // content area.
@ -501,15 +501,15 @@ void fmt::BasicWriter<Char>::FormatDouble(T value, const FormatSpec &spec) {
} }
template <typename Char> template <typename Char>
fmt::ULongLong fmt::BasicWriter<Char>::GetIntValue(const ArgInfo &arg) { fmt::ULongLong fmt::BasicWriter<Char>::GetIntValue(const Arg &arg) {
switch (arg.type) { switch (arg.type) {
case INT: case Arg::INT:
return arg.int_value; return arg.int_value;
case UINT: case Arg::UINT:
return arg.uint_value; return arg.uint_value;
case LONG_LONG: case Arg::LONG_LONG:
return arg.long_long_value; return arg.long_long_value;
case ULONG_LONG: case Arg::ULONG_LONG:
return arg.ulong_long_value; return arg.ulong_long_value;
default: default:
return -1; return -1;
@ -517,7 +517,24 @@ fmt::ULongLong fmt::BasicWriter<Char>::GetIntValue(const ArgInfo &arg) {
} }
template <typename Char> template <typename Char>
inline const typename fmt::BasicWriter<Char>::ArgInfo template <typename StringChar>
void fmt::BasicWriter<Char>::FormatString(
const Arg::StringValue<StringChar> &str, const FormatSpec &spec) {
if (spec.type_ && spec.type_ != 's')
internal::ReportUnknownType(spec.type_, "string");
const StringChar *s = str.value;
std::size_t size = str.size;
if (size == 0) {
if (!s)
throw FormatError("string pointer is null");
if (*s)
size = std::char_traits<StringChar>::length(s);
}
FormatString(s, size, spec);
}
template <typename Char>
inline const typename fmt::BasicWriter<Char>::Arg
&fmt::BasicWriter<Char>::FormatParser::ParseArgIndex(const Char *&s) { &fmt::BasicWriter<Char>::FormatParser::ParseArgIndex(const Char *&s) {
unsigned arg_index = 0; unsigned arg_index = 0;
if (*s < '0' || *s > '9') { if (*s < '0' || *s > '9') {
@ -539,20 +556,20 @@ inline const typename fmt::BasicWriter<Char>::ArgInfo
if (error) if (error)
report_error_(s, error); // TODO report_error_(s, error); // TODO
} }
if (arg_index >= num_args_) if (arg_index >= args_.size())
report_error_(s, "argument index is out of range in format"); report_error_(s, "argument index is out of range in format");
return args_[arg_index]; return args_[arg_index];
} }
template <typename Char> template <typename Char>
void fmt::BasicWriter<Char>::FormatParser::CheckSign( void fmt::BasicWriter<Char>::FormatParser::CheckSign(
const Char *&s, const ArgInfo &arg) { const Char *&s, const Arg &arg) {
char sign = static_cast<char>(*s); char sign = static_cast<char>(*s);
if (arg.type > LAST_NUMERIC_TYPE) { if (arg.type > Arg::LAST_NUMERIC_TYPE) {
report_error_(s, report_error_(s,
fmt::Format("format specifier '{}' requires numeric argument") << sign); fmt::Format("format specifier '{}' requires numeric argument") << sign);
} }
if (arg.type == UINT || arg.type == ULONG_LONG) { if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) {
report_error_(s, report_error_(s,
fmt::Format("format specifier '{}' requires signed argument") << sign); fmt::Format("format specifier '{}' requires signed argument") << sign);
} }
@ -615,27 +632,28 @@ unsigned fmt::BasicWriter<Char>::PrintfParser::ParseHeader(
spec.width_ = internal::ParseNonnegativeInt(s, error); spec.width_ = internal::ParseNonnegativeInt(s, error);
} else if (*s == '*') { } else if (*s == '*') {
++s; ++s;
const ArgInfo &arg = HandleArgIndex(UINT_MAX, error); const Arg &arg = HandleArgIndex(UINT_MAX, error);
// TODO: use ArgVisitor
ULongLong width = 0; ULongLong width = 0;
switch (arg.type) { switch (arg.type) {
case INT: case Arg::INT:
width = arg.int_value; width = arg.int_value;
if (arg.int_value < 0) { if (arg.int_value < 0) {
spec.align_ = ALIGN_LEFT; spec.align_ = ALIGN_LEFT;
width = 0 - width; width = 0 - width;
} }
break; break;
case UINT: case Arg::UINT:
width = arg.uint_value; width = arg.uint_value;
break; break;
case LONG_LONG: case Arg::LONG_LONG:
width = arg.long_long_value; width = arg.long_long_value;
if (arg.long_long_value < 0) { if (arg.long_long_value < 0) {
spec.align_ = ALIGN_LEFT; spec.align_ = ALIGN_LEFT;
width = 0 - width; width = 0 - width;
} }
break; break;
case ULONG_LONG: case Arg::ULONG_LONG:
width = arg.ulong_long_value; width = arg.ulong_long_value;
break; break;
default: default:
@ -652,7 +670,7 @@ unsigned fmt::BasicWriter<Char>::PrintfParser::ParseHeader(
// TODO: move to a base class that doesn't depend on template argument // TODO: move to a base class that doesn't depend on template argument
template <typename Char> template <typename Char>
const typename fmt::BasicWriter<Char>::ArgInfo const typename fmt::BasicWriter<Char>::Arg
&fmt::BasicWriter<Char>::PrintfParser::HandleArgIndex( &fmt::BasicWriter<Char>::PrintfParser::HandleArgIndex(
unsigned arg_index, const char *&error) { unsigned arg_index, const char *&error) {
if (arg_index != UINT_MAX) { if (arg_index != UINT_MAX) {
@ -667,7 +685,7 @@ const typename fmt::BasicWriter<Char>::ArgInfo
} else if (!error) { } else if (!error) {
error = "cannot switch from manual to automatic argument indexing"; error = "cannot switch from manual to automatic argument indexing";
} }
if (arg_index < num_args_) if (arg_index < args_.size())
return args_[arg_index]; return args_[arg_index];
if (!error) if (!error)
error = "argument index is out of range in format"; error = "argument index is out of range in format";
@ -677,9 +695,8 @@ const typename fmt::BasicWriter<Char>::ArgInfo
template <typename Char> template <typename Char>
void fmt::BasicWriter<Char>::PrintfParser::Format( void fmt::BasicWriter<Char>::PrintfParser::Format(
BasicWriter<Char> &writer, BasicStringRef<Char> format, BasicWriter<Char> &writer, BasicStringRef<Char> format,
std::size_t num_args, const ArgInfo *args) { const ArgList &args) {
const Char *start = format.c_str(); const Char *start = format.c_str();
num_args_ = num_args;
args_ = args; args_ = args;
next_arg_index_ = 0; next_arg_index_ = 0;
const Char *s = start; const Char *s = start;
@ -718,25 +735,37 @@ void fmt::BasicWriter<Char>::PrintfParser::Format(
spec.precision_ = internal::ParseNonnegativeInt(s, error); spec.precision_ = internal::ParseNonnegativeInt(s, error);
} else if (*s == '*') { } else if (*s == '*') {
++s; ++s;
const ArgInfo &arg = HandleArgIndex(UINT_MAX, error); const Arg &arg = HandleArgIndex(UINT_MAX, error);
if (arg.type <= LAST_INTEGER_TYPE) if (arg.type <= Arg::LAST_INTEGER_TYPE)
spec.precision_ = GetIntValue(arg); spec.precision_ = GetIntValue(arg);
else if (!error) else if (!error)
error = "precision is not integer"; error = "precision is not integer";
} }
} }
const ArgInfo &arg = HandleArgIndex(arg_index, error); const Arg &arg = HandleArgIndex(arg_index, error);
if (spec.hash_flag() && GetIntValue(arg) == 0) if (spec.hash_flag() && GetIntValue(arg) == 0)
spec.flags_ &= ~HASH_FLAG; spec.flags_ &= ~HASH_FLAG;
if (spec.fill_ == '0') { if (spec.fill_ == '0') {
if (arg.type <= LAST_NUMERIC_TYPE) if (arg.type <= Arg::LAST_NUMERIC_TYPE)
spec.align_ = ALIGN_NUMERIC; spec.align_ = ALIGN_NUMERIC;
else else
spec.fill_ = ' '; // Ignore '0' flag for non-numeric types. spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
} }
// TODO: parse length // Parse length.
switch (*s) {
case 'h':
// TODO: convert to short
case 'l':
case 'j':
case 'z':
case 't':
case 'L':
// TODO: handle length
++s;
break;
}
// Parse type. // Parse type.
if (!*s) if (!*s)
@ -749,25 +778,25 @@ void fmt::BasicWriter<Char>::PrintfParser::Format(
// Format argument. // Format argument.
switch (arg.type) { switch (arg.type) {
case INT: case Arg::INT:
writer.FormatInt(arg.int_value, spec); writer.FormatInt(arg.int_value, spec);
break; break;
case UINT: case Arg::UINT:
writer.FormatInt(arg.uint_value, spec); writer.FormatInt(arg.uint_value, spec);
break; break;
case LONG_LONG: case Arg::LONG_LONG:
writer.FormatInt(arg.long_long_value, spec); writer.FormatInt(arg.long_long_value, spec);
break; break;
case ULONG_LONG: case Arg::ULONG_LONG:
writer.FormatInt(arg.ulong_long_value, spec); writer.FormatInt(arg.ulong_long_value, spec);
break; break;
case DOUBLE: case Arg::DOUBLE:
writer.FormatDouble(arg.double_value, spec); writer.FormatDouble(arg.double_value, spec);
break; break;
case LONG_DOUBLE: case Arg::LONG_DOUBLE:
writer.FormatDouble(arg.long_double_value, spec); writer.FormatDouble(arg.long_double_value, spec);
break; break;
case CHAR: { case Arg::CHAR: {
if (spec.type_ && spec.type_ != 'c') if (spec.type_ && spec.type_ != 'c')
internal::ReportUnknownType(spec.type_, "char"); internal::ReportUnknownType(spec.type_, "char");
typedef typename BasicWriter<Char>::CharPtr CharPtr; typedef typename BasicWriter<Char>::CharPtr CharPtr;
@ -789,31 +818,23 @@ void fmt::BasicWriter<Char>::PrintfParser::Format(
*out = static_cast<Char>(arg.int_value); *out = static_cast<Char>(arg.int_value);
break; break;
} }
case STRING: { case Arg::STRING:
if (spec.type_ && spec.type_ != 's') writer.FormatString(arg.string, spec);
internal::ReportUnknownType(spec.type_, "string");
const Char *str = arg.string.value;
std::size_t size = arg.string.size;
if (size == 0) {
if (!str)
throw FormatError("string pointer is null");
if (*str)
size = std::char_traits<Char>::length(str);
}
writer.FormatString(str, size, spec);
break; break;
} case Arg::WSTRING:
case POINTER: writer.FormatString(arg.wstring, spec);
break;
case Arg::POINTER:
if (spec.type_ && spec.type_ != 'p') if (spec.type_ && spec.type_ != 'p')
internal::ReportUnknownType(spec.type_, "pointer"); internal::ReportUnknownType(spec.type_, "pointer");
spec.flags_= HASH_FLAG; spec.flags_= HASH_FLAG;
spec.type_ = 'x'; spec.type_ = 'x';
writer.FormatInt(reinterpret_cast<uintptr_t>(arg.pointer_value), spec); writer.FormatInt(reinterpret_cast<uintptr_t>(arg.pointer_value), spec);
break; break;
case CUSTOM: case Arg::CUSTOM:
if (spec.type_) if (spec.type_)
internal::ReportUnknownType(spec.type_, "object"); internal::ReportUnknownType(spec.type_, "object");
arg.custom.format(writer, arg.custom.value, spec); arg.custom.format(&writer, arg.custom.value, spec);
break; break;
default: default:
assert(false); assert(false);
@ -826,10 +847,9 @@ void fmt::BasicWriter<Char>::PrintfParser::Format(
template <typename Char> template <typename Char>
void fmt::BasicWriter<Char>::FormatParser::Format( void fmt::BasicWriter<Char>::FormatParser::Format(
BasicWriter<Char> &writer, BasicStringRef<Char> format, BasicWriter<Char> &writer, BasicStringRef<Char> format,
std::size_t num_args, const ArgInfo *args) { const ArgList &args) {
const char *error = 0; const char *error = 0;
const Char *start = format.c_str(); const Char *start = format.c_str();
num_args_ = num_args;
args_ = args; args_ = args;
next_arg_index_ = 0; next_arg_index_ = 0;
const Char *s = start; const Char *s = start;
@ -846,7 +866,7 @@ void fmt::BasicWriter<Char>::FormatParser::Format(
report_error_.num_open_braces = 1; report_error_.num_open_braces = 1;
writer.buffer_.append(start, s - 1); writer.buffer_.append(start, s - 1);
const ArgInfo &arg = ParseArgIndex(s); const Arg &arg = ParseArgIndex(s);
FormatSpec spec; FormatSpec spec;
if (*s == ':') { if (*s == ':') {
@ -879,7 +899,7 @@ void fmt::BasicWriter<Char>::FormatParser::Format(
s += 2; s += 2;
spec.fill_ = c; spec.fill_ = c;
} else ++s; } else ++s;
if (spec.align_ == ALIGN_NUMERIC && arg.type > LAST_NUMERIC_TYPE) if (spec.align_ == ALIGN_NUMERIC && arg.type > Arg::LAST_NUMERIC_TYPE)
report_error_(s, "format specifier '=' requires numeric argument"); report_error_(s, "format specifier '=' requires numeric argument");
break; break;
} }
@ -902,7 +922,7 @@ void fmt::BasicWriter<Char>::FormatParser::Format(
} }
if (*s == '#') { if (*s == '#') {
if (arg.type > LAST_NUMERIC_TYPE) if (arg.type > Arg::LAST_NUMERIC_TYPE)
report_error_(s, "format specifier '#' requires numeric argument"); report_error_(s, "format specifier '#' requires numeric argument");
spec.flags_ |= HASH_FLAG; spec.flags_ |= HASH_FLAG;
++s; ++s;
@ -911,7 +931,7 @@ void fmt::BasicWriter<Char>::FormatParser::Format(
// Parse width and zero flag. // Parse width and zero flag.
if ('0' <= *s && *s <= '9') { if ('0' <= *s && *s <= '9') {
if (*s == '0') { if (*s == '0') {
if (arg.type > LAST_NUMERIC_TYPE) if (arg.type > Arg::LAST_NUMERIC_TYPE)
report_error_(s, "format specifier '0' requires numeric argument"); report_error_(s, "format specifier '0' requires numeric argument");
spec.align_ = ALIGN_NUMERIC; spec.align_ = ALIGN_NUMERIC;
spec.fill_ = '0'; spec.fill_ = '0';
@ -934,23 +954,23 @@ void fmt::BasicWriter<Char>::FormatParser::Format(
} else if (*s == '{') { } else if (*s == '{') {
++s; ++s;
++report_error_.num_open_braces; ++report_error_.num_open_braces;
const ArgInfo &precision_arg = ParseArgIndex(s); const Arg &precision_arg = ParseArgIndex(s);
ULongLong value = 0; ULongLong value = 0;
switch (precision_arg.type) { switch (precision_arg.type) {
case INT: case Arg::INT:
if (precision_arg.int_value < 0) if (precision_arg.int_value < 0)
report_error_(s, "negative precision in format"); report_error_(s, "negative precision in format");
value = precision_arg.int_value; value = precision_arg.int_value;
break; break;
case UINT: case Arg::UINT:
value = precision_arg.uint_value; value = precision_arg.uint_value;
break; break;
case LONG_LONG: case Arg::LONG_LONG:
if (precision_arg.long_long_value < 0) if (precision_arg.long_long_value < 0)
report_error_(s, "negative precision in format"); report_error_(s, "negative precision in format");
value = precision_arg.long_long_value; value = precision_arg.long_long_value;
break; break;
case ULONG_LONG: case Arg::ULONG_LONG:
value = precision_arg.ulong_long_value; value = precision_arg.ulong_long_value;
break; break;
default: default:
@ -965,7 +985,7 @@ void fmt::BasicWriter<Char>::FormatParser::Format(
} else { } else {
report_error_(s, "missing precision in format"); report_error_(s, "missing precision in format");
} }
if (arg.type != DOUBLE && arg.type != LONG_DOUBLE) { if (arg.type != Arg::DOUBLE && arg.type != Arg::LONG_DOUBLE) {
report_error_(s, report_error_(s,
"precision specifier requires floating-point argument"); "precision specifier requires floating-point argument");
} }
@ -982,25 +1002,25 @@ void fmt::BasicWriter<Char>::FormatParser::Format(
// Format argument. // Format argument.
switch (arg.type) { switch (arg.type) {
case INT: case Arg::INT:
writer.FormatInt(arg.int_value, spec); writer.FormatInt(arg.int_value, spec);
break; break;
case UINT: case Arg::UINT:
writer.FormatInt(arg.uint_value, spec); writer.FormatInt(arg.uint_value, spec);
break; break;
case LONG_LONG: case Arg::LONG_LONG:
writer.FormatInt(arg.long_long_value, spec); writer.FormatInt(arg.long_long_value, spec);
break; break;
case ULONG_LONG: case Arg::ULONG_LONG:
writer.FormatInt(arg.ulong_long_value, spec); writer.FormatInt(arg.ulong_long_value, spec);
break; break;
case DOUBLE: case Arg::DOUBLE:
writer.FormatDouble(arg.double_value, spec); writer.FormatDouble(arg.double_value, spec);
break; break;
case LONG_DOUBLE: case Arg::LONG_DOUBLE:
writer.FormatDouble(arg.long_double_value, spec); writer.FormatDouble(arg.long_double_value, spec);
break; break;
case CHAR: { case Arg::CHAR: {
if (spec.type_ && spec.type_ != 'c') if (spec.type_ && spec.type_ != 'c')
internal::ReportUnknownType(spec.type_, "char"); internal::ReportUnknownType(spec.type_, "char");
typedef typename BasicWriter<Char>::CharPtr CharPtr; typedef typename BasicWriter<Char>::CharPtr CharPtr;
@ -1022,31 +1042,23 @@ void fmt::BasicWriter<Char>::FormatParser::Format(
*out = static_cast<Char>(arg.int_value); *out = static_cast<Char>(arg.int_value);
break; break;
} }
case STRING: { case Arg::STRING:
if (spec.type_ && spec.type_ != 's') writer.FormatString(arg.string, spec);
internal::ReportUnknownType(spec.type_, "string");
const Char *str = arg.string.value;
std::size_t size = arg.string.size;
if (size == 0) {
if (!str)
throw FormatError("string pointer is null");
if (*str)
size = std::char_traits<Char>::length(str);
}
writer.FormatString(str, size, spec);
break; break;
} case Arg::WSTRING:
case POINTER: writer.FormatString(arg.wstring, spec);
break;
case Arg::POINTER:
if (spec.type_ && spec.type_ != 'p') if (spec.type_ && spec.type_ != 'p')
internal::ReportUnknownType(spec.type_, "pointer"); internal::ReportUnknownType(spec.type_, "pointer");
spec.flags_= HASH_FLAG; spec.flags_= HASH_FLAG;
spec.type_ = 'x'; spec.type_ = 'x';
writer.FormatInt(reinterpret_cast<uintptr_t>(arg.pointer_value), spec); writer.FormatInt(reinterpret_cast<uintptr_t>(arg.pointer_value), spec);
break; break;
case CUSTOM: case Arg::CUSTOM:
if (spec.type_) if (spec.type_)
internal::ReportUnknownType(spec.type_, "object"); internal::ReportUnknownType(spec.type_, "object");
arg.custom.format(writer, arg.custom.value, spec); arg.custom.format(&writer, arg.custom.value, spec);
break; break;
default: default:
assert(false); assert(false);
@ -1098,12 +1110,10 @@ template fmt::BasicWriter<char>::CharPtr
unsigned total_size, std::size_t content_size, wchar_t fill); unsigned total_size, std::size_t content_size, wchar_t fill);
template void fmt::BasicWriter<char>::FormatParser::Format( template void fmt::BasicWriter<char>::FormatParser::Format(
BasicWriter<char> &writer, BasicStringRef<char> format, BasicWriter<char> &writer, BasicStringRef<char> format, const ArgList &args);
std::size_t num_args, const ArgInfo *args);
template void fmt::BasicWriter<char>::PrintfParser::Format( template void fmt::BasicWriter<char>::PrintfParser::Format(
BasicWriter<char> &writer, BasicStringRef<char> format, BasicWriter<char> &writer, BasicStringRef<char> format, const ArgList &args);
std::size_t num_args, const ArgInfo *args);
// Explicit instantiations for wchar_t. // Explicit instantiations for wchar_t.
@ -1113,11 +1123,11 @@ template fmt::BasicWriter<wchar_t>::CharPtr
template void fmt::BasicWriter<wchar_t>::FormatParser::Format( template void fmt::BasicWriter<wchar_t>::FormatParser::Format(
BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format, BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,
std::size_t num_args, const ArgInfo *args); const ArgList &args);
template void fmt::BasicWriter<wchar_t>::PrintfParser::Format( template void fmt::BasicWriter<wchar_t>::PrintfParser::Format(
BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format, BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,
std::size_t num_args, const ArgInfo *args); const ArgList &args);
#if _MSC_VER #if _MSC_VER
# pragma warning(pop) # pragma warning(pop)

257
format.h
View File

@ -477,8 +477,7 @@ void FormatDecimal(Char *buffer, UInt value, unsigned num_digits) {
} }
template <typename Char, typename T> template <typename Char, typename T>
void FormatCustomArg( void FormatCustomArg(void *writer, const void *arg, const FormatSpec &spec);
BasicWriter<Char> &w, const void *arg, const FormatSpec &spec);
#ifdef _WIN32 #ifdef _WIN32
// A converter from UTF-8 to UTF-16. // A converter from UTF-8 to UTF-16.
@ -563,6 +562,46 @@ template <>
struct NonZero<0> { struct NonZero<0> {
enum { VALUE = 1 }; enum { VALUE = 1 };
}; };
// Information about a format argument. It is a POD type to allow
// storage in internal::Array.
struct ArgInfo {
enum Type {
// Integer types should go first,
INT, UINT, LONG_LONG, ULONG_LONG, LAST_INTEGER_TYPE = ULONG_LONG,
// followed by floating-point types.
DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE,
CHAR, STRING, WSTRING, POINTER, CUSTOM
};
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);
struct CustomValue {
const void *value;
FormatFunc format;
};
union {
int int_value;
unsigned uint_value;
double double_value;
LongLong long_long_value;
ULongLong ulong_long_value;
long double long_double_value;
const void *pointer_value;
StringValue<char> string;
StringValue<wchar_t> wstring;
CustomValue custom;
};
};
} // namespace internal } // namespace internal
/** /**
@ -806,6 +845,23 @@ inline StrFormatSpec<wchar_t> pad(
return StrFormatSpec<wchar_t>(str, width, fill); return StrFormatSpec<wchar_t>(str, width, fill);
} }
class ArgList {
private:
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) {}
std::size_t size() const { return size_; }
const internal::ArgInfo &operator[](std::size_t index) const {
return args_[index];
}
};
/** /**
\rst \rst
This template provides operations for formatting and writing data into This template provides operations for formatting and writing data into
@ -850,6 +906,10 @@ class BasicWriter {
typedef typename internal::CharTraits<Char>::CharPtr CharPtr; typedef typename internal::CharTraits<Char>::CharPtr CharPtr;
typedef internal::ArgInfo Arg;
static const Arg DUMMY_ARG;
#if _SECURE_SCL #if _SECURE_SCL
static Char *GetBase(CharPtr p) { return p.base(); } static Char *GetBase(CharPtr p) { return p.base(); }
#else #else
@ -893,53 +953,17 @@ class BasicWriter {
CharPtr FormatString( CharPtr FormatString(
const StringChar *s, std::size_t size, const AlignSpec &spec); const StringChar *s, std::size_t size, const AlignSpec &spec);
// This method is private to disallow writing a wide string to a template <typename StringChar>
void FormatString(
const Arg::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 // char stream and vice versa. If you want to print a wide string
// as a pointer as std::ostream does, cast it to const void*. // as a pointer as std::ostream does, cast it to const void*.
// Do not implement! // Do not implement!
void operator<<(typename internal::CharTraits<Char>::UnsupportedStrType); void operator<<(typename internal::CharTraits<Char>::UnsupportedStrType);
enum Type { static ULongLong GetIntValue(const Arg &arg);
// Integer types should go first,
INT, UINT, LONG_LONG, ULONG_LONG, LAST_INTEGER_TYPE = ULONG_LONG,
// followed by floating-point types.
DOUBLE, LONG_DOUBLE, LAST_NUMERIC_TYPE = LONG_DOUBLE,
CHAR, STRING, WSTRING, POINTER, CUSTOM
};
struct StringValue {
const Char *value;
std::size_t size;
};
typedef void (*FormatFunc)(
BasicWriter<Char> &w, const void *arg, const FormatSpec &spec);
struct CustomValue {
const void *value;
FormatFunc format;
};
// Information about a format argument. It is a POD type to allow
// storage in internal::Array.
struct ArgInfo {
Type type;
union {
int int_value;
unsigned uint_value;
double double_value;
LongLong long_long_value;
ULongLong ulong_long_value;
long double long_double_value;
const void *pointer_value;
StringValue string;
CustomValue custom;
};
};
static const ArgInfo DUMMY_ARG;
static ULongLong GetIntValue(const ArgInfo &arg);
// An argument action that does nothing. // An argument action that does nothing.
struct NullArgAction { struct NullArgAction {
@ -948,7 +972,7 @@ class BasicWriter {
// A wrapper around a format argument. // A wrapper around a format argument.
template <typename Action = NullArgAction> template <typename Action = NullArgAction>
class BasicArg : public Action, public ArgInfo { class BasicArg : public Action, public Arg {
private: private:
// This method is private to disallow formatting of arbitrary pointers. // 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! // If you want to output a pointer cast it to const void*. Do not implement!
@ -961,83 +985,96 @@ class BasicWriter {
BasicArg(T *value); BasicArg(T *value);
public: public:
using ArgInfo::type; using Arg::type;
BasicArg() {} BasicArg() {}
BasicArg(short value) { type = INT; this->int_value = value; } // TODO: unsigned char & signed char
BasicArg(unsigned short value) { type = UINT; this->int_value = value; } BasicArg(short value) { type = Arg::INT; Arg::int_value = value; }
BasicArg(int value) { type = INT; this->int_value = value; } BasicArg(unsigned short value) {
BasicArg(unsigned value) { type = UINT; this->uint_value = 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) { BasicArg(long value) {
if (sizeof(long) == sizeof(int)) { if (sizeof(long) == sizeof(int)) {
type = INT; type = Arg::INT;
this->int_value = static_cast<int>(value); Arg::int_value = static_cast<int>(value);
} else { } else {
type = LONG_LONG; type = Arg::LONG_LONG;
this->long_long_value = value; Arg::long_long_value = value;
} }
} }
BasicArg(unsigned long value) { BasicArg(unsigned long value) {
if (sizeof(unsigned long) == sizeof(unsigned)) { if (sizeof(unsigned long) == sizeof(unsigned)) {
type = UINT; type = Arg::UINT;
this->uint_value = static_cast<unsigned>(value); Arg::uint_value = static_cast<unsigned>(value);
} else { } else {
type = ULONG_LONG; type = Arg::ULONG_LONG;
this->ulong_long_value = value; Arg::ulong_long_value = value;
} }
} }
BasicArg(LongLong value) { BasicArg(LongLong value) {
type = LONG_LONG; type = Arg::LONG_LONG;
this->long_long_value = value; Arg::long_long_value = value;
} }
BasicArg(ULongLong value) { BasicArg(ULongLong value) {
type = ULONG_LONG; type = Arg::ULONG_LONG;
this->ulong_long_value = value; Arg::ulong_long_value = value;
} }
BasicArg(float value) { type = DOUBLE; this->double_value = value; } BasicArg(float value) { type = Arg::DOUBLE; Arg::double_value = value; }
BasicArg(double value) { type = DOUBLE; this->double_value = value; } BasicArg(double value) { type = Arg::DOUBLE; Arg::double_value = value; }
BasicArg(long double value) { BasicArg(long double value) {
type = LONG_DOUBLE; type = Arg::LONG_DOUBLE;
this->long_double_value = value; Arg::long_double_value = value;
} }
BasicArg(char value) { type = CHAR; this->int_value = value; } BasicArg(char value) { type = Arg::CHAR; Arg::int_value = value; }
BasicArg(wchar_t value) { BasicArg(wchar_t value) {
type = CHAR; type = Arg::CHAR;
this->int_value = internal::CharTraits<Char>::ConvertChar(value); Arg::int_value = internal::CharTraits<Char>::ConvertChar(value);
} }
BasicArg(const Char *value) { BasicArg(const char *value) {
type = STRING; type = Arg::STRING;
this->string.value = value; Arg::string.value = value;
this->string.size = 0; Arg::string.size = 0;
}
BasicArg(const wchar_t *value) {
type = Arg::WSTRING;
Arg::wstring.value = value;
Arg::wstring.size = 0;
} }
BasicArg(Char *value) { BasicArg(Char *value) {
type = STRING; type = Arg::STRING;
this->string.value = value; Arg::string.value = value;
this->string.size = 0; Arg::string.size = 0;
} }
BasicArg(const void *value) { type = POINTER; this->pointer_value = value; } BasicArg(const void *value) {
BasicArg(void *value) { type = POINTER; this->pointer_value = 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) { BasicArg(const std::basic_string<Char> &value) {
type = STRING; type = Arg::STRING;
this->string.value = value.c_str(); Arg::string.value = value.c_str();
this->string.size = value.size(); Arg::string.size = value.size();
} }
BasicArg(BasicStringRef<Char> value) { BasicArg(BasicStringRef<Char> value) {
type = STRING; type = Arg::STRING;
this->string.value = value.c_str(); Arg::string.value = value.c_str();
this->string.size = value.size(); Arg::string.size = value.size();
} }
template <typename T> template <typename T>
BasicArg(const T &value) { BasicArg(const T &value) {
type = CUSTOM; type = Arg::CUSTOM;
this->custom.value = &value; Arg::custom.value = &value;
this->custom.format = &internal::FormatCustomArg<Char, T>; Arg::custom.format = &internal::FormatCustomArg<Char, T>;
} }
// The destructor is declared noexcept(false) because the action may throw // The destructor is declared noexcept(false) because the action may throw
@ -1048,31 +1085,27 @@ class BasicWriter {
} }
}; };
typedef BasicArg<> Arg;
// Format string parser. // Format string parser.
class FormatParser { class FormatParser {
private: private:
std::size_t num_args_; ArgList args_;
const ArgInfo *args_;
int next_arg_index_; int next_arg_index_;
fmt::internal::FormatErrorReporter<Char> report_error_; fmt::internal::FormatErrorReporter<Char> report_error_;
// Parses argument index and returns an argument with this index. // Parses argument index and returns an argument with this index.
const ArgInfo &ParseArgIndex(const Char *&s); const Arg &ParseArgIndex(const Char *&s);
void CheckSign(const Char *&s, const ArgInfo &arg); void CheckSign(const Char *&s, const Arg &arg);
public: public:
void Format(BasicWriter<Char> &writer, void Format(BasicWriter<Char> &writer,
BasicStringRef<Char> format, std::size_t num_args, const ArgInfo *args); BasicStringRef<Char> format, const ArgList &args);
}; };
// Printf format string parser. // Printf format string parser.
class PrintfParser { class PrintfParser {
private: private:
std::size_t num_args_; ArgList args_;
const ArgInfo *args_;
int next_arg_index_; int next_arg_index_;
void ParseFlags(FormatSpec &spec, const Char *&s); void ParseFlags(FormatSpec &spec, const Char *&s);
@ -1081,11 +1114,11 @@ class BasicWriter {
// argument index. // argument index.
unsigned ParseHeader(const Char *&s, FormatSpec &spec, const char *&error); unsigned ParseHeader(const Char *&s, FormatSpec &spec, const char *&error);
const ArgInfo &HandleArgIndex(unsigned arg_index, const char *&error); const Arg &HandleArgIndex(unsigned arg_index, const char *&error);
public: public:
void Format(BasicWriter<Char> &writer, void Format(BasicWriter<Char> &writer,
BasicStringRef<Char> format, std::size_t num_args, const ArgInfo *args); BasicStringRef<Char> format, const ArgList &args);
}; };
public: public:
@ -1140,14 +1173,12 @@ class BasicWriter {
return std::basic_string<Char>(&buffer_[0], buffer_.size()); return std::basic_string<Char>(&buffer_[0], buffer_.size());
} }
inline void VFormat(BasicStringRef<Char> format, inline void format(BasicStringRef<Char> format, const ArgList &args) {
std::size_t num_args, const ArgInfo *args) { FormatParser().Format(*this, format, args);
FormatParser().Format(*this, format, num_args, args);
} }
inline void vprintf(BasicStringRef<Char> format, inline void printf(BasicStringRef<Char> format, const ArgList &args) {
std::size_t num_args, const ArgInfo *args) { PrintfParser().Format(*this, format, args);
PrintfParser().Format(*this, format, num_args, args);
} }
/** /**
@ -1207,14 +1238,14 @@ class BasicWriter {
*/ */
template<typename... Args> template<typename... Args>
void Format(BasicStringRef<Char> format, const Args & ... args) { void Format(BasicStringRef<Char> format, const Args & ... args) {
Arg arg_array[] = {args...}; BasicArg<> arg_array[] = {args...};
VFormat(format, sizeof...(Args), arg_array); this->format(format, ArgList(arg_array, sizeof...(Args)));
} }
template<typename... Args> template<typename... Args>
void printf(BasicStringRef<Char> format, const Args & ... args) { void printf(BasicStringRef<Char> format, const Args & ... args) {
Arg arg_array[internal::NonZero<sizeof...(Args)>::VALUE] = {args...}; BasicArg<> arg_array[internal::NonZero<sizeof...(Args)>::VALUE] = {args...};
vprintf(format, sizeof...(Args), arg_array); this->printf(format, ArgList(arg_array, sizeof...(Args)));
} }
#endif #endif
@ -1486,9 +1517,9 @@ void Format(BasicWriter<Char> &w, const FormatSpec &spec, const T &value) {
namespace internal { namespace internal {
// Formats an argument of a custom type, such as a user-defined class. // Formats an argument of a custom type, such as a user-defined class.
template <typename Char, typename T> template <typename Char, typename T>
void FormatCustomArg( void FormatCustomArg(void *writer, const void *arg, const FormatSpec &spec) {
BasicWriter<Char> &w, const void *arg, const FormatSpec &spec) { Format(*static_cast<BasicWriter<Char>*>(writer),
Format(w, spec, *static_cast<const T*>(arg)); spec, *static_cast<const T*>(arg));
} }
} }
@ -1527,7 +1558,7 @@ class BasicFormatter {
} }
}; };
typedef typename BasicWriter<Char>::ArgInfo ArgInfo; typedef typename internal::ArgInfo ArgInfo;
typedef typename BasicWriter<Char>::template BasicArg<ArgAction> Arg; typedef typename BasicWriter<Char>::template BasicArg<ArgAction> Arg;
enum { NUM_INLINE_ARGS = 10 }; enum { NUM_INLINE_ARGS = 10 };
@ -1554,7 +1585,7 @@ class BasicFormatter {
if (!format_) return; if (!format_) return;
const Char *format = format_; const Char *format = format_;
format_ = 0; format_ = 0;
writer_->VFormat(format, args_.size(), &args_[0]); writer_->format(format, ArgList(&args_[0], args_.size()));
} }
public: public: