1//===- BinaryStreamArray.h - Array backed by an arbitrary stream *- C++ -*-===//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7//===----------------------------------------------------------------------===//
10/// Lightweight arrays that are backed by an arbitrary BinaryStream. This file
11/// provides two different array implementations.
13/// VarStreamArray - Arrays of variable length records. The user specifies
14/// an Extractor type that can extract a record from a given offset and
15/// return the number of bytes consumed by the record.
17/// FixedStreamArray - Arrays of fixed length records. This is similar in
18/// spirit to ArrayRef<T>, but since it is backed by a BinaryStream, the
19/// elements of the array need not be laid out in contiguous memory.
22#ifndef LLVM_SUPPORT_BINARYSTREAMARRAY_H
23#define LLVM_SUPPORT_BINARYSTREAMARRAY_H
35/// VarStreamArrayExtractor is intended to be specialized to provide customized
36/// extraction logic. On input it receives a BinaryStreamRef pointing to the
37/// beginning of the next record, but where the length of the record is not yet
38/// known. Upon completion, it should return an appropriate Error instance if
39/// a record could not be extracted, or if one could be extracted it should
40/// return success and set Len to the number of bytes this record occupied in
41/// the underlying stream, and it should fill out the fields of the value type
42/// Item appropriately to represent the current record.
44/// You can specialize this template for your own custom value types to avoid
45/// having to specify a second template argument to VarStreamArray (documented
48 // Method intentionally deleted. You must provide an explicit specialization
49 // with the following method implemented.
51 T &Item)
const =
delete;
54/// VarStreamArray represents an array of variable length records backed by a
55/// stream. This could be a contiguous sequence of bytes in memory, it could
56/// be a file on disk, or it could be a PDB stream where bytes are stored as
57/// discontiguous blocks in a file. Usually it is desirable to treat arrays
58/// as contiguous blocks of memory, but doing so with large PDB files, for
59/// example, could mean allocating huge amounts of memory just to allow
60/// re-ordering of stream data to be contiguous before iterating over it. By
61/// abstracting this out, we need not duplicate this memory, and we can
62/// iterate over arrays in arbitrarily formatted streams. Elements are parsed
63/// lazily on iteration, so there is no upfront cost associated with building
64/// or copying a VarStreamArray, no matter how large it may be.
66/// You create a VarStreamArray by specifying a ValueType and an Extractor type.
67/// If you do not specify an Extractor type, you are expected to specialize
68/// VarStreamArrayExtractor<T> for your ValueType.
70/// By default an Extractor is default constructed in the class, but in some
71/// cases you might find it useful for an Extractor to maintain state across
72/// extractions. In this case you can provide your own Extractor through a
73/// secondary constructor. The following examples show various ways of
74/// creating a VarStreamArray.
76/// // Will use VarStreamArrayExtractor<MyType> as the extractor.
77/// VarStreamArray<MyType> MyTypeArray;
79/// // Will use a default-constructed MyExtractor as the extractor.
80/// VarStreamArray<MyType, MyExtractor> MyTypeArray2;
82/// // Will use the specific instance of MyExtractor provided.
83/// // MyExtractor need not be default-constructible in this case.
84/// MyExtractor E(SomeContext);
85/// VarStreamArray<MyType, MyExtractor> MyTypeArray3(E);
103 : Stream(Stream), Skew(Skew) {}
106 : Stream(Stream), E(E), Skew(Skew) {}
109 return Iterator(*
this, E, Skew,
nullptr);
112 bool valid()
const {
return Stream.valid(); }
119 bool empty()
const {
return Stream.getLength() == 0; }
124 // We should never cut off the beginning of the stream since it might be
125 // skewed, meaning the initial bytes are important.
127 return {NewStream, E, Begin};
130 /// given an offset into the array's underlying stream, return an
131 /// iterator to the record at that offset. This is considered unsafe
132 /// since the behavior is undefined if \p Offset does not refer to the
133 /// beginning of a valid record.
155template <
typename ValueType,
typename Extractor>
158 std::forward_iterator_tag, const ValueType> {
165 : IterRef(Array.Stream.drop_front(
Offset)), Extract(
E),
166 Array(&Array), AbsOffset(
Offset), HadError(HadError) {
167 if (IterRef.getLength() == 0)
170 auto EC = Extract(IterRef, ThisLen, ThisValue);
183 if (Array && R.Array) {
184 // Both have a valid array, make sure they're same.
186 return IterRef == R.IterRef;
189 // Both iterators are at the end.
190 if (!Array && !R.Array)
193 // One is not at the end and one is.
198 assert(Array && !HasError);
203 for (
unsigned I = 0;
I <
N; ++
I) {
204 // We are done with the current record, discard it so that we are
205 // positioned at the next record.
206 AbsOffset += ThisLen;
207 IterRef = IterRef.drop_front(ThisLen);
208 if (IterRef.getLength() == 0) {
209 // There is nothing after the current record, we must make this an end
213 // There is some data after the current record.
214 auto EC = Extract(IterRef, ThisLen, ThisValue);
218 }
else if (ThisLen == 0) {
219 // An empty record? Make this an end iterator.
238 if (HadError !=
nullptr)
243 BinaryStreamRef IterRef;
245 const ArrayType *Array{
nullptr};
247 uint32_t AbsOffset{0};
248 bool HasError{
false};
249 bool *HadError{
nullptr};
252template <
typename T>
class FixedStreamArrayIterator;
254/// FixedStreamArray is similar to VarStreamArray, except with each record
255/// having a fixed-length. As with VarStreamArray, there is no upfront
256/// cost associated with building or copying a FixedStreamArray, as the
257/// memory for each element is not read from the backing stream until that
258/// element is iterated.
267 assert(Stream.getLength() %
sizeof(
T) == 0);
271 return Stream ==
Other.Stream;
275 return !(*
this ==
Other);
285 if (
auto EC = Stream.readBytes(Off,
sizeof(
T),
Data)) {
286 assert(
false &&
"Unexpected failure reading from stream");
287 // This should never happen since we asserted that the stream length was
288 // an exact multiple of the element size.
292 return *
reinterpret_cast<const T *
>(
Data.data());
322 std::random_access_iterator_tag, const T> {
326 : Array(Array), Index(Index) {}
342 return (Index == R.Index) && (Array == R.Array);
351 assert(std::ptrdiff_t(Index) >=
N);
359 return Index - R.Index;
364 return Index <
RHS.Index;
374#endif // LLVM_SUPPORT_BINARYSTREAMARRAY_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
RefType slice(uint64_t Offset, uint64_t Len) const
Return a new BinaryStreamRef with the first Offset elements removed, and retaining exactly Len elemen...
BinaryStreamRef is to BinaryStream what ArrayRef is to an Array.
Lightweight error class with error context and mandatory checking.
std::ptrdiff_t operator-(const FixedStreamArrayIterator< T > &R) const
FixedStreamArrayIterator< T > & operator+=(std::ptrdiff_t N)
FixedStreamArrayIterator< T > & operator=(const FixedStreamArrayIterator< T > &Other)
bool operator<(const FixedStreamArrayIterator< T > &RHS) const
bool operator==(const FixedStreamArrayIterator< T > &R) const
FixedStreamArrayIterator< T > & operator-=(std::ptrdiff_t N)
const T & operator*() const
FixedStreamArrayIterator(const FixedStreamArray< T > &Array, uint32_t Index)
FixedStreamArrayIterator(const FixedStreamArrayIterator< T > &Other)
FixedStreamArray is similar to VarStreamArray, except with each record having a fixed-length.
BinaryStreamRef getUnderlyingStream() const
FixedStreamArrayIterator< T > begin() const
bool operator!=(const FixedStreamArray< T > &Other) const
FixedStreamArray & operator=(const FixedStreamArray &)=default
FixedStreamArrayIterator< T > end() const
bool operator==(const FixedStreamArray< T > &Other) const
friend class FixedStreamArrayIterator< T >
const T & operator[](uint32_t Index) const
FixedStreamArrayIterator< CrossModuleExport > Iterator
FixedStreamArray(BinaryStreamRef Stream)
FixedStreamArray()=default
FixedStreamArray(const FixedStreamArray &)=default
VarStreamArray represents an array of variable length records backed by a stream.
VarStreamArrayIterator(const ArrayType &Array, const Extractor &E, uint32_t Offset, bool *HadError)
uint32_t getRecordLength() const
VarStreamArrayIterator(const Extractor &E)
~VarStreamArrayIterator()=default
VarStreamArrayIterator()=default
bool operator==(const IterType &R) const
IterType & operator+=(unsigned N)
const ValueType & operator*() const
VarStreamArray(BinaryStreamRef Stream, const Extractor &E, uint32_t Skew=0)
void setUnderlyingStream(BinaryStreamRef NewStream, uint32_t NewSkew=0)
Iterator at(uint32_t Offset) const
VarStreamArray(const Extractor &E)
Extractor & getExtractor()
BinaryStreamRef getUnderlyingStream() const
bool isOffsetValid(uint32_t Offset) const
Iterator begin(bool *HadError=nullptr) const
const Extractor & getExtractor() const
VarStreamArrayIterator< CVSymbol, VarStreamArrayExtractor< CVSymbol > > Iterator
VarStreamArray(BinaryStreamRef Stream, uint32_t Skew=0)
VarStreamArray< ValueType, Extractor > substream(uint32_t Begin, uint32_t End) const
CRTP base class which implements the entire standard iterator facade in terms of a minimal subset of ...
This is an optimization pass for GlobalISel generic memory operations.
FunctionAddr VTableAddr uintptr_t uintptr_t Data
PointerUnion< const Value *, const PseudoSourceValue * > ValueType
void consumeError(Error Err)
Consume a Error without doing anything.
bool isAddrAligned(Align Lhs, const void *Addr)
Checks that Addr is a multiple of the alignment.
static constexpr Align Of()
Allow constructions of constexpr Align from types.