[InstCombine] Signed saturation patterns
[llvm-core.git] / include / llvm / Support / BinaryByteStream.h
blob7acce9a038885762fb3fecac194184ce17247bcc
1 //===- BinaryByteStream.h ---------------------------------------*- 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 // A BinaryStream which stores data in a single continguous memory buffer.
8 //===----------------------------------------------------------------------===//
10 #ifndef LLVM_SUPPORT_BINARYBYTESTREAM_H
11 #define LLVM_SUPPORT_BINARYBYTESTREAM_H
13 #include "llvm/ADT/ArrayRef.h"
14 #include "llvm/ADT/StringRef.h"
15 #include "llvm/Support/BinaryStream.h"
16 #include "llvm/Support/BinaryStreamError.h"
17 #include "llvm/Support/Error.h"
18 #include "llvm/Support/FileOutputBuffer.h"
19 #include "llvm/Support/MemoryBuffer.h"
20 #include <algorithm>
21 #include <cstdint>
22 #include <cstring>
23 #include <memory>
25 namespace llvm {
27 /// An implementation of BinaryStream which holds its entire data set
28 /// in a single contiguous buffer. BinaryByteStream guarantees that no read
29 /// operation will ever incur a copy. Note that BinaryByteStream does not
30 /// own the underlying buffer.
31 class BinaryByteStream : public BinaryStream {
32 public:
33 BinaryByteStream() = default;
34 BinaryByteStream(ArrayRef<uint8_t> Data, llvm::support::endianness Endian)
35 : Endian(Endian), Data(Data) {}
36 BinaryByteStream(StringRef Data, llvm::support::endianness Endian)
37 : Endian(Endian), Data(Data.bytes_begin(), Data.bytes_end()) {}
39 llvm::support::endianness getEndian() const override { return Endian; }
41 Error readBytes(uint32_t Offset, uint32_t Size,
42 ArrayRef<uint8_t> &Buffer) override {
43 if (auto EC = checkOffsetForRead(Offset, Size))
44 return EC;
45 Buffer = Data.slice(Offset, Size);
46 return Error::success();
49 Error readLongestContiguousChunk(uint32_t Offset,
50 ArrayRef<uint8_t> &Buffer) override {
51 if (auto EC = checkOffsetForRead(Offset, 1))
52 return EC;
53 Buffer = Data.slice(Offset);
54 return Error::success();
57 uint32_t getLength() override { return Data.size(); }
59 ArrayRef<uint8_t> data() const { return Data; }
61 StringRef str() const {
62 const char *CharData = reinterpret_cast<const char *>(Data.data());
63 return StringRef(CharData, Data.size());
66 protected:
67 llvm::support::endianness Endian;
68 ArrayRef<uint8_t> Data;
71 /// An implementation of BinaryStream whose data is backed by an llvm
72 /// MemoryBuffer object. MemoryBufferByteStream owns the MemoryBuffer in
73 /// question. As with BinaryByteStream, reading from a MemoryBufferByteStream
74 /// will never cause a copy.
75 class MemoryBufferByteStream : public BinaryByteStream {
76 public:
77 MemoryBufferByteStream(std::unique_ptr<MemoryBuffer> Buffer,
78 llvm::support::endianness Endian)
79 : BinaryByteStream(Buffer->getBuffer(), Endian),
80 MemBuffer(std::move(Buffer)) {}
82 std::unique_ptr<MemoryBuffer> MemBuffer;
85 /// An implementation of BinaryStream which holds its entire data set
86 /// in a single contiguous buffer. As with BinaryByteStream, the mutable
87 /// version also guarantees that no read operation will ever incur a copy,
88 /// and similarly it does not own the underlying buffer.
89 class MutableBinaryByteStream : public WritableBinaryStream {
90 public:
91 MutableBinaryByteStream() = default;
92 MutableBinaryByteStream(MutableArrayRef<uint8_t> Data,
93 llvm::support::endianness Endian)
94 : Data(Data), ImmutableStream(Data, Endian) {}
96 llvm::support::endianness getEndian() const override {
97 return ImmutableStream.getEndian();
100 Error readBytes(uint32_t Offset, uint32_t Size,
101 ArrayRef<uint8_t> &Buffer) override {
102 return ImmutableStream.readBytes(Offset, Size, Buffer);
105 Error readLongestContiguousChunk(uint32_t Offset,
106 ArrayRef<uint8_t> &Buffer) override {
107 return ImmutableStream.readLongestContiguousChunk(Offset, Buffer);
110 uint32_t getLength() override { return ImmutableStream.getLength(); }
112 Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Buffer) override {
113 if (Buffer.empty())
114 return Error::success();
116 if (auto EC = checkOffsetForWrite(Offset, Buffer.size()))
117 return EC;
119 uint8_t *DataPtr = const_cast<uint8_t *>(Data.data());
120 ::memcpy(DataPtr + Offset, Buffer.data(), Buffer.size());
121 return Error::success();
124 Error commit() override { return Error::success(); }
126 MutableArrayRef<uint8_t> data() const { return Data; }
128 private:
129 MutableArrayRef<uint8_t> Data;
130 BinaryByteStream ImmutableStream;
133 /// An implementation of WritableBinaryStream which can write at its end
134 /// causing the underlying data to grow. This class owns the underlying data.
135 class AppendingBinaryByteStream : public WritableBinaryStream {
136 std::vector<uint8_t> Data;
137 llvm::support::endianness Endian = llvm::support::little;
139 public:
140 AppendingBinaryByteStream() = default;
141 AppendingBinaryByteStream(llvm::support::endianness Endian)
142 : Endian(Endian) {}
144 void clear() { Data.clear(); }
146 llvm::support::endianness getEndian() const override { return Endian; }
148 Error readBytes(uint32_t Offset, uint32_t Size,
149 ArrayRef<uint8_t> &Buffer) override {
150 if (auto EC = checkOffsetForWrite(Offset, Buffer.size()))
151 return EC;
153 Buffer = makeArrayRef(Data).slice(Offset, Size);
154 return Error::success();
157 void insert(uint32_t Offset, ArrayRef<uint8_t> Bytes) {
158 Data.insert(Data.begin() + Offset, Bytes.begin(), Bytes.end());
161 Error readLongestContiguousChunk(uint32_t Offset,
162 ArrayRef<uint8_t> &Buffer) override {
163 if (auto EC = checkOffsetForWrite(Offset, 1))
164 return EC;
166 Buffer = makeArrayRef(Data).slice(Offset);
167 return Error::success();
170 uint32_t getLength() override { return Data.size(); }
172 Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Buffer) override {
173 if (Buffer.empty())
174 return Error::success();
176 // This is well-defined for any case except where offset is strictly
177 // greater than the current length. If offset is equal to the current
178 // length, we can still grow. If offset is beyond the current length, we
179 // would have to decide how to deal with the intermediate uninitialized
180 // bytes. So we punt on that case for simplicity and just say it's an
181 // error.
182 if (Offset > getLength())
183 return make_error<BinaryStreamError>(stream_error_code::invalid_offset);
185 uint32_t RequiredSize = Offset + Buffer.size();
186 if (RequiredSize > Data.size())
187 Data.resize(RequiredSize);
189 ::memcpy(Data.data() + Offset, Buffer.data(), Buffer.size());
190 return Error::success();
193 Error commit() override { return Error::success(); }
195 /// Return the properties of this stream.
196 virtual BinaryStreamFlags getFlags() const override {
197 return BSF_Write | BSF_Append;
200 MutableArrayRef<uint8_t> data() { return Data; }
203 /// An implementation of WritableBinaryStream backed by an llvm
204 /// FileOutputBuffer.
205 class FileBufferByteStream : public WritableBinaryStream {
206 private:
207 class StreamImpl : public MutableBinaryByteStream {
208 public:
209 StreamImpl(std::unique_ptr<FileOutputBuffer> Buffer,
210 llvm::support::endianness Endian)
211 : MutableBinaryByteStream(
212 MutableArrayRef<uint8_t>(Buffer->getBufferStart(),
213 Buffer->getBufferEnd()),
214 Endian),
215 FileBuffer(std::move(Buffer)) {}
217 Error commit() override {
218 if (FileBuffer->commit())
219 return make_error<BinaryStreamError>(
220 stream_error_code::filesystem_error);
221 return Error::success();
224 /// Returns a pointer to the start of the buffer.
225 uint8_t *getBufferStart() const { return FileBuffer->getBufferStart(); }
227 /// Returns a pointer to the end of the buffer.
228 uint8_t *getBufferEnd() const { return FileBuffer->getBufferEnd(); }
230 private:
231 std::unique_ptr<FileOutputBuffer> FileBuffer;
234 public:
235 FileBufferByteStream(std::unique_ptr<FileOutputBuffer> Buffer,
236 llvm::support::endianness Endian)
237 : Impl(std::move(Buffer), Endian) {}
239 llvm::support::endianness getEndian() const override {
240 return Impl.getEndian();
243 Error readBytes(uint32_t Offset, uint32_t Size,
244 ArrayRef<uint8_t> &Buffer) override {
245 return Impl.readBytes(Offset, Size, Buffer);
248 Error readLongestContiguousChunk(uint32_t Offset,
249 ArrayRef<uint8_t> &Buffer) override {
250 return Impl.readLongestContiguousChunk(Offset, Buffer);
253 uint32_t getLength() override { return Impl.getLength(); }
255 Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) override {
256 return Impl.writeBytes(Offset, Data);
259 Error commit() override { return Impl.commit(); }
261 /// Returns a pointer to the start of the buffer.
262 uint8_t *getBufferStart() const { return Impl.getBufferStart(); }
264 /// Returns a pointer to the end of the buffer.
265 uint8_t *getBufferEnd() const { return Impl.getBufferEnd(); }
267 private:
268 StreamImpl Impl;
271 } // end namespace llvm
273 #endif // LLVM_SUPPORT_BYTESTREAM_H