mirror of
https://github.com/fmtlib/fmt.git
synced 2024-12-24 03:17:53 +00:00
Pass ranges by value
This commit is contained in:
parent
22994c62f7
commit
217e7c76f1
@ -488,9 +488,9 @@ class value {
|
||||
value(char val) { set<CHAR>(int_value, val); }
|
||||
|
||||
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
|
||||
value(wchar_t value) {
|
||||
value(wchar_t val) {
|
||||
require_wchar<char_type>();
|
||||
set<CHAR>(int_value, value);
|
||||
set<CHAR>(int_value, val);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -514,27 +514,27 @@ class value {
|
||||
value(std::nullptr_t) { pointer = nullptr; }
|
||||
|
||||
template <typename T>
|
||||
value(const T &value,
|
||||
value(const T &val,
|
||||
typename std::enable_if<convert_to_int<T>::value, int>::type = 0) {
|
||||
static_assert(get_type<T>() == INT, "invalid type");
|
||||
int_value = value;
|
||||
int_value = val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
value(const T &value,
|
||||
value(const T &val,
|
||||
typename std::enable_if<!convert_to_int<T>::value, int>::type = 0) {
|
||||
static_assert(get_type<T>() == CUSTOM, "invalid type");
|
||||
custom.value = &value;
|
||||
custom.value = &val;
|
||||
custom.format = &format_custom_arg<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,
|
||||
"invalid type");
|
||||
basic_arg<Context> arg = make_arg<Context>(na.value);
|
||||
std::memcpy(na.data, &arg, sizeof(arg));
|
||||
pointer = &na;
|
||||
basic_arg<Context> arg = make_arg<Context>(val.value);
|
||||
std::memcpy(val.data, &arg, sizeof(arg));
|
||||
pointer = &val;
|
||||
}
|
||||
|
||||
const named_arg_base<char_type> &as_named_arg() {
|
||||
@ -543,16 +543,16 @@ class value {
|
||||
|
||||
private:
|
||||
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");
|
||||
field = value;
|
||||
field = val;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void set_string(const T &value) {
|
||||
void set_string(const T &val) {
|
||||
static_assert(get_type<T>() == STRING, "invalid type");
|
||||
string.value = value.data();
|
||||
string.size = value.size();
|
||||
string.value = val.data();
|
||||
string.size = val.size();
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
@ -752,14 +752,14 @@ class arg_map {
|
||||
template <typename Range, typename Context>
|
||||
class context_base : public basic_parse_context<typename Range::value_type> {
|
||||
private:
|
||||
Range &range_;
|
||||
Range range_;
|
||||
basic_format_args<Context> args_;
|
||||
|
||||
protected:
|
||||
using char_type = typename Range::value_type;
|
||||
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_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:
|
||||
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
|
||||
|
||||
// Formatting context.
|
||||
template <typename Range>
|
||||
class basic_context :
|
||||
public internal::context_base<Range, basic_context<Range>> {
|
||||
@ -802,7 +832,6 @@ class basic_context :
|
||||
FMT_DISALLOW_COPY_AND_ASSIGN(basic_context);
|
||||
|
||||
using base = internal::context_base<Range, basic_context>;
|
||||
|
||||
using format_arg = typename base::format_arg;
|
||||
using base::get_arg;
|
||||
|
||||
@ -813,7 +842,7 @@ class basic_context :
|
||||
stored in the object so make sure they have appropriate lifetimes.
|
||||
\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)
|
||||
: base(range, format_str, args) {}
|
||||
|
||||
@ -825,8 +854,8 @@ class basic_context :
|
||||
format_arg get_arg(basic_string_view<char_type> name);
|
||||
};
|
||||
|
||||
using context = basic_context<buffer>;
|
||||
using wcontext = basic_context<wbuffer>;
|
||||
using context = basic_context<internal::dynamic_range<buffer>>;
|
||||
using wcontext = basic_context<internal::dynamic_range<wbuffer>>;
|
||||
|
||||
template <typename Context, typename ...Args>
|
||||
class arg_store {
|
||||
|
@ -178,7 +178,7 @@ void format_error_code(buffer &out, int error_code,
|
||||
++error_code_size;
|
||||
}
|
||||
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) {
|
||||
w.write(message);
|
||||
w.write(SEP);
|
||||
@ -339,7 +339,7 @@ FMT_FUNC void internal::format_windows_error(
|
||||
if (result != 0) {
|
||||
utf16_to_utf8 utf8_message;
|
||||
if (utf8_message.convert(system_message) == ERROR_SUCCESS) {
|
||||
basic_writer<buffer> w(out);
|
||||
writer w(out);
|
||||
w.write(message);
|
||||
w.write(": ");
|
||||
w.write(utf8_message);
|
||||
@ -366,7 +366,7 @@ FMT_FUNC void format_system_error(
|
||||
char *system_message = &buf[0];
|
||||
int result = safe_strerror(error_code, system_message, buf.size());
|
||||
if (result == 0) {
|
||||
basic_writer<buffer> w(out);
|
||||
writer w(out);
|
||||
w.write(message);
|
||||
w.write(": ");
|
||||
w.write(system_message);
|
||||
|
@ -610,33 +610,6 @@ constexpr const Char *pointer_from(null_terminating_iterator<Char> it) {
|
||||
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.
|
||||
// Same as (value < 0) but doesn't produce warnings if T is an unsigned type.
|
||||
template <typename T>
|
||||
@ -1131,8 +1104,8 @@ constexpr void handle_cstring_type_spec(char spec, Handler &&handler) {
|
||||
handler.on_error("invalid type specifier");
|
||||
}
|
||||
|
||||
template <typename ErrorHandler>
|
||||
constexpr void check_string_type_spec(char spec, ErrorHandler &&eh) {
|
||||
template <typename Char, typename ErrorHandler>
|
||||
constexpr void check_string_type_spec(Char spec, ErrorHandler &&eh) {
|
||||
if (spec != 0 && spec != 's')
|
||||
eh.on_error("invalid type specifier");
|
||||
}
|
||||
@ -1275,7 +1248,7 @@ class arg_formatter_base {
|
||||
}
|
||||
|
||||
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) {
|
||||
FMT_ASSERT(false, "invalid argument type");
|
||||
@ -2002,14 +1975,12 @@ class arg_formatter: public internal::arg_formatter_base<Range> {
|
||||
/**
|
||||
\rst
|
||||
Constructs an argument formatter object.
|
||||
*buffer* is a reference to the buffer to be used for output,
|
||||
*ctx* is a reference to the formatting context, *spec* contains
|
||||
format specifier information for standard argument types.
|
||||
*r* is an output range, *ctx* is a reference to the formatting context,
|
||||
*spec* contains format specifier information for standard argument types.
|
||||
\endrst
|
||||
*/
|
||||
arg_formatter(basic_buffer<char_type> &buffer, basic_context<Range> &ctx,
|
||||
format_specs &spec)
|
||||
: base(buffer, spec), ctx_(ctx) {}
|
||||
arg_formatter(Range r, basic_context<Range> &ctx, format_specs &spec)
|
||||
: base(r, spec), ctx_(ctx) {}
|
||||
|
||||
using base::operator();
|
||||
|
||||
@ -2108,7 +2079,7 @@ class basic_writer {
|
||||
using iterator = decltype(std::declval<Range>().begin());
|
||||
|
||||
// Output range.
|
||||
internal::dynamic_range<Range> range_;
|
||||
Range range_;
|
||||
iterator out_;
|
||||
|
||||
std::unique_ptr<locale_provider> locale_;
|
||||
@ -2334,7 +2305,7 @@ class basic_writer {
|
||||
|
||||
public:
|
||||
/** 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) {
|
||||
write_decimal(value);
|
||||
@ -2455,10 +2426,10 @@ template <typename T>
|
||||
void basic_writer<Range>::write_double(T value, const format_specs &spec) {
|
||||
// Check type.
|
||||
struct spec_handler {
|
||||
char type;
|
||||
char_type type;
|
||||
bool upper = false;
|
||||
|
||||
explicit spec_handler(char t) : type(t) {}
|
||||
explicit spec_handler(char_type t) : type(t) {}
|
||||
|
||||
void on_general() {
|
||||
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.
|
||||
// Can be used to report errors from destructors.
|
||||
FMT_API void report_system_error(int error_code,
|
||||
@ -2861,9 +2835,8 @@ struct dynamic_formatter {
|
||||
return pointer_from(it);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void format(basic_buffer<Char> &buf, const T &val,
|
||||
basic_context<basic_buffer<Char>> &ctx) {
|
||||
template <typename Range, typename T>
|
||||
void format(const T &val, basic_context<Range> &ctx) {
|
||||
handle_specs(ctx);
|
||||
struct null_handler : internal::error_handler {
|
||||
void on_align(alignment) {}
|
||||
@ -2889,8 +2862,8 @@ struct dynamic_formatter {
|
||||
}
|
||||
if (specs_.precision_ != -1)
|
||||
checker.end_precision();
|
||||
visit(arg_formatter<basic_buffer<Char>>(buf, ctx, specs_),
|
||||
internal::make_arg<basic_context<basic_buffer<Char>>>(val));
|
||||
visit(arg_formatter<Range>(ctx.range(), ctx, specs_),
|
||||
internal::make_arg<basic_context<Range>>(val));
|
||||
}
|
||||
|
||||
private:
|
||||
@ -2917,19 +2890,20 @@ typename basic_context<Range>::format_arg
|
||||
|
||||
/** Formats arguments and writes the output to the buffer. */
|
||||
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_format_args<Context> args) {
|
||||
using iterator = internal::null_terminating_iterator<Char>;
|
||||
using range = typename ArgFormatter::range;
|
||||
|
||||
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)
|
||||
: out(o), context(o, str, format_args) {}
|
||||
: out(r), context(r, str, format_args) {}
|
||||
|
||||
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(); }
|
||||
@ -2967,7 +2941,7 @@ void vformat_to(typename ArgFormatter::range &out,
|
||||
return it;
|
||||
}
|
||||
|
||||
range &out;
|
||||
range out;
|
||||
Context context;
|
||||
basic_arg<Context> arg;
|
||||
};
|
||||
@ -3005,13 +2979,26 @@ constexpr fill_spec_factory fill;
|
||||
constexpr format_spec_factory<width_spec> width;
|
||||
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) {
|
||||
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,
|
||||
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) {
|
||||
|
@ -202,7 +202,7 @@ template <typename Range>
|
||||
class printf_arg_formatter;
|
||||
|
||||
template <typename Range, typename ArgFormatter = printf_arg_formatter<Range>>
|
||||
class printf_context;
|
||||
class basic_printf_context;
|
||||
|
||||
/**
|
||||
\rst
|
||||
@ -210,10 +210,9 @@ class printf_context;
|
||||
\endrst
|
||||
*/
|
||||
template <typename Range>
|
||||
class printf_arg_formatter :
|
||||
public internal::arg_formatter_base<Range> {
|
||||
class printf_arg_formatter : public internal::arg_formatter_base<Range> {
|
||||
private:
|
||||
printf_context<Range>& context_;
|
||||
basic_printf_context<Range> &context_;
|
||||
|
||||
void write_null_pointer() {
|
||||
this->spec().type_ = 0;
|
||||
@ -234,7 +233,7 @@ class printf_arg_formatter :
|
||||
\endrst
|
||||
*/
|
||||
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) {}
|
||||
|
||||
using base::operator();
|
||||
@ -277,7 +276,8 @@ class printf_arg_formatter :
|
||||
}
|
||||
|
||||
/** 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_);
|
||||
}
|
||||
};
|
||||
@ -288,15 +288,16 @@ struct printf_formatter {
|
||||
auto parse(ParseContext& ctx) { return ctx.begin(); }
|
||||
|
||||
template <typename Range>
|
||||
void format(const T &value, printf_context<Range> &ctx) {
|
||||
internal::format_value(ctx.range(), value);
|
||||
void format(const T &value, basic_printf_context<Range> &ctx) {
|
||||
internal::format_value(ctx.range().container(), value);
|
||||
}
|
||||
};
|
||||
|
||||
/** This template formats data and writes the output to a writer. */
|
||||
template <typename Range, typename ArgFormatter>
|
||||
class printf_context :
|
||||
private internal::context_base<Range, printf_context<Range, ArgFormatter>> {
|
||||
class basic_printf_context :
|
||||
private internal::context_base<
|
||||
Range, basic_printf_context<Range, ArgFormatter>> {
|
||||
public:
|
||||
/** The character type for the output. */
|
||||
using char_type = typename Range::value_type;
|
||||
@ -305,7 +306,7 @@ class printf_context :
|
||||
using formatter_type = printf_formatter<T>;
|
||||
|
||||
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_specs = basic_format_specs<char_type>;
|
||||
using iterator = internal::null_terminating_iterator<char_type>;
|
||||
@ -329,8 +330,8 @@ class printf_context :
|
||||
appropriate lifetimes.
|
||||
\endrst
|
||||
*/
|
||||
printf_context(Range &range, basic_string_view<char_type> format_str,
|
||||
basic_format_args<printf_context> args)
|
||||
basic_printf_context(Range range, basic_string_view<char_type> format_str,
|
||||
basic_format_args<basic_printf_context> args)
|
||||
: Base(range, format_str, args) {}
|
||||
|
||||
using Base::parse_context;
|
||||
@ -341,7 +342,8 @@ class printf_context :
|
||||
};
|
||||
|
||||
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 (;;) {
|
||||
switch (*it++) {
|
||||
case '-':
|
||||
@ -367,8 +369,8 @@ void printf_context<Range, AF>::parse_flags(format_specs &spec, iterator &it) {
|
||||
}
|
||||
|
||||
template <typename Range, typename AF>
|
||||
typename printf_context<Range, AF>::format_arg
|
||||
printf_context<Range, AF>::get_arg(iterator it, unsigned arg_index) {
|
||||
typename basic_printf_context<Range, AF>::format_arg
|
||||
basic_printf_context<Range, AF>::get_arg(iterator it, unsigned arg_index) {
|
||||
(void)it;
|
||||
if (arg_index == std::numeric_limits<unsigned>::max())
|
||||
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>
|
||||
unsigned printf_context<Range, AF>::parse_header(
|
||||
unsigned basic_printf_context<Range, AF>::parse_header(
|
||||
iterator &it, format_specs &spec) {
|
||||
unsigned arg_index = std::numeric_limits<unsigned>::max();
|
||||
char_type c = *it;
|
||||
@ -413,8 +415,8 @@ unsigned printf_context<Range, AF>::parse_header(
|
||||
}
|
||||
|
||||
template <typename Range, typename AF>
|
||||
void printf_context<Range, AF>::format() {
|
||||
Range &buffer = this->range();
|
||||
void basic_printf_context<Range, AF>::format() {
|
||||
auto &buffer = this->range().container();
|
||||
Base &base = *this;
|
||||
auto start = iterator(base);
|
||||
auto it = start;
|
||||
@ -503,7 +505,8 @@ void printf_context<Range, AF>::format() {
|
||||
break;
|
||||
case 'c':
|
||||
// TODO: handle wchar_t
|
||||
visit(internal::CharConverter<printf_context<Range, AF>>(arg), arg);
|
||||
visit(internal::CharConverter<basic_printf_context<Range, AF>>(arg),
|
||||
arg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -516,13 +519,16 @@ void printf_context<Range, AF>::format() {
|
||||
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,
|
||||
basic_format_args<printf_context<basic_buffer<Char>>> args) {
|
||||
printf_context<basic_buffer<Char>>(buf, format, args).format();
|
||||
basic_format_args<Context> args) {
|
||||
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) {
|
||||
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...));
|
||||
}
|
||||
|
||||
inline std::wstring vsprintf(
|
||||
wstring_view format, basic_format_args<printf_context<wbuffer>> args) {
|
||||
inline std::wstring vsprintf(wstring_view format,
|
||||
basic_format_args<printf_context<wbuffer>> args) {
|
||||
wmemory_buffer buffer;
|
||||
printf(buffer, format, args);
|
||||
return to_string(buffer);
|
||||
|
@ -82,7 +82,7 @@ typedef basic_string_buffer<wchar_t> wstring_buffer;
|
||||
template <typename T>
|
||||
std::string to_string(const T &value) {
|
||||
string_buffer buf;
|
||||
basic_writer<buffer>(buf).write(value);
|
||||
writer(buf).write(value);
|
||||
std::string str;
|
||||
buf.move_to(str);
|
||||
return str;
|
||||
|
@ -31,7 +31,7 @@ struct formatter<std::tm> {
|
||||
}
|
||||
|
||||
void format(const std::tm &tm, context &ctx) {
|
||||
buffer &buf = ctx.range();
|
||||
buffer &buf = ctx.range().container();
|
||||
std::size_t start = buf.size();
|
||||
for (;;) {
|
||||
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
|
||||
// rounded to 0.
|
||||
class CustomArgFormatter : public fmt::arg_formatter<fmt::buffer> {
|
||||
class CustomArgFormatter :
|
||||
public fmt::arg_formatter<fmt::internal::dynamic_range<fmt::buffer>> {
|
||||
public:
|
||||
CustomArgFormatter(fmt::buffer &buf, fmt::basic_context<fmt::buffer> &ctx,
|
||||
fmt::format_specs &s)
|
||||
: fmt::arg_formatter<fmt::buffer>(buf, ctx, s) {}
|
||||
using range = fmt::internal::dynamic_range<fmt::buffer>;
|
||||
using base = fmt::arg_formatter<range>;
|
||||
|
||||
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) {
|
||||
if (round(value * pow(10, spec().precision())) == 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>
|
||||
::testing::AssertionResult check_write(const T &value, const char *type) {
|
||||
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);
|
||||
std::basic_string<Char> actual = to_string(buffer);
|
||||
std::basic_string<Char> expected;
|
||||
@ -141,16 +142,16 @@ TEST(StringViewTest, ConvertToString) {
|
||||
}
|
||||
|
||||
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) {
|
||||
EXPECT_FALSE(std::is_copy_assignable<basic_writer<fmt::buffer>>::value);
|
||||
EXPECT_FALSE(std::is_copy_assignable<fmt::writer>::value);
|
||||
}
|
||||
|
||||
TEST(WriterTest, Data) {
|
||||
memory_buffer buf;
|
||||
fmt::basic_writer<fmt::buffer> w(buf);
|
||||
fmt::writer w(buf);
|
||||
w.write(42);
|
||||
EXPECT_EQ("42", to_string(buf));
|
||||
}
|
||||
@ -203,14 +204,14 @@ TEST(WriterTest, WriteLongDouble) {
|
||||
|
||||
TEST(WriterTest, WriteDoubleAtBufferBoundary) {
|
||||
memory_buffer buf;
|
||||
fmt::basic_writer<fmt::buffer> writer(buf);
|
||||
fmt::writer writer(buf);
|
||||
for (int i = 0; i < 100; ++i)
|
||||
writer.write(1.23456789);
|
||||
}
|
||||
|
||||
TEST(WriterTest, WriteDoubleWithFilledBuffer) {
|
||||
memory_buffer buf;
|
||||
fmt::basic_writer<fmt::buffer> writer(buf);
|
||||
fmt::writer writer(buf);
|
||||
// Fill the buffer.
|
||||
for (int i = 0; i < fmt::internal::INLINE_BUFFER_SIZE; ++i)
|
||||
writer.write(' ');
|
||||
@ -244,7 +245,7 @@ TEST(WriterTest, WriteWideString) {
|
||||
template <typename... T>
|
||||
std::string write_str(T... args) {
|
||||
memory_buffer buf;
|
||||
fmt::basic_writer<fmt::buffer> writer(buf);
|
||||
fmt::writer writer(buf);
|
||||
writer.write(args...);
|
||||
return to_string(buf);
|
||||
}
|
||||
@ -252,7 +253,7 @@ std::string write_str(T... args) {
|
||||
template <typename... T>
|
||||
std::wstring write_wstr(T... args) {
|
||||
wmemory_buffer buf;
|
||||
fmt::basic_writer<fmt::wbuffer> writer(buf);
|
||||
fmt::wwriter writer(buf);
|
||||
writer.write(args...);
|
||||
return to_string(buf);
|
||||
}
|
||||
@ -345,13 +346,13 @@ TEST(WriterTest, pad) {
|
||||
|
||||
{
|
||||
memory_buffer buf;
|
||||
fmt::basic_writer<fmt::buffer> w(buf);
|
||||
fmt::writer w(buf);
|
||||
w << Date(2012, 12, 9);
|
||||
EXPECT_EQ("2012-12-9", to_string(buf));
|
||||
}
|
||||
{
|
||||
memory_buffer buf;
|
||||
fmt::basic_writer<fmt::buffer> w(buf);
|
||||
fmt::writer w(buf);
|
||||
w << iso8601(Date(2012, 1, 9));
|
||||
EXPECT_EQ("2012-01-09", to_string(buf));
|
||||
}
|
||||
@ -1223,7 +1224,7 @@ struct formatter<Date> {
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
class mock_arg_formatter:
|
||||
public fmt::internal::arg_formatter_base<fmt::buffer> {
|
||||
using buffer_range = fmt::internal::dynamic_range<fmt::buffer>;
|
||||
|
||||
class mock_arg_formatter :
|
||||
public fmt::internal::arg_formatter_base<buffer_range> {
|
||||
private:
|
||||
MOCK_METHOD1(call, void (int value));
|
||||
|
||||
public:
|
||||
using base = fmt::internal::arg_formatter_base<fmt::buffer>;
|
||||
using range = fmt::buffer;
|
||||
using base = fmt::internal::arg_formatter_base<buffer_range>;
|
||||
using range = buffer_range;
|
||||
|
||||
mock_arg_formatter(fmt::buffer &b, fmt::context &, fmt::format_specs &s)
|
||||
: base(b, s) {
|
||||
mock_arg_formatter(buffer_range r, fmt::context &, fmt::format_specs &s)
|
||||
: base(r, s) {
|
||||
EXPECT_CALL(*this, call(42));
|
||||
}
|
||||
|
||||
@ -1533,9 +1536,9 @@ template <>
|
||||
struct formatter<variant> : dynamic_formatter<> {
|
||||
void format(variant value, context& ctx) {
|
||||
if (value.type == variant::INT)
|
||||
dynamic_formatter::format(ctx.range(), 42, ctx);
|
||||
dynamic_formatter::format(42, ctx);
|
||||
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));
|
||||
}
|
||||
|
||||
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)
|
||||
: fmt::arg_formatter<fmt::buffer>(buf, ctx, s) {}
|
||||
: base(buf, ctx, s) {}
|
||||
};
|
||||
|
||||
TEST(OStreamTest, CustomArg) {
|
||||
|
@ -81,9 +81,11 @@ struct formatter<Test, Char> {
|
||||
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";
|
||||
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) { \
|
||||
testing::StrictMock<MockVisitor<decltype(expected)>> visitor; \
|
||||
EXPECT_CALL(visitor, visit(expected)); \
|
||||
fmt::visit(visitor, \
|
||||
make_arg<fmt::basic_context<basic_buffer<Char>>>(value)); \
|
||||
using range = fmt::internal::dynamic_range<basic_buffer<Char>>; \
|
||||
fmt::visit(visitor, make_arg<fmt::basic_context<range>>(value)); \
|
||||
}
|
||||
|
||||
#define CHECK_ARG(value) { \
|
||||
|
Loading…
Reference in New Issue
Block a user