1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 03:02:36 +01:00
llvm-mirror/include/llvm/Support/BinaryItemStream.h
Zachary Turner 00fd9be463 [BinaryStream] Support growable streams.
The existing library assumed that a stream's length would never
change.  This makes some things simpler, but it's not flexible
enough for what we need, especially for writable streams where
what you really want is for each call to write to actually append.

llvm-svn: 319070
2017-11-27 18:48:37 +00:00

109 lines
3.6 KiB
C++

//===- BinaryItemStream.h ---------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#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