1 // Copyright 2011 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 // These memory-resident streams are used for serializing data into a sequential
9 // Streams are divided into SourceStreams for reading and SinkStreams for
10 // writing. Streams are aggregated into Sets which allows several streams to be
11 // used at once. Example: we can write A1, B1, A2, B2 but achieve the memory
12 // layout A1 A2 B1 B2 by writing 'A's to one stream and 'B's to another.
14 #ifndef COURGETTE_STREAMS_H_
15 #define COURGETTE_STREAMS_H_
19 #include <stdio.h> // for FILE*
22 #include "courgette/memory_allocator.h"
23 #include "courgette/region.h"
31 // Maximum number of streams in a stream set.
32 static const unsigned int kMaxStreams = 10;
34 // A simple interface for reading binary data.
38 virtual ~BasicBuffer() {}
39 virtual const uint8_t* data() const = 0;
40 virtual size_t length() const = 0;
43 // A SourceStream allows a region of memory to be scanned by a sequence of Read
44 // operations. The stream does not own the memory.
47 SourceStream() : start_(nullptr), end_(nullptr), current_(nullptr) {}
49 SourceStream(const SourceStream&) = delete;
50 SourceStream& operator=(const SourceStream&) = delete;
52 // Initializes the SourceStream to yield the bytes at |pointer|. The caller
53 // still owns the memory at |pointer| and should free the memory only after
54 // the last use of the stream.
55 void Init(const void* pointer, size_t length) {
56 start_ = static_cast<const uint8_t*>(pointer);
57 end_ = start_ + length;
61 // Initializes the SourceStream to yield the bytes in |region|. The caller
62 // still owns the memory at |region| and should free the memory only after
63 // the last use of the stream.
64 void Init(const Region& region) { Init(region.start(), region.length()); }
66 // Initializes the SourceStream to yield the bytes in |string|. The caller
67 // still owns the memory at |string| and should free the memory only after
68 // the last use of the stream.
69 void Init(const std::string& string) { Init(string.c_str(), string.size()); }
71 // Initializes the SourceStream to yield the bytes written to |sink|. |sink|
72 // still owns the memory, so needs to outlive |this|. |sink| should not be
73 // written to after |this| is initialized.
74 void Init(const SinkStream& sink);
76 // Returns number of bytes remaining to be read from stream.
77 size_t Remaining() const { return end_ - current_; }
79 // Returns initial length of stream before any data consumed by reading.
80 size_t OriginalLength() const { return end_ - start_; }
82 const uint8_t* Buffer() const { return current_; }
83 bool Empty() const { return current_ == end_; }
85 // Copies bytes from stream to memory at |destination|. Returns 'false' if
86 // insufficient data to satisfy request.
87 bool Read(void* destination, size_t byte_count);
89 // Reads a varint formatted unsigned integer from stream. Returns 'false' if
90 // the read failed due to insufficient data or malformed Varint32.
91 bool ReadVarint32(uint32_t* output_value);
93 // Reads a varint formatted signed integer from stream. Returns 'false' if
94 // the read failed due to insufficient data or malformed Varint32.
95 bool ReadVarint32Signed(int32_t* output_value);
97 // Initializes |substream| to yield |length| bytes from |this| stream,
98 // starting at |offset| bytes from the current position. Returns 'false' if
99 // there are insufficient bytes in |this| stream.
100 bool ShareSubstream(size_t offset, size_t length, SourceStream* substream);
102 // Initializes |substream| to yield |length| bytes from |this| stream,
103 // starting at the current position. Returns 'false' if there are
104 // insufficient bytes in |this| stream.
105 bool ShareSubstream(size_t length, SourceStream* substream) {
106 return ShareSubstream(0, length, substream);
109 // Reads |length| bytes from |this| stream. Initializes |substream| to yield
110 // the bytes. Returns 'false' if there are insufficient bytes in |this|
112 bool ReadSubstream(size_t length, SourceStream* substream);
114 // Skips over bytes. Returns 'false' if insufficient data to satisfy request.
115 bool Skip(size_t byte_count);
118 const uint8_t* start_; // Points to start of buffer.
119 const uint8_t* end_; // Points to first location after buffer.
120 const uint8_t* current_; // Points into buffer at current read location.
123 // A SinkStream accumulates writes into a buffer that it owns. The stream is
124 // initially in an 'accumulating' state where writes are permitted. Accessing
125 // the buffer moves the stream into a 'locked' state where no more writes are
126 // permitted. The stream may also be in a 'retired' state where the buffer
127 // contents are no longer available.
132 SinkStream(const SinkStream&) = delete;
133 SinkStream& operator=(const SinkStream&) = delete;
137 // Appends |byte_count| bytes from |data| to the stream.
138 [[nodiscard]] CheckBool Write(const void* data, size_t byte_count);
140 // Appends the 'varint32' encoding of |value| to the stream.
141 [[nodiscard]] CheckBool WriteVarint32(uint32_t value);
143 // Appends the 'varint32' encoding of |value| to the stream.
144 [[nodiscard]] CheckBool WriteVarint32Signed(int32_t value);
146 // Appends the 'varint32' encoding of |value| to the stream.
147 // On platforms where sizeof(size_t) != sizeof(int32_t), do a safety check.
148 [[nodiscard]] CheckBool WriteSizeVarint32(size_t value);
150 // Contents of |other| are appended to |this| stream. The |other| stream
152 [[nodiscard]] CheckBool Append(SinkStream* other);
154 // Returns the number of bytes in this SinkStream
155 size_t Length() const { return buffer_.size(); }
157 // Returns a pointer to contiguously allocated Length() bytes in the stream.
158 // Writing to the stream invalidates the pointer. The SinkStream continues to
160 const uint8_t* Buffer() const {
161 return reinterpret_cast<const uint8_t*>(buffer_.data());
164 // Hints that the stream will grow by an additional |length| bytes.
165 // Caller must be prepared to handle memory allocation problems.
166 [[nodiscard]] CheckBool Reserve(size_t length) {
167 return buffer_.reserve(length + buffer_.size());
170 // Finished with this stream and any storage it has.
174 NoThrowBuffer<char> buffer_;
177 // A SourceStreamSet is a set of SourceStreams.
178 class SourceStreamSet {
182 SourceStreamSet(const SourceStreamSet&) = delete;
183 SourceStreamSet& operator=(const SourceStreamSet&) = delete;
187 // Initializes the SourceStreamSet with the stream data in memory at |source|.
188 // The caller continues to own the memory and should not modify or free the
189 // memory until the SourceStreamSet destructor has been called.
191 // The layout of the streams are as written by SinkStreamSet::CopyTo.
192 // Init returns 'false' if the layout is inconsistent with |byte_count|.
193 bool Init(const void* source, size_t byte_count);
195 // Initializes |this| from |source|. The caller continues to own the memory
196 // because it continues to be owned by |source|.
197 bool Init(SourceStream* source);
199 // Returns a pointer to one of the sub-streams.
200 SourceStream* stream(size_t id) {
201 return id < count_ ? &streams_[id] : nullptr;
204 // Initialize |set| from |this|.
205 bool ReadSet(SourceStreamSet* set);
207 // Returns 'true' if all streams are completely consumed.
212 SourceStream streams_[kMaxStreams];
215 // A SinkStreamSet is a set of SinkStreams. Data is collected by writing to the
216 // component streams. When data collection is complete, it is destructively
217 // transferred, either by flattening into one stream (CopyTo), or transfering
218 // data pairwise into another SinkStreamSet by calling that SinkStreamSet's
220 class SinkStreamSet {
224 SinkStreamSet(const SinkStreamSet&) = delete;
225 SinkStreamSet& operator=(const SinkStreamSet&) = delete;
229 // Initializes the SinkStreamSet to have |stream_index_limit| streams. Must
230 // be <= kMaxStreams. If Init is not called the default is has kMaxStream.
231 void Init(size_t stream_index_limit);
233 // Returns a pointer to a substream.
234 SinkStream* stream(size_t id) {
235 return id < count_ ? &streams_[id] : nullptr;
238 // CopyTo serializes the streams in this SinkStreamSet into a single target
239 // stream. The serialized format may be re-read by initializing a
240 // SourceStreamSet with a buffer containing the data.
241 [[nodiscard]] CheckBool CopyTo(SinkStream* combined_stream);
243 // Writes the streams of |set| into the corresponding streams of |this|.
244 // Stream zero first has some metadata written to it. |set| becomes retired.
245 // Partner to SourceStreamSet::ReadSet.
246 [[nodiscard]] CheckBool WriteSet(SinkStreamSet* set);
249 [[nodiscard]] CheckBool CopyHeaderTo(SinkStream* stream);
252 SinkStream streams_[kMaxStreams];
255 } // namespace courgette
257 #endif // COURGETTE_STREAMS_H_