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 20namespace llvm { 21 22template <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. 34template <typename T, typename Traits = BinaryItemTraits<T>> 35class BinaryItemStream : public BinaryStream { 36public: 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 74private: 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