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