forked from fmtlib/fmt
Pass ranges by value
This commit is contained in:
@ -488,9 +488,9 @@ class value {
|
|||||||
value(char val) { set<CHAR>(int_value, val); }
|
value(char val) { set<CHAR>(int_value, val); }
|
||||||
|
|
||||||
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
|
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
|
||||||
value(wchar_t value) {
|
value(wchar_t val) {
|
||||||
require_wchar<char_type>();
|
require_wchar<char_type>();
|
||||||
set<CHAR>(int_value, value);
|
set<CHAR>(int_value, val);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -514,27 +514,27 @@ class value {
|
|||||||
value(std::nullptr_t) { pointer = nullptr; }
|
value(std::nullptr_t) { pointer = nullptr; }
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
value(const T &value,
|
value(const T &val,
|
||||||
typename std::enable_if<convert_to_int<T>::value, int>::type = 0) {
|
typename std::enable_if<convert_to_int<T>::value, int>::type = 0) {
|
||||||
static_assert(get_type<T>() == INT, "invalid type");
|
static_assert(get_type<T>() == INT, "invalid type");
|
||||||
int_value = value;
|
int_value = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
value(const T &value,
|
value(const T &val,
|
||||||
typename std::enable_if<!convert_to_int<T>::value, int>::type = 0) {
|
typename std::enable_if<!convert_to_int<T>::value, int>::type = 0) {
|
||||||
static_assert(get_type<T>() == CUSTOM, "invalid type");
|
static_assert(get_type<T>() == CUSTOM, "invalid type");
|
||||||
custom.value = &value;
|
custom.value = &val;
|
||||||
custom.format = &format_custom_arg<T>;
|
custom.format = &format_custom_arg<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
value(const named_arg<T, char_type> &na) {
|
value(const named_arg<T, char_type> &val) {
|
||||||
static_assert(get_type<const named_arg<T, char_type> &>() == NAMED_ARG,
|
static_assert(get_type<const named_arg<T, char_type> &>() == NAMED_ARG,
|
||||||
"invalid type");
|
"invalid type");
|
||||||
basic_arg<Context> arg = make_arg<Context>(na.value);
|
basic_arg<Context> arg = make_arg<Context>(val.value);
|
||||||
std::memcpy(na.data, &arg, sizeof(arg));
|
std::memcpy(val.data, &arg, sizeof(arg));
|
||||||
pointer = &na;
|
pointer = &val;
|
||||||
}
|
}
|
||||||
|
|
||||||
const named_arg_base<char_type> &as_named_arg() {
|
const named_arg_base<char_type> &as_named_arg() {
|
||||||
@ -543,16 +543,16 @@ class value {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
template <type TYPE, typename T, typename U>
|
template <type TYPE, typename T, typename U>
|
||||||
constexpr void set(T &field, const U &value) {
|
constexpr void set(T &field, const U &val) {
|
||||||
static_assert(get_type<U>() == TYPE, "invalid type");
|
static_assert(get_type<U>() == TYPE, "invalid type");
|
||||||
field = value;
|
field = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void set_string(const T &value) {
|
void set_string(const T &val) {
|
||||||
static_assert(get_type<T>() == STRING, "invalid type");
|
static_assert(get_type<T>() == STRING, "invalid type");
|
||||||
string.value = value.data();
|
string.value = val.data();
|
||||||
string.size = value.size();
|
string.size = val.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, typename U>
|
template <typename T, typename U>
|
||||||
@ -752,14 +752,14 @@ class arg_map {
|
|||||||
template <typename Range, typename Context>
|
template <typename Range, typename Context>
|
||||||
class context_base : public basic_parse_context<typename Range::value_type> {
|
class context_base : public basic_parse_context<typename Range::value_type> {
|
||||||
private:
|
private:
|
||||||
Range &range_;
|
Range range_;
|
||||||
basic_format_args<Context> args_;
|
basic_format_args<Context> args_;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
using char_type = typename Range::value_type;
|
using char_type = typename Range::value_type;
|
||||||
using format_arg = basic_arg<Context>;
|
using format_arg = basic_arg<Context>;
|
||||||
|
|
||||||
context_base(Range &range, basic_string_view<char_type> format_str,
|
context_base(Range range, basic_string_view<char_type> format_str,
|
||||||
basic_format_args<Context> args)
|
basic_format_args<Context> args)
|
||||||
: basic_parse_context<char_type>(format_str), range_(range), args_(args) {}
|
: basic_parse_context<char_type>(format_str), range_(range), args_(args) {}
|
||||||
|
|
||||||
@ -782,10 +782,40 @@ class context_base : public basic_parse_context<typename Range::value_type> {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
basic_parse_context<char_type> &parse_context() { return *this; }
|
basic_parse_context<char_type> &parse_context() { return *this; }
|
||||||
Range &range() { return range_; }
|
Range range() { return range_; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// A range that can grow dynamically.
|
||||||
|
template <typename Container>
|
||||||
|
class dynamic_range {
|
||||||
|
private:
|
||||||
|
Container &container_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using iterator = decltype(container_.begin());
|
||||||
|
using value_type = typename Container::value_type;
|
||||||
|
|
||||||
|
struct sentinel {
|
||||||
|
friend bool operator!=(sentinel, iterator) { return false; }
|
||||||
|
friend bool operator!=(iterator, sentinel) { return false; }
|
||||||
|
};
|
||||||
|
|
||||||
|
dynamic_range(Container &c) : container_(c) {}
|
||||||
|
|
||||||
|
iterator begin() const { return container_.begin(); }
|
||||||
|
sentinel end() const { return sentinel(); }
|
||||||
|
|
||||||
|
friend iterator grow(dynamic_range r, size_t n) {
|
||||||
|
auto size = r.container_.size();
|
||||||
|
r.container_.resize(size + n);
|
||||||
|
return r.container_.begin() + size;
|
||||||
|
}
|
||||||
|
|
||||||
|
Container &container() const { return container_; }
|
||||||
};
|
};
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
|
// Formatting context.
|
||||||
template <typename Range>
|
template <typename Range>
|
||||||
class basic_context :
|
class basic_context :
|
||||||
public internal::context_base<Range, basic_context<Range>> {
|
public internal::context_base<Range, basic_context<Range>> {
|
||||||
@ -802,7 +832,6 @@ class basic_context :
|
|||||||
FMT_DISALLOW_COPY_AND_ASSIGN(basic_context);
|
FMT_DISALLOW_COPY_AND_ASSIGN(basic_context);
|
||||||
|
|
||||||
using base = internal::context_base<Range, basic_context>;
|
using base = internal::context_base<Range, basic_context>;
|
||||||
|
|
||||||
using format_arg = typename base::format_arg;
|
using format_arg = typename base::format_arg;
|
||||||
using base::get_arg;
|
using base::get_arg;
|
||||||
|
|
||||||
@ -813,7 +842,7 @@ class basic_context :
|
|||||||
stored in the object so make sure they have appropriate lifetimes.
|
stored in the object so make sure they have appropriate lifetimes.
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
basic_context(Range &range, basic_string_view<char_type> format_str,
|
basic_context(Range range, basic_string_view<char_type> format_str,
|
||||||
basic_format_args<basic_context> args)
|
basic_format_args<basic_context> args)
|
||||||
: base(range, format_str, args) {}
|
: base(range, format_str, args) {}
|
||||||
|
|
||||||
@ -825,8 +854,8 @@ class basic_context :
|
|||||||
format_arg get_arg(basic_string_view<char_type> name);
|
format_arg get_arg(basic_string_view<char_type> name);
|
||||||
};
|
};
|
||||||
|
|
||||||
using context = basic_context<buffer>;
|
using context = basic_context<internal::dynamic_range<buffer>>;
|
||||||
using wcontext = basic_context<wbuffer>;
|
using wcontext = basic_context<internal::dynamic_range<wbuffer>>;
|
||||||
|
|
||||||
template <typename Context, typename ...Args>
|
template <typename Context, typename ...Args>
|
||||||
class arg_store {
|
class arg_store {
|
||||||
|
@ -178,7 +178,7 @@ void format_error_code(buffer &out, int error_code,
|
|||||||
++error_code_size;
|
++error_code_size;
|
||||||
}
|
}
|
||||||
error_code_size += internal::count_digits(abs_value);
|
error_code_size += internal::count_digits(abs_value);
|
||||||
basic_writer<buffer> w(out);
|
writer w(out);
|
||||||
if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size) {
|
if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size) {
|
||||||
w.write(message);
|
w.write(message);
|
||||||
w.write(SEP);
|
w.write(SEP);
|
||||||
@ -339,7 +339,7 @@ FMT_FUNC void internal::format_windows_error(
|
|||||||
if (result != 0) {
|
if (result != 0) {
|
||||||
utf16_to_utf8 utf8_message;
|
utf16_to_utf8 utf8_message;
|
||||||
if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
|
if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
|
||||||
basic_writer<buffer> w(out);
|
writer w(out);
|
||||||
w.write(message);
|
w.write(message);
|
||||||
w.write(": ");
|
w.write(": ");
|
||||||
w.write(utf8_message);
|
w.write(utf8_message);
|
||||||
@ -366,7 +366,7 @@ FMT_FUNC void format_system_error(
|
|||||||
char *system_message = &buf[0];
|
char *system_message = &buf[0];
|
||||||
int result = safe_strerror(error_code, system_message, buf.size());
|
int result = safe_strerror(error_code, system_message, buf.size());
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
basic_writer<buffer> w(out);
|
writer w(out);
|
||||||
w.write(message);
|
w.write(message);
|
||||||
w.write(": ");
|
w.write(": ");
|
||||||
w.write(system_message);
|
w.write(system_message);
|
||||||
|
@ -610,33 +610,6 @@ constexpr const Char *pointer_from(null_terminating_iterator<Char> it) {
|
|||||||
return it.ptr_;
|
return it.ptr_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A range that can grow dynamically.
|
|
||||||
template <typename Container>
|
|
||||||
class dynamic_range {
|
|
||||||
private:
|
|
||||||
Container &container_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
using iterator = decltype(container_.begin());
|
|
||||||
using value_type = typename Container::value_type;
|
|
||||||
|
|
||||||
struct sentinel {
|
|
||||||
friend bool operator!=(sentinel, iterator) { return false; }
|
|
||||||
friend bool operator!=(iterator, sentinel) { return false; }
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit dynamic_range(Container &c) : container_(c) {}
|
|
||||||
|
|
||||||
iterator begin() const { return container_.begin(); }
|
|
||||||
sentinel end() const { return sentinel(); }
|
|
||||||
|
|
||||||
friend iterator grow(dynamic_range r, size_t n) {
|
|
||||||
auto size = r.container_.size();
|
|
||||||
r.container_.resize(size + n);
|
|
||||||
return r.container_.begin() + size;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Returns true if value is negative, false otherwise.
|
// Returns true if value is negative, false otherwise.
|
||||||
// Same as (value < 0) but doesn't produce warnings if T is an unsigned type.
|
// Same as (value < 0) but doesn't produce warnings if T is an unsigned type.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -1131,8 +1104,8 @@ constexpr void handle_cstring_type_spec(char spec, Handler &&handler) {
|
|||||||
handler.on_error("invalid type specifier");
|
handler.on_error("invalid type specifier");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename ErrorHandler>
|
template <typename Char, typename ErrorHandler>
|
||||||
constexpr void check_string_type_spec(char spec, ErrorHandler &&eh) {
|
constexpr void check_string_type_spec(Char spec, ErrorHandler &&eh) {
|
||||||
if (spec != 0 && spec != 's')
|
if (spec != 0 && spec != 's')
|
||||||
eh.on_error("invalid type specifier");
|
eh.on_error("invalid type specifier");
|
||||||
}
|
}
|
||||||
@ -1275,7 +1248,7 @@ class arg_formatter_base {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
arg_formatter_base(Range &r, format_specs &s): writer_(r), specs_(s) {}
|
arg_formatter_base(Range r, format_specs &s): writer_(r), specs_(s) {}
|
||||||
|
|
||||||
void operator()(monostate) {
|
void operator()(monostate) {
|
||||||
FMT_ASSERT(false, "invalid argument type");
|
FMT_ASSERT(false, "invalid argument type");
|
||||||
@ -2002,14 +1975,12 @@ class arg_formatter: public internal::arg_formatter_base<Range> {
|
|||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
Constructs an argument formatter object.
|
Constructs an argument formatter object.
|
||||||
*buffer* is a reference to the buffer to be used for output,
|
*r* is an output range, *ctx* is a reference to the formatting context,
|
||||||
*ctx* is a reference to the formatting context, *spec* contains
|
*spec* contains format specifier information for standard argument types.
|
||||||
format specifier information for standard argument types.
|
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
arg_formatter(basic_buffer<char_type> &buffer, basic_context<Range> &ctx,
|
arg_formatter(Range r, basic_context<Range> &ctx, format_specs &spec)
|
||||||
format_specs &spec)
|
: base(r, spec), ctx_(ctx) {}
|
||||||
: base(buffer, spec), ctx_(ctx) {}
|
|
||||||
|
|
||||||
using base::operator();
|
using base::operator();
|
||||||
|
|
||||||
@ -2108,7 +2079,7 @@ class basic_writer {
|
|||||||
using iterator = decltype(std::declval<Range>().begin());
|
using iterator = decltype(std::declval<Range>().begin());
|
||||||
|
|
||||||
// Output range.
|
// Output range.
|
||||||
internal::dynamic_range<Range> range_;
|
Range range_;
|
||||||
iterator out_;
|
iterator out_;
|
||||||
|
|
||||||
std::unique_ptr<locale_provider> locale_;
|
std::unique_ptr<locale_provider> locale_;
|
||||||
@ -2334,7 +2305,7 @@ class basic_writer {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
/** Constructs a ``basic_writer`` object. */
|
/** Constructs a ``basic_writer`` object. */
|
||||||
explicit basic_writer(Range &r): range_(r), out_(r.begin()) {}
|
explicit basic_writer(Range out): range_(out), out_(out.begin()) {}
|
||||||
|
|
||||||
void write(int value) {
|
void write(int value) {
|
||||||
write_decimal(value);
|
write_decimal(value);
|
||||||
@ -2455,10 +2426,10 @@ template <typename T>
|
|||||||
void basic_writer<Range>::write_double(T value, const format_specs &spec) {
|
void basic_writer<Range>::write_double(T value, const format_specs &spec) {
|
||||||
// Check type.
|
// Check type.
|
||||||
struct spec_handler {
|
struct spec_handler {
|
||||||
char type;
|
char_type type;
|
||||||
bool upper = false;
|
bool upper = false;
|
||||||
|
|
||||||
explicit spec_handler(char t) : type(t) {}
|
explicit spec_handler(char_type t) : type(t) {}
|
||||||
|
|
||||||
void on_general() {
|
void on_general() {
|
||||||
if (type == 'G')
|
if (type == 'G')
|
||||||
@ -2600,6 +2571,9 @@ void basic_writer<Range>::write_double(T value, const format_specs &spec) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using writer = basic_writer<internal::dynamic_range<buffer>>;
|
||||||
|
using wwriter = basic_writer<internal::dynamic_range<wbuffer>>;
|
||||||
|
|
||||||
// Reports a system error without throwing an exception.
|
// Reports a system error without throwing an exception.
|
||||||
// Can be used to report errors from destructors.
|
// Can be used to report errors from destructors.
|
||||||
FMT_API void report_system_error(int error_code,
|
FMT_API void report_system_error(int error_code,
|
||||||
@ -2861,9 +2835,8 @@ struct dynamic_formatter {
|
|||||||
return pointer_from(it);
|
return pointer_from(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename Range, typename T>
|
||||||
void format(basic_buffer<Char> &buf, const T &val,
|
void format(const T &val, basic_context<Range> &ctx) {
|
||||||
basic_context<basic_buffer<Char>> &ctx) {
|
|
||||||
handle_specs(ctx);
|
handle_specs(ctx);
|
||||||
struct null_handler : internal::error_handler {
|
struct null_handler : internal::error_handler {
|
||||||
void on_align(alignment) {}
|
void on_align(alignment) {}
|
||||||
@ -2889,8 +2862,8 @@ struct dynamic_formatter {
|
|||||||
}
|
}
|
||||||
if (specs_.precision_ != -1)
|
if (specs_.precision_ != -1)
|
||||||
checker.end_precision();
|
checker.end_precision();
|
||||||
visit(arg_formatter<basic_buffer<Char>>(buf, ctx, specs_),
|
visit(arg_formatter<Range>(ctx.range(), ctx, specs_),
|
||||||
internal::make_arg<basic_context<basic_buffer<Char>>>(val));
|
internal::make_arg<basic_context<Range>>(val));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -2917,19 +2890,20 @@ typename basic_context<Range>::format_arg
|
|||||||
|
|
||||||
/** Formats arguments and writes the output to the buffer. */
|
/** Formats arguments and writes the output to the buffer. */
|
||||||
template <typename ArgFormatter, typename Char, typename Context>
|
template <typename ArgFormatter, typename Char, typename Context>
|
||||||
void vformat_to(typename ArgFormatter::range &out,
|
void vformat_to(typename ArgFormatter::range out,
|
||||||
basic_string_view<Char> format_str,
|
basic_string_view<Char> format_str,
|
||||||
basic_format_args<Context> args) {
|
basic_format_args<Context> args) {
|
||||||
using iterator = internal::null_terminating_iterator<Char>;
|
using iterator = internal::null_terminating_iterator<Char>;
|
||||||
using range = typename ArgFormatter::range;
|
using range = typename ArgFormatter::range;
|
||||||
|
|
||||||
struct handler : internal::error_handler {
|
struct handler : internal::error_handler {
|
||||||
handler(range &o, basic_string_view<Char> str,
|
handler(range r, basic_string_view<Char> str,
|
||||||
basic_format_args<Context> format_args)
|
basic_format_args<Context> format_args)
|
||||||
: out(o), context(o, str, format_args) {}
|
: out(r), context(r, str, format_args) {}
|
||||||
|
|
||||||
void on_text(iterator begin, iterator end) {
|
void on_text(iterator begin, iterator end) {
|
||||||
out.append(pointer_from(begin), pointer_from(end));
|
size_t size = end - begin;
|
||||||
|
std::uninitialized_copy_n(begin, size, grow(out, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_arg_id() { arg = context.next_arg(); }
|
void on_arg_id() { arg = context.next_arg(); }
|
||||||
@ -2967,7 +2941,7 @@ void vformat_to(typename ArgFormatter::range &out,
|
|||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
range &out;
|
range out;
|
||||||
Context context;
|
Context context;
|
||||||
basic_arg<Context> arg;
|
basic_arg<Context> arg;
|
||||||
};
|
};
|
||||||
@ -3005,13 +2979,26 @@ constexpr fill_spec_factory fill;
|
|||||||
constexpr format_spec_factory<width_spec> width;
|
constexpr format_spec_factory<width_spec> width;
|
||||||
constexpr format_spec_factory<type_spec> type;
|
constexpr format_spec_factory<type_spec> type;
|
||||||
|
|
||||||
|
template <typename Range>
|
||||||
|
inline void vformat_range(Range out, string_view format_str, format_args args) {
|
||||||
|
vformat_to<arg_formatter<Range>>(out, format_str, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Range, typename... Args>
|
||||||
|
inline void format_range(Range out, string_view format_str,
|
||||||
|
const Args & ... args) {
|
||||||
|
vformat_range(out, format_str, make_args(args...));
|
||||||
|
}
|
||||||
|
|
||||||
inline void vformat_to(buffer &buf, string_view format_str, format_args args) {
|
inline void vformat_to(buffer &buf, string_view format_str, format_args args) {
|
||||||
vformat_to<arg_formatter<buffer>>(buf, format_str, args);
|
using range = internal::dynamic_range<buffer>;
|
||||||
|
vformat_to<arg_formatter<range>>(buf, format_str, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void vformat_to(wbuffer &buf, wstring_view format_str,
|
inline void vformat_to(wbuffer &buf, wstring_view format_str,
|
||||||
wformat_args args) {
|
wformat_args args) {
|
||||||
vformat_to<arg_formatter<wbuffer>>(buf, format_str, args);
|
using range = internal::dynamic_range<wbuffer>;
|
||||||
|
vformat_to<arg_formatter<range>>(buf, format_str, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::string vformat(string_view format_str, format_args args) {
|
inline std::string vformat(string_view format_str, format_args args) {
|
||||||
|
@ -202,7 +202,7 @@ template <typename Range>
|
|||||||
class printf_arg_formatter;
|
class printf_arg_formatter;
|
||||||
|
|
||||||
template <typename Range, typename ArgFormatter = printf_arg_formatter<Range>>
|
template <typename Range, typename ArgFormatter = printf_arg_formatter<Range>>
|
||||||
class printf_context;
|
class basic_printf_context;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
@ -210,10 +210,9 @@ class printf_context;
|
|||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename Range>
|
template <typename Range>
|
||||||
class printf_arg_formatter :
|
class printf_arg_formatter : public internal::arg_formatter_base<Range> {
|
||||||
public internal::arg_formatter_base<Range> {
|
|
||||||
private:
|
private:
|
||||||
printf_context<Range>& context_;
|
basic_printf_context<Range> &context_;
|
||||||
|
|
||||||
void write_null_pointer() {
|
void write_null_pointer() {
|
||||||
this->spec().type_ = 0;
|
this->spec().type_ = 0;
|
||||||
@ -234,7 +233,7 @@ class printf_arg_formatter :
|
|||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
printf_arg_formatter(basic_buffer<char_type> &buffer, format_specs &spec,
|
printf_arg_formatter(basic_buffer<char_type> &buffer, format_specs &spec,
|
||||||
printf_context<Range> &ctx)
|
basic_printf_context<Range> &ctx)
|
||||||
: base(buffer, spec), context_(ctx) {}
|
: base(buffer, spec), context_(ctx) {}
|
||||||
|
|
||||||
using base::operator();
|
using base::operator();
|
||||||
@ -277,7 +276,8 @@ class printf_arg_formatter :
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Formats an argument of a custom (user-defined) type. */
|
/** Formats an argument of a custom (user-defined) type. */
|
||||||
void operator()(typename basic_arg<printf_context<Range>>::handle handle) {
|
void operator()(
|
||||||
|
typename basic_arg<basic_printf_context<Range>>::handle handle) {
|
||||||
handle.format(context_);
|
handle.format(context_);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -288,15 +288,16 @@ struct printf_formatter {
|
|||||||
auto parse(ParseContext& ctx) { return ctx.begin(); }
|
auto parse(ParseContext& ctx) { return ctx.begin(); }
|
||||||
|
|
||||||
template <typename Range>
|
template <typename Range>
|
||||||
void format(const T &value, printf_context<Range> &ctx) {
|
void format(const T &value, basic_printf_context<Range> &ctx) {
|
||||||
internal::format_value(ctx.range(), value);
|
internal::format_value(ctx.range().container(), value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/** This template formats data and writes the output to a writer. */
|
/** This template formats data and writes the output to a writer. */
|
||||||
template <typename Range, typename ArgFormatter>
|
template <typename Range, typename ArgFormatter>
|
||||||
class printf_context :
|
class basic_printf_context :
|
||||||
private internal::context_base<Range, printf_context<Range, ArgFormatter>> {
|
private internal::context_base<
|
||||||
|
Range, basic_printf_context<Range, ArgFormatter>> {
|
||||||
public:
|
public:
|
||||||
/** The character type for the output. */
|
/** The character type for the output. */
|
||||||
using char_type = typename Range::value_type;
|
using char_type = typename Range::value_type;
|
||||||
@ -305,7 +306,7 @@ class printf_context :
|
|||||||
using formatter_type = printf_formatter<T>;
|
using formatter_type = printf_formatter<T>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef internal::context_base<Range, printf_context> Base;
|
typedef internal::context_base<Range, basic_printf_context> Base;
|
||||||
using format_arg = typename Base::format_arg;
|
using format_arg = typename Base::format_arg;
|
||||||
using format_specs = basic_format_specs<char_type>;
|
using format_specs = basic_format_specs<char_type>;
|
||||||
using iterator = internal::null_terminating_iterator<char_type>;
|
using iterator = internal::null_terminating_iterator<char_type>;
|
||||||
@ -329,8 +330,8 @@ class printf_context :
|
|||||||
appropriate lifetimes.
|
appropriate lifetimes.
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
printf_context(Range &range, basic_string_view<char_type> format_str,
|
basic_printf_context(Range range, basic_string_view<char_type> format_str,
|
||||||
basic_format_args<printf_context> args)
|
basic_format_args<basic_printf_context> args)
|
||||||
: Base(range, format_str, args) {}
|
: Base(range, format_str, args) {}
|
||||||
|
|
||||||
using Base::parse_context;
|
using Base::parse_context;
|
||||||
@ -341,7 +342,8 @@ class printf_context :
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename Range, typename AF>
|
template <typename Range, typename AF>
|
||||||
void printf_context<Range, AF>::parse_flags(format_specs &spec, iterator &it) {
|
void basic_printf_context<Range, AF>::parse_flags(
|
||||||
|
format_specs &spec, iterator &it) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
switch (*it++) {
|
switch (*it++) {
|
||||||
case '-':
|
case '-':
|
||||||
@ -367,8 +369,8 @@ void printf_context<Range, AF>::parse_flags(format_specs &spec, iterator &it) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Range, typename AF>
|
template <typename Range, typename AF>
|
||||||
typename printf_context<Range, AF>::format_arg
|
typename basic_printf_context<Range, AF>::format_arg
|
||||||
printf_context<Range, AF>::get_arg(iterator it, unsigned arg_index) {
|
basic_printf_context<Range, AF>::get_arg(iterator it, unsigned arg_index) {
|
||||||
(void)it;
|
(void)it;
|
||||||
if (arg_index == std::numeric_limits<unsigned>::max())
|
if (arg_index == std::numeric_limits<unsigned>::max())
|
||||||
return this->do_get_arg(this->next_arg_id());
|
return this->do_get_arg(this->next_arg_id());
|
||||||
@ -376,7 +378,7 @@ typename printf_context<Range, AF>::format_arg
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Range, typename AF>
|
template <typename Range, typename AF>
|
||||||
unsigned printf_context<Range, AF>::parse_header(
|
unsigned basic_printf_context<Range, AF>::parse_header(
|
||||||
iterator &it, format_specs &spec) {
|
iterator &it, format_specs &spec) {
|
||||||
unsigned arg_index = std::numeric_limits<unsigned>::max();
|
unsigned arg_index = std::numeric_limits<unsigned>::max();
|
||||||
char_type c = *it;
|
char_type c = *it;
|
||||||
@ -413,8 +415,8 @@ unsigned printf_context<Range, AF>::parse_header(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Range, typename AF>
|
template <typename Range, typename AF>
|
||||||
void printf_context<Range, AF>::format() {
|
void basic_printf_context<Range, AF>::format() {
|
||||||
Range &buffer = this->range();
|
auto &buffer = this->range().container();
|
||||||
Base &base = *this;
|
Base &base = *this;
|
||||||
auto start = iterator(base);
|
auto start = iterator(base);
|
||||||
auto it = start;
|
auto it = start;
|
||||||
@ -503,7 +505,8 @@ void printf_context<Range, AF>::format() {
|
|||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
// TODO: handle wchar_t
|
// TODO: handle wchar_t
|
||||||
visit(internal::CharConverter<printf_context<Range, AF>>(arg), arg);
|
visit(internal::CharConverter<basic_printf_context<Range, AF>>(arg),
|
||||||
|
arg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -516,13 +519,16 @@ void printf_context<Range, AF>::format() {
|
|||||||
buffer.append(pointer_from(start), pointer_from(it));
|
buffer.append(pointer_from(start), pointer_from(it));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char, typename Context>
|
||||||
void printf(basic_buffer<Char> &buf, basic_string_view<Char> format,
|
void printf(basic_buffer<Char> &buf, basic_string_view<Char> format,
|
||||||
basic_format_args<printf_context<basic_buffer<Char>>> args) {
|
basic_format_args<Context> args) {
|
||||||
printf_context<basic_buffer<Char>>(buf, format, args).format();
|
Context(buf, format, args).format();
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef basic_format_args<printf_context<buffer>> printf_args;
|
template <typename Buffer>
|
||||||
|
using printf_context = basic_printf_context<internal::dynamic_range<Buffer>>;
|
||||||
|
|
||||||
|
using printf_args = basic_format_args<printf_context<buffer>>;
|
||||||
|
|
||||||
inline std::string vsprintf(string_view format, printf_args args) {
|
inline std::string vsprintf(string_view format, printf_args args) {
|
||||||
memory_buffer buffer;
|
memory_buffer buffer;
|
||||||
@ -544,8 +550,8 @@ inline std::string sprintf(string_view format_str, const Args & ... args) {
|
|||||||
return vsprintf(format_str, make_args<printf_context<buffer>>(args...));
|
return vsprintf(format_str, make_args<printf_context<buffer>>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline std::wstring vsprintf(
|
inline std::wstring vsprintf(wstring_view format,
|
||||||
wstring_view format, basic_format_args<printf_context<wbuffer>> args) {
|
basic_format_args<printf_context<wbuffer>> args) {
|
||||||
wmemory_buffer buffer;
|
wmemory_buffer buffer;
|
||||||
printf(buffer, format, args);
|
printf(buffer, format, args);
|
||||||
return to_string(buffer);
|
return to_string(buffer);
|
||||||
|
@ -82,7 +82,7 @@ typedef basic_string_buffer<wchar_t> wstring_buffer;
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
std::string to_string(const T &value) {
|
std::string to_string(const T &value) {
|
||||||
string_buffer buf;
|
string_buffer buf;
|
||||||
basic_writer<buffer>(buf).write(value);
|
writer(buf).write(value);
|
||||||
std::string str;
|
std::string str;
|
||||||
buf.move_to(str);
|
buf.move_to(str);
|
||||||
return str;
|
return str;
|
||||||
|
@ -31,7 +31,7 @@ struct formatter<std::tm> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void format(const std::tm &tm, context &ctx) {
|
void format(const std::tm &tm, context &ctx) {
|
||||||
buffer &buf = ctx.range();
|
buffer &buf = ctx.range().container();
|
||||||
std::size_t start = buf.size();
|
std::size_t start = buf.size();
|
||||||
for (;;) {
|
for (;;) {
|
||||||
std::size_t size = buf.capacity() - start;
|
std::size_t size = buf.capacity() - start;
|
||||||
|
@ -14,18 +14,22 @@ using fmt::printf_arg_formatter;
|
|||||||
|
|
||||||
// A custom argument formatter that doesn't print `-` for floating-point values
|
// A custom argument formatter that doesn't print `-` for floating-point values
|
||||||
// rounded to 0.
|
// rounded to 0.
|
||||||
class CustomArgFormatter : public fmt::arg_formatter<fmt::buffer> {
|
class CustomArgFormatter :
|
||||||
|
public fmt::arg_formatter<fmt::internal::dynamic_range<fmt::buffer>> {
|
||||||
public:
|
public:
|
||||||
CustomArgFormatter(fmt::buffer &buf, fmt::basic_context<fmt::buffer> &ctx,
|
using range = fmt::internal::dynamic_range<fmt::buffer>;
|
||||||
fmt::format_specs &s)
|
using base = fmt::arg_formatter<range>;
|
||||||
: fmt::arg_formatter<fmt::buffer>(buf, ctx, s) {}
|
|
||||||
|
|
||||||
using fmt::arg_formatter<fmt::buffer>::operator();
|
CustomArgFormatter(range r, fmt::basic_context<range> &ctx,
|
||||||
|
fmt::format_specs &s)
|
||||||
|
: base(r, ctx, s) {}
|
||||||
|
|
||||||
|
using base::operator();
|
||||||
|
|
||||||
void operator()(double value) {
|
void operator()(double value) {
|
||||||
if (round(value * pow(10, spec().precision())) == 0)
|
if (round(value * pow(10, spec().precision())) == 0)
|
||||||
value = 0;
|
value = 0;
|
||||||
fmt::arg_formatter<fmt::buffer>::operator()(value);
|
base::operator()(value);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -88,7 +88,8 @@ void std_format(long double value, std::wstring &result) {
|
|||||||
template <typename Char, typename T>
|
template <typename Char, typename T>
|
||||||
::testing::AssertionResult check_write(const T &value, const char *type) {
|
::testing::AssertionResult check_write(const T &value, const char *type) {
|
||||||
fmt::basic_memory_buffer<Char> buffer;
|
fmt::basic_memory_buffer<Char> buffer;
|
||||||
fmt::basic_writer<fmt::basic_buffer<Char>> writer(buffer);
|
using range = fmt::internal::dynamic_range<fmt::basic_buffer<Char>>;
|
||||||
|
fmt::basic_writer<range> writer(buffer);
|
||||||
writer.write(value);
|
writer.write(value);
|
||||||
std::basic_string<Char> actual = to_string(buffer);
|
std::basic_string<Char> actual = to_string(buffer);
|
||||||
std::basic_string<Char> expected;
|
std::basic_string<Char> expected;
|
||||||
@ -141,16 +142,16 @@ TEST(StringViewTest, ConvertToString) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST(WriterTest, NotCopyConstructible) {
|
TEST(WriterTest, NotCopyConstructible) {
|
||||||
EXPECT_FALSE(std::is_copy_constructible<basic_writer<fmt::buffer>>::value);
|
EXPECT_FALSE(std::is_copy_constructible<fmt::writer>::value);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(WriterTest, NotCopyAssignable) {
|
TEST(WriterTest, NotCopyAssignable) {
|
||||||
EXPECT_FALSE(std::is_copy_assignable<basic_writer<fmt::buffer>>::value);
|
EXPECT_FALSE(std::is_copy_assignable<fmt::writer>::value);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(WriterTest, Data) {
|
TEST(WriterTest, Data) {
|
||||||
memory_buffer buf;
|
memory_buffer buf;
|
||||||
fmt::basic_writer<fmt::buffer> w(buf);
|
fmt::writer w(buf);
|
||||||
w.write(42);
|
w.write(42);
|
||||||
EXPECT_EQ("42", to_string(buf));
|
EXPECT_EQ("42", to_string(buf));
|
||||||
}
|
}
|
||||||
@ -203,14 +204,14 @@ TEST(WriterTest, WriteLongDouble) {
|
|||||||
|
|
||||||
TEST(WriterTest, WriteDoubleAtBufferBoundary) {
|
TEST(WriterTest, WriteDoubleAtBufferBoundary) {
|
||||||
memory_buffer buf;
|
memory_buffer buf;
|
||||||
fmt::basic_writer<fmt::buffer> writer(buf);
|
fmt::writer writer(buf);
|
||||||
for (int i = 0; i < 100; ++i)
|
for (int i = 0; i < 100; ++i)
|
||||||
writer.write(1.23456789);
|
writer.write(1.23456789);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(WriterTest, WriteDoubleWithFilledBuffer) {
|
TEST(WriterTest, WriteDoubleWithFilledBuffer) {
|
||||||
memory_buffer buf;
|
memory_buffer buf;
|
||||||
fmt::basic_writer<fmt::buffer> writer(buf);
|
fmt::writer writer(buf);
|
||||||
// Fill the buffer.
|
// Fill the buffer.
|
||||||
for (int i = 0; i < fmt::internal::INLINE_BUFFER_SIZE; ++i)
|
for (int i = 0; i < fmt::internal::INLINE_BUFFER_SIZE; ++i)
|
||||||
writer.write(' ');
|
writer.write(' ');
|
||||||
@ -244,7 +245,7 @@ TEST(WriterTest, WriteWideString) {
|
|||||||
template <typename... T>
|
template <typename... T>
|
||||||
std::string write_str(T... args) {
|
std::string write_str(T... args) {
|
||||||
memory_buffer buf;
|
memory_buffer buf;
|
||||||
fmt::basic_writer<fmt::buffer> writer(buf);
|
fmt::writer writer(buf);
|
||||||
writer.write(args...);
|
writer.write(args...);
|
||||||
return to_string(buf);
|
return to_string(buf);
|
||||||
}
|
}
|
||||||
@ -252,7 +253,7 @@ std::string write_str(T... args) {
|
|||||||
template <typename... T>
|
template <typename... T>
|
||||||
std::wstring write_wstr(T... args) {
|
std::wstring write_wstr(T... args) {
|
||||||
wmemory_buffer buf;
|
wmemory_buffer buf;
|
||||||
fmt::basic_writer<fmt::wbuffer> writer(buf);
|
fmt::wwriter writer(buf);
|
||||||
writer.write(args...);
|
writer.write(args...);
|
||||||
return to_string(buf);
|
return to_string(buf);
|
||||||
}
|
}
|
||||||
@ -345,13 +346,13 @@ TEST(WriterTest, pad) {
|
|||||||
|
|
||||||
{
|
{
|
||||||
memory_buffer buf;
|
memory_buffer buf;
|
||||||
fmt::basic_writer<fmt::buffer> w(buf);
|
fmt::writer w(buf);
|
||||||
w << Date(2012, 12, 9);
|
w << Date(2012, 12, 9);
|
||||||
EXPECT_EQ("2012-12-9", to_string(buf));
|
EXPECT_EQ("2012-12-9", to_string(buf));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
memory_buffer buf;
|
memory_buffer buf;
|
||||||
fmt::basic_writer<fmt::buffer> w(buf);
|
fmt::writer w(buf);
|
||||||
w << iso8601(Date(2012, 1, 9));
|
w << iso8601(Date(2012, 1, 9));
|
||||||
EXPECT_EQ("2012-01-09", to_string(buf));
|
EXPECT_EQ("2012-01-09", to_string(buf));
|
||||||
}
|
}
|
||||||
@ -1223,7 +1224,7 @@ struct formatter<Date> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void format(const Date &d, context &ctx) {
|
void format(const Date &d, context &ctx) {
|
||||||
format_to(ctx.range(), "{}-{}-{}", d.year(), d.month(), d.day());
|
format_range(ctx.range(), "{}-{}-{}", d.year(), d.month(), d.day());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -1482,17 +1483,19 @@ TEST(FormatTest, Enum) {
|
|||||||
EXPECT_EQ("0", fmt::format("{}", A));
|
EXPECT_EQ("0", fmt::format("{}", A));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using buffer_range = fmt::internal::dynamic_range<fmt::buffer>;
|
||||||
|
|
||||||
class mock_arg_formatter :
|
class mock_arg_formatter :
|
||||||
public fmt::internal::arg_formatter_base<fmt::buffer> {
|
public fmt::internal::arg_formatter_base<buffer_range> {
|
||||||
private:
|
private:
|
||||||
MOCK_METHOD1(call, void (int value));
|
MOCK_METHOD1(call, void (int value));
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using base = fmt::internal::arg_formatter_base<fmt::buffer>;
|
using base = fmt::internal::arg_formatter_base<buffer_range>;
|
||||||
using range = fmt::buffer;
|
using range = buffer_range;
|
||||||
|
|
||||||
mock_arg_formatter(fmt::buffer &b, fmt::context &, fmt::format_specs &s)
|
mock_arg_formatter(buffer_range r, fmt::context &, fmt::format_specs &s)
|
||||||
: base(b, s) {
|
: base(r, s) {
|
||||||
EXPECT_CALL(*this, call(42));
|
EXPECT_CALL(*this, call(42));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1533,9 +1536,9 @@ template <>
|
|||||||
struct formatter<variant> : dynamic_formatter<> {
|
struct formatter<variant> : dynamic_formatter<> {
|
||||||
void format(variant value, context& ctx) {
|
void format(variant value, context& ctx) {
|
||||||
if (value.type == variant::INT)
|
if (value.type == variant::INT)
|
||||||
dynamic_formatter::format(ctx.range(), 42, ctx);
|
dynamic_formatter::format(42, ctx);
|
||||||
else
|
else
|
||||||
dynamic_formatter::format(ctx.range(), "foo", ctx);
|
dynamic_formatter::format("foo", ctx);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -58,9 +58,11 @@ TEST(OStreamTest, Enum) {
|
|||||||
EXPECT_EQ("0", fmt::format("{}", A));
|
EXPECT_EQ("0", fmt::format("{}", A));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TestArgFormatter : fmt::arg_formatter<fmt::buffer> {
|
struct TestArgFormatter
|
||||||
|
: fmt::arg_formatter<fmt::internal::dynamic_range<fmt::buffer>> {
|
||||||
|
using base = fmt::arg_formatter<fmt::internal::dynamic_range<fmt::buffer>>;
|
||||||
TestArgFormatter(fmt::buffer &buf, fmt::context &ctx, fmt::format_specs &s)
|
TestArgFormatter(fmt::buffer &buf, fmt::context &ctx, fmt::format_specs &s)
|
||||||
: fmt::arg_formatter<fmt::buffer>(buf, ctx, s) {}
|
: base(buf, ctx, s) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST(OStreamTest, CustomArg) {
|
TEST(OStreamTest, CustomArg) {
|
||||||
|
@ -81,9 +81,11 @@ struct formatter<Test, Char> {
|
|||||||
return ctx.begin();
|
return ctx.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
void format(Test, basic_context<basic_buffer<Char>> &ctx) {
|
using range = fmt::internal::dynamic_range<basic_buffer<Char>>;
|
||||||
|
|
||||||
|
void format(Test, basic_context<range> &ctx) {
|
||||||
const Char *test = "test";
|
const Char *test = "test";
|
||||||
ctx.range().append(test, test + std::strlen(test));
|
ctx.range().container().append(test, test + std::strlen(test));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -517,8 +519,8 @@ VISIT_TYPE(float, double);
|
|||||||
#define CHECK_ARG_(Char, expected, value) { \
|
#define CHECK_ARG_(Char, expected, value) { \
|
||||||
testing::StrictMock<MockVisitor<decltype(expected)>> visitor; \
|
testing::StrictMock<MockVisitor<decltype(expected)>> visitor; \
|
||||||
EXPECT_CALL(visitor, visit(expected)); \
|
EXPECT_CALL(visitor, visit(expected)); \
|
||||||
fmt::visit(visitor, \
|
using range = fmt::internal::dynamic_range<basic_buffer<Char>>; \
|
||||||
make_arg<fmt::basic_context<basic_buffer<Char>>>(value)); \
|
fmt::visit(visitor, make_arg<fmt::basic_context<range>>(value)); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CHECK_ARG(value) { \
|
#define CHECK_ARG(value) { \
|
||||||
|
Reference in New Issue
Block a user