Changeset View
Changeset View
Standalone View
Standalone View
llvm/include/llvm/Support/BinaryItemStream.h
Show All 32 Lines | |||||
template <typename T, typename Traits = BinaryItemTraits<T>> | template <typename T, typename Traits = BinaryItemTraits<T>> | ||||
class BinaryItemStream : public BinaryStream { | class BinaryItemStream : public BinaryStream { | ||||
public: | public: | ||||
explicit BinaryItemStream(llvm::support::endianness Endian) | explicit BinaryItemStream(llvm::support::endianness Endian) | ||||
: Endian(Endian) {} | : Endian(Endian) {} | ||||
llvm::support::endianness getEndian() const override { return Endian; } | llvm::support::endianness getEndian() const override { return Endian; } | ||||
Error readBytes(uint32_t Offset, uint32_t Size, | Error readBytes(uint64_t Offset, uint64_t Size, | ||||
ArrayRef<uint8_t> &Buffer) override { | ArrayRef<uint8_t> &Buffer) override { | ||||
auto ExpectedIndex = translateOffsetIndex(Offset); | auto ExpectedIndex = translateOffsetIndex(Offset); | ||||
if (!ExpectedIndex) | if (!ExpectedIndex) | ||||
return ExpectedIndex.takeError(); | return ExpectedIndex.takeError(); | ||||
const auto &Item = Items[*ExpectedIndex]; | const auto &Item = Items[*ExpectedIndex]; | ||||
if (auto EC = checkOffsetForRead(Offset, Size)) | if (auto EC = checkOffsetForRead(Offset, Size)) | ||||
return EC; | return EC; | ||||
if (Size > Traits::length(Item)) | if (Size > Traits::length(Item)) | ||||
return make_error<BinaryStreamError>(stream_error_code::stream_too_short); | return make_error<BinaryStreamError>(stream_error_code::stream_too_short); | ||||
Buffer = Traits::bytes(Item).take_front(Size); | Buffer = Traits::bytes(Item).take_front(Size); | ||||
return Error::success(); | return Error::success(); | ||||
} | } | ||||
Error readLongestContiguousChunk(uint32_t Offset, | Error readLongestContiguousChunk(uint64_t Offset, | ||||
ArrayRef<uint8_t> &Buffer) override { | ArrayRef<uint8_t> &Buffer) override { | ||||
auto ExpectedIndex = translateOffsetIndex(Offset); | auto ExpectedIndex = translateOffsetIndex(Offset); | ||||
if (!ExpectedIndex) | if (!ExpectedIndex) | ||||
return ExpectedIndex.takeError(); | return ExpectedIndex.takeError(); | ||||
Buffer = Traits::bytes(Items[*ExpectedIndex]); | Buffer = Traits::bytes(Items[*ExpectedIndex]); | ||||
return Error::success(); | return Error::success(); | ||||
} | } | ||||
void setItems(ArrayRef<T> ItemArray) { | void setItems(ArrayRef<T> ItemArray) { | ||||
Items = ItemArray; | Items = ItemArray; | ||||
computeItemOffsets(); | computeItemOffsets(); | ||||
} | } | ||||
uint32_t getLength() override { | uint64_t getLength() override { | ||||
return ItemEndOffsets.empty() ? 0 : ItemEndOffsets.back(); | return ItemEndOffsets.empty() ? 0 : ItemEndOffsets.back(); | ||||
} | } | ||||
private: | private: | ||||
void computeItemOffsets() { | void computeItemOffsets() { | ||||
ItemEndOffsets.clear(); | ItemEndOffsets.clear(); | ||||
ItemEndOffsets.reserve(Items.size()); | ItemEndOffsets.reserve(Items.size()); | ||||
uint32_t CurrentOffset = 0; | uint64_t CurrentOffset = 0; | ||||
for (const auto &Item : Items) { | for (const auto &Item : Items) { | ||||
uint32_t Len = Traits::length(Item); | uint64_t Len = Traits::length(Item); | ||||
assert(Len > 0 && "no empty items"); | assert(Len > 0 && "no empty items"); | ||||
CurrentOffset += Len; | CurrentOffset += Len; | ||||
ItemEndOffsets.push_back(CurrentOffset); | ItemEndOffsets.push_back(CurrentOffset); | ||||
} | } | ||||
} | } | ||||
Expected<uint32_t> translateOffsetIndex(uint32_t Offset) { | Expected<uint32_t> translateOffsetIndex(uint64_t Offset) { | ||||
// Make sure the offset is somewhere in our items array. | // Make sure the offset is somewhere in our items array. | ||||
if (Offset >= getLength()) | if (Offset >= getLength()) | ||||
return make_error<BinaryStreamError>(stream_error_code::stream_too_short); | return make_error<BinaryStreamError>(stream_error_code::stream_too_short); | ||||
++Offset; | ++Offset; | ||||
auto Iter = llvm::lower_bound(ItemEndOffsets, Offset); | auto Iter = llvm::lower_bound(ItemEndOffsets, Offset); | ||||
size_t Idx = std::distance(ItemEndOffsets.begin(), Iter); | size_t Idx = std::distance(ItemEndOffsets.begin(), Iter); | ||||
assert(Idx < Items.size() && "binary search for offset failed"); | assert(Idx < Items.size() && "binary search for offset failed"); | ||||
return Idx; | return Idx; | ||||
} | } | ||||
llvm::support::endianness Endian; | llvm::support::endianness Endian; | ||||
ArrayRef<T> Items; | ArrayRef<T> Items; | ||||
// Sorted vector of offsets to accelerate lookup. | // Sorted vector of offsets to accelerate lookup. | ||||
std::vector<uint32_t> ItemEndOffsets; | std::vector<uint64_t> ItemEndOffsets; | ||||
}; | }; | ||||
} // end namespace llvm | } // end namespace llvm | ||||
#endif // LLVM_SUPPORT_BINARYITEMSTREAM_H | #endif // LLVM_SUPPORT_BINARYITEMSTREAM_H |