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