Line data Source code
1 : //===- BinaryByteStream.h ---------------------------------------*- C++ -*-===//
2 : //
3 : // The LLVM Compiler Infrastructure
4 : //
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 : //===----------------------------------------------------------------------===//
10 :
11 : #ifndef LLVM_SUPPORT_BINARYBYTESTREAM_H
12 : #define LLVM_SUPPORT_BINARYBYTESTREAM_H
13 :
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"
21 : #include <algorithm>
22 : #include <cstdint>
23 : #include <cstring>
24 : #include <memory>
25 :
26 : namespace llvm {
27 :
28 : /// 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 801 : class BinaryByteStream : public BinaryStream {
33 : public:
34 663 : BinaryByteStream() = default;
35 : BinaryByteStream(ArrayRef<uint8_t> Data, llvm::support::endianness Endian)
36 16517 : : Endian(Endian), Data(Data) {}
37 : BinaryByteStream(StringRef Data, llvm::support::endianness Endian)
38 6 : : Endian(Endian), Data(Data.bytes_begin(), Data.bytes_end()) {}
39 :
40 112236 : llvm::support::endianness getEndian() const override { return Endian; }
41 :
42 267479 : Error readBytes(uint32_t Offset, uint32_t Size,
43 : ArrayRef<uint8_t> &Buffer) override {
44 534958 : if (auto EC = checkOffsetForRead(Offset, Size))
45 : return EC;
46 534952 : Buffer = Data.slice(Offset, Size);
47 : return Error::success();
48 : }
49 :
50 21266 : Error readLongestContiguousChunk(uint32_t Offset,
51 : ArrayRef<uint8_t> &Buffer) override {
52 42532 : if (auto EC = checkOffsetForRead(Offset, 1))
53 : return EC;
54 42532 : Buffer = Data.slice(Offset);
55 : return Error::success();
56 : }
57 :
58 698686 : uint32_t getLength() override { return Data.size(); }
59 :
60 : ArrayRef<uint8_t> data() const { return Data; }
61 :
62 : StringRef str() const {
63 : const char *CharData = reinterpret_cast<const char *>(Data.data());
64 : return StringRef(CharData, Data.size());
65 : }
66 :
67 : protected:
68 : llvm::support::endianness Endian;
69 : ArrayRef<uint8_t> Data;
70 : };
71 :
72 : /// 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 {
77 : public:
78 : MemoryBufferByteStream(std::unique_ptr<MemoryBuffer> Buffer,
79 : llvm::support::endianness Endian)
80 0 : : BinaryByteStream(Buffer->getBuffer(), Endian),
81 0 : MemBuffer(std::move(Buffer)) {}
82 :
83 : std::unique_ptr<MemoryBuffer> MemBuffer;
84 : };
85 :
86 : /// 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 443 : class MutableBinaryByteStream : public WritableBinaryStream {
91 : public:
92 114 : MutableBinaryByteStream() = default;
93 : MutableBinaryByteStream(MutableArrayRef<uint8_t> Data,
94 : llvm::support::endianness Endian)
95 1343 : : Data(Data), ImmutableStream(Data, Endian) {}
96 :
97 8232 : llvm::support::endianness getEndian() const override {
98 8232 : return ImmutableStream.getEndian();
99 : }
100 :
101 74 : Error readBytes(uint32_t Offset, uint32_t Size,
102 : ArrayRef<uint8_t> &Buffer) override {
103 74 : return ImmutableStream.readBytes(Offset, Size, Buffer);
104 : }
105 :
106 109 : Error readLongestContiguousChunk(uint32_t Offset,
107 : ArrayRef<uint8_t> &Buffer) override {
108 109 : return ImmutableStream.readLongestContiguousChunk(Offset, Buffer);
109 : }
110 :
111 196288 : uint32_t getLength() override { return ImmutableStream.getLength(); }
112 :
113 48369 : Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Buffer) override {
114 48369 : if (Buffer.empty())
115 : return Error::success();
116 :
117 96556 : if (auto EC = checkOffsetForWrite(Offset, Buffer.size()))
118 : return EC;
119 :
120 : uint8_t *DataPtr = const_cast<uint8_t *>(Data.data());
121 48275 : ::memcpy(DataPtr + Offset, Buffer.data(), Buffer.size());
122 : return Error::success();
123 : }
124 :
125 0 : Error commit() override { return Error::success(); }
126 :
127 : MutableArrayRef<uint8_t> data() const { return Data; }
128 :
129 : private:
130 : MutableArrayRef<uint8_t> Data;
131 : BinaryByteStream ImmutableStream;
132 : };
133 :
134 : /// An implementation of WritableBinaryStream which can write at its end
135 : /// causing the underlying data to grow. This class owns the underlying data.
136 516 : class AppendingBinaryByteStream : public WritableBinaryStream {
137 : std::vector<uint8_t> Data;
138 : llvm::support::endianness Endian = llvm::support::little;
139 :
140 : public:
141 546 : AppendingBinaryByteStream() = default;
142 : AppendingBinaryByteStream(llvm::support::endianness Endian)
143 6 : : Endian(Endian) {}
144 :
145 : void clear() { Data.clear(); }
146 :
147 22764 : llvm::support::endianness getEndian() const override { return Endian; }
148 :
149 6 : Error readBytes(uint32_t Offset, uint32_t Size,
150 : ArrayRef<uint8_t> &Buffer) override {
151 12 : if (auto EC = checkOffsetForWrite(Offset, Buffer.size()))
152 : return EC;
153 :
154 12 : Buffer = makeArrayRef(Data).slice(Offset, Size);
155 : return Error::success();
156 : }
157 :
158 : void insert(uint32_t Offset, ArrayRef<uint8_t> Bytes) {
159 4 : Data.insert(Data.begin() + Offset, Bytes.begin(), Bytes.end());
160 : }
161 :
162 5 : Error readLongestContiguousChunk(uint32_t Offset,
163 : ArrayRef<uint8_t> &Buffer) override {
164 10 : if (auto EC = checkOffsetForWrite(Offset, 1))
165 : return EC;
166 :
167 10 : Buffer = makeArrayRef(Data).slice(Offset);
168 : return Error::success();
169 : }
170 :
171 145034 : uint32_t getLength() override { return Data.size(); }
172 :
173 36233 : Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Buffer) override {
174 36233 : if (Buffer.empty())
175 : return Error::success();
176 :
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
182 : // error.
183 36231 : if (Offset > getLength())
184 1 : return make_error<BinaryStreamError>(stream_error_code::invalid_offset);
185 :
186 36230 : uint32_t RequiredSize = Offset + Buffer.size();
187 72460 : if (RequiredSize > Data.size())
188 36230 : Data.resize(RequiredSize);
189 :
190 36230 : ::memcpy(Data.data() + Offset, Buffer.data(), Buffer.size());
191 : return Error::success();
192 : }
193 :
194 0 : Error commit() override { return Error::success(); }
195 :
196 : /// Return the properties of this stream.
197 36519 : virtual BinaryStreamFlags getFlags() const override {
198 36519 : return BSF_Write | BSF_Append;
199 : }
200 :
201 : MutableArrayRef<uint8_t> data() { return Data; }
202 : };
203 :
204 : /// An implementation of WritableBinaryStream backed by an llvm
205 : /// FileOutputBuffer.
206 333 : class FileBufferByteStream : public WritableBinaryStream {
207 : private:
208 444 : class StreamImpl : public MutableBinaryByteStream {
209 : public:
210 111 : StreamImpl(std::unique_ptr<FileOutputBuffer> Buffer,
211 : llvm::support::endianness Endian)
212 111 : : MutableBinaryByteStream(
213 111 : MutableArrayRef<uint8_t>(Buffer->getBufferStart(),
214 111 : Buffer->getBufferEnd()),
215 : Endian),
216 111 : FileBuffer(std::move(Buffer)) {}
217 :
218 111 : Error commit() override {
219 222 : if (FileBuffer->commit())
220 : return make_error<BinaryStreamError>(
221 0 : stream_error_code::filesystem_error);
222 : return Error::success();
223 : }
224 :
225 : /// Returns a pointer to the start of the buffer.
226 199 : uint8_t *getBufferStart() const { return FileBuffer->getBufferStart(); }
227 :
228 : /// Returns a pointer to the end of the buffer.
229 88 : uint8_t *getBufferEnd() const { return FileBuffer->getBufferEnd(); }
230 :
231 : private:
232 : std::unique_ptr<FileOutputBuffer> FileBuffer;
233 : };
234 :
235 : public:
236 111 : FileBufferByteStream(std::unique_ptr<FileOutputBuffer> Buffer,
237 : llvm::support::endianness Endian)
238 222 : : Impl(std::move(Buffer), Endian) {}
239 :
240 0 : llvm::support::endianness getEndian() const override {
241 0 : return Impl.getEndian();
242 : }
243 :
244 0 : Error readBytes(uint32_t Offset, uint32_t Size,
245 : ArrayRef<uint8_t> &Buffer) override {
246 0 : return Impl.readBytes(Offset, Size, Buffer);
247 : }
248 :
249 0 : Error readLongestContiguousChunk(uint32_t Offset,
250 : ArrayRef<uint8_t> &Buffer) override {
251 0 : return Impl.readLongestContiguousChunk(Offset, Buffer);
252 : }
253 :
254 2168 : uint32_t getLength() override { return Impl.getLength(); }
255 :
256 12929 : Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) override {
257 12929 : return Impl.writeBytes(Offset, Data);
258 : }
259 :
260 111 : Error commit() override { return Impl.commit(); }
261 :
262 : /// Returns a pointer to the start of the buffer.
263 : uint8_t *getBufferStart() const { return Impl.getBufferStart(); }
264 :
265 : /// Returns a pointer to the end of the buffer.
266 : uint8_t *getBufferEnd() const { return Impl.getBufferEnd(); }
267 :
268 : private:
269 : StreamImpl Impl;
270 : };
271 :
272 : } // end namespace llvm
273 :
274 : #endif // LLVM_SUPPORT_BYTESTREAM_H
|