Pass ranges by value

This commit is contained in:
Victor Zverovich
2018-01-14 07:19:23 -08:00
parent 22994c62f7
commit 217e7c76f1
10 changed files with 169 additions and 136 deletions

View File

@ -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 {

View File

@ -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);

View File

@ -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) {

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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);
} }
}; };

View File

@ -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));
} }
class mock_arg_formatter: using buffer_range = fmt::internal::dynamic_range<fmt::buffer>;
public fmt::internal::arg_formatter_base<fmt::buffer> {
class mock_arg_formatter :
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);
} }
}; };
} }

View File

@ -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) {

View File

@ -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) { \