- //===- BinaryItemStream.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 
- // 
- //===----------------------------------------------------------------------===// 
-   
- #ifndef LLVM_SUPPORT_BINARYITEMSTREAM_H 
- #define LLVM_SUPPORT_BINARYITEMSTREAM_H 
-   
- #include "llvm/ADT/ArrayRef.h" 
- #include "llvm/Support/BinaryStream.h" 
- #include "llvm/Support/BinaryStreamError.h" 
- #include "llvm/Support/Error.h" 
- #include <cstddef> 
- #include <cstdint> 
-   
- namespace llvm { 
-   
- template <typename T> struct BinaryItemTraits { 
-   static size_t length(const T &Item) = delete; 
-   static ArrayRef<uint8_t> bytes(const T &Item) = delete; 
- }; 
-   
- /// BinaryItemStream represents a sequence of objects stored in some kind of 
- /// external container but for which it is useful to view as a stream of 
- /// contiguous bytes.  An example of this might be if you have a collection of 
- /// records and you serialize each one into a buffer, and store these serialized 
- /// records in a container.  The pointers themselves are not laid out 
- /// contiguously in memory, but we may wish to read from or write to these 
- /// records as if they were. 
- template <typename T, typename Traits = BinaryItemTraits<T>> 
- class BinaryItemStream : public BinaryStream { 
- public: 
-   explicit BinaryItemStream(llvm::support::endianness Endian) 
-       : Endian(Endian) {} 
-   
-   llvm::support::endianness getEndian() const override { return Endian; } 
-   
-   Error readBytes(uint64_t Offset, uint64_t Size, 
-                   ArrayRef<uint8_t> &Buffer) override { 
-     auto ExpectedIndex = translateOffsetIndex(Offset); 
-     if (!ExpectedIndex) 
-       return ExpectedIndex.takeError(); 
-     const auto &Item = Items[*ExpectedIndex]; 
-     if (auto EC = checkOffsetForRead(Offset, Size)) 
-       return EC; 
-     if (Size > Traits::length(Item)) 
-       return make_error<BinaryStreamError>(stream_error_code::stream_too_short); 
-     Buffer = Traits::bytes(Item).take_front(Size); 
-     return Error::success(); 
-   } 
-   
-   Error readLongestContiguousChunk(uint64_t Offset, 
-                                    ArrayRef<uint8_t> &Buffer) override { 
-     auto ExpectedIndex = translateOffsetIndex(Offset); 
-     if (!ExpectedIndex) 
-       return ExpectedIndex.takeError(); 
-     Buffer = Traits::bytes(Items[*ExpectedIndex]); 
-     return Error::success(); 
-   } 
-   
-   void setItems(ArrayRef<T> ItemArray) { 
-     Items = ItemArray; 
-     computeItemOffsets(); 
-   } 
-   
-   uint64_t getLength() override { 
-     return ItemEndOffsets.empty() ? 0 : ItemEndOffsets.back(); 
-   } 
-   
- private: 
-   void computeItemOffsets() { 
-     ItemEndOffsets.clear(); 
-     ItemEndOffsets.reserve(Items.size()); 
-     uint64_t CurrentOffset = 0; 
-     for (const auto &Item : Items) { 
-       uint64_t Len = Traits::length(Item); 
-       assert(Len > 0 && "no empty items"); 
-       CurrentOffset += Len; 
-       ItemEndOffsets.push_back(CurrentOffset); 
-     } 
-   } 
-   
-   Expected<uint32_t> translateOffsetIndex(uint64_t Offset) { 
-     // Make sure the offset is somewhere in our items array. 
-     if (Offset >= getLength()) 
-       return make_error<BinaryStreamError>(stream_error_code::stream_too_short); 
-     ++Offset; 
-     auto Iter = llvm::lower_bound(ItemEndOffsets, Offset); 
-     size_t Idx = std::distance(ItemEndOffsets.begin(), Iter); 
-     assert(Idx < Items.size() && "binary search for offset failed"); 
-     return Idx; 
-   } 
-   
-   llvm::support::endianness Endian; 
-   ArrayRef<T> Items; 
-   
-   // Sorted vector of offsets to accelerate lookup. 
-   std::vector<uint64_t> ItemEndOffsets; 
- }; 
-   
- } // end namespace llvm 
-   
- #endif // LLVM_SUPPORT_BINARYITEMSTREAM_H 
-