xref: /freebsd-src/contrib/llvm-project/llvm/include/llvm/Support/BinaryByteStream.h (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //===- BinaryByteStream.h ---------------------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
70b57cec5SDimitry Andric // A BinaryStream which stores data in a single continguous memory buffer.
80b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
90b57cec5SDimitry Andric 
100b57cec5SDimitry Andric #ifndef LLVM_SUPPORT_BINARYBYTESTREAM_H
110b57cec5SDimitry Andric #define LLVM_SUPPORT_BINARYBYTESTREAM_H
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
140b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
150b57cec5SDimitry Andric #include "llvm/Support/BinaryStream.h"
160b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamError.h"
170b57cec5SDimitry Andric #include "llvm/Support/Error.h"
180b57cec5SDimitry Andric #include "llvm/Support/FileOutputBuffer.h"
190b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
200b57cec5SDimitry Andric #include <cstdint>
210b57cec5SDimitry Andric #include <cstring>
220b57cec5SDimitry Andric #include <memory>
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric namespace llvm {
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric /// An implementation of BinaryStream which holds its entire data set
270b57cec5SDimitry Andric /// in a single contiguous buffer.  BinaryByteStream guarantees that no read
280b57cec5SDimitry Andric /// operation will ever incur a copy.  Note that BinaryByteStream does not
290b57cec5SDimitry Andric /// own the underlying buffer.
300b57cec5SDimitry Andric class BinaryByteStream : public BinaryStream {
310b57cec5SDimitry Andric public:
320b57cec5SDimitry Andric   BinaryByteStream() = default;
BinaryByteStream(ArrayRef<uint8_t> Data,llvm::endianness Endian)33*5f757f3fSDimitry Andric   BinaryByteStream(ArrayRef<uint8_t> Data, llvm::endianness Endian)
340b57cec5SDimitry Andric       : Endian(Endian), Data(Data) {}
BinaryByteStream(StringRef Data,llvm::endianness Endian)35*5f757f3fSDimitry Andric   BinaryByteStream(StringRef Data, llvm::endianness Endian)
360b57cec5SDimitry Andric       : Endian(Endian), Data(Data.bytes_begin(), Data.bytes_end()) {}
370b57cec5SDimitry Andric 
getEndian()38*5f757f3fSDimitry Andric   llvm::endianness getEndian() const override { return Endian; }
390b57cec5SDimitry Andric 
readBytes(uint64_t Offset,uint64_t Size,ArrayRef<uint8_t> & Buffer)40349cc55cSDimitry Andric   Error readBytes(uint64_t Offset, uint64_t Size,
410b57cec5SDimitry Andric                   ArrayRef<uint8_t> &Buffer) override {
420b57cec5SDimitry Andric     if (auto EC = checkOffsetForRead(Offset, Size))
430b57cec5SDimitry Andric       return EC;
440b57cec5SDimitry Andric     Buffer = Data.slice(Offset, Size);
450b57cec5SDimitry Andric     return Error::success();
460b57cec5SDimitry Andric   }
470b57cec5SDimitry Andric 
readLongestContiguousChunk(uint64_t Offset,ArrayRef<uint8_t> & Buffer)48349cc55cSDimitry Andric   Error readLongestContiguousChunk(uint64_t Offset,
490b57cec5SDimitry Andric                                    ArrayRef<uint8_t> &Buffer) override {
500b57cec5SDimitry Andric     if (auto EC = checkOffsetForRead(Offset, 1))
510b57cec5SDimitry Andric       return EC;
520b57cec5SDimitry Andric     Buffer = Data.slice(Offset);
530b57cec5SDimitry Andric     return Error::success();
540b57cec5SDimitry Andric   }
550b57cec5SDimitry Andric 
getLength()56349cc55cSDimitry Andric   uint64_t getLength() override { return Data.size(); }
570b57cec5SDimitry Andric 
data()580b57cec5SDimitry Andric   ArrayRef<uint8_t> data() const { return Data; }
590b57cec5SDimitry Andric 
str()600b57cec5SDimitry Andric   StringRef str() const {
610b57cec5SDimitry Andric     const char *CharData = reinterpret_cast<const char *>(Data.data());
620b57cec5SDimitry Andric     return StringRef(CharData, Data.size());
630b57cec5SDimitry Andric   }
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric protected:
66*5f757f3fSDimitry Andric   llvm::endianness Endian;
670b57cec5SDimitry Andric   ArrayRef<uint8_t> Data;
680b57cec5SDimitry Andric };
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric /// An implementation of BinaryStream whose data is backed by an llvm
710b57cec5SDimitry Andric /// MemoryBuffer object.  MemoryBufferByteStream owns the MemoryBuffer in
720b57cec5SDimitry Andric /// question.  As with BinaryByteStream, reading from a MemoryBufferByteStream
730b57cec5SDimitry Andric /// will never cause a copy.
740b57cec5SDimitry Andric class MemoryBufferByteStream : public BinaryByteStream {
750b57cec5SDimitry Andric public:
MemoryBufferByteStream(std::unique_ptr<MemoryBuffer> Buffer,llvm::endianness Endian)760b57cec5SDimitry Andric   MemoryBufferByteStream(std::unique_ptr<MemoryBuffer> Buffer,
77*5f757f3fSDimitry Andric                          llvm::endianness Endian)
780b57cec5SDimitry Andric       : BinaryByteStream(Buffer->getBuffer(), Endian),
790b57cec5SDimitry Andric         MemBuffer(std::move(Buffer)) {}
800b57cec5SDimitry Andric 
810b57cec5SDimitry Andric   std::unique_ptr<MemoryBuffer> MemBuffer;
820b57cec5SDimitry Andric };
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric /// An implementation of BinaryStream which holds its entire data set
850b57cec5SDimitry Andric /// in a single contiguous buffer.  As with BinaryByteStream, the mutable
860b57cec5SDimitry Andric /// version also guarantees that no read operation will ever incur a copy,
870b57cec5SDimitry Andric /// and similarly it does not own the underlying buffer.
880b57cec5SDimitry Andric class MutableBinaryByteStream : public WritableBinaryStream {
890b57cec5SDimitry Andric public:
900b57cec5SDimitry Andric   MutableBinaryByteStream() = default;
MutableBinaryByteStream(MutableArrayRef<uint8_t> Data,llvm::endianness Endian)910b57cec5SDimitry Andric   MutableBinaryByteStream(MutableArrayRef<uint8_t> Data,
92*5f757f3fSDimitry Andric                           llvm::endianness Endian)
930b57cec5SDimitry Andric       : Data(Data), ImmutableStream(Data, Endian) {}
940b57cec5SDimitry Andric 
getEndian()95*5f757f3fSDimitry Andric   llvm::endianness getEndian() const override {
960b57cec5SDimitry Andric     return ImmutableStream.getEndian();
970b57cec5SDimitry Andric   }
980b57cec5SDimitry Andric 
readBytes(uint64_t Offset,uint64_t Size,ArrayRef<uint8_t> & Buffer)99349cc55cSDimitry Andric   Error readBytes(uint64_t Offset, uint64_t Size,
1000b57cec5SDimitry Andric                   ArrayRef<uint8_t> &Buffer) override {
1010b57cec5SDimitry Andric     return ImmutableStream.readBytes(Offset, Size, Buffer);
1020b57cec5SDimitry Andric   }
1030b57cec5SDimitry Andric 
readLongestContiguousChunk(uint64_t Offset,ArrayRef<uint8_t> & Buffer)104349cc55cSDimitry Andric   Error readLongestContiguousChunk(uint64_t Offset,
1050b57cec5SDimitry Andric                                    ArrayRef<uint8_t> &Buffer) override {
1060b57cec5SDimitry Andric     return ImmutableStream.readLongestContiguousChunk(Offset, Buffer);
1070b57cec5SDimitry Andric   }
1080b57cec5SDimitry Andric 
getLength()109349cc55cSDimitry Andric   uint64_t getLength() override { return ImmutableStream.getLength(); }
1100b57cec5SDimitry Andric 
writeBytes(uint64_t Offset,ArrayRef<uint8_t> Buffer)111349cc55cSDimitry Andric   Error writeBytes(uint64_t Offset, ArrayRef<uint8_t> Buffer) override {
1120b57cec5SDimitry Andric     if (Buffer.empty())
1130b57cec5SDimitry Andric       return Error::success();
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric     if (auto EC = checkOffsetForWrite(Offset, Buffer.size()))
1160b57cec5SDimitry Andric       return EC;
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric     uint8_t *DataPtr = const_cast<uint8_t *>(Data.data());
1190b57cec5SDimitry Andric     ::memcpy(DataPtr + Offset, Buffer.data(), Buffer.size());
1200b57cec5SDimitry Andric     return Error::success();
1210b57cec5SDimitry Andric   }
1220b57cec5SDimitry Andric 
commit()1230b57cec5SDimitry Andric   Error commit() override { return Error::success(); }
1240b57cec5SDimitry Andric 
data()1250b57cec5SDimitry Andric   MutableArrayRef<uint8_t> data() const { return Data; }
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric private:
1280b57cec5SDimitry Andric   MutableArrayRef<uint8_t> Data;
1290b57cec5SDimitry Andric   BinaryByteStream ImmutableStream;
1300b57cec5SDimitry Andric };
1310b57cec5SDimitry Andric 
1320b57cec5SDimitry Andric /// An implementation of WritableBinaryStream which can write at its end
1330b57cec5SDimitry Andric /// causing the underlying data to grow.  This class owns the underlying data.
1340b57cec5SDimitry Andric class AppendingBinaryByteStream : public WritableBinaryStream {
1350b57cec5SDimitry Andric   std::vector<uint8_t> Data;
136*5f757f3fSDimitry Andric   llvm::endianness Endian = llvm::endianness::little;
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric public:
1390b57cec5SDimitry Andric   AppendingBinaryByteStream() = default;
AppendingBinaryByteStream(llvm::endianness Endian)140*5f757f3fSDimitry Andric   AppendingBinaryByteStream(llvm::endianness Endian) : Endian(Endian) {}
1410b57cec5SDimitry Andric 
clear()1420b57cec5SDimitry Andric   void clear() { Data.clear(); }
1430b57cec5SDimitry Andric 
getEndian()144*5f757f3fSDimitry Andric   llvm::endianness getEndian() const override { return Endian; }
1450b57cec5SDimitry Andric 
readBytes(uint64_t Offset,uint64_t Size,ArrayRef<uint8_t> & Buffer)146349cc55cSDimitry Andric   Error readBytes(uint64_t Offset, uint64_t Size,
1470b57cec5SDimitry Andric                   ArrayRef<uint8_t> &Buffer) override {
1480b57cec5SDimitry Andric     if (auto EC = checkOffsetForWrite(Offset, Buffer.size()))
1490b57cec5SDimitry Andric       return EC;
1500b57cec5SDimitry Andric 
151bdd1243dSDimitry Andric     Buffer = ArrayRef(Data).slice(Offset, Size);
1520b57cec5SDimitry Andric     return Error::success();
1530b57cec5SDimitry Andric   }
1540b57cec5SDimitry Andric 
insert(uint64_t Offset,ArrayRef<uint8_t> Bytes)155349cc55cSDimitry Andric   void insert(uint64_t Offset, ArrayRef<uint8_t> Bytes) {
1560b57cec5SDimitry Andric     Data.insert(Data.begin() + Offset, Bytes.begin(), Bytes.end());
1570b57cec5SDimitry Andric   }
1580b57cec5SDimitry Andric 
readLongestContiguousChunk(uint64_t Offset,ArrayRef<uint8_t> & Buffer)159349cc55cSDimitry Andric   Error readLongestContiguousChunk(uint64_t Offset,
1600b57cec5SDimitry Andric                                    ArrayRef<uint8_t> &Buffer) override {
1610b57cec5SDimitry Andric     if (auto EC = checkOffsetForWrite(Offset, 1))
1620b57cec5SDimitry Andric       return EC;
1630b57cec5SDimitry Andric 
164bdd1243dSDimitry Andric     Buffer = ArrayRef(Data).slice(Offset);
1650b57cec5SDimitry Andric     return Error::success();
1660b57cec5SDimitry Andric   }
1670b57cec5SDimitry Andric 
getLength()168349cc55cSDimitry Andric   uint64_t getLength() override { return Data.size(); }
1690b57cec5SDimitry Andric 
writeBytes(uint64_t Offset,ArrayRef<uint8_t> Buffer)170349cc55cSDimitry Andric   Error writeBytes(uint64_t Offset, ArrayRef<uint8_t> Buffer) override {
1710b57cec5SDimitry Andric     if (Buffer.empty())
1720b57cec5SDimitry Andric       return Error::success();
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric     // This is well-defined for any case except where offset is strictly
1750b57cec5SDimitry Andric     // greater than the current length.  If offset is equal to the current
1760b57cec5SDimitry Andric     // length, we can still grow.  If offset is beyond the current length, we
1770b57cec5SDimitry Andric     // would have to decide how to deal with the intermediate uninitialized
1780b57cec5SDimitry Andric     // bytes.  So we punt on that case for simplicity and just say it's an
1790b57cec5SDimitry Andric     // error.
1800b57cec5SDimitry Andric     if (Offset > getLength())
1810b57cec5SDimitry Andric       return make_error<BinaryStreamError>(stream_error_code::invalid_offset);
1820b57cec5SDimitry Andric 
183349cc55cSDimitry Andric     uint64_t RequiredSize = Offset + Buffer.size();
1840b57cec5SDimitry Andric     if (RequiredSize > Data.size())
1850b57cec5SDimitry Andric       Data.resize(RequiredSize);
1860b57cec5SDimitry Andric 
1870b57cec5SDimitry Andric     ::memcpy(Data.data() + Offset, Buffer.data(), Buffer.size());
1880b57cec5SDimitry Andric     return Error::success();
1890b57cec5SDimitry Andric   }
1900b57cec5SDimitry Andric 
commit()1910b57cec5SDimitry Andric   Error commit() override { return Error::success(); }
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric   /// Return the properties of this stream.
getFlags()194972a253aSDimitry Andric   BinaryStreamFlags getFlags() const override { return BSF_Write | BSF_Append; }
1950b57cec5SDimitry Andric 
data()1960b57cec5SDimitry Andric   MutableArrayRef<uint8_t> data() { return Data; }
1970b57cec5SDimitry Andric };
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric /// An implementation of WritableBinaryStream backed by an llvm
2000b57cec5SDimitry Andric /// FileOutputBuffer.
2010b57cec5SDimitry Andric class FileBufferByteStream : public WritableBinaryStream {
2020b57cec5SDimitry Andric private:
2030b57cec5SDimitry Andric   class StreamImpl : public MutableBinaryByteStream {
2040b57cec5SDimitry Andric   public:
StreamImpl(std::unique_ptr<FileOutputBuffer> Buffer,llvm::endianness Endian)2050b57cec5SDimitry Andric     StreamImpl(std::unique_ptr<FileOutputBuffer> Buffer,
206*5f757f3fSDimitry Andric                llvm::endianness Endian)
2070b57cec5SDimitry Andric         : MutableBinaryByteStream(
2080b57cec5SDimitry Andric               MutableArrayRef<uint8_t>(Buffer->getBufferStart(),
2090b57cec5SDimitry Andric                                        Buffer->getBufferEnd()),
2100b57cec5SDimitry Andric               Endian),
2110b57cec5SDimitry Andric           FileBuffer(std::move(Buffer)) {}
2120b57cec5SDimitry Andric 
commit()2130b57cec5SDimitry Andric     Error commit() override {
2140b57cec5SDimitry Andric       if (FileBuffer->commit())
2150b57cec5SDimitry Andric         return make_error<BinaryStreamError>(
2160b57cec5SDimitry Andric             stream_error_code::filesystem_error);
2170b57cec5SDimitry Andric       return Error::success();
2180b57cec5SDimitry Andric     }
2190b57cec5SDimitry Andric 
2200b57cec5SDimitry Andric     /// Returns a pointer to the start of the buffer.
getBufferStart()2210b57cec5SDimitry Andric     uint8_t *getBufferStart() const { return FileBuffer->getBufferStart(); }
2220b57cec5SDimitry Andric 
2230b57cec5SDimitry Andric     /// Returns a pointer to the end of the buffer.
getBufferEnd()2240b57cec5SDimitry Andric     uint8_t *getBufferEnd() const { return FileBuffer->getBufferEnd(); }
2250b57cec5SDimitry Andric 
2260b57cec5SDimitry Andric   private:
2270b57cec5SDimitry Andric     std::unique_ptr<FileOutputBuffer> FileBuffer;
2280b57cec5SDimitry Andric   };
2290b57cec5SDimitry Andric 
2300b57cec5SDimitry Andric public:
FileBufferByteStream(std::unique_ptr<FileOutputBuffer> Buffer,llvm::endianness Endian)2310b57cec5SDimitry Andric   FileBufferByteStream(std::unique_ptr<FileOutputBuffer> Buffer,
232*5f757f3fSDimitry Andric                        llvm::endianness Endian)
2330b57cec5SDimitry Andric       : Impl(std::move(Buffer), Endian) {}
2340b57cec5SDimitry Andric 
getEndian()235*5f757f3fSDimitry Andric   llvm::endianness getEndian() const override { return Impl.getEndian(); }
2360b57cec5SDimitry Andric 
readBytes(uint64_t Offset,uint64_t Size,ArrayRef<uint8_t> & Buffer)237349cc55cSDimitry Andric   Error readBytes(uint64_t Offset, uint64_t Size,
2380b57cec5SDimitry Andric                   ArrayRef<uint8_t> &Buffer) override {
2390b57cec5SDimitry Andric     return Impl.readBytes(Offset, Size, Buffer);
2400b57cec5SDimitry Andric   }
2410b57cec5SDimitry Andric 
readLongestContiguousChunk(uint64_t Offset,ArrayRef<uint8_t> & Buffer)242349cc55cSDimitry Andric   Error readLongestContiguousChunk(uint64_t Offset,
2430b57cec5SDimitry Andric                                    ArrayRef<uint8_t> &Buffer) override {
2440b57cec5SDimitry Andric     return Impl.readLongestContiguousChunk(Offset, Buffer);
2450b57cec5SDimitry Andric   }
2460b57cec5SDimitry Andric 
getLength()247349cc55cSDimitry Andric   uint64_t getLength() override { return Impl.getLength(); }
2480b57cec5SDimitry Andric 
writeBytes(uint64_t Offset,ArrayRef<uint8_t> Data)249349cc55cSDimitry Andric   Error writeBytes(uint64_t Offset, ArrayRef<uint8_t> Data) override {
2500b57cec5SDimitry Andric     return Impl.writeBytes(Offset, Data);
2510b57cec5SDimitry Andric   }
2520b57cec5SDimitry Andric 
commit()2530b57cec5SDimitry Andric   Error commit() override { return Impl.commit(); }
2540b57cec5SDimitry Andric 
2550b57cec5SDimitry Andric   /// Returns a pointer to the start of the buffer.
getBufferStart()2560b57cec5SDimitry Andric   uint8_t *getBufferStart() const { return Impl.getBufferStart(); }
2570b57cec5SDimitry Andric 
2580b57cec5SDimitry Andric   /// Returns a pointer to the end of the buffer.
getBufferEnd()2590b57cec5SDimitry Andric   uint8_t *getBufferEnd() const { return Impl.getBufferEnd(); }
2600b57cec5SDimitry Andric 
2610b57cec5SDimitry Andric private:
2620b57cec5SDimitry Andric   StreamImpl Impl;
2630b57cec5SDimitry Andric };
2640b57cec5SDimitry Andric 
2650b57cec5SDimitry Andric } // end namespace llvm
2660b57cec5SDimitry Andric 
267fe6060f1SDimitry Andric #endif // LLVM_SUPPORT_BINARYBYTESTREAM_H
268