Add support for back_insert_iterator

This commit is contained in:
Victor Zverovich
2018-01-14 12:25:03 -08:00
parent 91ee9c9acd
commit 9a53a706fc
11 changed files with 124 additions and 229 deletions

View File

@@ -176,6 +176,18 @@ class basic_string_view {
using string_view = basic_string_view<char>;
using wstring_view = basic_string_view<wchar_t>;
template <typename Context>
class basic_arg;
template <typename Context>
class basic_format_args;
// A formatter for objects of type T.
template <typename T, typename Char = char, typename Enable = void>
struct formatter;
namespace internal {
/** A contiguous memory buffer with an optional growing ability. */
template <typename T>
class basic_buffer {
@@ -253,21 +265,6 @@ class basic_buffer {
const T &operator[](std::size_t index) const { return ptr_[index]; }
};
using buffer = basic_buffer<char>;
using wbuffer = basic_buffer<wchar_t>;
template <typename Context>
class basic_arg;
template <typename Context>
class basic_format_args;
// A formatter for objects of type T.
template <typename T, typename Char = char, typename Enable = void>
struct formatter;
namespace internal {
// A helper function to suppress bogus "conditional expression is constant"
// warnings.
template <typename T>
@@ -583,7 +580,7 @@ class value {
typename Context::template formatter_type<T> f;
auto &&parse_ctx = ctx.parse_context();
parse_ctx.advance_to(f.parse(parse_ctx));
ctx.advance_to(f.format(*static_cast<const T*>(arg), ctx));
f.format(*static_cast<const T*>(arg), ctx);
}
};
@@ -797,7 +794,7 @@ class context_base {
Range range() { return range_; }
// Returns an iterator to the beginning of the output range.
iterator begin() { return out_; }
auto begin() { return std::back_inserter(range_.container()); }
// Advances the begin iterator to ``it``.
void advance_to(iterator it) { out_ = it; }
@@ -878,6 +875,9 @@ class basic_context :
format_arg get_arg(basic_string_view<char_type> name);
};
using buffer = internal::basic_buffer<char>;
using wbuffer = internal::basic_buffer<wchar_t>;
using context = basic_context<internal::dynamic_range<buffer>>;
using wcontext = basic_context<internal::dynamic_range<wbuffer>>;

View File

@@ -31,6 +31,7 @@
#include <cassert>
#include <cmath>
#include <cstring>
#include <iterator>
#include <limits>
#include <memory>
#include <stdexcept>
@@ -296,17 +297,6 @@ inline stdext::checked_array_iterator<T*> make_ptr(T *ptr, std::size_t size) {
template <typename T>
inline T *make_ptr(T *ptr, std::size_t) { return ptr; }
#endif
} // namespace internal
// A wrapper around std::locale used to reduce compile times since <locale>
// is very heavy.
class locale;
class locale_provider {
public:
virtual ~locale_provider() {}
virtual fmt::locale locale();
};
template <typename T>
template <typename U>
@@ -318,10 +308,32 @@ void basic_buffer<T>::append(const U *begin, const U *end) {
size_ = new_size;
}
template <typename Char>
inline std::basic_string<Char> to_string(const basic_buffer<Char>& buffer) {
return std::basic_string<Char>(buffer.data(), buffer.size());
}
template <typename Container>
class container_buffer
: public internal::basic_buffer<typename Container::value_type> {
private:
Container &container_;
protected:
virtual void grow(std::size_t capacity) {
container_.resize(capacity);
this->set(&container_[0], capacity);
}
public:
explicit container_buffer(Container &c) : container_(c) {}
};
} // namespace internal
// A wrapper around std::locale used to reduce compile times since <locale>
// is very heavy.
class locale;
class locale_provider {
public:
virtual ~locale_provider() {}
virtual fmt::locale locale();
};
/**
\rst
@@ -354,7 +366,7 @@ inline std::basic_string<Char> to_string(const basic_buffer<Char>& buffer) {
*/
template <typename T, std::size_t SIZE = internal::INLINE_BUFFER_SIZE,
typename Allocator = std::allocator<T> >
class basic_memory_buffer : private Allocator, public basic_buffer<T> {
class basic_memory_buffer: private Allocator, public internal::basic_buffer<T> {
private:
T store_[SIZE];
@@ -453,7 +465,7 @@ typedef basic_memory_buffer<wchar_t> wmemory_buffer;
\endrst
*/
template <typename Char>
class basic_fixed_buffer : public basic_buffer<Char> {
class basic_fixed_buffer : public internal::basic_buffer<Char> {
public:
/**
\rst
@@ -2790,7 +2802,7 @@ struct formatter<
}
template <typename FormatContext>
typename FormatContext::iterator format(const T &val, FormatContext &ctx) {
auto format(const T &val, FormatContext &ctx) -> decltype(ctx.begin()) {
internal::handle_dynamic_spec<internal::width_checker>(
specs_.width_, specs_.width_ref, ctx);
internal::handle_dynamic_spec<internal::precision_checker>(
@@ -2893,9 +2905,9 @@ 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,
basic_string_view<Char> format_str,
basic_format_args<Context> args) {
void do_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;
@@ -2983,32 +2995,64 @@ 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);
/**
\rst
Converts *value* to ``std::string`` using the default format for type *T*.
**Example**::
#include "fmt/string.h"
std::string answer = fmt::to_string(42);
\endrst
*/
template <typename T>
std::string to_string(const T &value) {
std::string str;
internal::container_buffer<std::string> buf(str);
writer(buf).write(value);
return str;
}
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...));
template <typename Char>
std::basic_string<Char> to_string(const basic_memory_buffer<Char> &buffer) {
return std::basic_string<Char>(buffer.data(), buffer.size());
}
inline void vformat_to(buffer &buf, string_view format_str, format_args args) {
using range = internal::dynamic_range<buffer>;
vformat_to<arg_formatter<range>>(buf, format_str, args);
do_vformat_to<arg_formatter<range>>(buf, format_str, args);
}
inline void vformat_to(wbuffer &buf, wstring_view format_str,
wformat_args args) {
using range = internal::dynamic_range<wbuffer>;
vformat_to<arg_formatter<range>>(buf, format_str, args);
do_vformat_to<arg_formatter<range>>(buf, format_str, args);
}
template <typename Container>
void vformat_to(std::back_insert_iterator<Container> out,
string_view format_str, format_args args) {
using iterator = std::back_insert_iterator<Container>;
struct container_extractor : iterator {
container_extractor(iterator it) : iterator(it) {}
using iterator::container;
} extractor(out);
internal::container_buffer<Container> buf(*extractor.container);
vformat_to(buf, format_str, args);
}
template <typename Container, typename... Args>
inline void format_to(std::back_insert_iterator<Container> out,
string_view format_str,
const Args & ... args) {
vformat_to(out, format_str, make_args(args...));
}
inline std::string vformat(string_view format_str, format_args args) {
memory_buffer buffer;
vformat_to(buffer, format_str, args);
return to_string(buffer);
return fmt::to_string(buffer);
}
inline std::wstring vformat(wstring_view format_str, wformat_args args) {

View File

@@ -232,8 +232,8 @@ class printf_arg_formatter : public internal::arg_formatter_base<Range> {
specifier information for standard argument types.
\endrst
*/
printf_arg_formatter(basic_buffer<char_type> &buffer, format_specs &spec,
basic_printf_context<Range> &ctx)
printf_arg_formatter(internal::basic_buffer<char_type> &buffer,
format_specs &spec, basic_printf_context<Range> &ctx)
: base(buffer, spec), context_(ctx) {}
using base::operator();
@@ -522,7 +522,7 @@ void basic_printf_context<Range, AF>::format() {
}
template <typename Char, typename Context>
void printf(basic_buffer<Char> &buf, basic_string_view<Char> format,
void printf(internal::basic_buffer<Char> &buf, basic_string_view<Char> format,
basic_format_args<Context> args) {
Context(buf, format, args).format();
}

View File

@@ -1,92 +0,0 @@
// Formatting library for C++ - string utilities
//
// Copyright (c) 2012 - 2016, Victor Zverovich
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_STRING_H_
#define FMT_STRING_H_
#include "fmt/format.h"
namespace fmt {
/**
\rst
This class template represents a character buffer backed by std::string.
You can use one of the following typedefs for common character types
and the standard allocator:
+----------------+------------------------------+
| Type | Definition |
+================+==============================+
| string_buffer | basic_string_buffer<char> |
+----------------+------------------------------+
| wstring_buffer | basic_string_buffer<wchar_t> |
+----------------+------------------------------+
**Example**::
string_buffer out;
format_to(out, "The answer is {}", 42);
This will write the following output to the ``out`` object:
.. code-block:: none
The answer is 42
The output can be moved to an ``std::string`` with ``out.move_to()``.
\endrst
*/template <typename Char>
class basic_string_buffer : public basic_buffer<Char> {
private:
std::basic_string<Char> str_;
protected:
virtual void grow(std::size_t capacity) {
str_.resize(capacity);
this->set(&str_[0], capacity);
}
public:
/**
\rst
Moves the buffer content to *str* clearing the buffer.
\endrst
*/
void move_to(std::basic_string<Char> &str) {
str_.resize(this->size());
str.swap(str_);
this->resize(0);
this->set(0, 0);
}
};
typedef basic_string_buffer<char> string_buffer;
typedef basic_string_buffer<wchar_t> wstring_buffer;
/**
\rst
Converts *value* to ``std::string`` using the default format for type *T*.
**Example**::
#include "fmt/string.h"
std::string answer = fmt::to_string(42);
\endrst
*/
template <typename T>
std::string to_string(const T &value) {
string_buffer buf;
writer(buf).write(value);
std::string str;
buf.move_to(str);
return str;
}
}
#endif // FMT_STRING_H_