BinaryStreamRef.h revision 317017
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 20namespace llvm { 21 22/// Common stuff for mutable and immutable StreamRefs. 23template <class StreamType, class RefType> class BinaryStreamRefBase { 24public: 25 BinaryStreamRefBase() : Stream(nullptr), ViewOffset(0), Length(0) {} 26 BinaryStreamRefBase(StreamType &Stream, uint32_t Offset, uint32_t Length) 27 : Stream(&Stream), ViewOffset(Offset), Length(Length) {} 28 29 llvm::support::endianness getEndian() const { return Stream->getEndian(); } 30 31 uint32_t getLength() const { return Length; } 32 const StreamType *getStream() const { return Stream; } 33 34 /// Return a new BinaryStreamRef with the first \p N elements removed. 35 RefType drop_front(uint32_t N) const { 36 if (!Stream) 37 return RefType(); 38 39 N = std::min(N, Length); 40 return RefType(*Stream, ViewOffset + N, Length - N); 41 } 42 43 /// Return a new BinaryStreamRef with only the first \p N elements remaining. 44 RefType keep_front(uint32_t N) const { 45 if (!Stream) 46 return RefType(); 47 N = std::min(N, Length); 48 return RefType(*Stream, ViewOffset, N); 49 } 50 51 /// Return a new BinaryStreamRef with the first \p Offset elements removed, 52 /// and retaining exactly \p Len elements. 53 RefType slice(uint32_t Offset, uint32_t Len) const { 54 return drop_front(Offset).keep_front(Len); 55 } 56 57 bool operator==(const RefType &Other) const { 58 if (Stream != Other.Stream) 59 return false; 60 if (ViewOffset != Other.ViewOffset) 61 return false; 62 if (Length != Other.Length) 63 return false; 64 return true; 65 } 66 67protected: 68 Error checkOffset(uint32_t Offset, uint32_t DataSize) const { 69 if (Offset > getLength()) 70 return make_error<BinaryStreamError>(stream_error_code::invalid_offset); 71 if (getLength() < DataSize + Offset) 72 return make_error<BinaryStreamError>(stream_error_code::stream_too_short); 73 return Error::success(); 74 } 75 76 StreamType *Stream; 77 uint32_t ViewOffset; 78 uint32_t Length; 79}; 80 81/// \brief BinaryStreamRef is to BinaryStream what ArrayRef is to an Array. It 82/// provides copy-semantics and read only access to a "window" of the underlying 83/// BinaryStream. Note that BinaryStreamRef is *not* a BinaryStream. That is to 84/// say, it does not inherit and override the methods of BinaryStream. In 85/// general, you should not pass around pointers or references to BinaryStreams 86/// and use inheritance to achieve polymorphism. Instead, you should pass 87/// around BinaryStreamRefs by value and achieve polymorphism that way. 88class BinaryStreamRef 89 : public BinaryStreamRefBase<BinaryStream, BinaryStreamRef> { 90public: 91 BinaryStreamRef() = default; 92 BinaryStreamRef(BinaryStream &Stream) 93 : BinaryStreamRefBase(Stream, 0, Stream.getLength()) {} 94 BinaryStreamRef(BinaryStream &Stream, uint32_t Offset, uint32_t Length) 95 : BinaryStreamRefBase(Stream, Offset, Length) {} 96 97 // Use BinaryStreamRef.slice() instead. 98 BinaryStreamRef(BinaryStreamRef &S, uint32_t Offset, 99 uint32_t Length) = delete; 100 101 /// Given an Offset into this StreamRef and a Size, return a reference to a 102 /// buffer owned by the stream. 103 /// 104 /// \returns a success error code if the entire range of data is within the 105 /// bounds of this BinaryStreamRef's view and the implementation could read 106 /// the data, and an appropriate error code otherwise. 107 Error readBytes(uint32_t Offset, uint32_t Size, 108 ArrayRef<uint8_t> &Buffer) const { 109 if (auto EC = checkOffset(Offset, Size)) 110 return EC; 111 112 return Stream->readBytes(ViewOffset + Offset, Size, Buffer); 113 } 114 115 /// Given an Offset into this BinaryStreamRef, return a reference to the 116 /// largest buffer the stream could support without necessitating a copy. 117 /// 118 /// \returns a success error code if implementation could read the data, 119 /// and an appropriate error code otherwise. 120 Error readLongestContiguousChunk(uint32_t Offset, 121 ArrayRef<uint8_t> &Buffer) const { 122 if (auto EC = checkOffset(Offset, 1)) 123 return EC; 124 125 if (auto EC = 126 Stream->readLongestContiguousChunk(ViewOffset + Offset, Buffer)) 127 return EC; 128 // This StreamRef might refer to a smaller window over a larger stream. In 129 // that case we will have read out more bytes than we should return, because 130 // we should not read past the end of the current view. 131 uint32_t MaxLength = Length - Offset; 132 if (Buffer.size() > MaxLength) 133 Buffer = Buffer.slice(0, MaxLength); 134 return Error::success(); 135 } 136}; 137 138class WritableBinaryStreamRef 139 : public BinaryStreamRefBase<WritableBinaryStream, 140 WritableBinaryStreamRef> { 141public: 142 WritableBinaryStreamRef() = default; 143 WritableBinaryStreamRef(WritableBinaryStream &Stream) 144 : BinaryStreamRefBase(Stream, 0, Stream.getLength()) {} 145 WritableBinaryStreamRef(WritableBinaryStream &Stream, uint32_t Offset, 146 uint32_t Length) 147 : BinaryStreamRefBase(Stream, Offset, Length) {} 148 149 // Use WritableBinaryStreamRef.slice() instead. 150 WritableBinaryStreamRef(WritableBinaryStreamRef &S, uint32_t Offset, 151 uint32_t Length) = delete; 152 153 /// Given an Offset into this WritableBinaryStreamRef and some input data, 154 /// writes the data to the underlying stream. 155 /// 156 /// \returns a success error code if the data could fit within the underlying 157 /// stream at the specified location and the implementation could write the 158 /// data, and an appropriate error code otherwise. 159 Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) const { 160 if (auto EC = checkOffset(Offset, Data.size())) 161 return EC; 162 163 return Stream->writeBytes(ViewOffset + Offset, Data); 164 } 165 166 operator BinaryStreamRef() { return BinaryStreamRef(*Stream); } 167 168 /// \brief For buffered streams, commits changes to the backing store. 169 Error commit() { return Stream->commit(); } 170}; 171 172} // end namespace llvm 173 174#endif // LLVM_SUPPORT_BINARYSTREAMREF_H 175