/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/include/llvm/Support/BinaryByteStream.h
Line | Count | Source (jump to first uncovered line) |
1 | | //===- BinaryByteStream.h ---------------------------------------*- C++ -*-===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | //===----------------------------------------------------------------------===// |
7 | | // A BinaryStream which stores data in a single continguous memory buffer. |
8 | | //===----------------------------------------------------------------------===// |
9 | | |
10 | | #ifndef LLVM_SUPPORT_BINARYBYTESTREAM_H |
11 | | #define LLVM_SUPPORT_BINARYBYTESTREAM_H |
12 | | |
13 | | #include "llvm/ADT/ArrayRef.h" |
14 | | #include "llvm/ADT/StringRef.h" |
15 | | #include "llvm/Support/BinaryStream.h" |
16 | | #include "llvm/Support/BinaryStreamError.h" |
17 | | #include "llvm/Support/Error.h" |
18 | | #include "llvm/Support/FileOutputBuffer.h" |
19 | | #include "llvm/Support/MemoryBuffer.h" |
20 | | #include <algorithm> |
21 | | #include <cstdint> |
22 | | #include <cstring> |
23 | | #include <memory> |
24 | | |
25 | | namespace llvm { |
26 | | |
27 | | /// An implementation of BinaryStream which holds its entire data set |
28 | | /// in a single contiguous buffer. BinaryByteStream guarantees that no read |
29 | | /// operation will ever incur a copy. Note that BinaryByteStream does not |
30 | | /// own the underlying buffer. |
31 | | class BinaryByteStream : public BinaryStream { |
32 | | public: |
33 | 822 | BinaryByteStream() = default; |
34 | | BinaryByteStream(ArrayRef<uint8_t> Data, llvm::support::endianness Endian) |
35 | 42.0k | : Endian(Endian), Data(Data) {} |
36 | | BinaryByteStream(StringRef Data, llvm::support::endianness Endian) |
37 | 218 | : Endian(Endian), Data(Data.bytes_begin(), Data.bytes_end()) {} |
38 | | |
39 | 247k | llvm::support::endianness getEndian() const override { return Endian; } |
40 | | |
41 | | Error readBytes(uint32_t Offset, uint32_t Size, |
42 | 524k | ArrayRef<uint8_t> &Buffer) override { |
43 | 524k | if (auto EC = checkOffsetForRead(Offset, Size)) |
44 | 3 | return EC; |
45 | 524k | Buffer = Data.slice(Offset, Size); |
46 | 524k | return Error::success(); |
47 | 524k | } |
48 | | |
49 | | Error readLongestContiguousChunk(uint32_t Offset, |
50 | 57.1k | ArrayRef<uint8_t> &Buffer) override { |
51 | 57.1k | if (auto EC = checkOffsetForRead(Offset, 1)) |
52 | 0 | return EC; |
53 | 57.1k | Buffer = Data.slice(Offset); |
54 | 57.1k | return Error::success(); |
55 | 57.1k | } |
56 | | |
57 | 1.34M | uint32_t getLength() override { return Data.size(); } |
58 | | |
59 | 0 | ArrayRef<uint8_t> data() const { return Data; } |
60 | | |
61 | 0 | StringRef str() const { |
62 | 0 | const char *CharData = reinterpret_cast<const char *>(Data.data()); |
63 | 0 | return StringRef(CharData, Data.size()); |
64 | 0 | } |
65 | | |
66 | | protected: |
67 | | llvm::support::endianness Endian; |
68 | | ArrayRef<uint8_t> Data; |
69 | | }; |
70 | | |
71 | | /// An implementation of BinaryStream whose data is backed by an llvm |
72 | | /// MemoryBuffer object. MemoryBufferByteStream owns the MemoryBuffer in |
73 | | /// question. As with BinaryByteStream, reading from a MemoryBufferByteStream |
74 | | /// will never cause a copy. |
75 | | class MemoryBufferByteStream : public BinaryByteStream { |
76 | | public: |
77 | | MemoryBufferByteStream(std::unique_ptr<MemoryBuffer> Buffer, |
78 | | llvm::support::endianness Endian) |
79 | | : BinaryByteStream(Buffer->getBuffer(), Endian), |
80 | 157 | MemBuffer(std::move(Buffer)) {} |
81 | | |
82 | | std::unique_ptr<MemoryBuffer> MemBuffer; |
83 | | }; |
84 | | |
85 | | /// An implementation of BinaryStream which holds its entire data set |
86 | | /// in a single contiguous buffer. As with BinaryByteStream, the mutable |
87 | | /// version also guarantees that no read operation will ever incur a copy, |
88 | | /// and similarly it does not own the underlying buffer. |
89 | | class MutableBinaryByteStream : public WritableBinaryStream { |
90 | | public: |
91 | 137 | MutableBinaryByteStream() = default; |
92 | | MutableBinaryByteStream(MutableArrayRef<uint8_t> Data, |
93 | | llvm::support::endianness Endian) |
94 | 6.80k | : Data(Data), ImmutableStream(Data, Endian) {} |
95 | | |
96 | 31.1k | llvm::support::endianness getEndian() const override { |
97 | 31.1k | return ImmutableStream.getEndian(); |
98 | 31.1k | } |
99 | | |
100 | | Error readBytes(uint32_t Offset, uint32_t Size, |
101 | 74 | ArrayRef<uint8_t> &Buffer) override { |
102 | 74 | return ImmutableStream.readBytes(Offset, Size, Buffer); |
103 | 74 | } |
104 | | |
105 | | Error readLongestContiguousChunk(uint32_t Offset, |
106 | 132 | ArrayRef<uint8_t> &Buffer) override { |
107 | 132 | return ImmutableStream.readLongestContiguousChunk(Offset, Buffer); |
108 | 132 | } |
109 | | |
110 | 144k | uint32_t getLength() override { return ImmutableStream.getLength(); } |
111 | | |
112 | 70.6k | Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Buffer) override { |
113 | 70.6k | if (Buffer.empty()) |
114 | 119 | return Error::success(); |
115 | 70.5k | |
116 | 70.5k | if (auto EC = checkOffsetForWrite(Offset, Buffer.size())) |
117 | 3 | return EC; |
118 | 70.5k | |
119 | 70.5k | uint8_t *DataPtr = const_cast<uint8_t *>(Data.data()); |
120 | 70.5k | ::memcpy(DataPtr + Offset, Buffer.data(), Buffer.size()); |
121 | 70.5k | return Error::success(); |
122 | 70.5k | } |
123 | | |
124 | 0 | Error commit() override { return Error::success(); } |
125 | | |
126 | 0 | MutableArrayRef<uint8_t> data() const { return Data; } |
127 | | |
128 | | private: |
129 | | MutableArrayRef<uint8_t> Data; |
130 | | BinaryByteStream ImmutableStream; |
131 | | }; |
132 | | |
133 | | /// An implementation of WritableBinaryStream which can write at its end |
134 | | /// causing the underlying data to grow. This class owns the underlying data. |
135 | | class AppendingBinaryByteStream : public WritableBinaryStream { |
136 | | std::vector<uint8_t> Data; |
137 | | llvm::support::endianness Endian = llvm::support::little; |
138 | | |
139 | | public: |
140 | 403 | AppendingBinaryByteStream() = default; |
141 | | AppendingBinaryByteStream(llvm::support::endianness Endian) |
142 | | : Endian(Endian) {} |
143 | | |
144 | 374 | void clear() { Data.clear(); } |
145 | | |
146 | 42.0k | llvm::support::endianness getEndian() const override { return Endian; } |
147 | | |
148 | | Error readBytes(uint32_t Offset, uint32_t Size, |
149 | 6 | ArrayRef<uint8_t> &Buffer) override { |
150 | 6 | if (auto EC = checkOffsetForWrite(Offset, Buffer.size())) |
151 | 0 | return EC; |
152 | 6 | |
153 | 6 | Buffer = makeArrayRef(Data).slice(Offset, Size); |
154 | 6 | return Error::success(); |
155 | 6 | } |
156 | | |
157 | 8 | void insert(uint32_t Offset, ArrayRef<uint8_t> Bytes) { |
158 | 8 | Data.insert(Data.begin() + Offset, Bytes.begin(), Bytes.end()); |
159 | 8 | } |
160 | | |
161 | | Error readLongestContiguousChunk(uint32_t Offset, |
162 | 5 | ArrayRef<uint8_t> &Buffer) override { |
163 | 5 | if (auto EC = checkOffsetForWrite(Offset, 1)) |
164 | 0 | return EC; |
165 | 5 | |
166 | 5 | Buffer = makeArrayRef(Data).slice(Offset); |
167 | 5 | return Error::success(); |
168 | 5 | } |
169 | | |
170 | 134k | uint32_t getLength() override { return Data.size(); } |
171 | | |
172 | 67.3k | Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Buffer) override { |
173 | 67.3k | if (Buffer.empty()) |
174 | 6 | return Error::success(); |
175 | 67.3k | |
176 | 67.3k | // This is well-defined for any case except where offset is strictly |
177 | 67.3k | // greater than the current length. If offset is equal to the current |
178 | 67.3k | // length, we can still grow. If offset is beyond the current length, we |
179 | 67.3k | // would have to decide how to deal with the intermediate uninitialized |
180 | 67.3k | // bytes. So we punt on that case for simplicity and just say it's an |
181 | 67.3k | // error. |
182 | 67.3k | if (Offset > getLength()) |
183 | 1 | return make_error<BinaryStreamError>(stream_error_code::invalid_offset); |
184 | 67.3k | |
185 | 67.3k | uint32_t RequiredSize = Offset + Buffer.size(); |
186 | 67.3k | if (RequiredSize > Data.size()) |
187 | 67.3k | Data.resize(RequiredSize); |
188 | 67.3k | |
189 | 67.3k | ::memcpy(Data.data() + Offset, Buffer.data(), Buffer.size()); |
190 | 67.3k | return Error::success(); |
191 | 67.3k | } |
192 | | |
193 | 0 | Error commit() override { return Error::success(); } |
194 | | |
195 | | /// Return the properties of this stream. |
196 | 67.8k | virtual BinaryStreamFlags getFlags() const override { |
197 | 67.8k | return BSF_Write | BSF_Append; |
198 | 67.8k | } |
199 | | |
200 | 382 | MutableArrayRef<uint8_t> data() { return Data; } |
201 | | }; |
202 | | |
203 | | /// An implementation of WritableBinaryStream backed by an llvm |
204 | | /// FileOutputBuffer. |
205 | | class FileBufferByteStream : public WritableBinaryStream { |
206 | | private: |
207 | | class StreamImpl : public MutableBinaryByteStream { |
208 | | public: |
209 | | StreamImpl(std::unique_ptr<FileOutputBuffer> Buffer, |
210 | | llvm::support::endianness Endian) |
211 | | : MutableBinaryByteStream( |
212 | | MutableArrayRef<uint8_t>(Buffer->getBufferStart(), |
213 | | Buffer->getBufferEnd()), |
214 | | Endian), |
215 | 135 | FileBuffer(std::move(Buffer)) {} |
216 | | |
217 | 135 | Error commit() override { |
218 | 135 | if (FileBuffer->commit()) |
219 | 0 | return make_error<BinaryStreamError>( |
220 | 0 | stream_error_code::filesystem_error); |
221 | 135 | return Error::success(); |
222 | 135 | } |
223 | | |
224 | | /// Returns a pointer to the start of the buffer. |
225 | 244 | uint8_t *getBufferStart() const { return FileBuffer->getBufferStart(); } |
226 | | |
227 | | /// Returns a pointer to the end of the buffer. |
228 | 110 | uint8_t *getBufferEnd() const { return FileBuffer->getBufferEnd(); } |
229 | | |
230 | | private: |
231 | | std::unique_ptr<FileOutputBuffer> FileBuffer; |
232 | | }; |
233 | | |
234 | | public: |
235 | | FileBufferByteStream(std::unique_ptr<FileOutputBuffer> Buffer, |
236 | | llvm::support::endianness Endian) |
237 | 135 | : Impl(std::move(Buffer), Endian) {} |
238 | | |
239 | 0 | llvm::support::endianness getEndian() const override { |
240 | 0 | return Impl.getEndian(); |
241 | 0 | } |
242 | | |
243 | | Error readBytes(uint32_t Offset, uint32_t Size, |
244 | 0 | ArrayRef<uint8_t> &Buffer) override { |
245 | 0 | return Impl.readBytes(Offset, Size, Buffer); |
246 | 0 | } |
247 | | |
248 | | Error readLongestContiguousChunk(uint32_t Offset, |
249 | 0 | ArrayRef<uint8_t> &Buffer) override { |
250 | 0 | return Impl.readLongestContiguousChunk(Offset, Buffer); |
251 | 0 | } |
252 | | |
253 | 1.31k | uint32_t getLength() override { return Impl.getLength(); } |
254 | | |
255 | 20.6k | Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) override { |
256 | 20.6k | return Impl.writeBytes(Offset, Data); |
257 | 20.6k | } |
258 | | |
259 | 135 | Error commit() override { return Impl.commit(); } |
260 | | |
261 | | /// Returns a pointer to the start of the buffer. |
262 | 244 | uint8_t *getBufferStart() const { return Impl.getBufferStart(); } |
263 | | |
264 | | /// Returns a pointer to the end of the buffer. |
265 | 110 | uint8_t *getBufferEnd() const { return Impl.getBufferEnd(); } |
266 | | |
267 | | private: |
268 | | StreamImpl Impl; |
269 | | }; |
270 | | |
271 | | } // end namespace llvm |
272 | | |
273 | | #endif // LLVM_SUPPORT_BYTESTREAM_H |