[InstCombine] Signed saturation patterns
[llvm-complete.git] / include / llvm / Support / BinaryStreamRef.h
blob7427b8da5b43554caafc3c66fefe70be79cdb82a
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 //===----------------------------------------------------------------------===//
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"
17 #include <algorithm>
18 #include <cstdint>
19 #include <memory>
21 namespace llvm {
23 /// Common stuff for mutable and immutable StreamRefs.
24 template <class RefType, class StreamType> class BinaryStreamRefBase {
25 protected:
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;
46 public:
47 llvm::support::endianness getEndian() const {
48 return BorrowedImpl->getEndian();
51 uint32_t getLength() const {
52 if (Length.hasValue())
53 return *Length;
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
60 /// too.
61 RefType drop_front(uint32_t N) const {
62 if (!BorrowedImpl)
63 return RefType();
65 N = std::min(N, getLength());
66 RefType Result(static_cast<const RefType &>(*this));
67 if (N == 0)
68 return Result;
70 Result.ViewOffset += N;
71 if (Result.Length.hasValue())
72 *Result.Length -= N;
73 return Result;
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 {
80 if (!BorrowedImpl)
81 return RefType();
83 RefType Result(static_cast<const RefType &>(*this));
84 N = std::min(N, getLength());
86 if (N == 0)
87 return Result;
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();
94 *Result.Length -= N;
95 return Result;
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
111 /// removed.
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)
126 return false;
127 if (ViewOffset != Other.ViewOffset)
128 return false;
129 if (Length != Other.Length)
130 return false;
131 return true;
134 protected:
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) {}
164 public:
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();
239 public:
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.
269 Error commit();
272 } // end namespace llvm
274 #endif // LLVM_SUPPORT_BINARYSTREAMREF_H