roo_io
API Documentation for roo_io
Loading...
Searching...
No Matches
buffered_input_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 kInputStreamIteratorBufferSize = 64;
12
14 public:
15 /// Creates a detached iterator with `kClosed` status.
17 : input_(nullptr),
18 buffer_(nullptr),
19 offset_(0),
20 length_(0),
21 status_(kClosed) {}
22
23 /// Creates iterator over `input`.
24 ///
25 /// Initializes `status()` from `input.status()`. Allocates internal buffer
26 /// only when initial status is `kOk`.
28 : input_(&input), offset_(0), length_(0), status_(input.status()) {
29 buffer_ =
30 (status_ == kOk)
31 ? std::unique_ptr<byte[]>(new byte[kInputStreamIteratorBufferSize])
32 : nullptr;
33 }
34
35 /// Move-constructs iterator state.
36 ///
37 /// Source iterator becomes detached with `kClosed` status.
39 : input_(other.input_),
40 buffer_(std::move(other.buffer_)),
41 offset_(other.offset_),
42 length_(other.length_),
43 status_(other.status_) {
44 other.input_ = nullptr;
45 other.offset_ = 0;
46 other.length_ = 0;
47 other.status_ = kClosed;
48 }
49
50 /// Move-assigns iterator state.
51 ///
52 /// Source iterator becomes detached with `kClosed` status.
54 if (this != &other) {
55 input_ = other.input_;
56 buffer_ = std::move(other.buffer_);
57 offset_ = other.offset_;
58 length_ = other.length_;
59 status_ = other.status_;
60 other.input_ = nullptr;
61 other.offset_ = 0;
62 other.length_ = 0;
63 other.status_ = kClosed;
64 }
65 return *this;
66 }
67
68 /// Reads one byte.
69 ///
70 /// If buffered data is available, returns it without changing `status()`.
71 /// If `status() != kOk`, returns zero byte and leaves status unchanged.
72 /// Otherwise reads from underlying stream; when that read returns zero,
73 /// updates `status()` from `input.status()`.
74 ///
75 /// @return Read byte, or zero byte when no byte can be read.
76 byte read() {
77 if (offset_ < length_) {
78 return buffer_[offset_++];
79 }
80 if (status_ != kOk) return byte{0};
81 size_t len = input_->read(buffer_.get(), kInputStreamIteratorBufferSize);
82 if (len == 0) {
83 offset_ = 0;
84 length_ = 0;
85 status_ = input_->status();
86 return byte{0};
87 }
88 offset_ = 1;
89 length_ = len;
90 return buffer_[0];
91 }
92
93 /// Reads up to `count` bytes into `buf`.
94 ///
95 /// Uses buffered bytes first. If `status() != kOk`, returns zero and leaves
96 /// status unchanged. When delegated stream read returns zero, updates
97 /// `status()` from `input.status()`.
98 ///
99 /// @return Number of bytes read.
100 size_t read(byte* buf, size_t count) {
101 if (offset_ < length_) {
102 // Have some data still in the buffer; just return that.
103 size_t remaining = static_cast<size_t>(length_ - offset_);
105 memcpy(buf, &buffer_[offset_], count);
106 offset_ += count;
107 return count;
108 }
109 if (status_ != kOk) {
110 // Already done.
111 return 0;
112 }
114 // Skip buffering; read directly into the client's buffer.
115 size_t len = input_->read(buf, count);
116 if (len == 0) {
117 offset_ = 0;
118 length_ = 0;
119 status_ = input_->status();
120 }
121 return len;
122 }
123 size_t len = input_->read(buffer_.get(), kInputStreamIteratorBufferSize);
124 if (len == 0) {
125 offset_ = 0;
126 length_ = 0;
127 status_ = input_->status();
128 return 0;
129 }
130 length_ = len;
131 if (count > static_cast<size_t>(length_))
132 count = static_cast<size_t>(length_);
133 memcpy(buf, buffer_.get(), count);
134 offset_ = count;
135 return count;
136 }
137
138 /// Skips up to `count` bytes.
139 ///
140 /// If skip is satisfied from buffered bytes, `status()` is unchanged.
141 /// Otherwise clears local buffer state and, when `status() == kOk`, delegates
142 /// remaining skip to underlying stream and updates `status()` from
143 /// `input.status()`.
144 void skip(size_t count) {
145 size_t remaining = (length_ - offset_);
146 if (count < remaining) {
147 offset_ += count;
148 } else {
149 offset_ = 0;
150 length_ = 0;
151 if (status_ != kOk) return;
152 input_->skip(count - remaining);
153 status_ = input_->status();
154 }
155 }
156
157 /// Returns current iterator status.
158 ///
159 /// @return Current status value.
160 Status status() const { return status_; }
161
162 /// Returns whether `status() == kOk`.
163 ///
164 /// @return `true` iff current status is `kOk`.
165 bool ok() const { return status() == roo_io::kOk; }
166
167 /// Returns whether `status() == kEndOfStream`.
168 ///
169 /// @return `true` iff current status is `kEndOfStream`.
170 bool eos() const { return status() == roo_io::kEndOfStream; }
171
172 /// Rebinds iterator to `input` and clears buffered state.
173 ///
174 /// Updates `status()` to `input.status()`. Allocates buffer lazily when
175 /// needed and status is `kOk`.
177 input_ = &input;
178 offset_ = 0;
179 length_ = 0;
180 status_ = input.status();
181 if (status_ == kOk && buffer_ == nullptr) {
182 buffer_ =
183 std::unique_ptr<byte[]>(new byte[kInputStreamIteratorBufferSize]);
184 }
185 }
186
187 /// Detaches from stream and releases internal buffer.
188 ///
189 /// Sets status to `kClosed`.
190 void reset() {
191 input_ = nullptr;
192 buffer_ = nullptr;
193 offset_ = 0;
194 length_ = 0;
195 status_ = kClosed;
196 }
197
198 private:
199 roo_io::InputStream* input_;
200 std::unique_ptr<byte[]> buffer_;
201 uint8_t offset_;
202 uint8_t length_;
203 Status status_;
204};
205
206} // namespace roo_io
void skip(size_t count)
Skips up to count bytes.
Status status() const
Returns current iterator status.
BufferedInputStreamIterator & operator=(BufferedInputStreamIterator &&other)
Move-assigns iterator state.
bool ok() const
Returns whether status() == kOk.
BufferedInputStreamIterator(BufferedInputStreamIterator &&other)
Move-constructs iterator state.
size_t read(byte *buf, size_t count)
Reads up to count bytes into buf.
void reset(roo_io::InputStream &input)
Rebinds iterator to input and clears buffered state.
BufferedInputStreamIterator()
Creates a detached iterator with kClosed status.
BufferedInputStreamIterator(roo_io::InputStream &input)
Creates iterator over input.
void reset()
Detaches from stream and releases internal buffer.
bool eos() const
Returns whether status() == kEndOfStream.
Virtualizes access to files, memory, and other readable sources.
virtual size_t read(byte *result, size_t count)=0
Attempts to read up to count bytes into result.
virtual void skip(uint64_t count)
Skips over count bytes, updating status().
virtual Status status() const =0
Returns status of the most recent I/O operation.
Definition byte.h:6
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
@ kEndOfStream
Definition status.h:9
static const size_t kInputStreamIteratorBufferSize