1 //===- BinaryByteStream.h ---------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //===----------------------------------------------------------------------===//
8 // A BinaryStream which stores data in a single continguous memory buffer.
9 //===----------------------------------------------------------------------===//
11 #ifndef LLVM_SUPPORT_BINARYBYTESTREAM_H
12 #define LLVM_SUPPORT_BINARYBYTESTREAM_H
14 #include "llvm/ADT/ArrayRef.h"
15 #include "llvm/ADT/StringRef.h"
16 #include "llvm/Support/BinaryStream.h"
17 #include "llvm/Support/BinaryStreamError.h"
18 #include "llvm/Support/Error.h"
19 #include "llvm/Support/FileOutputBuffer.h"
20 #include "llvm/Support/MemoryBuffer.h"
28 /// \brief An implementation of BinaryStream which holds its entire data set
29 /// in a single contiguous buffer. BinaryByteStream guarantees that no read
30 /// operation will ever incur a copy. Note that BinaryByteStream does not
31 /// own the underlying buffer.
32 class BinaryByteStream : public BinaryStream {
34 BinaryByteStream() = default;
35 BinaryByteStream(ArrayRef<uint8_t> Data, llvm::support::endianness Endian)
36 : Endian(Endian), Data(Data) {}
37 BinaryByteStream(StringRef Data, llvm::support::endianness Endian)
38 : Endian(Endian), Data(Data.bytes_begin(), Data.bytes_end()) {}
40 llvm::support::endianness getEndian() const override { return Endian; }
42 Error readBytes(uint32_t Offset, uint32_t Size,
43 ArrayRef<uint8_t> &Buffer) override {
44 if (auto EC = checkOffsetForRead(Offset, Size))
46 Buffer = Data.slice(Offset, Size);
47 return Error::success();
50 Error readLongestContiguousChunk(uint32_t Offset,
51 ArrayRef<uint8_t> &Buffer) override {
52 if (auto EC = checkOffsetForRead(Offset, 1))
54 Buffer = Data.slice(Offset);
55 return Error::success();
58 uint32_t getLength() override { return Data.size(); }
60 ArrayRef<uint8_t> data() const { return Data; }
62 StringRef str() const {
63 const char *CharData = reinterpret_cast<const char *>(Data.data());
64 return StringRef(CharData, Data.size());
68 llvm::support::endianness Endian;
69 ArrayRef<uint8_t> Data;
72 /// \brief An implementation of BinaryStream whose data is backed by an llvm
73 /// MemoryBuffer object. MemoryBufferByteStream owns the MemoryBuffer in
74 /// question. As with BinaryByteStream, reading from a MemoryBufferByteStream
75 /// will never cause a copy.
76 class MemoryBufferByteStream : public BinaryByteStream {
78 MemoryBufferByteStream(std::unique_ptr<MemoryBuffer> Buffer,
79 llvm::support::endianness Endian)
80 : BinaryByteStream(Buffer->getBuffer(), Endian),
81 MemBuffer(std::move(Buffer)) {}
83 std::unique_ptr<MemoryBuffer> MemBuffer;
86 /// \brief An implementation of BinaryStream which holds its entire data set
87 /// in a single contiguous buffer. As with BinaryByteStream, the mutable
88 /// version also guarantees that no read operation will ever incur a copy,
89 /// and similarly it does not own the underlying buffer.
90 class MutableBinaryByteStream : public WritableBinaryStream {
92 MutableBinaryByteStream() = default;
93 MutableBinaryByteStream(MutableArrayRef<uint8_t> Data,
94 llvm::support::endianness Endian)
95 : Data(Data), ImmutableStream(Data, Endian) {}
97 llvm::support::endianness getEndian() const override {
98 return ImmutableStream.getEndian();
101 Error readBytes(uint32_t Offset, uint32_t Size,
102 ArrayRef<uint8_t> &Buffer) override {
103 return ImmutableStream.readBytes(Offset, Size, Buffer);
106 Error readLongestContiguousChunk(uint32_t Offset,
107 ArrayRef<uint8_t> &Buffer) override {
108 return ImmutableStream.readLongestContiguousChunk(Offset, Buffer);
111 uint32_t getLength() override { return ImmutableStream.getLength(); }
113 Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Buffer) override {
115 return Error::success();
117 if (auto EC = checkOffsetForWrite(Offset, Buffer.size()))
120 uint8_t *DataPtr = const_cast<uint8_t *>(Data.data());
121 ::memcpy(DataPtr + Offset, Buffer.data(), Buffer.size());
122 return Error::success();
125 Error commit() override { return Error::success(); }
127 MutableArrayRef<uint8_t> data() const { return Data; }
130 MutableArrayRef<uint8_t> Data;
131 BinaryByteStream ImmutableStream;
134 /// \brief An implementation of WritableBinaryStream which can write at its end
135 /// causing the underlying data to grow. This class owns the underlying data.
136 class AppendingBinaryByteStream : public WritableBinaryStream {
137 std::vector<uint8_t> Data;
138 llvm::support::endianness Endian = llvm::support::little;
141 AppendingBinaryByteStream() = default;
142 AppendingBinaryByteStream(llvm::support::endianness Endian)
145 void clear() { Data.clear(); }
147 llvm::support::endianness getEndian() const override { return Endian; }
149 Error readBytes(uint32_t Offset, uint32_t Size,
150 ArrayRef<uint8_t> &Buffer) override {
151 if (auto EC = checkOffsetForWrite(Offset, Buffer.size()))
154 Buffer = makeArrayRef(Data).slice(Offset, Size);
155 return Error::success();
158 void insert(uint32_t Offset, ArrayRef<uint8_t> Bytes) {
159 Data.insert(Data.begin() + Offset, Bytes.begin(), Bytes.end());
162 Error readLongestContiguousChunk(uint32_t Offset,
163 ArrayRef<uint8_t> &Buffer) override {
164 if (auto EC = checkOffsetForWrite(Offset, 1))
167 Buffer = makeArrayRef(Data).slice(Offset);
168 return Error::success();
171 uint32_t getLength() override { return Data.size(); }
173 Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Buffer) override {
175 return Error::success();
177 // This is well-defined for any case except where offset is strictly
178 // greater than the current length. If offset is equal to the current
179 // length, we can still grow. If offset is beyond the current length, we
180 // would have to decide how to deal with the intermediate uninitialized
181 // bytes. So we punt on that case for simplicity and just say it's an
183 if (Offset > getLength())
184 return make_error<BinaryStreamError>(stream_error_code::invalid_offset);
186 uint32_t RequiredSize = Offset + Buffer.size();
187 if (RequiredSize > Data.size())
188 Data.resize(RequiredSize);
190 ::memcpy(Data.data() + Offset, Buffer.data(), Buffer.size());
191 return Error::success();
194 Error commit() override { return Error::success(); }
196 /// \brief Return the properties of this stream.
197 virtual BinaryStreamFlags getFlags() const override {
198 return BSF_Write | BSF_Append;
201 MutableArrayRef<uint8_t> data() { return Data; }
204 /// \brief An implementation of WritableBinaryStream backed by an llvm
205 /// FileOutputBuffer.
206 class FileBufferByteStream : public WritableBinaryStream {
208 class StreamImpl : public MutableBinaryByteStream {
210 StreamImpl(std::unique_ptr<FileOutputBuffer> Buffer,
211 llvm::support::endianness Endian)
212 : MutableBinaryByteStream(
213 MutableArrayRef<uint8_t>(Buffer->getBufferStart(),
214 Buffer->getBufferEnd()),
216 FileBuffer(std::move(Buffer)) {}
218 Error commit() override {
219 if (FileBuffer->commit())
220 return make_error<BinaryStreamError>(
221 stream_error_code::filesystem_error);
222 return Error::success();
226 std::unique_ptr<FileOutputBuffer> FileBuffer;
230 FileBufferByteStream(std::unique_ptr<FileOutputBuffer> Buffer,
231 llvm::support::endianness Endian)
232 : Impl(std::move(Buffer), Endian) {}
234 llvm::support::endianness getEndian() const override {
235 return Impl.getEndian();
238 Error readBytes(uint32_t Offset, uint32_t Size,
239 ArrayRef<uint8_t> &Buffer) override {
240 return Impl.readBytes(Offset, Size, Buffer);
243 Error readLongestContiguousChunk(uint32_t Offset,
244 ArrayRef<uint8_t> &Buffer) override {
245 return Impl.readLongestContiguousChunk(Offset, Buffer);
248 uint32_t getLength() override { return Impl.getLength(); }
250 Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) override {
251 return Impl.writeBytes(Offset, Data);
254 Error commit() override { return Impl.commit(); }
260 } // end namespace llvm
262 #endif // LLVM_SUPPORT_BYTESTREAM_H