1 //===- BinaryStreamRef.h - A copyable reference to a stream -----*- 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
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_SUPPORT_BINARYSTREAMREF_H
10 #define LLVM_SUPPORT_BINARYSTREAMREF_H
12 #include "llvm/ADT/ArrayRef.h"
13 #include "llvm/ADT/Optional.h"
14 #include "llvm/Support/BinaryStream.h"
15 #include "llvm/Support/BinaryStreamError.h"
16 #include "llvm/Support/Error.h"
23 /// Common stuff for mutable and immutable StreamRefs.
24 template <class RefType
, class StreamType
> class BinaryStreamRefBase
{
26 BinaryStreamRefBase() = default;
27 explicit BinaryStreamRefBase(StreamType
&BorrowedImpl
)
28 : BorrowedImpl(&BorrowedImpl
), ViewOffset(0) {
29 if (!(BorrowedImpl
.getFlags() & BSF_Append
))
30 Length
= BorrowedImpl
.getLength();
33 BinaryStreamRefBase(std::shared_ptr
<StreamType
> SharedImpl
, uint32_t Offset
,
34 Optional
<uint32_t> Length
)
35 : SharedImpl(SharedImpl
), BorrowedImpl(SharedImpl
.get()),
36 ViewOffset(Offset
), Length(Length
) {}
37 BinaryStreamRefBase(StreamType
&BorrowedImpl
, uint32_t Offset
,
38 Optional
<uint32_t> Length
)
39 : BorrowedImpl(&BorrowedImpl
), ViewOffset(Offset
), Length(Length
) {}
40 BinaryStreamRefBase(const BinaryStreamRefBase
&Other
) = default;
41 BinaryStreamRefBase
&operator=(const BinaryStreamRefBase
&Other
) = default;
43 BinaryStreamRefBase
&operator=(BinaryStreamRefBase
&&Other
) = default;
44 BinaryStreamRefBase(BinaryStreamRefBase
&&Other
) = default;
47 llvm::support::endianness
getEndian() const {
48 return BorrowedImpl
->getEndian();
51 uint32_t getLength() const {
52 if (Length
.hasValue())
55 return BorrowedImpl
? (BorrowedImpl
->getLength() - ViewOffset
) : 0;
58 /// Return a new BinaryStreamRef with the first \p N elements removed. If
59 /// this BinaryStreamRef is length-tracking, then the resulting one will be
61 RefType
drop_front(uint32_t N
) const {
65 N
= std::min(N
, getLength());
66 RefType
Result(static_cast<const RefType
&>(*this));
70 Result
.ViewOffset
+= N
;
71 if (Result
.Length
.hasValue())
76 /// Return a new BinaryStreamRef with the last \p N elements removed. If
77 /// this BinaryStreamRef is length-tracking and \p N is greater than 0, then
78 /// this BinaryStreamRef will no longer length-track.
79 RefType
drop_back(uint32_t N
) const {
83 RefType
Result(static_cast<const RefType
&>(*this));
84 N
= std::min(N
, getLength());
89 // Since we're dropping non-zero bytes from the end, stop length-tracking
90 // by setting the length of the resulting StreamRef to an explicit value.
91 if (!Result
.Length
.hasValue())
92 Result
.Length
= getLength();
98 /// Return a new BinaryStreamRef with only the first \p N elements remaining.
99 RefType
keep_front(uint32_t N
) const {
100 assert(N
<= getLength());
101 return drop_back(getLength() - N
);
104 /// Return a new BinaryStreamRef with only the last \p N elements remaining.
105 RefType
keep_back(uint32_t N
) const {
106 assert(N
<= getLength());
107 return drop_front(getLength() - N
);
110 /// Return a new BinaryStreamRef with the first and last \p N elements
112 RefType
drop_symmetric(uint32_t N
) const {
113 return drop_front(N
).drop_back(N
);
116 /// Return a new BinaryStreamRef with the first \p Offset elements removed,
117 /// and retaining exactly \p Len elements.
118 RefType
slice(uint32_t Offset
, uint32_t Len
) const {
119 return drop_front(Offset
).keep_front(Len
);
122 bool valid() const { return BorrowedImpl
!= nullptr; }
124 bool operator==(const RefType
&Other
) const {
125 if (BorrowedImpl
!= Other
.BorrowedImpl
)
127 if (ViewOffset
!= Other
.ViewOffset
)
129 if (Length
!= Other
.Length
)
135 Error
checkOffsetForRead(uint32_t Offset
, uint32_t DataSize
) const {
136 if (Offset
> getLength())
137 return make_error
<BinaryStreamError
>(stream_error_code::invalid_offset
);
138 if (getLength() < DataSize
+ Offset
)
139 return make_error
<BinaryStreamError
>(stream_error_code::stream_too_short
);
140 return Error::success();
143 std::shared_ptr
<StreamType
> SharedImpl
;
144 StreamType
*BorrowedImpl
= nullptr;
145 uint32_t ViewOffset
= 0;
146 Optional
<uint32_t> Length
;
149 /// BinaryStreamRef is to BinaryStream what ArrayRef is to an Array. It
150 /// provides copy-semantics and read only access to a "window" of the underlying
151 /// BinaryStream. Note that BinaryStreamRef is *not* a BinaryStream. That is to
152 /// say, it does not inherit and override the methods of BinaryStream. In
153 /// general, you should not pass around pointers or references to BinaryStreams
154 /// and use inheritance to achieve polymorphism. Instead, you should pass
155 /// around BinaryStreamRefs by value and achieve polymorphism that way.
156 class BinaryStreamRef
157 : public BinaryStreamRefBase
<BinaryStreamRef
, BinaryStream
> {
158 friend BinaryStreamRefBase
<BinaryStreamRef
, BinaryStream
>;
159 friend class WritableBinaryStreamRef
;
160 BinaryStreamRef(std::shared_ptr
<BinaryStream
> Impl
, uint32_t ViewOffset
,
161 Optional
<uint32_t> Length
)
162 : BinaryStreamRefBase(Impl
, ViewOffset
, Length
) {}
165 BinaryStreamRef() = default;
166 BinaryStreamRef(BinaryStream
&Stream
);
167 BinaryStreamRef(BinaryStream
&Stream
, uint32_t Offset
,
168 Optional
<uint32_t> Length
);
169 explicit BinaryStreamRef(ArrayRef
<uint8_t> Data
,
170 llvm::support::endianness Endian
);
171 explicit BinaryStreamRef(StringRef Data
, llvm::support::endianness Endian
);
173 BinaryStreamRef(const BinaryStreamRef
&Other
) = default;
174 BinaryStreamRef
&operator=(const BinaryStreamRef
&Other
) = default;
175 BinaryStreamRef(BinaryStreamRef
&&Other
) = default;
176 BinaryStreamRef
&operator=(BinaryStreamRef
&&Other
) = default;
178 // Use BinaryStreamRef.slice() instead.
179 BinaryStreamRef(BinaryStreamRef
&S
, uint32_t Offset
,
180 uint32_t Length
) = delete;
182 /// Given an Offset into this StreamRef and a Size, return a reference to a
183 /// buffer owned by the stream.
185 /// \returns a success error code if the entire range of data is within the
186 /// bounds of this BinaryStreamRef's view and the implementation could read
187 /// the data, and an appropriate error code otherwise.
188 Error
readBytes(uint32_t Offset
, uint32_t Size
,
189 ArrayRef
<uint8_t> &Buffer
) const;
191 /// Given an Offset into this BinaryStreamRef, return a reference to the
192 /// largest buffer the stream could support without necessitating a copy.
194 /// \returns a success error code if implementation could read the data,
195 /// and an appropriate error code otherwise.
196 Error
readLongestContiguousChunk(uint32_t Offset
,
197 ArrayRef
<uint8_t> &Buffer
) const;
200 struct BinarySubstreamRef
{
201 uint32_t Offset
; // Offset in the parent stream
202 BinaryStreamRef StreamData
; // Stream Data
204 BinarySubstreamRef
slice(uint32_t Off
, uint32_t Size
) const {
205 BinaryStreamRef SubSub
= StreamData
.slice(Off
, Size
);
206 return {Off
+ Offset
, SubSub
};
208 BinarySubstreamRef
drop_front(uint32_t N
) const {
209 return slice(N
, size() - N
);
211 BinarySubstreamRef
keep_front(uint32_t N
) const { return slice(0, N
); }
213 std::pair
<BinarySubstreamRef
, BinarySubstreamRef
>
214 split(uint32_t Offset
) const {
215 return std::make_pair(keep_front(Offset
), drop_front(Offset
));
218 uint32_t size() const { return StreamData
.getLength(); }
219 bool empty() const { return size() == 0; }
222 class WritableBinaryStreamRef
223 : public BinaryStreamRefBase
<WritableBinaryStreamRef
,
224 WritableBinaryStream
> {
225 friend BinaryStreamRefBase
<WritableBinaryStreamRef
, WritableBinaryStream
>;
226 WritableBinaryStreamRef(std::shared_ptr
<WritableBinaryStream
> Impl
,
227 uint32_t ViewOffset
, Optional
<uint32_t> Length
)
228 : BinaryStreamRefBase(Impl
, ViewOffset
, Length
) {}
230 Error
checkOffsetForWrite(uint32_t Offset
, uint32_t DataSize
) const {
231 if (!(BorrowedImpl
->getFlags() & BSF_Append
))
232 return checkOffsetForRead(Offset
, DataSize
);
234 if (Offset
> getLength())
235 return make_error
<BinaryStreamError
>(stream_error_code::invalid_offset
);
236 return Error::success();
240 WritableBinaryStreamRef() = default;
241 WritableBinaryStreamRef(WritableBinaryStream
&Stream
);
242 WritableBinaryStreamRef(WritableBinaryStream
&Stream
, uint32_t Offset
,
243 Optional
<uint32_t> Length
);
244 explicit WritableBinaryStreamRef(MutableArrayRef
<uint8_t> Data
,
245 llvm::support::endianness Endian
);
246 WritableBinaryStreamRef(const WritableBinaryStreamRef
&Other
) = default;
247 WritableBinaryStreamRef
&
248 operator=(const WritableBinaryStreamRef
&Other
) = default;
250 WritableBinaryStreamRef(WritableBinaryStreamRef
&&Other
) = default;
251 WritableBinaryStreamRef
&operator=(WritableBinaryStreamRef
&&Other
) = default;
253 // Use WritableBinaryStreamRef.slice() instead.
254 WritableBinaryStreamRef(WritableBinaryStreamRef
&S
, uint32_t Offset
,
255 uint32_t Length
) = delete;
257 /// Given an Offset into this WritableBinaryStreamRef and some input data,
258 /// writes the data to the underlying stream.
260 /// \returns a success error code if the data could fit within the underlying
261 /// stream at the specified location and the implementation could write the
262 /// data, and an appropriate error code otherwise.
263 Error
writeBytes(uint32_t Offset
, ArrayRef
<uint8_t> Data
) const;
265 /// Conver this WritableBinaryStreamRef to a read-only BinaryStreamRef.
266 operator BinaryStreamRef() const;
268 /// For buffered streams, commits changes to the backing store.
272 } // end namespace llvm
274 #endif // LLVM_SUPPORT_BINARYSTREAMREF_H