1 //===- BinaryStreamRef.h - A copyable reference to a stream -----*- 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 //===----------------------------------------------------------------------===// 9 10 #ifndef LLVM_SUPPORT_BINARYSTREAMREF_H 11 #define LLVM_SUPPORT_BINARYSTREAMREF_H 12 13 #include "llvm/ADT/ArrayRef.h" 14 #include "llvm/Support/BinaryStream.h" 15 #include "llvm/Support/BinaryStreamError.h" 16 #include "llvm/Support/Error.h" 17 #include <algorithm> 18 #include <cstdint> 19 #include <memory> 20 21 namespace llvm { 22 23 /// Common stuff for mutable and immutable StreamRefs. 24 template <class RefType, class StreamType> class BinaryStreamRefBase { 25 protected: 26 BinaryStreamRefBase() = default; 27 BinaryStreamRefBase(std::shared_ptr<StreamType> SharedImpl, uint32_t Offset, 28 uint32_t Length) 29 : SharedImpl(SharedImpl), BorrowedImpl(SharedImpl.get()), 30 ViewOffset(Offset), Length(Length) {} 31 BinaryStreamRefBase(StreamType &BorrowedImpl, uint32_t Offset, 32 uint32_t Length) 33 : BorrowedImpl(&BorrowedImpl), ViewOffset(Offset), Length(Length) {} 34 BinaryStreamRefBase(const BinaryStreamRefBase &Other) { 35 SharedImpl = Other.SharedImpl; 36 BorrowedImpl = Other.BorrowedImpl; 37 ViewOffset = Other.ViewOffset; 38 Length = Other.Length; 39 } 40 41 public: 42 llvm::support::endianness getEndian() const { 43 return BorrowedImpl->getEndian(); 44 } 45 46 uint32_t getLength() const { return Length; } 47 48 /// Return a new BinaryStreamRef with the first \p N elements removed. 49 RefType drop_front(uint32_t N) const { 50 if (!BorrowedImpl) 51 return RefType(); 52 53 N = std::min(N, Length); 54 RefType Result(static_cast<const RefType &>(*this)); 55 Result.ViewOffset += N; 56 Result.Length -= N; 57 return Result; 58 } 59 60 /// Return a new BinaryStreamRef with the first \p N elements removed. 61 RefType drop_back(uint32_t N) const { 62 if (!BorrowedImpl) 63 return RefType(); 64 65 N = std::min(N, Length); 66 RefType Result(static_cast<const RefType &>(*this)); 67 Result.Length -= N; 68 return Result; 69 } 70 71 /// Return a new BinaryStreamRef with only the first \p N elements remaining. 72 RefType keep_front(uint32_t N) const { 73 assert(N <= getLength()); 74 return drop_back(getLength() - N); 75 } 76 77 /// Return a new BinaryStreamRef with only the last \p N elements remaining. 78 RefType keep_back(uint32_t N) const { 79 assert(N <= getLength()); 80 return drop_front(getLength() - N); 81 } 82 83 /// Return a new BinaryStreamRef with the first and last \p N elements 84 /// removed. 85 RefType drop_symmetric(uint32_t N) const { 86 return drop_front(N).drop_back(N); 87 } 88 89 /// Return a new BinaryStreamRef with the first \p Offset elements removed, 90 /// and retaining exactly \p Len elements. 91 RefType slice(uint32_t Offset, uint32_t Len) const { 92 return drop_front(Offset).keep_front(Len); 93 } 94 95 bool valid() const { return BorrowedImpl != nullptr; } 96 97 bool operator==(const RefType &Other) const { 98 if (BorrowedImpl != Other.BorrowedImpl) 99 return false; 100 if (ViewOffset != Other.ViewOffset) 101 return false; 102 if (Length != Other.Length) 103 return false; 104 return true; 105 } 106 107 protected: 108 Error checkOffset(uint32_t Offset, uint32_t DataSize) const { 109 if (Offset > getLength()) 110 return make_error<BinaryStreamError>(stream_error_code::invalid_offset); 111 if (getLength() < DataSize + Offset) 112 return make_error<BinaryStreamError>(stream_error_code::stream_too_short); 113 return Error::success(); 114 } 115 116 std::shared_ptr<StreamType> SharedImpl; 117 StreamType *BorrowedImpl = nullptr; 118 uint32_t ViewOffset = 0; 119 uint32_t Length = 0; 120 }; 121 122 /// \brief BinaryStreamRef is to BinaryStream what ArrayRef is to an Array. It 123 /// provides copy-semantics and read only access to a "window" of the underlying 124 /// BinaryStream. Note that BinaryStreamRef is *not* a BinaryStream. That is to 125 /// say, it does not inherit and override the methods of BinaryStream. In 126 /// general, you should not pass around pointers or references to BinaryStreams 127 /// and use inheritance to achieve polymorphism. Instead, you should pass 128 /// around BinaryStreamRefs by value and achieve polymorphism that way. 129 class BinaryStreamRef 130 : public BinaryStreamRefBase<BinaryStreamRef, BinaryStream> { 131 friend BinaryStreamRefBase<BinaryStreamRef, BinaryStream>; 132 friend class WritableBinaryStreamRef; 133 BinaryStreamRef(std::shared_ptr<BinaryStream> Impl, uint32_t ViewOffset, 134 uint32_t Length) 135 : BinaryStreamRefBase(Impl, ViewOffset, Length) {} 136 137 public: 138 BinaryStreamRef() = default; 139 BinaryStreamRef(BinaryStream &Stream); 140 BinaryStreamRef(BinaryStream &Stream, uint32_t Offset, uint32_t Length); 141 explicit BinaryStreamRef(ArrayRef<uint8_t> Data, 142 llvm::support::endianness Endian); 143 explicit BinaryStreamRef(StringRef Data, llvm::support::endianness Endian); 144 145 BinaryStreamRef(const BinaryStreamRef &Other); 146 147 // Use BinaryStreamRef.slice() instead. 148 BinaryStreamRef(BinaryStreamRef &S, uint32_t Offset, 149 uint32_t Length) = delete; 150 151 /// Given an Offset into this StreamRef and a Size, return a reference to a 152 /// buffer owned by the stream. 153 /// 154 /// \returns a success error code if the entire range of data is within the 155 /// bounds of this BinaryStreamRef's view and the implementation could read 156 /// the data, and an appropriate error code otherwise. 157 Error readBytes(uint32_t Offset, uint32_t Size, 158 ArrayRef<uint8_t> &Buffer) const; 159 160 /// Given an Offset into this BinaryStreamRef, return a reference to the 161 /// largest buffer the stream could support without necessitating a copy. 162 /// 163 /// \returns a success error code if implementation could read the data, 164 /// and an appropriate error code otherwise. 165 Error readLongestContiguousChunk(uint32_t Offset, 166 ArrayRef<uint8_t> &Buffer) const; 167 }; 168 169 class WritableBinaryStreamRef 170 : public BinaryStreamRefBase<WritableBinaryStreamRef, 171 WritableBinaryStream> { 172 friend BinaryStreamRefBase<WritableBinaryStreamRef, WritableBinaryStream>; 173 WritableBinaryStreamRef(std::shared_ptr<WritableBinaryStream> Impl, 174 uint32_t ViewOffset, uint32_t Length) 175 : BinaryStreamRefBase(Impl, ViewOffset, Length) {} 176 177 public: 178 WritableBinaryStreamRef() = default; 179 WritableBinaryStreamRef(WritableBinaryStream &Stream); 180 WritableBinaryStreamRef(WritableBinaryStream &Stream, uint32_t Offset, 181 uint32_t Length); 182 explicit WritableBinaryStreamRef(MutableArrayRef<uint8_t> Data, 183 llvm::support::endianness Endian); 184 WritableBinaryStreamRef(const WritableBinaryStreamRef &Other); 185 186 // Use WritableBinaryStreamRef.slice() instead. 187 WritableBinaryStreamRef(WritableBinaryStreamRef &S, uint32_t Offset, 188 uint32_t Length) = delete; 189 190 /// Given an Offset into this WritableBinaryStreamRef and some input data, 191 /// writes the data to the underlying stream. 192 /// 193 /// \returns a success error code if the data could fit within the underlying 194 /// stream at the specified location and the implementation could write the 195 /// data, and an appropriate error code otherwise. 196 Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) const; 197 198 /// Conver this WritableBinaryStreamRef to a read-only BinaryStreamRef. 199 operator BinaryStreamRef() const; 200 201 /// \brief For buffered streams, commits changes to the backing store. 202 Error commit(); 203 }; 204 205 } // end namespace llvm 206 207 #endif // LLVM_SUPPORT_BINARYSTREAMREF_H 208