Line data Source code
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/ADT/Optional.h"
15 : #include "llvm/Support/BinaryStream.h"
16 : #include "llvm/Support/BinaryStreamError.h"
17 : #include "llvm/Support/Error.h"
18 : #include <algorithm>
19 : #include <cstdint>
20 : #include <memory>
21 :
22 : namespace llvm {
23 :
24 : /// Common stuff for mutable and immutable StreamRefs.
25 42801 : template <class RefType, class StreamType> class BinaryStreamRefBase {
26 : protected:
27 14158 : BinaryStreamRefBase() = default;
28 26062 : explicit BinaryStreamRefBase(StreamType &BorrowedImpl)
29 26062 : : BorrowedImpl(&BorrowedImpl), ViewOffset(0) {
30 26062 : if (!(BorrowedImpl.getFlags() & BSF_Append))
31 25784 : Length = BorrowedImpl.getLength();
32 26062 : }
33 4517 :
34 4517 : BinaryStreamRefBase(std::shared_ptr<StreamType> SharedImpl, uint32_t Offset,
35 4517 : Optional<uint32_t> Length)
36 4242 : : SharedImpl(SharedImpl), BorrowedImpl(SharedImpl.get()),
37 4517 : ViewOffset(Offset), Length(Length) {}
38 21545 : BinaryStreamRefBase(StreamType &BorrowedImpl, uint32_t Offset,
39 21545 : Optional<uint32_t> Length)
40 21545 : : BorrowedImpl(&BorrowedImpl), ViewOffset(Offset), Length(Length) {}
41 180631 : BinaryStreamRefBase(const BinaryStreamRefBase &Other) = default;
42 21545 : BinaryStreamRefBase &operator=(const BinaryStreamRefBase &Other) = default;
43 :
44 5488 : BinaryStreamRefBase &operator=(BinaryStreamRefBase &&Other) = default;
45 45754 : BinaryStreamRefBase(BinaryStreamRefBase &&Other) = default;
46 :
47 5488 : public:
48 1782 : llvm::support::endianness getEndian() const {
49 140149 : return BorrowedImpl->getEndian();
50 1782 : }
51 0 :
52 0 : uint32_t getLength() const {
53 91834 : if (Length.hasValue())
54 101769 : return *Length;
55 0 :
56 318 : return BorrowedImpl ? (BorrowedImpl->getLength() - ViewOffset) : 0;
57 : }
58 :
59 13784 : /// Return a new BinaryStreamRef with the first \p N elements removed. If
60 13774 : /// this BinaryStreamRef is length-tracking, then the resulting one will be
61 : /// too.
62 29398 : RefType drop_front(uint32_t N) const {
63 558664 : if (!BorrowedImpl)
64 959537 : return RefType();
65 :
66 65629 : N = std::min(N, getLength());
67 : RefType Result(static_cast<const RefType &>(*this));
68 30496 : if (N == 0)
69 1126 : return Result;
70 0 :
71 22494 : Result.ViewOffset += N;
72 23620 : if (Result.Length.hasValue())
73 22494 : *Result.Length -= N;
74 1126 : return Result;
75 : }
76 641 :
77 1761 : /// Return a new BinaryStreamRef with the last \p N elements removed. If
78 1120 : /// this BinaryStreamRef is length-tracking and \p N is greater than 0, then
79 1119 : /// this BinaryStreamRef will no longer length-track.
80 9371 : RefType drop_back(uint32_t N) const {
81 8730 : if (!BorrowedImpl)
82 641 : return RefType();
83 :
84 : RefType Result(static_cast<const RefType &>(*this));
85 8730 : N = std::min(N, getLength());
86 5 :
87 8735 : if (N == 0)
88 0 : return Result;
89 :
90 1760 : // Since we're dropping non-zero bytes from the end, stop length-tracking
91 1765 : // by setting the length of the resulting StreamRef to an explicit value.
92 4040 : if (!Result.Length.hasValue())
93 5 : Result.Length = getLength();
94 1760 :
95 4040 : *Result.Length -= N;
96 1760 : return Result;
97 : }
98 4 :
99 988 : /// Return a new BinaryStreamRef with only the first \p N elements remaining.
100 9718 : RefType keep_front(uint32_t N) const {
101 992 : assert(N <= getLength());
102 8730 : return drop_back(getLength() - N);
103 : }
104 :
105 : /// Return a new BinaryStreamRef with only the last \p N elements remaining.
106 1 : RefType keep_back(uint32_t N) const {
107 : assert(N <= getLength());
108 1522 : return drop_front(getLength() - N);
109 1521 : }
110 0 :
111 : /// Return a new BinaryStreamRef with the first and last \p N elements
112 1 : /// removed.
113 1521 : RefType drop_symmetric(uint32_t N) const {
114 1 : return drop_front(N).drop_back(N);
115 1521 : }
116 :
117 : /// Return a new BinaryStreamRef with the first \p Offset elements removed,
118 : /// and retaining exactly \p Len elements.
119 8124 : RefType slice(uint32_t Offset, uint32_t Len) const {
120 8892 : return drop_front(Offset).keep_front(Len);
121 : }
122 :
123 768 : bool valid() const { return BorrowedImpl != nullptr; }
124 :
125 : bool operator==(const RefType &Other) const {
126 1584 : if (BorrowedImpl != Other.BorrowedImpl)
127 641 : return false;
128 943 : if (ViewOffset != Other.ViewOffset)
129 : return false;
130 943 : if (Length != Other.Length)
131 641 : return false;
132 12 : return true;
133 641 : }
134 12 :
135 : protected:
136 12 : Error checkOffsetForRead(uint32_t Offset, uint32_t DataSize) const {
137 : if (Offset > getLength())
138 0 : return make_error<BinaryStreamError>(stream_error_code::invalid_offset);
139 : if (getLength() < DataSize + Offset)
140 : return make_error<BinaryStreamError>(stream_error_code::stream_too_short);
141 0 : return Error::success();
142 : }
143 :
144 880 : std::shared_ptr<StreamType> SharedImpl;
145 880 : StreamType *BorrowedImpl = nullptr;
146 466502 : uint32_t ViewOffset = 0;
147 466502 : Optional<uint32_t> Length;
148 6 : };
149 467376 :
150 269 : /// BinaryStreamRef is to BinaryStream what ArrayRef is to an Array. It
151 880 : /// provides copy-semantics and read only access to a "window" of the underlying
152 : /// BinaryStream. Note that BinaryStreamRef is *not* a BinaryStream. That is to
153 404886 : /// say, it does not inherit and override the methods of BinaryStream. In
154 404886 : /// general, you should not pass around pointers or references to BinaryStreams
155 6 : /// and use inheritance to achieve polymorphism. Instead, you should pass
156 405648 : /// around BinaryStreamRefs by value and achieve polymorphism that way.
157 32444 : class BinaryStreamRef
158 : : public BinaryStreamRefBase<BinaryStreamRef, BinaryStream> {
159 768 : friend BinaryStreamRefBase<BinaryStreamRef, BinaryStream>;
160 61616 : friend class WritableBinaryStreamRef;
161 61616 : BinaryStreamRef(std::shared_ptr<BinaryStream> Impl, uint32_t ViewOffset,
162 0 : Optional<uint32_t> Length)
163 62771 : : BinaryStreamRefBase(Impl, ViewOffset, Length) {}
164 1533 :
165 : public:
166 1521 : BinaryStreamRef() = default;
167 : BinaryStreamRef(BinaryStream &Stream);
168 641 : BinaryStreamRef(BinaryStream &Stream, uint32_t Offset,
169 : Optional<uint32_t> Length);
170 641 : explicit BinaryStreamRef(ArrayRef<uint8_t> Data,
171 : llvm::support::endianness Endian);
172 880 : explicit BinaryStreamRef(StringRef Data, llvm::support::endianness Endian);
173 :
174 880 : BinaryStreamRef(const BinaryStreamRef &Other) = default;
175 : BinaryStreamRef &operator=(const BinaryStreamRef &Other) = default;
176 : BinaryStreamRef(BinaryStreamRef &&Other) = default;
177 : BinaryStreamRef &operator=(BinaryStreamRef &&Other) = default;
178 :
179 : // Use BinaryStreamRef.slice() instead.
180 : BinaryStreamRef(BinaryStreamRef &S, uint32_t Offset,
181 : uint32_t Length) = delete;
182 :
183 : /// Given an Offset into this StreamRef and a Size, return a reference to a
184 : /// buffer owned by the stream.
185 : ///
186 : /// \returns a success error code if the entire range of data is within the
187 : /// bounds of this BinaryStreamRef's view and the implementation could read
188 : /// the data, and an appropriate error code otherwise.
189 : Error readBytes(uint32_t Offset, uint32_t Size,
190 : ArrayRef<uint8_t> &Buffer) const;
191 641 :
192 641 : /// Given an Offset into this BinaryStreamRef, return a reference to the
193 : /// largest buffer the stream could support without necessitating a copy.
194 : ///
195 : /// \returns a success error code if implementation could read the data,
196 : /// and an appropriate error code otherwise.
197 : Error readLongestContiguousChunk(uint32_t Offset,
198 : ArrayRef<uint8_t> &Buffer) const;
199 : };
200 :
201 3478 : struct BinarySubstreamRef {
202 : uint32_t Offset; // Offset in the parent stream
203 : BinaryStreamRef StreamData; // Stream Data
204 :
205 6 : BinarySubstreamRef slice(uint32_t Off, uint32_t Size) const {
206 6 : BinaryStreamRef SubSub = StreamData.slice(Off, Size);
207 6 : return {Off + Offset, SubSub};
208 : }
209 2 : BinarySubstreamRef drop_front(uint32_t N) const {
210 2 : return slice(N, size() - N);
211 : }
212 2 : BinarySubstreamRef keep_front(uint32_t N) const { return slice(0, N); }
213 :
214 : std::pair<BinarySubstreamRef, BinarySubstreamRef>
215 2 : split(uint32_t Offset) const {
216 4 : return std::make_pair(keep_front(Offset), drop_front(Offset));
217 : }
218 :
219 : uint32_t size() const { return StreamData.getLength(); }
220 : bool empty() const { return size() == 0; }
221 : };
222 :
223 1315 : class WritableBinaryStreamRef
224 : : public BinaryStreamRefBase<WritableBinaryStreamRef,
225 : WritableBinaryStream> {
226 : friend BinaryStreamRefBase<WritableBinaryStreamRef, WritableBinaryStream>;
227 : WritableBinaryStreamRef(std::shared_ptr<WritableBinaryStream> Impl,
228 : uint32_t ViewOffset, Optional<uint32_t> Length)
229 : : BinaryStreamRefBase(Impl, ViewOffset, Length) {}
230 :
231 : Error checkOffsetForWrite(uint32_t Offset, uint32_t DataSize) const {
232 : if (!(BorrowedImpl->getFlags() & BSF_Append))
233 : return checkOffsetForRead(Offset, DataSize);
234 :
235 : if (Offset > getLength())
236 : return make_error<BinaryStreamError>(stream_error_code::invalid_offset);
237 : return Error::success();
238 : }
239 :
240 : public:
241 : WritableBinaryStreamRef() = default;
242 : WritableBinaryStreamRef(WritableBinaryStream &Stream);
243 : WritableBinaryStreamRef(WritableBinaryStream &Stream, uint32_t Offset,
244 : Optional<uint32_t> Length);
245 : explicit WritableBinaryStreamRef(MutableArrayRef<uint8_t> Data,
246 : llvm::support::endianness Endian);
247 : WritableBinaryStreamRef(const WritableBinaryStreamRef &Other) = default;
248 : WritableBinaryStreamRef &
249 : operator=(const WritableBinaryStreamRef &Other) = default;
250 :
251 : WritableBinaryStreamRef(WritableBinaryStreamRef &&Other) = default;
252 : WritableBinaryStreamRef &operator=(WritableBinaryStreamRef &&Other) = default;
253 :
254 : // Use WritableBinaryStreamRef.slice() instead.
255 97846 : WritableBinaryStreamRef(WritableBinaryStreamRef &S, uint32_t Offset,
256 97846 : uint32_t Length) = delete;
257 61616 :
258 : /// Given an Offset into this WritableBinaryStreamRef and some input data,
259 36230 : /// writes the data to the underlying stream.
260 0 : ///
261 : /// \returns a success error code if the data could fit within the underlying
262 : /// stream at the specified location and the implementation could write the
263 : /// data, and an appropriate error code otherwise.
264 : Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) const;
265 :
266 : /// Conver this WritableBinaryStreamRef to a read-only BinaryStreamRef.
267 : operator BinaryStreamRef() const;
268 :
269 : /// For buffered streams, commits changes to the backing store.
270 : Error commit();
271 : };
272 :
273 : } // end namespace llvm
274 :
275 : #endif // LLVM_SUPPORT_BINARYSTREAMREF_H
|