From 7ab83427af0f77b59941ceba41d509d7d097b065 Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Sat, 10 Jun 2017 13:44:06 +0000 Subject: Vendor import of llvm trunk r305145: https://llvm.org/svn/llvm-project/llvm/trunk@305145 --- include/llvm/Support/BinaryStreamArray.h | 258 +++++++++++++------------------ 1 file changed, 105 insertions(+), 153 deletions(-) (limited to 'include/llvm/Support/BinaryStreamArray.h') diff --git a/include/llvm/Support/BinaryStreamArray.h b/include/llvm/Support/BinaryStreamArray.h index 77c99ffff919..65ec15f6d9e0 100644 --- a/include/llvm/Support/BinaryStreamArray.h +++ b/include/llvm/Support/BinaryStreamArray.h @@ -42,36 +42,114 @@ namespace llvm { /// having to specify a second template argument to VarStreamArray (documented /// below). template struct VarStreamArrayExtractor { - struct ContextType {}; - // Method intentionally deleted. You must provide an explicit specialization - // with one of the following two methods implemented. - static Error extract(BinaryStreamRef Stream, uint32_t &Len, T &Item) = delete; + // with the following method implemented. + Error operator()(BinaryStreamRef Stream, uint32_t &Len, + T &Item) const = delete; +}; + +/// VarStreamArray represents an array of variable length records backed by a +/// stream. This could be a contiguous sequence of bytes in memory, it could +/// be a file on disk, or it could be a PDB stream where bytes are stored as +/// discontiguous blocks in a file. Usually it is desirable to treat arrays +/// as contiguous blocks of memory, but doing so with large PDB files, for +/// example, could mean allocating huge amounts of memory just to allow +/// re-ordering of stream data to be contiguous before iterating over it. By +/// abstracting this out, we need not duplicate this memory, and we can +/// iterate over arrays in arbitrarily formatted streams. Elements are parsed +/// lazily on iteration, so there is no upfront cost associated with building +/// or copying a VarStreamArray, no matter how large it may be. +/// +/// You create a VarStreamArray by specifying a ValueType and an Extractor type. +/// If you do not specify an Extractor type, you are expected to specialize +/// VarStreamArrayExtractor for your ValueType. +/// +/// By default an Extractor is default constructed in the class, but in some +/// cases you might find it useful for an Extractor to maintain state across +/// extractions. In this case you can provide your own Extractor through a +/// secondary constructor. The following examples show various ways of +/// creating a VarStreamArray. +/// +/// // Will use VarStreamArrayExtractor as the extractor. +/// VarStreamArray MyTypeArray; +/// +/// // Will use a default-constructed MyExtractor as the extractor. +/// VarStreamArray MyTypeArray2; +/// +/// // Will use the specific instance of MyExtractor provided. +/// // MyExtractor need not be default-constructible in this case. +/// MyExtractor E(SomeContext); +/// VarStreamArray MyTypeArray3(E); +/// + +template class VarStreamArrayIterator; + +template > +class VarStreamArray { + friend class VarStreamArrayIterator; + +public: + typedef VarStreamArrayIterator Iterator; + + VarStreamArray() = default; + + explicit VarStreamArray(const Extractor &E) : E(E) {} + + explicit VarStreamArray(BinaryStreamRef Stream) : Stream(Stream) {} - static Error extract(BinaryStreamRef Stream, uint32_t &Len, T &Item, - const ContextType &Ctx) = delete; + VarStreamArray(BinaryStreamRef Stream, const Extractor &E) + : Stream(Stream), E(E) {} + + Iterator begin(bool *HadError = nullptr) const { + return Iterator(*this, E, HadError); + } + + bool valid() const { return Stream.valid(); } + + Iterator end() const { return Iterator(E); } + + bool empty() const { return Stream.getLength() == 0; } + + /// \brief given an offset into the array's underlying stream, return an + /// iterator to the record at that offset. This is considered unsafe + /// since the behavior is undefined if \p Offset does not refer to the + /// beginning of a valid record. + Iterator at(uint32_t Offset) const { + return Iterator(*this, E, Offset, nullptr); + } + + const Extractor &getExtractor() const { return E; } + Extractor &getExtractor() { return E; } + + BinaryStreamRef getUnderlyingStream() const { return Stream; } + void setUnderlyingStream(BinaryStreamRef S) { Stream = S; } + +private: + BinaryStreamRef Stream; + Extractor E; }; -template +template class VarStreamArrayIterator - : public iterator_facade_base< - VarStreamArrayIterator, - std::forward_iterator_tag, Value> { - typedef VarStreamArrayIterator - IterType; + : public iterator_facade_base, + std::forward_iterator_tag, ValueType> { + typedef VarStreamArrayIterator IterType; + typedef VarStreamArray ArrayType; public: - VarStreamArrayIterator() = default; - VarStreamArrayIterator(const ArrayType &Array, const WrappedCtx &Ctx, - BinaryStreamRef Stream, bool *HadError = nullptr, - uint32_t Offset = 0) - : IterRef(Stream), Ctx(&Ctx), Array(&Array), AbsOffset(Offset), - HadError(HadError) { + VarStreamArrayIterator(const ArrayType &Array, const Extractor &E, + bool *HadError) + : VarStreamArrayIterator(Array, E, 0, HadError) {} + + VarStreamArrayIterator(const ArrayType &Array, const Extractor &E, + uint32_t Offset, bool *HadError) + : IterRef(Array.Stream.drop_front(Offset)), Extract(E), + Array(&Array), AbsOffset(Offset), HadError(HadError) { if (IterRef.getLength() == 0) moveToEnd(); else { - auto EC = Ctx.template invoke(IterRef, ThisLen, ThisValue); + auto EC = Extract(IterRef, ThisLen, ThisValue); if (EC) { consumeError(std::move(EC)); markError(); @@ -79,13 +157,8 @@ public: } } - VarStreamArrayIterator(const ArrayType &Array, const WrappedCtx &Ctx, - bool *HadError = nullptr) - : VarStreamArrayIterator(Array, Ctx, Array.Stream, HadError) {} - - VarStreamArrayIterator(const WrappedCtx &Ctx) : Ctx(&Ctx) {} - VarStreamArrayIterator(const VarStreamArrayIterator &Other) = default; - + VarStreamArrayIterator() = default; + explicit VarStreamArrayIterator(const Extractor &E) : Extract(E) {} ~VarStreamArrayIterator() = default; bool operator==(const IterType &R) const { @@ -103,12 +176,12 @@ public: return false; } - const Value &operator*() const { + const ValueType &operator*() const { assert(Array && !HasError); return ThisValue; } - Value &operator*() { + ValueType &operator*() { assert(Array && !HasError); return ThisValue; } @@ -125,7 +198,7 @@ public: moveToEnd(); } else { // There is some data after the current record. - auto EC = Ctx->template invoke(IterRef, ThisLen, ThisValue); + auto EC = Extract(IterRef, ThisLen, ThisValue); if (EC) { consumeError(std::move(EC)); markError(); @@ -153,9 +226,9 @@ private: *HadError = true; } - Value ThisValue; + ValueType ThisValue; BinaryStreamRef IterRef; - const WrappedCtx *Ctx{nullptr}; + Extractor Extract; const ArrayType *Array{nullptr}; uint32_t ThisLen{0}; uint32_t AbsOffset{0}; @@ -163,127 +236,6 @@ private: bool *HadError{nullptr}; }; -template struct ContextWrapper { - ContextWrapper() = default; - - explicit ContextWrapper(Context &&Ctx) : Ctx(Ctx) {} - - template - Error invoke(BinaryStreamRef Stream, uint32_t &Len, T &Item) const { - return Extractor::extract(Stream, Len, Item, Ctx); - } - - Context Ctx; -}; - -template struct ContextWrapper { - ContextWrapper() = default; - - template - Error invoke(BinaryStreamRef Stream, uint32_t &Len, T &Item) const { - return Extractor::extract(Stream, Len, Item); - } -}; - -/// VarStreamArray represents an array of variable length records backed by a -/// stream. This could be a contiguous sequence of bytes in memory, it could -/// be a file on disk, or it could be a PDB stream where bytes are stored as -/// discontiguous blocks in a file. Usually it is desirable to treat arrays -/// as contiguous blocks of memory, but doing so with large PDB files, for -/// example, could mean allocating huge amounts of memory just to allow -/// re-ordering of stream data to be contiguous before iterating over it. By -/// abstracting this out, we need not duplicate this memory, and we can -/// iterate over arrays in arbitrarily formatted streams. Elements are parsed -/// lazily on iteration, so there is no upfront cost associated with building -/// or copying a VarStreamArray, no matter how large it may be. -/// -/// You create a VarStreamArray by specifying a ValueType and an Extractor type. -/// If you do not specify an Extractor type, you are expected to specialize -/// VarStreamArrayExtractor for your ValueType. -/// -/// The default extractor type is stateless, but by specializing -/// VarStreamArrayExtractor or defining your own custom extractor type and -/// adding the appropriate ContextType typedef to the class, you can pass a -/// context field during construction of the VarStreamArray that will be -/// passed to each call to extract. -/// -template -class VarStreamArrayBase { - typedef VarStreamArrayBase MyType; - -public: - typedef VarStreamArrayIterator Iterator; - friend Iterator; - - VarStreamArrayBase() = default; - - VarStreamArrayBase(BinaryStreamRef Stream, const WrappedCtx &Ctx) - : Stream(Stream), Ctx(Ctx) {} - - VarStreamArrayBase(const MyType &Other) - : Stream(Other.Stream), Ctx(Other.Ctx) {} - - Iterator begin(bool *HadError = nullptr) const { - if (empty()) - return end(); - - return Iterator(*this, Ctx, Stream, HadError); - } - - bool valid() const { return Stream.valid(); } - - Iterator end() const { return Iterator(Ctx); } - - bool empty() const { return Stream.getLength() == 0; } - - /// \brief given an offset into the array's underlying stream, return an - /// iterator to the record at that offset. This is considered unsafe - /// since the behavior is undefined if \p Offset does not refer to the - /// beginning of a valid record. - Iterator at(uint32_t Offset) const { - return Iterator(*this, Ctx, Stream.drop_front(Offset), nullptr, Offset); - } - - BinaryStreamRef getUnderlyingStream() const { return Stream; } - -private: - BinaryStreamRef Stream; - WrappedCtx Ctx; -}; - -template -class VarStreamArrayImpl - : public VarStreamArrayBase> { - typedef ContextWrapper WrappedContext; - typedef VarStreamArrayImpl MyType; - typedef VarStreamArrayBase BaseType; - -public: - typedef Context ContextType; - - VarStreamArrayImpl() = default; - VarStreamArrayImpl(BinaryStreamRef Stream, Context &&Ctx) - : BaseType(Stream, WrappedContext(std::forward(Ctx))) {} -}; - -template -class VarStreamArrayImpl - : public VarStreamArrayBase> { - typedef ContextWrapper WrappedContext; - typedef VarStreamArrayImpl MyType; - typedef VarStreamArrayBase BaseType; - -public: - VarStreamArrayImpl() = default; - VarStreamArrayImpl(BinaryStreamRef Stream) - : BaseType(Stream, WrappedContext()) {} -}; - -template > -using VarStreamArray = - VarStreamArrayImpl; - template class FixedStreamArrayIterator; /// FixedStreamArray is similar to VarStreamArray, except with each record -- cgit v1.3