BinaryByteStream.h 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- BinaryByteStream.h ---------------------------------------*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //===----------------------------------------------------------------------===//
  12. // A BinaryStream which stores data in a single continguous memory buffer.
  13. //===----------------------------------------------------------------------===//
  14. #ifndef LLVM_SUPPORT_BINARYBYTESTREAM_H
  15. #define LLVM_SUPPORT_BINARYBYTESTREAM_H
  16. #include "llvm/ADT/ArrayRef.h"
  17. #include "llvm/ADT/StringRef.h"
  18. #include "llvm/Support/BinaryStream.h"
  19. #include "llvm/Support/BinaryStreamError.h"
  20. #include "llvm/Support/Error.h"
  21. #include "llvm/Support/FileOutputBuffer.h"
  22. #include "llvm/Support/MemoryBuffer.h"
  23. #include <cstdint>
  24. #include <cstring>
  25. #include <memory>
  26. 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()) {}
  38. llvm::support::endianness getEndian() const override { return Endian; }
  39. Error readBytes(uint64_t Offset, uint64_t Size,
  40. ArrayRef<uint8_t> &Buffer) override {
  41. if (auto EC = checkOffsetForRead(Offset, Size))
  42. return EC;
  43. Buffer = Data.slice(Offset, Size);
  44. return Error::success();
  45. }
  46. Error readLongestContiguousChunk(uint64_t Offset,
  47. ArrayRef<uint8_t> &Buffer) override {
  48. if (auto EC = checkOffsetForRead(Offset, 1))
  49. return EC;
  50. Buffer = Data.slice(Offset);
  51. return Error::success();
  52. }
  53. uint64_t getLength() override { return Data.size(); }
  54. ArrayRef<uint8_t> data() const { return Data; }
  55. StringRef str() const {
  56. const char *CharData = reinterpret_cast<const char *>(Data.data());
  57. return StringRef(CharData, Data.size());
  58. }
  59. protected:
  60. llvm::support::endianness Endian;
  61. ArrayRef<uint8_t> Data;
  62. };
  63. /// An implementation of BinaryStream whose data is backed by an llvm
  64. /// MemoryBuffer object. MemoryBufferByteStream owns the MemoryBuffer in
  65. /// question. As with BinaryByteStream, reading from a MemoryBufferByteStream
  66. /// will never cause a copy.
  67. class MemoryBufferByteStream : public BinaryByteStream {
  68. public:
  69. MemoryBufferByteStream(std::unique_ptr<MemoryBuffer> Buffer,
  70. llvm::support::endianness Endian)
  71. : BinaryByteStream(Buffer->getBuffer(), Endian),
  72. MemBuffer(std::move(Buffer)) {}
  73. std::unique_ptr<MemoryBuffer> MemBuffer;
  74. };
  75. /// An implementation of BinaryStream which holds its entire data set
  76. /// in a single contiguous buffer. As with BinaryByteStream, the mutable
  77. /// version also guarantees that no read operation will ever incur a copy,
  78. /// and similarly it does not own the underlying buffer.
  79. class MutableBinaryByteStream : public WritableBinaryStream {
  80. public:
  81. MutableBinaryByteStream() = default;
  82. MutableBinaryByteStream(MutableArrayRef<uint8_t> Data,
  83. llvm::support::endianness Endian)
  84. : Data(Data), ImmutableStream(Data, Endian) {}
  85. llvm::support::endianness getEndian() const override {
  86. return ImmutableStream.getEndian();
  87. }
  88. Error readBytes(uint64_t Offset, uint64_t Size,
  89. ArrayRef<uint8_t> &Buffer) override {
  90. return ImmutableStream.readBytes(Offset, Size, Buffer);
  91. }
  92. Error readLongestContiguousChunk(uint64_t Offset,
  93. ArrayRef<uint8_t> &Buffer) override {
  94. return ImmutableStream.readLongestContiguousChunk(Offset, Buffer);
  95. }
  96. uint64_t getLength() override { return ImmutableStream.getLength(); }
  97. Error writeBytes(uint64_t Offset, ArrayRef<uint8_t> Buffer) override {
  98. if (Buffer.empty())
  99. return Error::success();
  100. if (auto EC = checkOffsetForWrite(Offset, Buffer.size()))
  101. return EC;
  102. uint8_t *DataPtr = const_cast<uint8_t *>(Data.data());
  103. ::memcpy(DataPtr + Offset, Buffer.data(), Buffer.size());
  104. return Error::success();
  105. }
  106. Error commit() override { return Error::success(); }
  107. MutableArrayRef<uint8_t> data() const { return Data; }
  108. private:
  109. MutableArrayRef<uint8_t> Data;
  110. BinaryByteStream ImmutableStream;
  111. };
  112. /// An implementation of WritableBinaryStream which can write at its end
  113. /// causing the underlying data to grow. This class owns the underlying data.
  114. class AppendingBinaryByteStream : public WritableBinaryStream {
  115. std::vector<uint8_t> Data;
  116. llvm::support::endianness Endian = llvm::support::little;
  117. public:
  118. AppendingBinaryByteStream() = default;
  119. AppendingBinaryByteStream(llvm::support::endianness Endian)
  120. : Endian(Endian) {}
  121. void clear() { Data.clear(); }
  122. llvm::support::endianness getEndian() const override { return Endian; }
  123. Error readBytes(uint64_t Offset, uint64_t Size,
  124. ArrayRef<uint8_t> &Buffer) override {
  125. if (auto EC = checkOffsetForWrite(Offset, Buffer.size()))
  126. return EC;
  127. Buffer = ArrayRef(Data).slice(Offset, Size);
  128. return Error::success();
  129. }
  130. void insert(uint64_t Offset, ArrayRef<uint8_t> Bytes) {
  131. Data.insert(Data.begin() + Offset, Bytes.begin(), Bytes.end());
  132. }
  133. Error readLongestContiguousChunk(uint64_t Offset,
  134. ArrayRef<uint8_t> &Buffer) override {
  135. if (auto EC = checkOffsetForWrite(Offset, 1))
  136. return EC;
  137. Buffer = ArrayRef(Data).slice(Offset);
  138. return Error::success();
  139. }
  140. uint64_t getLength() override { return Data.size(); }
  141. Error writeBytes(uint64_t Offset, ArrayRef<uint8_t> Buffer) override {
  142. if (Buffer.empty())
  143. return Error::success();
  144. // This is well-defined for any case except where offset is strictly
  145. // greater than the current length. If offset is equal to the current
  146. // length, we can still grow. If offset is beyond the current length, we
  147. // would have to decide how to deal with the intermediate uninitialized
  148. // bytes. So we punt on that case for simplicity and just say it's an
  149. // error.
  150. if (Offset > getLength())
  151. return make_error<BinaryStreamError>(stream_error_code::invalid_offset);
  152. uint64_t RequiredSize = Offset + Buffer.size();
  153. if (RequiredSize > Data.size())
  154. Data.resize(RequiredSize);
  155. ::memcpy(Data.data() + Offset, Buffer.data(), Buffer.size());
  156. return Error::success();
  157. }
  158. Error commit() override { return Error::success(); }
  159. /// Return the properties of this stream.
  160. BinaryStreamFlags getFlags() const override { return BSF_Write | BSF_Append; }
  161. MutableArrayRef<uint8_t> data() { return Data; }
  162. };
  163. /// An implementation of WritableBinaryStream backed by an llvm
  164. /// FileOutputBuffer.
  165. class FileBufferByteStream : public WritableBinaryStream {
  166. private:
  167. class StreamImpl : public MutableBinaryByteStream {
  168. public:
  169. StreamImpl(std::unique_ptr<FileOutputBuffer> Buffer,
  170. llvm::support::endianness Endian)
  171. : MutableBinaryByteStream(
  172. MutableArrayRef<uint8_t>(Buffer->getBufferStart(),
  173. Buffer->getBufferEnd()),
  174. Endian),
  175. FileBuffer(std::move(Buffer)) {}
  176. Error commit() override {
  177. if (FileBuffer->commit())
  178. return make_error<BinaryStreamError>(
  179. stream_error_code::filesystem_error);
  180. return Error::success();
  181. }
  182. /// Returns a pointer to the start of the buffer.
  183. uint8_t *getBufferStart() const { return FileBuffer->getBufferStart(); }
  184. /// Returns a pointer to the end of the buffer.
  185. uint8_t *getBufferEnd() const { return FileBuffer->getBufferEnd(); }
  186. private:
  187. std::unique_ptr<FileOutputBuffer> FileBuffer;
  188. };
  189. public:
  190. FileBufferByteStream(std::unique_ptr<FileOutputBuffer> Buffer,
  191. llvm::support::endianness Endian)
  192. : Impl(std::move(Buffer), Endian) {}
  193. llvm::support::endianness getEndian() const override {
  194. return Impl.getEndian();
  195. }
  196. Error readBytes(uint64_t Offset, uint64_t Size,
  197. ArrayRef<uint8_t> &Buffer) override {
  198. return Impl.readBytes(Offset, Size, Buffer);
  199. }
  200. Error readLongestContiguousChunk(uint64_t Offset,
  201. ArrayRef<uint8_t> &Buffer) override {
  202. return Impl.readLongestContiguousChunk(Offset, Buffer);
  203. }
  204. uint64_t getLength() override { return Impl.getLength(); }
  205. Error writeBytes(uint64_t Offset, ArrayRef<uint8_t> Data) override {
  206. return Impl.writeBytes(Offset, Data);
  207. }
  208. Error commit() override { return Impl.commit(); }
  209. /// Returns a pointer to the start of the buffer.
  210. uint8_t *getBufferStart() const { return Impl.getBufferStart(); }
  211. /// Returns a pointer to the end of the buffer.
  212. uint8_t *getBufferEnd() const { return Impl.getBufferEnd(); }
  213. private:
  214. StreamImpl Impl;
  215. };
  216. } // end namespace llvm
  217. #endif // LLVM_SUPPORT_BINARYBYTESTREAM_H
  218. #ifdef __GNUC__
  219. #pragma GCC diagnostic pop
  220. #endif