1 //===- BinaryByteStream.h ---------------------------------------*- C++ -*-===//
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 //===----------------------------------------------------------------------===//
10 #ifndef LLVM_SUPPORT_BINARYBYTESTREAM_H
11 #define LLVM_SUPPORT_BINARYBYTESTREAM_H
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"
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
{
33 BinaryByteStream() = default;
34 BinaryByteStream(ArrayRef
<uint8_t> Data
, llvm::support::endianness Endian
)
35 : Endian(Endian
), Data(Data
) {}
36 BinaryByteStream(StringRef Data
, llvm::support::endianness Endian
)
37 : Endian(Endian
), Data(Data
.bytes_begin(), Data
.bytes_end()) {}
39 llvm::support::endianness
getEndian() const override
{ return Endian
; }
41 Error
readBytes(uint32_t Offset
, uint32_t Size
,
42 ArrayRef
<uint8_t> &Buffer
) override
{
43 if (auto EC
= checkOffsetForRead(Offset
, Size
))
45 Buffer
= Data
.slice(Offset
, Size
);
46 return Error::success();
49 Error
readLongestContiguousChunk(uint32_t Offset
,
50 ArrayRef
<uint8_t> &Buffer
) override
{
51 if (auto EC
= checkOffsetForRead(Offset
, 1))
53 Buffer
= Data
.slice(Offset
);
54 return Error::success();
57 uint32_t getLength() override
{ return Data
.size(); }
59 ArrayRef
<uint8_t> data() const { return Data
; }
61 StringRef
str() const {
62 const char *CharData
= reinterpret_cast<const char *>(Data
.data());
63 return StringRef(CharData
, Data
.size());
67 llvm::support::endianness Endian
;
68 ArrayRef
<uint8_t> Data
;
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
{
77 MemoryBufferByteStream(std::unique_ptr
<MemoryBuffer
> Buffer
,
78 llvm::support::endianness Endian
)
79 : BinaryByteStream(Buffer
->getBuffer(), Endian
),
80 MemBuffer(std::move(Buffer
)) {}
82 std::unique_ptr
<MemoryBuffer
> MemBuffer
;
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
{
91 MutableBinaryByteStream() = default;
92 MutableBinaryByteStream(MutableArrayRef
<uint8_t> Data
,
93 llvm::support::endianness Endian
)
94 : Data(Data
), ImmutableStream(Data
, Endian
) {}
96 llvm::support::endianness
getEndian() const override
{
97 return ImmutableStream
.getEndian();
100 Error
readBytes(uint32_t Offset
, uint32_t Size
,
101 ArrayRef
<uint8_t> &Buffer
) override
{
102 return ImmutableStream
.readBytes(Offset
, Size
, Buffer
);
105 Error
readLongestContiguousChunk(uint32_t Offset
,
106 ArrayRef
<uint8_t> &Buffer
) override
{
107 return ImmutableStream
.readLongestContiguousChunk(Offset
, Buffer
);
110 uint32_t getLength() override
{ return ImmutableStream
.getLength(); }
112 Error
writeBytes(uint32_t Offset
, ArrayRef
<uint8_t> Buffer
) override
{
114 return Error::success();
116 if (auto EC
= checkOffsetForWrite(Offset
, Buffer
.size()))
119 uint8_t *DataPtr
= const_cast<uint8_t *>(Data
.data());
120 ::memcpy(DataPtr
+ Offset
, Buffer
.data(), Buffer
.size());
121 return Error::success();
124 Error
commit() override
{ return Error::success(); }
126 MutableArrayRef
<uint8_t> data() const { return Data
; }
129 MutableArrayRef
<uint8_t> Data
;
130 BinaryByteStream ImmutableStream
;
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
;
140 AppendingBinaryByteStream() = default;
141 AppendingBinaryByteStream(llvm::support::endianness Endian
)
144 void clear() { Data
.clear(); }
146 llvm::support::endianness
getEndian() const override
{ return Endian
; }
148 Error
readBytes(uint32_t Offset
, uint32_t Size
,
149 ArrayRef
<uint8_t> &Buffer
) override
{
150 if (auto EC
= checkOffsetForWrite(Offset
, Buffer
.size()))
153 Buffer
= makeArrayRef(Data
).slice(Offset
, Size
);
154 return Error::success();
157 void insert(uint32_t Offset
, ArrayRef
<uint8_t> Bytes
) {
158 Data
.insert(Data
.begin() + Offset
, Bytes
.begin(), Bytes
.end());
161 Error
readLongestContiguousChunk(uint32_t Offset
,
162 ArrayRef
<uint8_t> &Buffer
) override
{
163 if (auto EC
= checkOffsetForWrite(Offset
, 1))
166 Buffer
= makeArrayRef(Data
).slice(Offset
);
167 return Error::success();
170 uint32_t getLength() override
{ return Data
.size(); }
172 Error
writeBytes(uint32_t Offset
, ArrayRef
<uint8_t> Buffer
) override
{
174 return Error::success();
176 // This is well-defined for any case except where offset is strictly
177 // greater than the current length. If offset is equal to the current
178 // length, we can still grow. If offset is beyond the current length, we
179 // would have to decide how to deal with the intermediate uninitialized
180 // bytes. So we punt on that case for simplicity and just say it's an
182 if (Offset
> getLength())
183 return make_error
<BinaryStreamError
>(stream_error_code::invalid_offset
);
185 uint32_t RequiredSize
= Offset
+ Buffer
.size();
186 if (RequiredSize
> Data
.size())
187 Data
.resize(RequiredSize
);
189 ::memcpy(Data
.data() + Offset
, Buffer
.data(), Buffer
.size());
190 return Error::success();
193 Error
commit() override
{ return Error::success(); }
195 /// Return the properties of this stream.
196 virtual BinaryStreamFlags
getFlags() const override
{
197 return BSF_Write
| BSF_Append
;
200 MutableArrayRef
<uint8_t> data() { return Data
; }
203 /// An implementation of WritableBinaryStream backed by an llvm
204 /// FileOutputBuffer.
205 class FileBufferByteStream
: public WritableBinaryStream
{
207 class StreamImpl
: public MutableBinaryByteStream
{
209 StreamImpl(std::unique_ptr
<FileOutputBuffer
> Buffer
,
210 llvm::support::endianness Endian
)
211 : MutableBinaryByteStream(
212 MutableArrayRef
<uint8_t>(Buffer
->getBufferStart(),
213 Buffer
->getBufferEnd()),
215 FileBuffer(std::move(Buffer
)) {}
217 Error
commit() override
{
218 if (FileBuffer
->commit())
219 return make_error
<BinaryStreamError
>(
220 stream_error_code::filesystem_error
);
221 return Error::success();
224 /// Returns a pointer to the start of the buffer.
225 uint8_t *getBufferStart() const { return FileBuffer
->getBufferStart(); }
227 /// Returns a pointer to the end of the buffer.
228 uint8_t *getBufferEnd() const { return FileBuffer
->getBufferEnd(); }
231 std::unique_ptr
<FileOutputBuffer
> FileBuffer
;
235 FileBufferByteStream(std::unique_ptr
<FileOutputBuffer
> Buffer
,
236 llvm::support::endianness Endian
)
237 : Impl(std::move(Buffer
), Endian
) {}
239 llvm::support::endianness
getEndian() const override
{
240 return Impl
.getEndian();
243 Error
readBytes(uint32_t Offset
, uint32_t Size
,
244 ArrayRef
<uint8_t> &Buffer
) override
{
245 return Impl
.readBytes(Offset
, Size
, Buffer
);
248 Error
readLongestContiguousChunk(uint32_t Offset
,
249 ArrayRef
<uint8_t> &Buffer
) override
{
250 return Impl
.readLongestContiguousChunk(Offset
, Buffer
);
253 uint32_t getLength() override
{ return Impl
.getLength(); }
255 Error
writeBytes(uint32_t Offset
, ArrayRef
<uint8_t> Data
) override
{
256 return Impl
.writeBytes(Offset
, Data
);
259 Error
commit() override
{ return Impl
.commit(); }
261 /// Returns a pointer to the start of the buffer.
262 uint8_t *getBufferStart() const { return Impl
.getBufferStart(); }
264 /// Returns a pointer to the end of the buffer.
265 uint8_t *getBufferEnd() const { return Impl
.getBufferEnd(); }
271 } // end namespace llvm
273 #endif // LLVM_SUPPORT_BYTESTREAM_H