123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 |
- #pragma once
- #ifdef __GNUC__
- #pragma GCC diagnostic push
- #pragma GCC diagnostic ignored "-Wunused-parameter"
- #endif
- //===- 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
- #ifdef __GNUC__
- #pragma GCC diagnostic pop
- #endif
|