diff options
Diffstat (limited to 'clang-r353983e/include/llvm/Support/BinaryItemStream.h')
| -rw-r--r-- | clang-r353983e/include/llvm/Support/BinaryItemStream.h | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/clang-r353983e/include/llvm/Support/BinaryItemStream.h b/clang-r353983e/include/llvm/Support/BinaryItemStream.h new file mode 100644 index 00000000..4cd66adc --- /dev/null +++ b/clang-r353983e/include/llvm/Support/BinaryItemStream.h @@ -0,0 +1,107 @@ +//===- 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(uint32_t Offset, uint32_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(uint32_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(); + } + + uint32_t getLength() override { + return ItemEndOffsets.empty() ? 0 : ItemEndOffsets.back(); + } + +private: + void computeItemOffsets() { + ItemEndOffsets.clear(); + ItemEndOffsets.reserve(Items.size()); + uint32_t CurrentOffset = 0; + for (const auto &Item : Items) { + uint32_t Len = Traits::length(Item); + assert(Len > 0 && "no empty items"); + CurrentOffset += Len; + ItemEndOffsets.push_back(CurrentOffset); + } + } + + Expected<uint32_t> translateOffsetIndex(uint32_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 = + std::lower_bound(ItemEndOffsets.begin(), ItemEndOffsets.end(), 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<uint32_t> ItemEndOffsets; +}; + +} // end namespace llvm + +#endif // LLVM_SUPPORT_BINARYITEMSTREAM_H |
