blob: 9808d3b721576b3fafa8a02f1cf2bc7e9d4b6496 [file] [log] [blame]
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01001//===- 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
26namespace llvm {
27
Andrew Scullcdfcccc2018-10-05 20:58:37 +010028/// An implementation of BinaryStream which holds its entire data set
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010029/// 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.
32class BinaryByteStream : public BinaryStream {
33public:
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()) {}
39
40 llvm::support::endianness getEndian() const override { return Endian; }
41
42 Error readBytes(uint32_t Offset, uint32_t Size,
43 ArrayRef<uint8_t> &Buffer) override {
44 if (auto EC = checkOffsetForRead(Offset, Size))
45 return EC;
46 Buffer = Data.slice(Offset, Size);
47 return Error::success();
48 }
49
50 Error readLongestContiguousChunk(uint32_t Offset,
51 ArrayRef<uint8_t> &Buffer) override {
52 if (auto EC = checkOffsetForRead(Offset, 1))
53 return EC;
54 Buffer = Data.slice(Offset);
55 return Error::success();
56 }
57
58 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
67protected:
68 llvm::support::endianness Endian;
69 ArrayRef<uint8_t> Data;
70};
71
Andrew Scullcdfcccc2018-10-05 20:58:37 +010072/// An implementation of BinaryStream whose data is backed by an llvm
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010073/// MemoryBuffer object. MemoryBufferByteStream owns the MemoryBuffer in
74/// question. As with BinaryByteStream, reading from a MemoryBufferByteStream
75/// will never cause a copy.
76class MemoryBufferByteStream : public BinaryByteStream {
77public:
78 MemoryBufferByteStream(std::unique_ptr<MemoryBuffer> Buffer,
79 llvm::support::endianness Endian)
80 : BinaryByteStream(Buffer->getBuffer(), Endian),
81 MemBuffer(std::move(Buffer)) {}
82
83 std::unique_ptr<MemoryBuffer> MemBuffer;
84};
85
Andrew Scullcdfcccc2018-10-05 20:58:37 +010086/// An implementation of BinaryStream which holds its entire data set
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010087/// 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.
90class MutableBinaryByteStream : public WritableBinaryStream {
91public:
92 MutableBinaryByteStream() = default;
93 MutableBinaryByteStream(MutableArrayRef<uint8_t> Data,
94 llvm::support::endianness Endian)
95 : Data(Data), ImmutableStream(Data, Endian) {}
96
97 llvm::support::endianness getEndian() const override {
98 return ImmutableStream.getEndian();
99 }
100
101 Error readBytes(uint32_t Offset, uint32_t Size,
102 ArrayRef<uint8_t> &Buffer) override {
103 return ImmutableStream.readBytes(Offset, Size, Buffer);
104 }
105
106 Error readLongestContiguousChunk(uint32_t Offset,
107 ArrayRef<uint8_t> &Buffer) override {
108 return ImmutableStream.readLongestContiguousChunk(Offset, Buffer);
109 }
110
111 uint32_t getLength() override { return ImmutableStream.getLength(); }
112
113 Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Buffer) override {
114 if (Buffer.empty())
115 return Error::success();
116
117 if (auto EC = checkOffsetForWrite(Offset, Buffer.size()))
118 return EC;
119
120 uint8_t *DataPtr = const_cast<uint8_t *>(Data.data());
121 ::memcpy(DataPtr + Offset, Buffer.data(), Buffer.size());
122 return Error::success();
123 }
124
125 Error commit() override { return Error::success(); }
126
127 MutableArrayRef<uint8_t> data() const { return Data; }
128
129private:
130 MutableArrayRef<uint8_t> Data;
131 BinaryByteStream ImmutableStream;
132};
133
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100134/// An implementation of WritableBinaryStream which can write at its end
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100135/// causing the underlying data to grow. This class owns the underlying data.
136class AppendingBinaryByteStream : public WritableBinaryStream {
137 std::vector<uint8_t> Data;
138 llvm::support::endianness Endian = llvm::support::little;
139
140public:
141 AppendingBinaryByteStream() = default;
142 AppendingBinaryByteStream(llvm::support::endianness Endian)
143 : Endian(Endian) {}
144
145 void clear() { Data.clear(); }
146
147 llvm::support::endianness getEndian() const override { return Endian; }
148
149 Error readBytes(uint32_t Offset, uint32_t Size,
150 ArrayRef<uint8_t> &Buffer) override {
151 if (auto EC = checkOffsetForWrite(Offset, Buffer.size()))
152 return EC;
153
154 Buffer = makeArrayRef(Data).slice(Offset, Size);
155 return Error::success();
156 }
157
158 void insert(uint32_t Offset, ArrayRef<uint8_t> Bytes) {
159 Data.insert(Data.begin() + Offset, Bytes.begin(), Bytes.end());
160 }
161
162 Error readLongestContiguousChunk(uint32_t Offset,
163 ArrayRef<uint8_t> &Buffer) override {
164 if (auto EC = checkOffsetForWrite(Offset, 1))
165 return EC;
166
167 Buffer = makeArrayRef(Data).slice(Offset);
168 return Error::success();
169 }
170
171 uint32_t getLength() override { return Data.size(); }
172
173 Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Buffer) override {
174 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 if (Offset > getLength())
184 return make_error<BinaryStreamError>(stream_error_code::invalid_offset);
185
186 uint32_t RequiredSize = Offset + Buffer.size();
187 if (RequiredSize > Data.size())
188 Data.resize(RequiredSize);
189
190 ::memcpy(Data.data() + Offset, Buffer.data(), Buffer.size());
191 return Error::success();
192 }
193
194 Error commit() override { return Error::success(); }
195
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100196 /// Return the properties of this stream.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100197 virtual BinaryStreamFlags getFlags() const override {
198 return BSF_Write | BSF_Append;
199 }
200
201 MutableArrayRef<uint8_t> data() { return Data; }
202};
203
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100204/// An implementation of WritableBinaryStream backed by an llvm
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100205/// FileOutputBuffer.
206class FileBufferByteStream : public WritableBinaryStream {
207private:
208 class StreamImpl : public MutableBinaryByteStream {
209 public:
210 StreamImpl(std::unique_ptr<FileOutputBuffer> Buffer,
211 llvm::support::endianness Endian)
212 : MutableBinaryByteStream(
213 MutableArrayRef<uint8_t>(Buffer->getBufferStart(),
214 Buffer->getBufferEnd()),
215 Endian),
216 FileBuffer(std::move(Buffer)) {}
217
218 Error commit() override {
219 if (FileBuffer->commit())
220 return make_error<BinaryStreamError>(
221 stream_error_code::filesystem_error);
222 return Error::success();
223 }
224
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100225 /// Returns a pointer to the start of the buffer.
226 uint8_t *getBufferStart() const { return FileBuffer->getBufferStart(); }
227
228 /// Returns a pointer to the end of the buffer.
229 uint8_t *getBufferEnd() const { return FileBuffer->getBufferEnd(); }
230
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100231 private:
232 std::unique_ptr<FileOutputBuffer> FileBuffer;
233 };
234
235public:
236 FileBufferByteStream(std::unique_ptr<FileOutputBuffer> Buffer,
237 llvm::support::endianness Endian)
238 : Impl(std::move(Buffer), Endian) {}
239
240 llvm::support::endianness getEndian() const override {
241 return Impl.getEndian();
242 }
243
244 Error readBytes(uint32_t Offset, uint32_t Size,
245 ArrayRef<uint8_t> &Buffer) override {
246 return Impl.readBytes(Offset, Size, Buffer);
247 }
248
249 Error readLongestContiguousChunk(uint32_t Offset,
250 ArrayRef<uint8_t> &Buffer) override {
251 return Impl.readLongestContiguousChunk(Offset, Buffer);
252 }
253
254 uint32_t getLength() override { return Impl.getLength(); }
255
256 Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) override {
257 return Impl.writeBytes(Offset, Data);
258 }
259
260 Error commit() override { return Impl.commit(); }
261
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100262 /// 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
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100268private:
269 StreamImpl Impl;
270};
271
272} // end namespace llvm
273
274#endif // LLVM_SUPPORT_BYTESTREAM_H