mirror of
https://github.com/fmtlib/fmt.git
synced 2025-07-31 19:24:48 +02:00
Add an experimental writer API
This commit is contained in:
@@ -1069,6 +1069,24 @@ template <typename T> class iterator_buffer<T*, T> : public buffer<T> {
|
|||||||
auto out() -> T* { return &*this->end(); }
|
auto out() -> T* { return &*this->end(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename Container>
|
||||||
|
class container_buffer : public buffer<typename Container::value_type> {
|
||||||
|
private:
|
||||||
|
using value_type = typename Container::value_type;
|
||||||
|
|
||||||
|
static FMT_CONSTEXPR void grow(buffer<value_type>& buf, size_t capacity) {
|
||||||
|
auto& self = static_cast<container_buffer&>(buf);
|
||||||
|
self.container.resize(capacity);
|
||||||
|
self.set(&self.container[0], capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
Container& container;
|
||||||
|
|
||||||
|
explicit container_buffer(Container& c)
|
||||||
|
: buffer<value_type>(grow, c.size()), container(c) {}
|
||||||
|
};
|
||||||
|
|
||||||
// A buffer that writes to a container with the contiguous storage.
|
// A buffer that writes to a container with the contiguous storage.
|
||||||
template <typename OutputIt>
|
template <typename OutputIt>
|
||||||
class iterator_buffer<
|
class iterator_buffer<
|
||||||
@@ -1076,25 +1094,16 @@ class iterator_buffer<
|
|||||||
enable_if_t<detail::is_back_insert_iterator<OutputIt>::value &&
|
enable_if_t<detail::is_back_insert_iterator<OutputIt>::value &&
|
||||||
is_contiguous<typename OutputIt::container_type>::value,
|
is_contiguous<typename OutputIt::container_type>::value,
|
||||||
typename OutputIt::container_type::value_type>>
|
typename OutputIt::container_type::value_type>>
|
||||||
: public buffer<typename OutputIt::container_type::value_type> {
|
: public container_buffer<typename OutputIt::container_type> {
|
||||||
private:
|
private:
|
||||||
using container_type = typename OutputIt::container_type;
|
using base = container_buffer<typename OutputIt::container_type>;
|
||||||
using value_type = typename container_type::value_type;
|
|
||||||
container_type& container_;
|
|
||||||
|
|
||||||
static FMT_CONSTEXPR void grow(buffer<value_type>& buf, size_t capacity) {
|
|
||||||
auto& self = static_cast<iterator_buffer&>(buf);
|
|
||||||
self.container_.resize(capacity);
|
|
||||||
self.set(&self.container_[0], capacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit iterator_buffer(container_type& c)
|
explicit iterator_buffer(typename OutputIt::container_type& c) : base(c) {}
|
||||||
: buffer<value_type>(grow, c.size()), container_(c) {}
|
|
||||||
explicit iterator_buffer(OutputIt out, size_t = 0)
|
explicit iterator_buffer(OutputIt out, size_t = 0)
|
||||||
: iterator_buffer(get_container(out)) {}
|
: base(get_container(out)) {}
|
||||||
|
|
||||||
auto out() -> OutputIt { return OutputIt(container_); }
|
auto out() -> OutputIt { return OutputIt(this->container); }
|
||||||
};
|
};
|
||||||
|
|
||||||
// A buffer that counts the number of code units written discarding the output.
|
// A buffer that counts the number of code units written discarding the output.
|
||||||
|
@@ -938,6 +938,41 @@ class basic_memory_buffer : public detail::buffer<T> {
|
|||||||
|
|
||||||
using memory_buffer = basic_memory_buffer<char>;
|
using memory_buffer = basic_memory_buffer<char>;
|
||||||
|
|
||||||
|
// A writer to a buffered stream. It doesn't own the underlying stream.
|
||||||
|
class writer {
|
||||||
|
private:
|
||||||
|
detail::buffer<char>* buf_;
|
||||||
|
|
||||||
|
// We cannot create a file buffer in advance because any write to a FILE may
|
||||||
|
// invalidate it.
|
||||||
|
FILE* file_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
writer(FILE* f) : buf_(nullptr), file_(f) {}
|
||||||
|
writer(detail::buffer<char>& buf) : buf_(&buf) {}
|
||||||
|
|
||||||
|
/// Formats `args` according to specifications in `fmt` and writes the
|
||||||
|
/// output to the file.
|
||||||
|
template <typename... T> void print(format_string<T...> fmt, T&&... args) {
|
||||||
|
if (buf_)
|
||||||
|
fmt::format_to(appender(*buf_), fmt, std::forward<T>(args)...);
|
||||||
|
else
|
||||||
|
fmt::print(file_, fmt, std::forward<T>(args)...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class string_buffer {
|
||||||
|
private:
|
||||||
|
std::string str_;
|
||||||
|
detail::container_buffer<std::string> buf_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
string_buffer() : buf_(str_) {}
|
||||||
|
|
||||||
|
operator writer() { return buf_; }
|
||||||
|
std::string& str() { return str_; }
|
||||||
|
};
|
||||||
|
|
||||||
template <typename T, size_t SIZE, typename Allocator>
|
template <typename T, size_t SIZE, typename Allocator>
|
||||||
struct is_contiguous<basic_memory_buffer<T, SIZE, Allocator>> : std::true_type {
|
struct is_contiguous<basic_memory_buffer<T, SIZE, Allocator>> : std::true_type {
|
||||||
};
|
};
|
||||||
|
@@ -376,6 +376,11 @@ class FMT_API ostream : private detail::buffer<char> {
|
|||||||
ostream(ostream&& other) noexcept;
|
ostream(ostream&& other) noexcept;
|
||||||
~ostream();
|
~ostream();
|
||||||
|
|
||||||
|
operator writer() {
|
||||||
|
detail::buffer<char>& buf = *this;
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
void flush() {
|
void flush() {
|
||||||
if (size() == 0) return;
|
if (size() == 0) return;
|
||||||
file_.write(data(), size() * sizeof(data()[0]));
|
file_.write(data(), size() * sizeof(data()[0]));
|
||||||
|
@@ -2478,3 +2478,27 @@ FMT_END_NAMESPACE
|
|||||||
TEST(format_test, ustring) {
|
TEST(format_test, ustring) {
|
||||||
EXPECT_EQ(fmt::format("{}", ustring()), "ustring");
|
EXPECT_EQ(fmt::format("{}", ustring()), "ustring");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(format_test, writer) {
|
||||||
|
auto write_to_stdout = []() {
|
||||||
|
auto w = fmt::writer(stdout);
|
||||||
|
w.print("{}", 42);
|
||||||
|
};
|
||||||
|
EXPECT_WRITE(stdout, write_to_stdout(), "42");
|
||||||
|
|
||||||
|
#if FMT_USE_FCNTL
|
||||||
|
auto pipe = fmt::pipe();
|
||||||
|
auto write_end = pipe.write_end.fdopen("w");
|
||||||
|
fmt::writer(write_end.get()).print("42");
|
||||||
|
write_end.close();
|
||||||
|
auto read_end = pipe.read_end.fdopen("r");
|
||||||
|
int n = 0;
|
||||||
|
int result = fscanf(read_end.get(), "%d", &n);
|
||||||
|
(void)result;
|
||||||
|
EXPECT_EQ(n, 42);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
auto s = fmt::string_buffer();
|
||||||
|
fmt::writer(s).print("foo");
|
||||||
|
EXPECT_EQ(s.str(), "foo");
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user