diff options
Diffstat (limited to 'third_party/llvm-project/include/llvm/Support/BinaryByteStream.h')
-rw-r--r-- | third_party/llvm-project/include/llvm/Support/BinaryByteStream.h | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/third_party/llvm-project/include/llvm/Support/BinaryByteStream.h b/third_party/llvm-project/include/llvm/Support/BinaryByteStream.h new file mode 100644 index 000000000..7acce9a03 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Support/BinaryByteStream.h @@ -0,0 +1,273 @@ +//===- BinaryByteStream.h ---------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +//===----------------------------------------------------------------------===// +// A BinaryStream which stores data in a single continguous memory buffer. +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_BINARYBYTESTREAM_H +#define LLVM_SUPPORT_BINARYBYTESTREAM_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/BinaryStream.h" +#include "llvm/Support/BinaryStreamError.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileOutputBuffer.h" +#include "llvm/Support/MemoryBuffer.h" +#include <algorithm> +#include <cstdint> +#include <cstring> +#include <memory> + +namespace llvm { + +/// An implementation of BinaryStream which holds its entire data set +/// in a single contiguous buffer. BinaryByteStream guarantees that no read +/// operation will ever incur a copy. Note that BinaryByteStream does not +/// own the underlying buffer. +class BinaryByteStream : public BinaryStream { +public: + BinaryByteStream() = default; + BinaryByteStream(ArrayRef<uint8_t> Data, llvm::support::endianness Endian) + : Endian(Endian), Data(Data) {} + BinaryByteStream(StringRef Data, llvm::support::endianness Endian) + : Endian(Endian), Data(Data.bytes_begin(), Data.bytes_end()) {} + + llvm::support::endianness getEndian() const override { return Endian; } + + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer) override { + if (auto EC = checkOffsetForRead(Offset, Size)) + return EC; + Buffer = Data.slice(Offset, Size); + return Error::success(); + } + + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef<uint8_t> &Buffer) override { + if (auto EC = checkOffsetForRead(Offset, 1)) + return EC; + Buffer = Data.slice(Offset); + return Error::success(); + } + + uint32_t getLength() override { return Data.size(); } + + ArrayRef<uint8_t> data() const { return Data; } + + StringRef str() const { + const char *CharData = reinterpret_cast<const char *>(Data.data()); + return StringRef(CharData, Data.size()); + } + +protected: + llvm::support::endianness Endian; + ArrayRef<uint8_t> Data; +}; + +/// An implementation of BinaryStream whose data is backed by an llvm +/// MemoryBuffer object. MemoryBufferByteStream owns the MemoryBuffer in +/// question. As with BinaryByteStream, reading from a MemoryBufferByteStream +/// will never cause a copy. +class MemoryBufferByteStream : public BinaryByteStream { +public: + MemoryBufferByteStream(std::unique_ptr<MemoryBuffer> Buffer, + llvm::support::endianness Endian) + : BinaryByteStream(Buffer->getBuffer(), Endian), + MemBuffer(std::move(Buffer)) {} + + std::unique_ptr<MemoryBuffer> MemBuffer; +}; + +/// An implementation of BinaryStream which holds its entire data set +/// in a single contiguous buffer. As with BinaryByteStream, the mutable +/// version also guarantees that no read operation will ever incur a copy, +/// and similarly it does not own the underlying buffer. +class MutableBinaryByteStream : public WritableBinaryStream { +public: + MutableBinaryByteStream() = default; + MutableBinaryByteStream(MutableArrayRef<uint8_t> Data, + llvm::support::endianness Endian) + : Data(Data), ImmutableStream(Data, Endian) {} + + llvm::support::endianness getEndian() const override { + return ImmutableStream.getEndian(); + } + + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer) override { + return ImmutableStream.readBytes(Offset, Size, Buffer); + } + + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef<uint8_t> &Buffer) override { + return ImmutableStream.readLongestContiguousChunk(Offset, Buffer); + } + + uint32_t getLength() override { return ImmutableStream.getLength(); } + + Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Buffer) override { + if (Buffer.empty()) + return Error::success(); + + if (auto EC = checkOffsetForWrite(Offset, Buffer.size())) + return EC; + + uint8_t *DataPtr = const_cast<uint8_t *>(Data.data()); + ::memcpy(DataPtr + Offset, Buffer.data(), Buffer.size()); + return Error::success(); + } + + Error commit() override { return Error::success(); } + + MutableArrayRef<uint8_t> data() const { return Data; } + +private: + MutableArrayRef<uint8_t> Data; + BinaryByteStream ImmutableStream; +}; + +/// An implementation of WritableBinaryStream which can write at its end +/// causing the underlying data to grow. This class owns the underlying data. +class AppendingBinaryByteStream : public WritableBinaryStream { + std::vector<uint8_t> Data; + llvm::support::endianness Endian = llvm::support::little; + +public: + AppendingBinaryByteStream() = default; + AppendingBinaryByteStream(llvm::support::endianness Endian) + : Endian(Endian) {} + + void clear() { Data.clear(); } + + llvm::support::endianness getEndian() const override { return Endian; } + + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer) override { + if (auto EC = checkOffsetForWrite(Offset, Buffer.size())) + return EC; + + Buffer = makeArrayRef(Data).slice(Offset, Size); + return Error::success(); + } + + void insert(uint32_t Offset, ArrayRef<uint8_t> Bytes) { + Data.insert(Data.begin() + Offset, Bytes.begin(), Bytes.end()); + } + + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef<uint8_t> &Buffer) override { + if (auto EC = checkOffsetForWrite(Offset, 1)) + return EC; + + Buffer = makeArrayRef(Data).slice(Offset); + return Error::success(); + } + + uint32_t getLength() override { return Data.size(); } + + Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Buffer) override { + if (Buffer.empty()) + return Error::success(); + + // This is well-defined for any case except where offset is strictly + // greater than the current length. If offset is equal to the current + // length, we can still grow. If offset is beyond the current length, we + // would have to decide how to deal with the intermediate uninitialized + // bytes. So we punt on that case for simplicity and just say it's an + // error. + if (Offset > getLength()) + return make_error<BinaryStreamError>(stream_error_code::invalid_offset); + + uint32_t RequiredSize = Offset + Buffer.size(); + if (RequiredSize > Data.size()) + Data.resize(RequiredSize); + + ::memcpy(Data.data() + Offset, Buffer.data(), Buffer.size()); + return Error::success(); + } + + Error commit() override { return Error::success(); } + + /// Return the properties of this stream. + virtual BinaryStreamFlags getFlags() const override { + return BSF_Write | BSF_Append; + } + + MutableArrayRef<uint8_t> data() { return Data; } +}; + +/// An implementation of WritableBinaryStream backed by an llvm +/// FileOutputBuffer. +class FileBufferByteStream : public WritableBinaryStream { +private: + class StreamImpl : public MutableBinaryByteStream { + public: + StreamImpl(std::unique_ptr<FileOutputBuffer> Buffer, + llvm::support::endianness Endian) + : MutableBinaryByteStream( + MutableArrayRef<uint8_t>(Buffer->getBufferStart(), + Buffer->getBufferEnd()), + Endian), + FileBuffer(std::move(Buffer)) {} + + Error commit() override { + if (FileBuffer->commit()) + return make_error<BinaryStreamError>( + stream_error_code::filesystem_error); + return Error::success(); + } + + /// Returns a pointer to the start of the buffer. + uint8_t *getBufferStart() const { return FileBuffer->getBufferStart(); } + + /// Returns a pointer to the end of the buffer. + uint8_t *getBufferEnd() const { return FileBuffer->getBufferEnd(); } + + private: + std::unique_ptr<FileOutputBuffer> FileBuffer; + }; + +public: + FileBufferByteStream(std::unique_ptr<FileOutputBuffer> Buffer, + llvm::support::endianness Endian) + : Impl(std::move(Buffer), Endian) {} + + llvm::support::endianness getEndian() const override { + return Impl.getEndian(); + } + + Error readBytes(uint32_t Offset, uint32_t Size, + ArrayRef<uint8_t> &Buffer) override { + return Impl.readBytes(Offset, Size, Buffer); + } + + Error readLongestContiguousChunk(uint32_t Offset, + ArrayRef<uint8_t> &Buffer) override { + return Impl.readLongestContiguousChunk(Offset, Buffer); + } + + uint32_t getLength() override { return Impl.getLength(); } + + Error writeBytes(uint32_t Offset, ArrayRef<uint8_t> Data) override { + return Impl.writeBytes(Offset, Data); + } + + Error commit() override { return Impl.commit(); } + + /// Returns a pointer to the start of the buffer. + uint8_t *getBufferStart() const { return Impl.getBufferStart(); } + + /// Returns a pointer to the end of the buffer. + uint8_t *getBufferEnd() const { return Impl.getBufferEnd(); } + +private: + StreamImpl Impl; +}; + +} // end namespace llvm + +#endif // LLVM_SUPPORT_BYTESTREAM_H |