Commit f6fd38bb authored by Victor Zverovich's avatar Victor Zverovich

More iterator support

parent c2fecb9b
......@@ -200,7 +200,8 @@ class basic_buffer {
std::size_t capacity_;
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. */
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]; }
};
using buffer = internal::basic_buffer<char>;
using wbuffer = internal::basic_buffer<wchar_t>;
using buffer = basic_buffer<char>;
using wbuffer = basic_buffer<wchar_t>;
// A container-backed buffer.
template <typename Container>
class container_buffer
: public internal::basic_buffer<typename Container::value_type> {
class container_buffer : public basic_buffer<typename Container::value_type> {
private:
Container &container_;
......@@ -282,7 +283,9 @@ class container_buffer
}
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"
......@@ -771,7 +774,6 @@ class context_base {
private:
basic_parse_context<typename Range::value_type> parse_context_;
Range range_;
iterator out_;
basic_format_args<Context> args_;
......@@ -779,9 +781,9 @@ class context_base {
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 r, basic_string_view<char_type> format_str,
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_; }
......@@ -811,23 +813,33 @@ class context_base {
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.
auto begin() { return std::back_inserter(range_.container()); }
auto begin() { return out_; }
// Advances the begin iterator to ``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>
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 dynamic_range {
class back_insert_range {
private:
Container &container_;
public:
using iterator = decltype(container_.begin());
using iterator = std::back_insert_iterator<Container>;
using value_type = typename Container::value_type;
struct sentinel {
......@@ -835,20 +847,11 @@ class dynamic_range {
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(); }
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>
......@@ -895,8 +898,8 @@ class basic_context :
format_arg get_arg(basic_string_view<char_type> name);
};
using context = basic_context<internal::dynamic_range<internal::buffer>>;
using wcontext = basic_context<internal::dynamic_range<internal::wbuffer>>;
using context = basic_context<back_insert_range<internal::buffer>>;
using wcontext = basic_context<back_insert_range<internal::wbuffer>>;
template <typename Context, typename ...Args>
class arg_store {
......@@ -1016,7 +1019,7 @@ struct named_arg_base {
// Serialized value<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>
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,
wformat_args args);
/**
Formats a string and writes the output to out.
*/
template <typename Container>
void vformat_to(std::back_insert_iterator<Container> out,
struct is_contiguous : std::false_type {};
template <typename Char>
struct is_contiguous<std::basic_string<Char>> : std::true_type {};
template <typename Char>
struct is_contiguous<fmt::internal::basic_buffer<Char>> : std::true_type {};
/** 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) {
using iterator = std::back_insert_iterator<Container>;
struct container_accessor : iterator {
container_accessor(iterator it) : iterator(it) {}
using iterator::container;
} accessor(out);
internal::container_buffer<Container> buf(*accessor.container);
internal::container_buffer<Container> buf(internal::get_container(out));
vformat_to(buf, format_str, args);
}
......
......@@ -326,7 +326,7 @@ FMT_FUNC void windows_error::init(
}
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 {
wmemory_buffer buf;
buf.resize(INLINE_BUFFER_SIZE);
......
This diff is collapsed.
......@@ -289,7 +289,7 @@ struct printf_formatter {
template <typename FormatContext>
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();
}
};
......@@ -336,7 +336,6 @@ class basic_printf_context :
: base(range, format_str, args) {}
using base::parse_context;
using base::range;
using base::begin;
using base::advance_to;
......@@ -419,7 +418,7 @@ unsigned basic_printf_context<Range, AF>::parse_header(
template <typename Range, typename AF>
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 it = start;
using internal::pointer_from;
......@@ -528,7 +527,7 @@ void printf(internal::basic_buffer<Char> &buf, basic_string_view<Char> format,
}
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>>;
......
......@@ -31,7 +31,7 @@ struct formatter<std::tm> {
}
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();
for (;;) {
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
// rounded to 0.
class CustomArgFormatter :
public fmt::arg_formatter<
fmt::internal::dynamic_range<fmt::internal::buffer>> {
public fmt::arg_formatter<fmt::back_insert_range<fmt::internal::buffer>> {
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>;
CustomArgFormatter(range r, fmt::basic_context<range> &ctx,
fmt::format_specs &s)
: base(r, ctx, s) {}
CustomArgFormatter(fmt::basic_context<range> &ctx, fmt::format_specs &s)
: base(ctx, s) {}
using base::operator();
......
......@@ -88,7 +88,7 @@ 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;
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);
writer.write(value);
std::basic_string<Char> actual = to_string(buffer);
......@@ -1481,7 +1481,7 @@ TEST(FormatTest, Enum) {
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 :
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 range = buffer_range;
mock_arg_formatter(buffer_range r, fmt::context &, fmt::format_specs &s)
: base(r, s) {
mock_arg_formatter(fmt::context &ctx, fmt::format_specs &s)
: base(fmt::internal::get_container(ctx.begin()), s) {
EXPECT_CALL(*this, call(42));
}
......@@ -1905,6 +1905,6 @@ TEST(FormatTest, FormatStringErrors) {
int, int);
}
TEST(StringTest, ToString) {
TEST(FormatTest, ToString) {
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> {
using base = fmt::arg_formatter<fmt::context::range_type>;
test_arg_formatter(fmt::internal::buffer &buf, fmt::context &ctx,
fmt::format_specs &s)
: base(buf, ctx, s) {}
test_arg_formatter(fmt::context &ctx, fmt::format_specs &s)
: fmt::arg_formatter<fmt::context::range_type>(ctx, s) {}
};
TEST(OStreamTest, CustomArg) {
fmt::memory_buffer buffer;
fmt::context ctx(buffer, "", fmt::format_args());
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()));
EXPECT_EQ("TestEnum", std::string(buffer.data(), buffer.size()));
}
......
......@@ -81,7 +81,7 @@ struct formatter<Test, Char> {
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()) {
const Char *test = "test";
......@@ -521,7 +521,7 @@ VISIT_TYPE(float, double);
#define CHECK_ARG_(Char, expected, value) { \
testing::StrictMock<MockVisitor<decltype(expected)>> visitor; \
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)); \
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment