mirror of
https://github.com/fmtlib/fmt.git
synced 2025-02-28 06:39:50 +00:00
Make ArgVisitor public and document it
Also remove unnecessary namespace qualification.
This commit is contained in:
parent
da3467b7f9
commit
bfdca8b576
@ -129,7 +129,7 @@ struct IntChecker<true> {
|
|||||||
|
|
||||||
const char RESET_COLOR[] = "\x1b[0m";
|
const char RESET_COLOR[] = "\x1b[0m";
|
||||||
|
|
||||||
typedef void (*FormatFunc)(fmt::Writer &, int, fmt::StringRef);
|
typedef void (*FormatFunc)(Writer &, int, StringRef);
|
||||||
|
|
||||||
// Portable thread-safe version of strerror.
|
// Portable thread-safe version of strerror.
|
||||||
// Sets buffer to point to a string describing the error code.
|
// Sets buffer to point to a string describing the error code.
|
||||||
@ -169,7 +169,7 @@ int safe_strerror(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle the case when strerror_r is not available.
|
// Handle the case when strerror_r is not available.
|
||||||
int handle(fmt::internal::Null<>) {
|
int handle(internal::Null<>) {
|
||||||
return fallback(strerror_s(buffer_, buffer_size_, error_code_));
|
return fallback(strerror_s(buffer_, buffer_size_, error_code_));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,7 +181,7 @@ int safe_strerror(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fallback to strerror if strerror_r and strerror_s are not available.
|
// Fallback to strerror if strerror_r and strerror_s are not available.
|
||||||
int fallback(fmt::internal::Null<>) {
|
int fallback(internal::Null<>) {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
buffer_ = strerror(error_code_);
|
buffer_ = strerror(error_code_);
|
||||||
return errno;
|
return errno;
|
||||||
@ -199,8 +199,8 @@ int safe_strerror(
|
|||||||
return StrError(error_code, buffer, buffer_size).run();
|
return StrError(error_code, buffer, buffer_size).run();
|
||||||
}
|
}
|
||||||
|
|
||||||
void format_error_code(fmt::Writer &out, int error_code,
|
void format_error_code(Writer &out, int error_code,
|
||||||
fmt::StringRef message) FMT_NOEXCEPT {
|
StringRef message) FMT_NOEXCEPT {
|
||||||
// Report error code making sure that the output fits into
|
// Report error code making sure that the output fits into
|
||||||
// INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
|
// INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
|
||||||
// bad_alloc.
|
// bad_alloc.
|
||||||
@ -209,22 +209,22 @@ void format_error_code(fmt::Writer &out, int error_code,
|
|||||||
static const char ERROR_STR[] = "error ";
|
static const char ERROR_STR[] = "error ";
|
||||||
// Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
|
// Subtract 2 to account for terminating null characters in SEP and ERROR_STR.
|
||||||
std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
|
std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2;
|
||||||
typedef fmt::internal::IntTraits<int>::MainType MainType;
|
typedef internal::IntTraits<int>::MainType MainType;
|
||||||
MainType abs_value = static_cast<MainType>(error_code);
|
MainType abs_value = static_cast<MainType>(error_code);
|
||||||
if (internal::is_negative(error_code)) {
|
if (internal::is_negative(error_code)) {
|
||||||
abs_value = 0 - abs_value;
|
abs_value = 0 - abs_value;
|
||||||
++error_code_size;
|
++error_code_size;
|
||||||
}
|
}
|
||||||
error_code_size += fmt::internal::count_digits(abs_value);
|
error_code_size += internal::count_digits(abs_value);
|
||||||
if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size)
|
if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size)
|
||||||
out << message << SEP;
|
out << message << SEP;
|
||||||
out << ERROR_STR << error_code;
|
out << ERROR_STR << error_code;
|
||||||
assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE);
|
assert(out.size() <= internal::INLINE_BUFFER_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void report_error(FormatFunc func,
|
void report_error(FormatFunc func, int error_code,
|
||||||
int error_code, fmt::StringRef message) FMT_NOEXCEPT {
|
StringRef message) FMT_NOEXCEPT {
|
||||||
fmt::MemoryWriter full_message;
|
MemoryWriter full_message;
|
||||||
func(full_message, error_code, message);
|
func(full_message, error_code, message);
|
||||||
// Use Writer::data instead of Writer::c_str to avoid potential memory
|
// Use Writer::data instead of Writer::c_str to avoid potential memory
|
||||||
// allocation.
|
// allocation.
|
||||||
@ -233,7 +233,7 @@ void report_error(FormatFunc func,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IsZeroInt::visit(arg) returns true iff arg is a zero integer.
|
// IsZeroInt::visit(arg) returns true iff arg is a zero integer.
|
||||||
class IsZeroInt : public fmt::internal::ArgVisitor<IsZeroInt, bool> {
|
class IsZeroInt : public ArgVisitor<IsZeroInt, bool> {
|
||||||
public:
|
public:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
bool visit_any_int(T value) { return value == 0; }
|
bool visit_any_int(T value) { return value == 0; }
|
||||||
@ -241,44 +241,43 @@ class IsZeroInt : public fmt::internal::ArgVisitor<IsZeroInt, bool> {
|
|||||||
|
|
||||||
// Checks if an argument is a valid printf width specifier and sets
|
// Checks if an argument is a valid printf width specifier and sets
|
||||||
// left alignment if it is negative.
|
// left alignment if it is negative.
|
||||||
class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> {
|
class WidthHandler : public ArgVisitor<WidthHandler, unsigned> {
|
||||||
private:
|
private:
|
||||||
fmt::FormatSpec &spec_;
|
FormatSpec &spec_;
|
||||||
|
|
||||||
FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
|
FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {}
|
explicit WidthHandler(FormatSpec &spec) : spec_(spec) {}
|
||||||
|
|
||||||
void report_unhandled_arg() {
|
void report_unhandled_arg() {
|
||||||
FMT_THROW(fmt::FormatError("width is not integer"));
|
FMT_THROW(FormatError("width is not integer"));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
unsigned visit_any_int(T value) {
|
unsigned visit_any_int(T value) {
|
||||||
typedef typename fmt::internal::IntTraits<T>::MainType UnsignedType;
|
typedef typename internal::IntTraits<T>::MainType UnsignedType;
|
||||||
UnsignedType width = static_cast<UnsignedType>(value);
|
UnsignedType width = static_cast<UnsignedType>(value);
|
||||||
if (fmt::internal::is_negative(value)) {
|
if (internal::is_negative(value)) {
|
||||||
spec_.align_ = fmt::ALIGN_LEFT;
|
spec_.align_ = ALIGN_LEFT;
|
||||||
width = 0 - width;
|
width = 0 - width;
|
||||||
}
|
}
|
||||||
if (width > INT_MAX)
|
if (width > INT_MAX)
|
||||||
FMT_THROW(fmt::FormatError("number is too big"));
|
FMT_THROW(FormatError("number is too big"));
|
||||||
return static_cast<unsigned>(width);
|
return static_cast<unsigned>(width);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class PrecisionHandler :
|
class PrecisionHandler : public ArgVisitor<PrecisionHandler, int> {
|
||||||
public fmt::internal::ArgVisitor<PrecisionHandler, int> {
|
|
||||||
public:
|
public:
|
||||||
void report_unhandled_arg() {
|
void report_unhandled_arg() {
|
||||||
FMT_THROW(fmt::FormatError("precision is not integer"));
|
FMT_THROW(FormatError("precision is not integer"));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
int visit_any_int(T value) {
|
int visit_any_int(T value) {
|
||||||
if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
|
if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
|
||||||
FMT_THROW(fmt::FormatError("number is too big"));
|
FMT_THROW(FormatError("number is too big"));
|
||||||
return static_cast<int>(value);
|
return static_cast<int>(value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -298,15 +297,15 @@ struct is_same<T, T> {
|
|||||||
// corresponding signed or unsigned type depending on the type specifier:
|
// corresponding signed or unsigned type depending on the type specifier:
|
||||||
// 'd' and 'i' - signed, other - unsigned)
|
// 'd' and 'i' - signed, other - unsigned)
|
||||||
template <typename T = void>
|
template <typename T = void>
|
||||||
class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
|
class ArgConverter : public ArgVisitor<ArgConverter<T>, void> {
|
||||||
private:
|
private:
|
||||||
fmt::internal::Arg &arg_;
|
internal::Arg &arg_;
|
||||||
wchar_t type_;
|
wchar_t type_;
|
||||||
|
|
||||||
FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
|
FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ArgConverter(fmt::internal::Arg &arg, wchar_t type)
|
ArgConverter(internal::Arg &arg, wchar_t type)
|
||||||
: arg_(arg), type_(type) {}
|
: arg_(arg), type_(type) {}
|
||||||
|
|
||||||
void visit_bool(bool value) {
|
void visit_bool(bool value) {
|
||||||
@ -317,8 +316,8 @@ class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
|
|||||||
template <typename U>
|
template <typename U>
|
||||||
void visit_any_int(U value) {
|
void visit_any_int(U value) {
|
||||||
bool is_signed = type_ == 'd' || type_ == 'i';
|
bool is_signed = type_ == 'd' || type_ == 'i';
|
||||||
using fmt::internal::Arg;
|
using internal::Arg;
|
||||||
typedef typename fmt::internal::Conditional<
|
typedef typename internal::Conditional<
|
||||||
is_same<T, void>::value, U, T>::type TargetType;
|
is_same<T, void>::value, U, T>::type TargetType;
|
||||||
if (sizeof(TargetType) <= sizeof(int)) {
|
if (sizeof(TargetType) <= sizeof(int)) {
|
||||||
// Extra casts are used to silence warnings.
|
// Extra casts are used to silence warnings.
|
||||||
@ -327,7 +326,7 @@ class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
|
|||||||
arg_.int_value = static_cast<int>(static_cast<TargetType>(value));
|
arg_.int_value = static_cast<int>(static_cast<TargetType>(value));
|
||||||
} else {
|
} else {
|
||||||
arg_.type = Arg::UINT;
|
arg_.type = Arg::UINT;
|
||||||
typedef typename fmt::internal::MakeUnsigned<TargetType>::Type Unsigned;
|
typedef typename internal::MakeUnsigned<TargetType>::Type Unsigned;
|
||||||
arg_.uint_value = static_cast<unsigned>(static_cast<Unsigned>(value));
|
arg_.uint_value = static_cast<unsigned>(static_cast<Unsigned>(value));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -336,35 +335,35 @@ class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
|
|||||||
// glibc's printf doesn't sign extend arguments of smaller types:
|
// glibc's printf doesn't sign extend arguments of smaller types:
|
||||||
// std::printf("%lld", -42); // prints "4294967254"
|
// std::printf("%lld", -42); // prints "4294967254"
|
||||||
// but we don't have to do the same because it's a UB.
|
// but we don't have to do the same because it's a UB.
|
||||||
arg_.long_long_value = static_cast<fmt::LongLong>(value);
|
arg_.long_long_value = static_cast<LongLong>(value);
|
||||||
} else {
|
} else {
|
||||||
arg_.type = Arg::ULONG_LONG;
|
arg_.type = Arg::ULONG_LONG;
|
||||||
arg_.ulong_long_value =
|
arg_.ulong_long_value =
|
||||||
static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
|
static_cast<typename internal::MakeUnsigned<U>::Type>(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Converts an integer argument to char for printf.
|
// Converts an integer argument to char for printf.
|
||||||
class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> {
|
class CharConverter : public ArgVisitor<CharConverter, void> {
|
||||||
private:
|
private:
|
||||||
fmt::internal::Arg &arg_;
|
internal::Arg &arg_;
|
||||||
|
|
||||||
FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
|
FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit CharConverter(fmt::internal::Arg &arg) : arg_(arg) {}
|
explicit CharConverter(internal::Arg &arg) : arg_(arg) {}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void visit_any_int(T value) {
|
void visit_any_int(T value) {
|
||||||
arg_.type = Arg::CHAR;
|
arg_.type = internal::Arg::CHAR;
|
||||||
arg_.int_value = static_cast<char>(value);
|
arg_.int_value = static_cast<char>(value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Write the content of w to os.
|
// Write the content of w to os.
|
||||||
void write(std::ostream &os, fmt::Writer &w) {
|
void write(std::ostream &os, Writer &w) {
|
||||||
const char *data = w.data();
|
const char *data = w.data();
|
||||||
typedef internal::MakeUnsigned<std::streamsize>::Type UnsignedStreamSize;
|
typedef internal::MakeUnsigned<std::streamsize>::Type UnsignedStreamSize;
|
||||||
UnsignedStreamSize size = w.size();
|
UnsignedStreamSize size = w.size();
|
||||||
|
@ -1305,30 +1305,114 @@ struct NamedArg : Arg {
|
|||||||
: Arg(MakeArg< BasicFormatter<Char> >(value)), name(argname) {}
|
: Arg(MakeArg< BasicFormatter<Char> >(value)), name(argname) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class RuntimeError : public std::runtime_error {
|
||||||
|
protected:
|
||||||
|
RuntimeError() : std::runtime_error("") {}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
class PrintfArgFormatter;
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
class ArgMap;
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
/** An argument list. */
|
||||||
|
class ArgList {
|
||||||
|
private:
|
||||||
|
// To reduce compiled code size per formatting function call, types of first
|
||||||
|
// MAX_PACKED_ARGS arguments are passed in the types_ field.
|
||||||
|
uint64_t types_;
|
||||||
|
union {
|
||||||
|
// If the number of arguments is less than MAX_PACKED_ARGS, the argument
|
||||||
|
// values are stored in values_, otherwise they are stored in args_.
|
||||||
|
// This is done to reduce compiled code size as storing larger objects
|
||||||
|
// may require more code (at least on x86-64) even if the same amount of
|
||||||
|
// data is actually copied to stack. It saves ~10% on the bloat test.
|
||||||
|
const internal::Value *values_;
|
||||||
|
const internal::Arg *args_;
|
||||||
|
};
|
||||||
|
|
||||||
|
internal::Arg::Type type(unsigned index) const {
|
||||||
|
unsigned shift = index * 4;
|
||||||
|
uint64_t mask = 0xf;
|
||||||
|
return static_cast<internal::Arg::Type>(
|
||||||
|
(types_ & (mask << shift)) >> shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
friend class internal::ArgMap;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Maximum number of arguments with packed types.
|
||||||
|
enum { MAX_PACKED_ARGS = 16 };
|
||||||
|
|
||||||
|
ArgList() : types_(0) {}
|
||||||
|
|
||||||
|
ArgList(ULongLong types, const internal::Value *values)
|
||||||
|
: types_(types), values_(values) {}
|
||||||
|
ArgList(ULongLong types, const internal::Arg *args)
|
||||||
|
: types_(types), args_(args) {}
|
||||||
|
|
||||||
|
/** Returns the argument at specified index. */
|
||||||
|
internal::Arg operator[](unsigned index) const {
|
||||||
|
using internal::Arg;
|
||||||
|
Arg arg;
|
||||||
|
bool use_values = type(MAX_PACKED_ARGS - 1) == Arg::NONE;
|
||||||
|
if (index < MAX_PACKED_ARGS) {
|
||||||
|
Arg::Type arg_type = type(index);
|
||||||
|
internal::Value &val = arg;
|
||||||
|
if (arg_type != Arg::NONE)
|
||||||
|
val = use_values ? values_[index] : args_[index];
|
||||||
|
arg.type = arg_type;
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
if (use_values) {
|
||||||
|
// The index is greater than the number of arguments that can be stored
|
||||||
|
// in values, so return a "none" argument.
|
||||||
|
arg.type = Arg::NONE;
|
||||||
|
return arg;
|
||||||
|
}
|
||||||
|
for (unsigned i = MAX_PACKED_ARGS; i <= index; ++i) {
|
||||||
|
if (args_[i].type == Arg::NONE)
|
||||||
|
return args_[i];
|
||||||
|
}
|
||||||
|
return args_[index];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#define FMT_DISPATCH(call) static_cast<Impl*>(this)->call
|
#define FMT_DISPATCH(call) static_cast<Impl*>(this)->call
|
||||||
|
|
||||||
// An argument visitor.
|
/**
|
||||||
// To use ArgVisitor define a subclass that implements some or all of the
|
\rst
|
||||||
// visit methods with the same signatures as the methods in ArgVisitor,
|
An argument visitor.
|
||||||
// for example, visit_int(int).
|
To use `~fmt::ArgVisitor` define a subclass that implements some or all of the
|
||||||
// Pass the subclass as the Impl template parameter. Then calling
|
visit methods with the same signatures as the methods in `~fmt::ArgVisitor`,
|
||||||
// ArgVisitor::visit for some argument will dispatch to a visit method
|
for example, `visit_int(int)`.
|
||||||
// specific to the argument type. For example, if the argument type is
|
Pass the subclass as the *Impl* template parameter. Then calling
|
||||||
// double then visit_double(double) method of a subclass will be called.
|
`~fmt::ArgVisitor::visit` for some argument will dispatch to a visit method
|
||||||
// If the subclass doesn't contain a method with this signature, then
|
specific to the argument type. For example, if the argument type is
|
||||||
// a corresponding method of ArgVisitor will be called.
|
``double`` then `visit_double(double)` method of a subclass will be called.
|
||||||
//
|
If the subclass doesn't contain a method with this signature, then
|
||||||
// Example:
|
a corresponding method of `~fmt::ArgVisitor` will be called.
|
||||||
// class MyArgVisitor : public ArgVisitor<MyArgVisitor, void> {
|
|
||||||
// public:
|
**Example**::
|
||||||
// void visit_int(int value) { print("{}", value); }
|
|
||||||
// void visit_double(double value) { print("{}", value ); }
|
class MyArgVisitor : public fmt::ArgVisitor<MyArgVisitor, void> {
|
||||||
// };
|
public:
|
||||||
//
|
void visit_int(int value) { fmt::print("{}", value); }
|
||||||
// ArgVisitor uses the curiously recurring template pattern:
|
void visit_double(double value) { fmt::print("{}", value ); }
|
||||||
// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
|
};
|
||||||
|
|
||||||
|
`~fmt::ArgVisitor` uses the `curiously recurring template pattern
|
||||||
|
<http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern>`_.
|
||||||
|
\endrst
|
||||||
|
*/
|
||||||
template <typename Impl, typename Result>
|
template <typename Impl, typename Result>
|
||||||
class ArgVisitor {
|
class ArgVisitor {
|
||||||
|
private:
|
||||||
|
typedef internal::Arg Arg;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void report_unhandled_arg() {}
|
void report_unhandled_arg() {}
|
||||||
|
|
||||||
@ -1422,82 +1506,6 @@ class ArgVisitor {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class RuntimeError : public std::runtime_error {
|
|
||||||
protected:
|
|
||||||
RuntimeError() : std::runtime_error("") {}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Char>
|
|
||||||
class PrintfArgFormatter;
|
|
||||||
|
|
||||||
template <typename Char>
|
|
||||||
class ArgMap;
|
|
||||||
} // namespace internal
|
|
||||||
|
|
||||||
/** An argument list. */
|
|
||||||
class ArgList {
|
|
||||||
private:
|
|
||||||
// To reduce compiled code size per formatting function call, types of first
|
|
||||||
// MAX_PACKED_ARGS arguments are passed in the types_ field.
|
|
||||||
uint64_t types_;
|
|
||||||
union {
|
|
||||||
// If the number of arguments is less than MAX_PACKED_ARGS, the argument
|
|
||||||
// values are stored in values_, otherwise they are stored in args_.
|
|
||||||
// This is done to reduce compiled code size as storing larger objects
|
|
||||||
// may require more code (at least on x86-64) even if the same amount of
|
|
||||||
// data is actually copied to stack. It saves ~10% on the bloat test.
|
|
||||||
const internal::Value *values_;
|
|
||||||
const internal::Arg *args_;
|
|
||||||
};
|
|
||||||
|
|
||||||
internal::Arg::Type type(unsigned index) const {
|
|
||||||
unsigned shift = index * 4;
|
|
||||||
uint64_t mask = 0xf;
|
|
||||||
return static_cast<internal::Arg::Type>(
|
|
||||||
(types_ & (mask << shift)) >> shift);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Char>
|
|
||||||
friend class internal::ArgMap;
|
|
||||||
|
|
||||||
public:
|
|
||||||
// Maximum number of arguments with packed types.
|
|
||||||
enum { MAX_PACKED_ARGS = 16 };
|
|
||||||
|
|
||||||
ArgList() : types_(0) {}
|
|
||||||
|
|
||||||
ArgList(ULongLong types, const internal::Value *values)
|
|
||||||
: types_(types), values_(values) {}
|
|
||||||
ArgList(ULongLong types, const internal::Arg *args)
|
|
||||||
: types_(types), args_(args) {}
|
|
||||||
|
|
||||||
/** Returns the argument at specified index. */
|
|
||||||
internal::Arg operator[](unsigned index) const {
|
|
||||||
using internal::Arg;
|
|
||||||
Arg arg;
|
|
||||||
bool use_values = type(MAX_PACKED_ARGS - 1) == Arg::NONE;
|
|
||||||
if (index < MAX_PACKED_ARGS) {
|
|
||||||
Arg::Type arg_type = type(index);
|
|
||||||
internal::Value &val = arg;
|
|
||||||
if (arg_type != Arg::NONE)
|
|
||||||
val = use_values ? values_[index] : args_[index];
|
|
||||||
arg.type = arg_type;
|
|
||||||
return arg;
|
|
||||||
}
|
|
||||||
if (use_values) {
|
|
||||||
// The index is greater than the number of arguments that can be stored
|
|
||||||
// in values, so return a "none" argument.
|
|
||||||
arg.type = Arg::NONE;
|
|
||||||
return arg;
|
|
||||||
}
|
|
||||||
for (unsigned i = MAX_PACKED_ARGS; i <= index; ++i) {
|
|
||||||
if (args_[i].type == Arg::NONE)
|
|
||||||
return args_[i];
|
|
||||||
}
|
|
||||||
return args_[index];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Alignment {
|
enum Alignment {
|
||||||
ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC
|
ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC
|
||||||
};
|
};
|
||||||
@ -1911,9 +1919,9 @@ class PrintfFormatter : private FormatterBase {
|
|||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
An argument formatter.
|
An argument formatter.
|
||||||
To use `~fmt::BasicArgFormatter` define a subclass that implements some or all
|
To use `~fmt::BasicArgFormatter` define a subclass that implements some or
|
||||||
of the visit methods with the same signatures as the methods in `ArgVisitor`,
|
all of the visit methods with the same signatures as the methods in
|
||||||
for example, `visit_int(int)`.
|
`~fmt::ArgVisitor`, for example, `visit_int(int)`.
|
||||||
Pass the subclass as the *Impl* template parameter. When a formatting
|
Pass the subclass as the *Impl* template parameter. When a formatting
|
||||||
function processes an argument, it will dispatch to a visit method
|
function processes an argument, it will dispatch to a visit method
|
||||||
specific to the argument type. For example, if the argument type is
|
specific to the argument type. For example, if the argument type is
|
||||||
|
@ -42,6 +42,9 @@ arguments in the resulting string.
|
|||||||
Argument formatters
|
Argument formatters
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
.. doxygenclass:: fmt::ArgVisitor
|
||||||
|
:members:
|
||||||
|
|
||||||
.. doxygenclass:: fmt::BasicArgFormatter
|
.. doxygenclass:: fmt::BasicArgFormatter
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
|
@ -603,7 +603,7 @@ struct Result {
|
|||||||
Result(const wchar_t *s) : arg(make_arg<wchar_t>(s)) {}
|
Result(const wchar_t *s) : arg(make_arg<wchar_t>(s)) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TestVisitor : fmt::internal::ArgVisitor<TestVisitor, Result> {
|
struct TestVisitor : fmt::ArgVisitor<TestVisitor, Result> {
|
||||||
Result visit_int(int value) { return value; }
|
Result visit_int(int value) { return value; }
|
||||||
Result visit_uint(unsigned value) { return value; }
|
Result visit_uint(unsigned value) { return value; }
|
||||||
Result visit_long_long(fmt::LongLong value) { return value; }
|
Result visit_long_long(fmt::LongLong value) { return value; }
|
||||||
@ -612,10 +612,14 @@ struct TestVisitor : fmt::internal::ArgVisitor<TestVisitor, Result> {
|
|||||||
Result visit_long_double(long double value) { return value; }
|
Result visit_long_double(long double value) { return value; }
|
||||||
Result visit_char(int value) { return static_cast<char>(value); }
|
Result visit_char(int value) { return static_cast<char>(value); }
|
||||||
Result visit_cstring(const char *s) { return s; }
|
Result visit_cstring(const char *s) { return s; }
|
||||||
Result visit_string(Arg::StringValue<char> s) { return s.value; }
|
Result visit_string(fmt::internal::Arg::StringValue<char> s) {
|
||||||
Result visit_wstring(Arg::StringValue<wchar_t> s) { return s.value; }
|
return s.value;
|
||||||
|
}
|
||||||
|
Result visit_wstring(fmt::internal::Arg::StringValue<wchar_t> s) {
|
||||||
|
return s.value;
|
||||||
|
}
|
||||||
Result visit_pointer(const void *p) { return p; }
|
Result visit_pointer(const void *p) { return p; }
|
||||||
Result visit_custom(Arg::CustomValue c) {
|
Result visit_custom(fmt::internal::Arg::CustomValue c) {
|
||||||
return *static_cast<const ::Test*>(c.value);
|
return *static_cast<const ::Test*>(c.value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -652,7 +656,7 @@ TEST(ArgVisitorTest, VisitAll) {
|
|||||||
EXPECT_EQ(&t, result.arg.custom.value);
|
EXPECT_EQ(&t, result.arg.custom.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TestAnyVisitor : fmt::internal::ArgVisitor<TestAnyVisitor, Result> {
|
struct TestAnyVisitor : fmt::ArgVisitor<TestAnyVisitor, Result> {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Result visit_any_int(T value) { return value; }
|
Result visit_any_int(T value) { return value; }
|
||||||
|
|
||||||
@ -677,7 +681,7 @@ TEST(ArgVisitorTest, VisitAny) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct TestUnhandledVisitor :
|
struct TestUnhandledVisitor :
|
||||||
fmt::internal::ArgVisitor<TestUnhandledVisitor, const char *> {
|
fmt::ArgVisitor<TestUnhandledVisitor, const char *> {
|
||||||
const char *visit_unhandled_arg() { return "test"; }
|
const char *visit_unhandled_arg() { return "test"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user