roo_io
API Documentation for roo_io
Loading...
Searching...
No Matches
buffered_output_stream_iterator.h
Go to the documentation of this file.
1#pragma once
2
3#include <cstring>
4#include <memory>
5
8
9namespace roo_io {
10
11static const size_t kOutputStreamIteratorBufferSize = 64;
12
14 public:
15 /// Creates a detached iterator with `kClosed` status.
17 : output_(nullptr),
18 buffer_(nullptr),
20 status_(kClosed) {}
21
22 /// Move-constructs iterator state.
23 ///
24 /// Source iterator becomes detached with `kClosed` status.
26 : output_(other.output_),
27 buffer_(std::move(other.buffer_)),
28 offset_(other.offset_),
29 status_(other.status_) {
30 other.output_ = nullptr;
32 other.status_ = kClosed;
33 }
34
35 /// Move-assigns iterator state.
36 ///
37 /// Source iterator becomes detached with `kClosed` status.
40 if (this != &other) {
41 output_ = other.output_;
42 buffer_ = std::move(other.buffer_);
43 offset_ = other.offset_;
44 status_ = other.status_;
45 other.output_ = nullptr;
47 other.status_ = kClosed;
48 }
49 return *this;
50 }
51
52 /// Creates iterator over `output`.
53 ///
54 /// Initializes `status()` from `output.status()`. Allocates internal buffer
55 /// only when initial status is `kOk`.
57 : output_(&output), status_(output.status()) {
58 if (status_ == kOk) {
59 buffer_.reset(new byte[kOutputStreamIteratorBufferSize]);
60 offset_ = 0;
61 } else {
63 }
64 }
65
66 /// Flushes pending output on destruction.
68
69 /// Writes one byte.
70 ///
71 /// If output is healthy, byte is buffered and may trigger flushing buffered
72 /// block first. If `status() != kOk` and buffer is full, call is a no-op.
73 /// Updates `status()` through internal buffer flush.
74 void write(byte v) {
75 if (offset_ >= kOutputStreamIteratorBufferSize) {
76 if (status_ != kOk) return;
77 writeBuffer();
78 }
79 buffer_[offset_++] = v;
80 }
81
82 /// Writes up to `count` bytes.
83 ///
84 /// May buffer bytes or write directly to underlying stream.
85 /// If stream is not writable at entry and no buffer space is available,
86 /// returns zero.
87 /// Updates `status()` after delegated writes/flushes.
88 ///
89 /// @return Number of bytes accepted from `buf`.
90 size_t write(const byte* buf, size_t count) {
91 if (offset_ >= kOutputStreamIteratorBufferSize) {
92 if (status_ != kOk) return 0;
93 writeBuffer();
94 }
95 if (offset_ > 0 || count < kOutputStreamIteratorBufferSize) {
96 size_t cap = kOutputStreamIteratorBufferSize - offset_;
97 if (count > cap) count = cap;
98 memcpy(&buffer_[offset_], buf, count);
99 offset_ += count;
100 return count;
101 }
102 if (status_ != roo_io::kOk) return 0;
103 size_t result = output_->write(buf, count);
104 if (result < count) {
105 status_ = output_->status();
106 }
107 return result;
108 }
109
110 /// Flushes buffered data and then flushes underlying stream.
111 ///
112 /// If `status() != kOk`, this call is a no-op.
113 /// Updates `status()` from `output.status()`.
114 void flush() {
115 if (status_ == kOk) {
116 if (offset_ > 0) writeBuffer();
117 output_->flush();
118 status_ = output_->status();
119 }
120 }
121
122 /// Returns current iterator status.
123 ///
124 /// @return Current status value.
125 Status status() const { return status_; }
126
127 /// Returns whether `status() == kOk`.
128 ///
129 /// @return `true` iff current status is `kOk`.
130 bool ok() const { return status() == roo_io::kOk; }
131
132 /// Detaches from stream and releases internal buffer.
133 ///
134 /// Sets status to `kClosed`.
135 void reset() {
136 output_ = nullptr;
137 buffer_.reset();
139 status_ = kClosed;
140 }
141
142 /// Rebinds iterator to `output` and clears buffered state.
143 ///
144 /// Updates `status()` to `output.status()`. Allocates buffer lazily when
145 /// needed and status is `kOk`.
147 output_ = &output;
148 status_ = output.status();
149 if (status_ == kOk) {
150 if (buffer_ == nullptr) {
151 buffer_.reset(new byte[kOutputStreamIteratorBufferSize]);
152 }
153 offset_ = 0;
154 } else {
155 buffer_.reset();
157 }
158 }
159
160 private:
161 inline void writeBuffer() {
162 if (output_->writeFully(buffer_.get(), offset_) < offset_) {
163 status_ = output_->status();
164 }
165 offset_ = 0;
166 }
167
168 roo_io::OutputStream* output_;
169 std::unique_ptr<byte[]> buffer_;
170 uint8_t offset_;
171 Status status_;
172};
173
174} // namespace roo_io
void reset(roo_io::OutputStream &output)
Rebinds iterator to output and clears buffered state.
~BufferedOutputStreamIterator()
Flushes pending output on destruction.
void flush()
Flushes buffered data and then flushes underlying stream.
void reset()
Detaches from stream and releases internal buffer.
Status status() const
Returns current iterator status.
BufferedOutputStreamIterator(roo_io::OutputStream &output)
Creates iterator over output.
BufferedOutputStreamIterator(BufferedOutputStreamIterator &&other)
Move-constructs iterator state.
BufferedOutputStreamIterator & operator=(BufferedOutputStreamIterator &&other)
Move-assigns iterator state.
bool ok() const
Returns whether status() == kOk.
size_t write(const byte *buf, size_t count)
Writes up to count bytes.
BufferedOutputStreamIterator()
Creates a detached iterator with kClosed status.
Virtualizes access to writable sinks (files, memory, devices).
virtual Status status() const =0
Returns underlying stream status.
virtual void flush()
Flushes buffered data to the underlying sink.
virtual size_t writeFully(const byte *buf, size_t count)
Attempts to write count bytes from buf.
virtual size_t write(const byte *buf, size_t count)=0
Attempts to write up to count bytes from buf.
Definition byte.h:6
static const size_t kOutputStreamIteratorBufferSize
roo::basic_string_view< CharT, Traits > basic_string_view
Definition string_view.h:8
size_t count
Definition compare.h:45
Status
Definition status.h:7
@ kOk
Definition status.h:8
@ kClosed
Definition status.h:10