forked from fmtlib/fmt
More iterator support
This commit is contained in:
@ -200,7 +200,8 @@ class basic_buffer {
|
|||||||
std::size_t capacity_;
|
std::size_t capacity_;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
basic_buffer() FMT_NOEXCEPT : ptr_(0), size_(0), capacity_(0) {}
|
basic_buffer(T *p = 0, std::size_t size = 0, std::size_t capacity = 0)
|
||||||
|
FMT_NOEXCEPT: ptr_(p), size_(size), capacity_(capacity) {}
|
||||||
|
|
||||||
/** Sets the buffer data and capacity. */
|
/** Sets the buffer data and capacity. */
|
||||||
void set(T *data, std::size_t capacity) FMT_NOEXCEPT {
|
void set(T *data, std::size_t capacity) FMT_NOEXCEPT {
|
||||||
@ -266,12 +267,12 @@ class basic_buffer {
|
|||||||
const T &operator[](std::size_t index) const { return ptr_[index]; }
|
const T &operator[](std::size_t index) const { return ptr_[index]; }
|
||||||
};
|
};
|
||||||
|
|
||||||
using buffer = internal::basic_buffer<char>;
|
using buffer = basic_buffer<char>;
|
||||||
using wbuffer = internal::basic_buffer<wchar_t>;
|
using wbuffer = basic_buffer<wchar_t>;
|
||||||
|
|
||||||
|
// A container-backed buffer.
|
||||||
template <typename Container>
|
template <typename Container>
|
||||||
class container_buffer
|
class container_buffer : public basic_buffer<typename Container::value_type> {
|
||||||
: public internal::basic_buffer<typename Container::value_type> {
|
|
||||||
private:
|
private:
|
||||||
Container &container_;
|
Container &container_;
|
||||||
|
|
||||||
@ -282,7 +283,9 @@ class container_buffer
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit container_buffer(Container &c) : container_(c) {}
|
explicit container_buffer(Container &c)
|
||||||
|
: basic_buffer<typename Container::value_type>(&c[0], c.size(), c.size()),
|
||||||
|
container_(c) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// A helper function to suppress bogus "conditional expression is constant"
|
// A helper function to suppress bogus "conditional expression is constant"
|
||||||
@ -771,7 +774,6 @@ class context_base {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
basic_parse_context<typename Range::value_type> parse_context_;
|
basic_parse_context<typename Range::value_type> parse_context_;
|
||||||
Range range_;
|
|
||||||
iterator out_;
|
iterator out_;
|
||||||
basic_format_args<Context> args_;
|
basic_format_args<Context> args_;
|
||||||
|
|
||||||
@ -779,9 +781,9 @@ class context_base {
|
|||||||
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 r, basic_string_view<char_type> format_str,
|
||||||
basic_format_args<Context> args)
|
basic_format_args<Context> args)
|
||||||
: parse_context_(format_str), range_(range), args_(args) {}
|
: parse_context_(format_str), out_(r.begin()), args_(args) {}
|
||||||
|
|
||||||
basic_format_args<Context> args() const { return args_; }
|
basic_format_args<Context> args() const { return args_; }
|
||||||
|
|
||||||
@ -811,23 +813,33 @@ class context_base {
|
|||||||
|
|
||||||
void on_error(const char *message) { parse_context_.on_error(message); }
|
void on_error(const char *message) { parse_context_.on_error(message); }
|
||||||
|
|
||||||
Range range() { return range_; }
|
|
||||||
|
|
||||||
// Returns an iterator to the beginning of the output range.
|
// Returns an iterator to the beginning of the output range.
|
||||||
auto begin() { return std::back_inserter(range_.container()); }
|
auto begin() { return out_; }
|
||||||
|
|
||||||
// Advances the begin iterator to ``it``.
|
// Advances the begin iterator to ``it``.
|
||||||
void advance_to(iterator it) { out_ = it; }
|
void advance_to(iterator it) { out_ = it; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// A range that can grow dynamically.
|
// Extracts a reference to the container from back_insert_iterator.
|
||||||
template <typename Container>
|
template <typename Container>
|
||||||
class dynamic_range {
|
inline Container &get_container(std::back_insert_iterator<Container> it) {
|
||||||
|
using iterator = std::back_insert_iterator<Container>;
|
||||||
|
struct accessor: iterator {
|
||||||
|
accessor(iterator it) : iterator(it) {}
|
||||||
|
using iterator::container;
|
||||||
|
};
|
||||||
|
return *accessor(it).container;
|
||||||
|
}
|
||||||
|
} // namespace internal
|
||||||
|
|
||||||
|
// A range where begin() returns back_insert_iterator.
|
||||||
|
template <typename Container>
|
||||||
|
class back_insert_range {
|
||||||
private:
|
private:
|
||||||
Container &container_;
|
Container &container_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using iterator = decltype(container_.begin());
|
using iterator = std::back_insert_iterator<Container>;
|
||||||
using value_type = typename Container::value_type;
|
using value_type = typename Container::value_type;
|
||||||
|
|
||||||
struct sentinel {
|
struct sentinel {
|
||||||
@ -835,20 +847,11 @@ class dynamic_range {
|
|||||||
friend bool operator!=(iterator, sentinel) { return false; }
|
friend bool operator!=(iterator, sentinel) { return false; }
|
||||||
};
|
};
|
||||||
|
|
||||||
dynamic_range(Container &c) : container_(c) {}
|
back_insert_range(Container &c) : container_(c) {}
|
||||||
|
|
||||||
iterator begin() const { return container_.begin(); }
|
iterator begin() const { return std::back_inserter(container_); }
|
||||||
sentinel end() const { return sentinel(); }
|
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.
|
// Formatting context.
|
||||||
template <typename Range>
|
template <typename Range>
|
||||||
@ -895,8 +898,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<internal::dynamic_range<internal::buffer>>;
|
using context = basic_context<back_insert_range<internal::buffer>>;
|
||||||
using wcontext = basic_context<internal::dynamic_range<internal::wbuffer>>;
|
using wcontext = basic_context<back_insert_range<internal::wbuffer>>;
|
||||||
|
|
||||||
template <typename Context, typename ...Args>
|
template <typename Context, typename ...Args>
|
||||||
class arg_store {
|
class arg_store {
|
||||||
@ -1016,7 +1019,7 @@ struct named_arg_base {
|
|||||||
// Serialized value<context>.
|
// Serialized value<context>.
|
||||||
mutable char data[sizeof(basic_arg<context>)];
|
mutable char data[sizeof(basic_arg<context>)];
|
||||||
|
|
||||||
named_arg_base(basic_string_view<Char> name) : name(name) {}
|
named_arg_base(basic_string_view<Char> nm) : name(nm) {}
|
||||||
|
|
||||||
template <typename Context>
|
template <typename Context>
|
||||||
basic_arg<Context> deserialize() const {
|
basic_arg<Context> deserialize() const {
|
||||||
@ -1082,18 +1085,21 @@ void vformat_to(internal::buffer &buf, string_view format_str,
|
|||||||
void vformat_to(internal::wbuffer &buf, wstring_view format_str,
|
void vformat_to(internal::wbuffer &buf, wstring_view format_str,
|
||||||
wformat_args args);
|
wformat_args args);
|
||||||
|
|
||||||
/**
|
|
||||||
Formats a string and writes the output to out.
|
|
||||||
*/
|
|
||||||
template <typename Container>
|
template <typename Container>
|
||||||
void vformat_to(std::back_insert_iterator<Container> out,
|
struct is_contiguous : std::false_type {};
|
||||||
string_view format_str, format_args args) {
|
|
||||||
using iterator = std::back_insert_iterator<Container>;
|
template <typename Char>
|
||||||
struct container_accessor : iterator {
|
struct is_contiguous<std::basic_string<Char>> : std::true_type {};
|
||||||
container_accessor(iterator it) : iterator(it) {}
|
|
||||||
using iterator::container;
|
template <typename Char>
|
||||||
} accessor(out);
|
struct is_contiguous<fmt::internal::basic_buffer<Char>> : std::true_type {};
|
||||||
internal::container_buffer<Container> buf(*accessor.container);
|
|
||||||
|
/** Formats a string and writes the output to ``out``. */
|
||||||
|
template <typename Container>
|
||||||
|
typename std::enable_if<is_contiguous<Container>::value>::type
|
||||||
|
vformat_to(std::back_insert_iterator<Container> out,
|
||||||
|
string_view format_str, format_args args) {
|
||||||
|
internal::container_buffer<Container> buf(internal::get_container(out));
|
||||||
vformat_to(buf, format_str, args);
|
vformat_to(buf, format_str, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,7 +326,7 @@ FMT_FUNC void windows_error::init(
|
|||||||
}
|
}
|
||||||
|
|
||||||
FMT_FUNC void internal::format_windows_error(
|
FMT_FUNC void internal::format_windows_error(
|
||||||
buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
|
internal::buffer &out, int error_code, string_view message) FMT_NOEXCEPT {
|
||||||
FMT_TRY {
|
FMT_TRY {
|
||||||
wmemory_buffer buf;
|
wmemory_buffer buf;
|
||||||
buf.resize(INLINE_BUFFER_SIZE);
|
buf.resize(INLINE_BUFFER_SIZE);
|
||||||
|
@ -512,6 +512,17 @@ class char_traits<wchar_t> : public basic_char_traits<wchar_t> {
|
|||||||
const wchar_t *format, unsigned width, int precision, T value);
|
const wchar_t *format, unsigned width, int precision, T value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename Container>
|
||||||
|
inline auto reserve(std::back_insert_iterator<Container> &it, std::size_t n) {
|
||||||
|
Container &c = internal::get_container(it);
|
||||||
|
std::size_t size = c.size();
|
||||||
|
c.resize(size + n);
|
||||||
|
return &c[size];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Iterator>
|
||||||
|
inline Iterator &reserve(Iterator &it, std::size_t) { return it; }
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
class null_terminating_iterator;
|
class null_terminating_iterator;
|
||||||
|
|
||||||
@ -818,7 +829,7 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits,
|
|||||||
|
|
||||||
template <typename UInt, typename Char>
|
template <typename UInt, typename Char>
|
||||||
inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) {
|
inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) {
|
||||||
return format_decimal(buffer, value, num_digits, no_thousands_sep());
|
format_decimal(buffer, value, num_digits, no_thousands_sep());
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
@ -864,7 +875,7 @@ class utf16_to_utf8 {
|
|||||||
FMT_API int convert(wstring_view s);
|
FMT_API int convert(wstring_view s);
|
||||||
};
|
};
|
||||||
|
|
||||||
FMT_API void format_windows_error(fmt::buffer &out, int error_code,
|
FMT_API void format_windows_error(fmt::internal::buffer &out, int error_code,
|
||||||
fmt::string_view message) FMT_NOEXCEPT;
|
fmt::string_view message) FMT_NOEXCEPT;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -1218,7 +1229,7 @@ class arg_formatter_base {
|
|||||||
FMT_DISALLOW_COPY_AND_ASSIGN(arg_formatter_base);
|
FMT_DISALLOW_COPY_AND_ASSIGN(arg_formatter_base);
|
||||||
|
|
||||||
void write_char(char_type value) {
|
void write_char(char_type value) {
|
||||||
writer_.write_padded(1, specs_, [value](auto &it) {
|
writer_.write_padded(1, specs_, [value](auto &&it) {
|
||||||
*it++ = internal::char_traits<char_type>::cast(value);
|
*it++ = internal::char_traits<char_type>::cast(value);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1970,12 +1981,12 @@ class arg_formatter: public internal::arg_formatter_base<Range> {
|
|||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
Constructs an argument formatter object.
|
Constructs an argument formatter object.
|
||||||
*r* is an output range, *ctx* is a reference to the formatting context,
|
*ctx* is a reference to the formatting context,
|
||||||
*spec* contains format specifier information for standard argument types.
|
*spec* contains format specifier information for standard argument types.
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
arg_formatter(Range r, basic_context<Range> &ctx, format_specs &spec)
|
arg_formatter(basic_context<Range> &ctx, format_specs &spec)
|
||||||
: base(r, spec), ctx_(ctx) {}
|
: base(Range(internal::get_container(ctx.begin())), spec), ctx_(ctx) {}
|
||||||
|
|
||||||
using base::operator();
|
using base::operator();
|
||||||
|
|
||||||
@ -2048,21 +2059,8 @@ FMT_API void format_system_error(fmt::internal::buffer &out, int error_code,
|
|||||||
fmt::string_view message) FMT_NOEXCEPT;
|
fmt::string_view message) FMT_NOEXCEPT;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
|
||||||
This template provides operations for formatting and writing data into a
|
This template provides operations for formatting and writing data into a
|
||||||
character range.
|
character range.
|
||||||
|
|
||||||
You can use one of the following typedefs for common character types:
|
|
||||||
|
|
||||||
+---------+-----------------------+
|
|
||||||
| Type | Definition |
|
|
||||||
+=========+=======================+
|
|
||||||
| writer | basic_writer<buffer> |
|
|
||||||
+---------+-----------------------+
|
|
||||||
| wwriter | basic_writer<wbuffer> |
|
|
||||||
+---------+-----------------------+
|
|
||||||
|
|
||||||
\endrst
|
|
||||||
*/
|
*/
|
||||||
template <typename Range>
|
template <typename Range>
|
||||||
class basic_writer {
|
class basic_writer {
|
||||||
@ -2071,10 +2069,8 @@ class basic_writer {
|
|||||||
using format_specs = basic_format_specs<char_type>;
|
using format_specs = basic_format_specs<char_type>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Output iterator.
|
||||||
using iterator = decltype(std::declval<Range>().begin());
|
using iterator = decltype(std::declval<Range>().begin());
|
||||||
|
|
||||||
// Output range.
|
|
||||||
Range range_;
|
|
||||||
iterator out_;
|
iterator out_;
|
||||||
|
|
||||||
std::unique_ptr<locale_provider> locale_;
|
std::unique_ptr<locale_provider> locale_;
|
||||||
@ -2090,9 +2086,10 @@ class basic_writer {
|
|||||||
static char_type *get(char_type *p) { return p; }
|
static char_type *get(char_type *p) { return p; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Attempts to reserve space for n characters in the output range.
|
// Attempts to reserve space for n extra characters in the output range.
|
||||||
void reserve(std::size_t n) {
|
// Returns a pointer to the reserved range or a reference to out_.
|
||||||
out_ = grow(range_, n);
|
auto reserve(std::size_t n) -> decltype(internal::reserve(out_, n)) {
|
||||||
|
return internal::reserve(out_, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes a value in the format
|
// Writes a value in the format
|
||||||
@ -2123,7 +2120,7 @@ class basic_writer {
|
|||||||
align_spec as = spec;
|
align_spec as = spec;
|
||||||
if (spec.align() == ALIGN_DEFAULT)
|
if (spec.align() == ALIGN_DEFAULT)
|
||||||
as.align_ = ALIGN_RIGHT;
|
as.align_ = ALIGN_RIGHT;
|
||||||
write_padded(size, as, [prefix, fill, padding, f](auto &it) {
|
write_padded(size, as, [prefix, fill, padding, f](auto &&it) {
|
||||||
if (prefix.size() != 0)
|
if (prefix.size() != 0)
|
||||||
it = std::uninitialized_copy_n(prefix.data(), prefix.size(), it);
|
it = std::uninitialized_copy_n(prefix.data(), prefix.size(), it);
|
||||||
it = std::uninitialized_fill_n(it, padding, fill);
|
it = std::uninitialized_fill_n(it, padding, fill);
|
||||||
@ -2140,10 +2137,10 @@ class basic_writer {
|
|||||||
if (is_negative)
|
if (is_negative)
|
||||||
abs_value = 0 - abs_value;
|
abs_value = 0 - abs_value;
|
||||||
unsigned num_digits = internal::count_digits(abs_value);
|
unsigned num_digits = internal::count_digits(abs_value);
|
||||||
reserve((is_negative ? 1 : 0) + num_digits);
|
auto &&it = reserve((is_negative ? 1 : 0) + num_digits);
|
||||||
if (is_negative)
|
if (is_negative)
|
||||||
*out_++ = '-';
|
*it++ = '-';
|
||||||
internal::format_decimal(out_, abs_value, num_digits);
|
internal::format_decimal(it, abs_value, num_digits);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The handle_int_type_spec handler that writes an integer.
|
// The handle_int_type_spec handler that writes an integer.
|
||||||
@ -2185,7 +2182,7 @@ class basic_writer {
|
|||||||
void on_dec() {
|
void on_dec() {
|
||||||
unsigned num_digits = internal::count_digits(abs_value);
|
unsigned num_digits = internal::count_digits(abs_value);
|
||||||
writer.write_int(num_digits, get_prefix(), spec,
|
writer.write_int(num_digits, get_prefix(), spec,
|
||||||
[this, num_digits](auto &it) {
|
[this, num_digits](auto &&it) {
|
||||||
internal::format_decimal(it, abs_value, num_digits);
|
internal::format_decimal(it, abs_value, num_digits);
|
||||||
it += num_digits;
|
it += num_digits;
|
||||||
});
|
});
|
||||||
@ -2198,7 +2195,7 @@ class basic_writer {
|
|||||||
}
|
}
|
||||||
unsigned num_digits = count_digits<4>();
|
unsigned num_digits = count_digits<4>();
|
||||||
writer.write_int(num_digits, get_prefix(), spec,
|
writer.write_int(num_digits, get_prefix(), spec,
|
||||||
[this, num_digits](auto &it) {
|
[this, num_digits](auto &&it) {
|
||||||
it += num_digits;
|
it += num_digits;
|
||||||
auto out = it;
|
auto out = it;
|
||||||
auto n = abs_value;
|
auto n = abs_value;
|
||||||
@ -2217,7 +2214,7 @@ class basic_writer {
|
|||||||
}
|
}
|
||||||
unsigned num_digits = count_digits<1>();
|
unsigned num_digits = count_digits<1>();
|
||||||
writer.write_int(num_digits, get_prefix(), spec,
|
writer.write_int(num_digits, get_prefix(), spec,
|
||||||
[this, num_digits](auto &it) {
|
[this, num_digits](auto &&it) {
|
||||||
it += num_digits;
|
it += num_digits;
|
||||||
auto out = it;
|
auto out = it;
|
||||||
auto n = abs_value;
|
auto n = abs_value;
|
||||||
@ -2236,7 +2233,7 @@ class basic_writer {
|
|||||||
prefix[prefix_size++] = '0';
|
prefix[prefix_size++] = '0';
|
||||||
}
|
}
|
||||||
writer.write_int(num_digits, get_prefix(), spec,
|
writer.write_int(num_digits, get_prefix(), spec,
|
||||||
[this, num_digits](auto &it) {
|
[this, num_digits](auto &&it) {
|
||||||
it += num_digits;
|
it += num_digits;
|
||||||
auto out = it;
|
auto out = it;
|
||||||
auto n = abs_value;
|
auto n = abs_value;
|
||||||
@ -2251,7 +2248,7 @@ class basic_writer {
|
|||||||
char_type sep = internal::thousands_sep<char_type>(writer.locale_.get());
|
char_type sep = internal::thousands_sep<char_type>(writer.locale_.get());
|
||||||
static constexpr unsigned SEP_SIZE = 1;
|
static constexpr unsigned SEP_SIZE = 1;
|
||||||
unsigned size = num_digits + SEP_SIZE * ((num_digits - 1) / 3);
|
unsigned size = num_digits + SEP_SIZE * ((num_digits - 1) / 3);
|
||||||
writer.write_int(size, get_prefix(), spec, [this, size, sep](auto &it) {
|
writer.write_int(size, get_prefix(), spec, [this, size, sep](auto &&it) {
|
||||||
basic_string_view<char_type> s(&sep, SEP_SIZE);
|
basic_string_view<char_type> s(&sep, SEP_SIZE);
|
||||||
internal::format_decimal(it, abs_value, size,
|
internal::format_decimal(it, abs_value, size,
|
||||||
internal::add_thousands_sep<char_type>(s));
|
internal::add_thousands_sep<char_type>(s));
|
||||||
@ -2278,7 +2275,7 @@ class basic_writer {
|
|||||||
// Writes a formatted string.
|
// Writes a formatted string.
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
void write_str(const Char *s, std::size_t size, const align_spec &spec) {
|
void write_str(const Char *s, std::size_t size, const align_spec &spec) {
|
||||||
write_padded(size, spec, [s, size](iterator &it) {
|
write_padded(size, spec, [s, size](auto &&it) {
|
||||||
it = std::uninitialized_copy_n(s, size, it);
|
it = std::uninitialized_copy_n(s, size, it);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -2300,7 +2297,7 @@ class basic_writer {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
/** Constructs a ``basic_writer`` object. */
|
/** Constructs a ``basic_writer`` object. */
|
||||||
explicit basic_writer(Range out): range_(out), out_(out.begin()) {}
|
explicit basic_writer(Range out): out_(out.begin()) {}
|
||||||
|
|
||||||
void write(int value) {
|
void write(int value) {
|
||||||
write_decimal(value);
|
write_decimal(value);
|
||||||
@ -2341,14 +2338,12 @@ class basic_writer {
|
|||||||
|
|
||||||
/** Writes a character to the buffer. */
|
/** Writes a character to the buffer. */
|
||||||
void write(char value) {
|
void write(char value) {
|
||||||
reserve(1);
|
*reserve(1) = value;
|
||||||
*out_++ = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(wchar_t value) {
|
void write(wchar_t value) {
|
||||||
internal::require_wchar<char_type>();
|
internal::require_wchar<char_type>();
|
||||||
reserve(1);
|
*reserve(1) = value;
|
||||||
*out_++ = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2357,14 +2352,14 @@ class basic_writer {
|
|||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
void write(string_view value) {
|
void write(string_view value) {
|
||||||
reserve(value.size());
|
auto &&it = reserve(value.size());
|
||||||
out_ = std::uninitialized_copy(value.begin(), value.end(), out_);
|
it = std::uninitialized_copy(value.begin(), value.end(), it);
|
||||||
}
|
}
|
||||||
|
|
||||||
void write(wstring_view value) {
|
void write(wstring_view value) {
|
||||||
internal::require_wchar<char_type>();
|
internal::require_wchar<char_type>();
|
||||||
reserve(value.size());
|
auto &&it = reserve(value.size());
|
||||||
out_ = std::uninitialized_copy(value.begin(), value.end(), out_);
|
it = std::uninitialized_copy(value.begin(), value.end(), it);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename... FormatSpecs>
|
template <typename... FormatSpecs>
|
||||||
@ -2378,24 +2373,22 @@ template <typename F>
|
|||||||
void basic_writer<Range>::write_padded(
|
void basic_writer<Range>::write_padded(
|
||||||
std::size_t size, const align_spec &spec, F f) {
|
std::size_t size, const align_spec &spec, F f) {
|
||||||
unsigned width = spec.width();
|
unsigned width = spec.width();
|
||||||
if (width <= size) {
|
if (width <= size)
|
||||||
reserve(size);
|
return f(reserve(size));
|
||||||
return f(out_);
|
auto &&it = reserve(width);
|
||||||
}
|
|
||||||
reserve(width);
|
|
||||||
char_type fill = internal::char_traits<char_type>::cast(spec.fill());
|
char_type fill = internal::char_traits<char_type>::cast(spec.fill());
|
||||||
std::size_t padding = width - size;
|
std::size_t padding = width - size;
|
||||||
if (spec.align() == ALIGN_RIGHT) {
|
if (spec.align() == ALIGN_RIGHT) {
|
||||||
out_ = std::uninitialized_fill_n(out_, padding, fill);
|
it = std::uninitialized_fill_n(it, padding, fill);
|
||||||
f(out_);
|
f(it);
|
||||||
} else if (spec.align() == ALIGN_CENTER) {
|
} else if (spec.align() == ALIGN_CENTER) {
|
||||||
std::size_t left_padding = padding / 2;
|
std::size_t left_padding = padding / 2;
|
||||||
out_ = std::uninitialized_fill_n(out_, left_padding, fill);
|
it = std::uninitialized_fill_n(it, left_padding, fill);
|
||||||
f(out_);
|
f(it);
|
||||||
out_ = std::uninitialized_fill_n(out_, padding - left_padding, fill);
|
it = std::uninitialized_fill_n(it, padding - left_padding, fill);
|
||||||
} else {
|
} else {
|
||||||
f(out_);
|
f(it);
|
||||||
out_ = std::uninitialized_fill_n(out_, padding, fill);
|
it = std::uninitialized_fill_n(it, padding, fill);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2472,7 +2465,7 @@ void basic_writer<Range>::write_double(T value, const format_specs &spec) {
|
|||||||
|
|
||||||
auto write_inf_or_nan = [this, &spec, sign](const char *str) {
|
auto write_inf_or_nan = [this, &spec, sign](const char *str) {
|
||||||
enum {SIZE = 3}; // This is an enum to workaround a bug in MSVC.
|
enum {SIZE = 3}; // This is an enum to workaround a bug in MSVC.
|
||||||
write_padded(SIZE + (sign ? 1 : 0), spec, [sign, str](auto &it) {
|
write_padded(SIZE + (sign ? 1 : 0), spec, [sign, str](auto &&it) {
|
||||||
if (sign)
|
if (sign)
|
||||||
*it++ = sign;
|
*it++ = sign;
|
||||||
it = std::uninitialized_copy_n(str, static_cast<std::size_t>(SIZE), it);
|
it = std::uninitialized_copy_n(str, static_cast<std::size_t>(SIZE), it);
|
||||||
@ -2544,8 +2537,7 @@ void basic_writer<Range>::write_double(T value, const format_specs &spec) {
|
|||||||
align_spec as = spec;
|
align_spec as = spec;
|
||||||
if (spec.align() == ALIGN_NUMERIC) {
|
if (spec.align() == ALIGN_NUMERIC) {
|
||||||
if (sign) {
|
if (sign) {
|
||||||
reserve(1);
|
*reserve(1) = sign;
|
||||||
*out_++ = sign;
|
|
||||||
sign = 0;
|
sign = 0;
|
||||||
--as.width_;
|
--as.width_;
|
||||||
}
|
}
|
||||||
@ -2556,7 +2548,7 @@ void basic_writer<Range>::write_double(T value, const format_specs &spec) {
|
|||||||
if (sign)
|
if (sign)
|
||||||
++n;
|
++n;
|
||||||
}
|
}
|
||||||
write_padded(n, as, [n, sign, &buffer](auto &it) mutable {
|
write_padded(n, as, [n, sign, &buffer](auto &&it) mutable {
|
||||||
if (sign) {
|
if (sign) {
|
||||||
*it++ = sign;
|
*it++ = sign;
|
||||||
--n;
|
--n;
|
||||||
@ -2565,8 +2557,8 @@ void basic_writer<Range>::write_double(T value, const format_specs &spec) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
using writer = basic_writer<internal::dynamic_range<internal::buffer>>;
|
using writer = basic_writer<back_insert_range<internal::buffer>>;
|
||||||
using wwriter = basic_writer<internal::dynamic_range<internal::wbuffer>>;
|
using wwriter = basic_writer<back_insert_range<internal::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.
|
||||||
@ -2791,7 +2783,7 @@ struct formatter<
|
|||||||
internal::handle_dynamic_spec<internal::precision_checker>(
|
internal::handle_dynamic_spec<internal::precision_checker>(
|
||||||
specs_.precision_, specs_.precision_ref, ctx);
|
specs_.precision_, specs_.precision_ref, ctx);
|
||||||
using range = typename FormatContext::range_type;
|
using range = typename FormatContext::range_type;
|
||||||
visit(arg_formatter<range>(ctx.range(), ctx, specs_),
|
visit(arg_formatter<range>(ctx, specs_),
|
||||||
internal::make_arg<FormatContext>(val));
|
internal::make_arg<FormatContext>(val));
|
||||||
return ctx.begin();
|
return ctx.begin();
|
||||||
}
|
}
|
||||||
@ -2858,8 +2850,7 @@ struct dynamic_formatter {
|
|||||||
}
|
}
|
||||||
if (specs_.precision_ != -1)
|
if (specs_.precision_ != -1)
|
||||||
checker.end_precision();
|
checker.end_precision();
|
||||||
using range = typename FormatContext::range_type;
|
visit(arg_formatter<typename FormatContext::range_type>(ctx, specs_),
|
||||||
visit(arg_formatter<range>(ctx.range(), ctx, specs_),
|
|
||||||
internal::make_arg<FormatContext>(val));
|
internal::make_arg<FormatContext>(val));
|
||||||
return ctx.begin();
|
return ctx.begin();
|
||||||
}
|
}
|
||||||
@ -2897,11 +2888,14 @@ void do_vformat_to(typename ArgFormatter::range out,
|
|||||||
struct handler : internal::error_handler {
|
struct handler : internal::error_handler {
|
||||||
handler(range r, 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(r), context(r, str, format_args) {}
|
: context(r, str, format_args) {}
|
||||||
|
|
||||||
void on_text(iterator begin, iterator end) {
|
void on_text(iterator begin, iterator end) {
|
||||||
|
auto out = context.begin();
|
||||||
size_t size = end - begin;
|
size_t size = end - begin;
|
||||||
std::uninitialized_copy_n(begin, size, grow(out, size));
|
auto &&it = internal::reserve(out, size);
|
||||||
|
it = std::uninitialized_copy_n(begin, size, it);
|
||||||
|
context.advance_to(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_arg_id() { arg = context.next_arg(); }
|
void on_arg_id() { arg = context.next_arg(); }
|
||||||
@ -2919,7 +2913,7 @@ void do_vformat_to(typename ArgFormatter::range out,
|
|||||||
if (visit(custom_formatter<Char, Context>(context), arg))
|
if (visit(custom_formatter<Char, Context>(context), arg))
|
||||||
return;
|
return;
|
||||||
basic_format_specs<Char> specs;
|
basic_format_specs<Char> specs;
|
||||||
visit(ArgFormatter(out, context, specs), arg);
|
visit(ArgFormatter(context, specs), arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator on_format_specs(iterator it) {
|
iterator on_format_specs(iterator it) {
|
||||||
@ -2936,11 +2930,10 @@ void do_vformat_to(typename ArgFormatter::range out,
|
|||||||
if (*it != '}')
|
if (*it != '}')
|
||||||
on_error("missing '}' in format string");
|
on_error("missing '}' in format string");
|
||||||
parse_ctx.advance_to(pointer_from(it));
|
parse_ctx.advance_to(pointer_from(it));
|
||||||
visit(ArgFormatter(out, context, specs), arg);
|
visit(ArgFormatter(context, specs), arg);
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
range out;
|
|
||||||
Context context;
|
Context context;
|
||||||
basic_arg<Context> arg;
|
basic_arg<Context> arg;
|
||||||
};
|
};
|
||||||
@ -3004,13 +2997,13 @@ std::basic_string<Char> to_string(const basic_memory_buffer<Char> &buffer) {
|
|||||||
|
|
||||||
inline void vformat_to(internal::buffer &buf, string_view format_str,
|
inline void vformat_to(internal::buffer &buf, string_view format_str,
|
||||||
format_args args) {
|
format_args args) {
|
||||||
using range = internal::dynamic_range<internal::buffer>;
|
using range = back_insert_range<internal::buffer>;
|
||||||
do_vformat_to<arg_formatter<range>>(buf, format_str, args);
|
do_vformat_to<arg_formatter<range>>(buf, format_str, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void vformat_to(internal::wbuffer &buf, wstring_view format_str,
|
inline void vformat_to(internal::wbuffer &buf, wstring_view format_str,
|
||||||
wformat_args args) {
|
wformat_args args) {
|
||||||
using range = internal::dynamic_range<internal::wbuffer>;
|
using range = back_insert_range<internal::wbuffer>;
|
||||||
do_vformat_to<arg_formatter<range>>(buf, format_str, args);
|
do_vformat_to<arg_formatter<range>>(buf, format_str, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3028,8 +3021,7 @@ inline void format_to(wmemory_buffer &buf, wstring_view format_str,
|
|||||||
|
|
||||||
template <typename Container, typename... Args>
|
template <typename Container, typename... Args>
|
||||||
inline void format_to(std::back_insert_iterator<Container> out,
|
inline void format_to(std::back_insert_iterator<Container> out,
|
||||||
string_view format_str,
|
string_view format_str, const Args & ... args) {
|
||||||
const Args & ... args) {
|
|
||||||
vformat_to(out, format_str, make_args(args...));
|
vformat_to(out, format_str, make_args(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,7 +289,7 @@ struct printf_formatter {
|
|||||||
|
|
||||||
template <typename FormatContext>
|
template <typename FormatContext>
|
||||||
auto format(const T &value, FormatContext &ctx) -> decltype(ctx.begin()) {
|
auto format(const T &value, FormatContext &ctx) -> decltype(ctx.begin()) {
|
||||||
internal::format_value(ctx.range().container(), value);
|
internal::format_value(internal::get_container(ctx.begin()), value);
|
||||||
return ctx.begin();
|
return ctx.begin();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -336,7 +336,6 @@ class basic_printf_context :
|
|||||||
: base(range, format_str, args) {}
|
: base(range, format_str, args) {}
|
||||||
|
|
||||||
using base::parse_context;
|
using base::parse_context;
|
||||||
using base::range;
|
|
||||||
using base::begin;
|
using base::begin;
|
||||||
using base::advance_to;
|
using base::advance_to;
|
||||||
|
|
||||||
@ -419,7 +418,7 @@ unsigned basic_printf_context<Range, AF>::parse_header(
|
|||||||
|
|
||||||
template <typename Range, typename AF>
|
template <typename Range, typename AF>
|
||||||
void basic_printf_context<Range, AF>::format() {
|
void basic_printf_context<Range, AF>::format() {
|
||||||
auto &buffer = this->range().container();
|
auto &buffer = internal::get_container(this->begin());
|
||||||
auto start = iterator(this->parse_context());
|
auto start = iterator(this->parse_context());
|
||||||
auto it = start;
|
auto it = start;
|
||||||
using internal::pointer_from;
|
using internal::pointer_from;
|
||||||
@ -528,7 +527,7 @@ void printf(internal::basic_buffer<Char> &buf, basic_string_view<Char> format,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename Buffer>
|
template <typename Buffer>
|
||||||
using printf_context = basic_printf_context<internal::dynamic_range<Buffer>>;
|
using printf_context = basic_printf_context<back_insert_range<Buffer>>;
|
||||||
|
|
||||||
using printf_args = basic_format_args<printf_context<internal::buffer>>;
|
using printf_args = basic_format_args<printf_context<internal::buffer>>;
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ struct formatter<std::tm> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto format(const std::tm &tm, context &ctx) -> decltype(ctx.begin()) {
|
auto format(const std::tm &tm, context &ctx) -> decltype(ctx.begin()) {
|
||||||
internal::buffer &buf = ctx.range().container();
|
internal::buffer &buf = internal::get_container(ctx.begin());
|
||||||
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;
|
||||||
|
@ -15,15 +15,13 @@ 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 :
|
class CustomArgFormatter :
|
||||||
public fmt::arg_formatter<
|
public fmt::arg_formatter<fmt::back_insert_range<fmt::internal::buffer>> {
|
||||||
fmt::internal::dynamic_range<fmt::internal::buffer>> {
|
|
||||||
public:
|
public:
|
||||||
using range = fmt::internal::dynamic_range<fmt::internal::buffer>;
|
using range = fmt::back_insert_range<fmt::internal::buffer>;
|
||||||
using base = fmt::arg_formatter<range>;
|
using base = fmt::arg_formatter<range>;
|
||||||
|
|
||||||
CustomArgFormatter(range r, fmt::basic_context<range> &ctx,
|
CustomArgFormatter(fmt::basic_context<range> &ctx, fmt::format_specs &s)
|
||||||
fmt::format_specs &s)
|
: base(ctx, s) {}
|
||||||
: base(r, ctx, s) {}
|
|
||||||
|
|
||||||
using base::operator();
|
using base::operator();
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ 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;
|
||||||
using range = fmt::internal::dynamic_range<fmt::internal::basic_buffer<Char>>;
|
using range = fmt::back_insert_range<fmt::internal::basic_buffer<Char>>;
|
||||||
fmt::basic_writer<range> writer(buffer);
|
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);
|
||||||
@ -1481,7 +1481,7 @@ TEST(FormatTest, Enum) {
|
|||||||
EXPECT_EQ("0", fmt::format("{}", A));
|
EXPECT_EQ("0", fmt::format("{}", A));
|
||||||
}
|
}
|
||||||
|
|
||||||
using buffer_range = fmt::internal::dynamic_range<fmt::internal::buffer>;
|
using buffer_range = fmt::back_insert_range<fmt::internal::buffer>;
|
||||||
|
|
||||||
class mock_arg_formatter :
|
class mock_arg_formatter :
|
||||||
public fmt::internal::arg_formatter_base<buffer_range> {
|
public fmt::internal::arg_formatter_base<buffer_range> {
|
||||||
@ -1492,8 +1492,8 @@ class mock_arg_formatter :
|
|||||||
using base = fmt::internal::arg_formatter_base<buffer_range>;
|
using base = fmt::internal::arg_formatter_base<buffer_range>;
|
||||||
using range = buffer_range;
|
using range = buffer_range;
|
||||||
|
|
||||||
mock_arg_formatter(buffer_range r, fmt::context &, fmt::format_specs &s)
|
mock_arg_formatter(fmt::context &ctx, fmt::format_specs &s)
|
||||||
: base(r, s) {
|
: base(fmt::internal::get_container(ctx.begin()), s) {
|
||||||
EXPECT_CALL(*this, call(42));
|
EXPECT_CALL(*this, call(42));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1905,6 +1905,6 @@ TEST(FormatTest, FormatStringErrors) {
|
|||||||
int, int);
|
int, int);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(StringTest, ToString) {
|
TEST(FormatTest, ToString) {
|
||||||
EXPECT_EQ("42", fmt::to_string(42));
|
EXPECT_EQ("42", fmt::to_string(42));
|
||||||
}
|
}
|
||||||
|
@ -59,17 +59,15 @@ TEST(OStreamTest, Enum) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct test_arg_formatter : fmt::arg_formatter<fmt::context::range_type> {
|
struct test_arg_formatter : fmt::arg_formatter<fmt::context::range_type> {
|
||||||
using base = fmt::arg_formatter<fmt::context::range_type>;
|
test_arg_formatter(fmt::context &ctx, fmt::format_specs &s)
|
||||||
test_arg_formatter(fmt::internal::buffer &buf, fmt::context &ctx,
|
: fmt::arg_formatter<fmt::context::range_type>(ctx, s) {}
|
||||||
fmt::format_specs &s)
|
|
||||||
: base(buf, ctx, s) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST(OStreamTest, CustomArg) {
|
TEST(OStreamTest, CustomArg) {
|
||||||
fmt::memory_buffer buffer;
|
fmt::memory_buffer buffer;
|
||||||
fmt::context ctx(buffer, "", fmt::format_args());
|
fmt::context ctx(buffer, "", fmt::format_args());
|
||||||
fmt::format_specs spec;
|
fmt::format_specs spec;
|
||||||
test_arg_formatter af(buffer, ctx, spec);
|
test_arg_formatter af(ctx, spec);
|
||||||
visit(af, fmt::internal::make_arg<fmt::context>(TestEnum()));
|
visit(af, fmt::internal::make_arg<fmt::context>(TestEnum()));
|
||||||
EXPECT_EQ("TestEnum", std::string(buffer.data(), buffer.size()));
|
EXPECT_EQ("TestEnum", std::string(buffer.data(), buffer.size()));
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,7 @@ struct formatter<Test, Char> {
|
|||||||
return ctx.begin();
|
return ctx.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
using range = fmt::internal::dynamic_range<basic_buffer<Char>>;
|
using range = fmt::back_insert_range<basic_buffer<Char>>;
|
||||||
|
|
||||||
auto format(Test, basic_context<range> &ctx) -> decltype(ctx.begin()) {
|
auto format(Test, basic_context<range> &ctx) -> decltype(ctx.begin()) {
|
||||||
const Char *test = "test";
|
const Char *test = "test";
|
||||||
@ -521,7 +521,7 @@ 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)); \
|
||||||
using range = fmt::internal::dynamic_range<basic_buffer<Char>>; \
|
using range = fmt::back_insert_range<basic_buffer<Char>>; \
|
||||||
fmt::visit(visitor, make_arg<fmt::basic_context<range>>(value)); \
|
fmt::visit(visitor, make_arg<fmt::basic_context<range>>(value)); \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user