1 //===- BinaryItemStream.h ---------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #ifndef LLVM_SUPPORT_BINARYITEMSTREAM_H 11 #define LLVM_SUPPORT_BINARYITEMSTREAM_H 12 13 #include "llvm/ADT/ArrayRef.h" 14 #include "llvm/Support/BinaryStream.h" 15 #include "llvm/Support/BinaryStreamError.h" 16 #include "llvm/Support/Error.h" 17 #include <cstddef> 18 #include <cstdint> 19 20 namespace llvm { 21 22 template <typename T> struct BinaryItemTraits { 23 static size_t length(const T &Item) = delete; 24 static ArrayRef<uint8_t> bytes(const T &Item) = delete; 25 }; 26 27 /// BinaryItemStream represents a sequence of objects stored in some kind of 28 /// external container but for which it is useful to view as a stream of 29 /// contiguous bytes. An example of this might be if you have a collection of 30 /// records and you serialize each one into a buffer, and store these serialized 31 /// records in a container. The pointers themselves are not laid out 32 /// contiguously in memory, but we may wish to read from or write to these 33 /// records as if they were. 34 template <typename T, typename Traits = BinaryItemTraits<T>> 35 class BinaryItemStream : public BinaryStream { 36 public: 37 explicit BinaryItemStream(llvm::support::endianness Endian) 38 : Endian(Endian) {} 39 40 llvm::support::endianness getEndian() const override { return Endian; } 41 42 Error readBytes(uint32_t Offset, uint32_t Size, 43 ArrayRef<uint8_t> &Buffer) override { 44 auto ExpectedIndex = translateOffsetIndex(Offset); 45 if (!ExpectedIndex) 46 return ExpectedIndex.takeError(); 47 const auto &Item = Items[*ExpectedIndex]; 48 if (auto EC = checkOffset(Offset, Size)) 49 return EC; 50 if (Size > Traits::length(Item)) 51 return make_error<BinaryStreamError>(stream_error_code::stream_too_short); 52 Buffer = Traits::bytes(Item).take_front(Size); 53 return Error::success(); 54 } 55 56 Error readLongestContiguousChunk(uint32_t Offset, 57 ArrayRef<uint8_t> &Buffer) override { 58 auto ExpectedIndex = translateOffsetIndex(Offset); 59 if (!ExpectedIndex) 60 return ExpectedIndex.takeError(); 61 Buffer = Traits::bytes(Items[*ExpectedIndex]); 62 return Error::success(); 63 } 64 65 void setItems(ArrayRef<T> ItemArray) { Items = ItemArray; } 66 67 uint32_t getLength() override { 68 uint32_t Size = 0; 69 for (const auto &Item : Items) 70 Size += Traits::length(Item); 71 return Size; 72 } 73 74 private: 75 Expected<uint32_t> translateOffsetIndex(uint32_t Offset) const { 76 uint32_t CurrentOffset = 0; 77 uint32_t CurrentIndex = 0; 78 for (const auto &Item : Items) { 79 if (CurrentOffset >= Offset) 80 break; 81 CurrentOffset += Traits::length(Item); 82 ++CurrentIndex; 83 } 84 if (CurrentOffset != Offset) 85 return make_error<BinaryStreamError>(stream_error_code::stream_too_short); 86 return CurrentIndex; 87 } 88 89 llvm::support::endianness Endian; 90 ArrayRef<T> Items; 91 }; 92 93 } // end namespace llvm 94 95 #endif // LLVM_SUPPORT_BINARYITEMSTREAM_H 96