123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- // Copyright (c) 2011 The Chromium Authors. All rights reserved.
- // 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_
|