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 /// \brief 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 class BinaryByteStream : public BinaryStream { 33 public: 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 = checkOffset(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 = checkOffset(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 67 protected: 68 llvm::support::endianness Endian; 69 ArrayRef<uint8_t> Data; 70 }; 71 72 /// \brief 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 : BinaryByteStream(Buffer->getBuffer(), Endian), 81 MemBuffer(std::move(Buffer)) {} 82 83 std::unique_ptr<MemoryBuffer> MemBuffer; 84 }; 85 86 /// \brief 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 class MutableBinaryByteStream : public WritableBinaryStream { 91 public: 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 = checkOffset(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 129 private: 130 MutableArrayRef<uint8_t> Data; 131 BinaryByteStream ImmutableStream; 132 }; 133 134 /// \brief An implementation of WritableBinaryStream backed by an llvm 135 /// FileOutputBuffer. 136 class FileBufferByteStream : public WritableBinaryStream { 137 private: 138 class StreamImpl : public MutableBinaryByteStream { 139 public: 140 StreamImpl(std::unique_ptr<FileOutputBuffer> Buffer, 141 llvm::support::endianness Endian) 142 : MutableBinaryByteStream( 143 MutableArrayRef<uint8_t>(Buffer->getBufferStart(), 144 Buffer->getBufferEnd()), 145 Endian), 146 FileBuffer(std::move(Buffer)) {} 147 148 Error commit() override { 149 if (FileBuffer->commit()) 150 return make_error<BinaryStreamError>( 151 stream_error_code::filesystem_error); 152 return Error::success(); 153 } 154 155 private: 156 std::unique_ptr<FileOutputBuffer> FileBuffer; 157 }; 158 159 public: 160 FileBufferByteStream(std::unique_ptr<FileOutputBuffer> Buffer, 161 llvm::support::endianness Endian) 162 : Impl(std::move(Buffer), Endian) {} 163 164 llvm::support::endianness getEndian() const override { 165 return Impl.getEndian(); 166 } 167 168 Error readBytes(uint32_t Offset, uint32_t Size, 169 ArrayRef<uint8_t> &Buffer) override { 170 return Impl.readBytes(Offset, Size, Buffer); 171 } 172 173 Error readLongestContiguousChunk(uint32_t Offset, 174 ArrayRef<uint8_t> &Buffer) override { 175 return Impl.readLongestContiguousChunk(Offset, Buffer); 176 } 177 178 uint32_t getLength() override { return Impl.getLength(); } 179 180 Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) override { 181 return Impl.writeBytes(Offset, Data); 182 } 183 184 Error commit() override { return Impl.commit(); } 185 186 private: 187 StreamImpl Impl; 188 }; 189 190 } // end namespace llvm 191 192 #endif // LLVM_SUPPORT_BYTESTREAM_H 193