From 67e6eced9e2b4e912ae6b0ef5d038324290a8230 Mon Sep 17 00:00:00 2001 From: Zachary Turner Date: Thu, 27 Apr 2017 16:11:47 +0000 Subject: [PATCH] [Support] Make BinaryStreamArray extractors stateless. Instead, we now pass a context memeber through the extraction process. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@301556 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/DebugInfo/CodeView/CVRecord.h | 6 +- .../DebugInfo/CodeView/ModuleDebugFragment.h | 6 +- .../CodeView/ModuleDebugFragmentVisitor.h | 16 ++-- .../PDB/Native/DbiModuleDescriptor.h | 5 +- include/llvm/Support/BinaryStreamArray.h | 83 +++++++++---------- include/llvm/Support/BinaryStreamReader.h | 6 +- .../CodeView/ModuleDebugFragmentVisitor.cpp | 5 +- unittests/Support/BinaryStreamTest.cpp | 18 ++-- 8 files changed, 70 insertions(+), 75 deletions(-) diff --git a/include/llvm/DebugInfo/CodeView/CVRecord.h b/include/llvm/DebugInfo/CodeView/CVRecord.h index 487f3b6446f..086d6dff11c 100644 --- a/include/llvm/DebugInfo/CodeView/CVRecord.h +++ b/include/llvm/DebugInfo/CodeView/CVRecord.h @@ -50,8 +50,10 @@ public: template struct VarStreamArrayExtractor> { - Error operator()(BinaryStreamRef Stream, uint32_t &Len, - codeview::CVRecord &Item) const { + typedef void ContextType; + + static Error extract(BinaryStreamRef Stream, uint32_t &Len, + codeview::CVRecord &Item, void *Ctx) { using namespace codeview; const RecordPrefix *Prefix = nullptr; BinaryStreamReader Reader(Stream); diff --git a/include/llvm/DebugInfo/CodeView/ModuleDebugFragment.h b/include/llvm/DebugInfo/CodeView/ModuleDebugFragment.h index 84172f837ae..a02f3b7ebd6 100644 --- a/include/llvm/DebugInfo/CodeView/ModuleDebugFragment.h +++ b/include/llvm/DebugInfo/CodeView/ModuleDebugFragment.h @@ -74,8 +74,10 @@ typedef VarStreamArray ModuleDebugFragmentArray; } // namespace codeview template <> struct VarStreamArrayExtractor { - Error operator()(BinaryStreamRef Stream, uint32_t &Length, - codeview::ModuleDebugFragment &Info) const { + typedef void ContextType; + + static Error extract(BinaryStreamRef Stream, uint32_t &Length, + codeview::ModuleDebugFragment &Info, void *Ctx) { if (auto EC = codeview::ModuleDebugFragment::initialize(Stream, Info)) return EC; Length = Info.getRecordLength(); diff --git a/include/llvm/DebugInfo/CodeView/ModuleDebugFragmentVisitor.h b/include/llvm/DebugInfo/CodeView/ModuleDebugFragmentVisitor.h index 162a9311df6..5205a380ad5 100644 --- a/include/llvm/DebugInfo/CodeView/ModuleDebugFragmentVisitor.h +++ b/include/llvm/DebugInfo/CodeView/ModuleDebugFragmentVisitor.h @@ -71,11 +71,10 @@ Error visitModuleDebugFragment(const ModuleDebugFragment &R, template <> class VarStreamArrayExtractor { public: - VarStreamArrayExtractor(const codeview::LineFragmentHeader *Header) - : Header(Header) {} + typedef const codeview::LineFragmentHeader ContextType; - Error operator()(BinaryStreamRef Stream, uint32_t &Len, - codeview::LineColumnEntry &Item) const { + static Error extract(BinaryStreamRef Stream, uint32_t &Len, + codeview::LineColumnEntry &Item, ContextType *Header) { using namespace codeview; const LineBlockFragmentHeader *BlockHeader; BinaryStreamReader Reader(Stream); @@ -104,15 +103,14 @@ public: } return Error::success(); } - -private: - const codeview::LineFragmentHeader *Header; }; template <> class VarStreamArrayExtractor { public: - Error operator()(BinaryStreamRef Stream, uint32_t &Len, - codeview::FileChecksumEntry &Item) const { + typedef void ContextType; + + static Error extract(BinaryStreamRef Stream, uint32_t &Len, + codeview::FileChecksumEntry &Item, void *Ctx) { using namespace codeview; const FileChecksum *Header; BinaryStreamReader Reader(Stream); diff --git a/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h b/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h index f6989dea7fd..ac29c63131f 100644 --- a/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h +++ b/include/llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h @@ -64,8 +64,9 @@ struct ModuleInfoEx { } // end namespace pdb template <> struct VarStreamArrayExtractor { - Error operator()(BinaryStreamRef Stream, uint32_t &Length, - pdb::DbiModuleDescriptor &Info) const { + typedef void ContextType; + static Error extract(BinaryStreamRef Stream, uint32_t &Length, + pdb::DbiModuleDescriptor &Info, void *Ctx) { if (auto EC = pdb::DbiModuleDescriptor::initialize(Stream, Info)) return EC; Length = Info.getRecordLength(); diff --git a/include/llvm/Support/BinaryStreamArray.h b/include/llvm/Support/BinaryStreamArray.h index 21b2474660f..e86dc423aee 100644 --- a/include/llvm/Support/BinaryStreamArray.h +++ b/include/llvm/Support/BinaryStreamArray.h @@ -42,10 +42,12 @@ namespace llvm { /// having to specify a second template argument to VarStreamArray (documented /// below). template struct VarStreamArrayExtractor { + typedef void Context; + // Method intentionally deleted. You must provide an explicit specialization // with the following method implemented. - Error operator()(BinaryStreamRef Stream, uint32_t &Len, - T &Item) const = delete; + static Error extract(BinaryStreamRef Stream, uint32_t &Len, T &Item, + Context *Ctx) = delete; }; /// VarStreamArray represents an array of variable length records backed by a @@ -64,74 +66,64 @@ template struct VarStreamArrayExtractor { /// 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); +/// 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 VarStreamArrayIterator; +template +class VarStreamArrayIterator; template > - + typename ExtractorType = VarStreamArrayExtractor> class VarStreamArray { - friend class VarStreamArrayIterator; - public: - typedef VarStreamArrayIterator Iterator; + typedef typename ExtractorType::ContextType ContextType; + typedef VarStreamArrayIterator Iterator; + friend Iterator; VarStreamArray() = default; - explicit VarStreamArray(const Extractor &E) : E(E) {} - explicit VarStreamArray(BinaryStreamRef Stream) : Stream(Stream) {} - VarStreamArray(BinaryStreamRef Stream, const Extractor &E) - : Stream(Stream), E(E) {} + explicit VarStreamArray(BinaryStreamRef Stream, + ContextType *Context = nullptr) + : Stream(Stream), Context(Context) {} - VarStreamArray(const VarStreamArray &Other) - : Stream(Other.Stream), E(Other.E) {} + VarStreamArray(const VarStreamArray &Other) + : Stream(Other.Stream), Context(Other.Context) {} Iterator begin(bool *HadError = nullptr) const { - return Iterator(*this, E, HadError); + return Iterator(*this, Context, HadError); } - Iterator end() const { return Iterator(E); } - - const Extractor &getExtractor() const { return E; } + Iterator end() const { return Iterator(); } BinaryStreamRef getUnderlyingStream() const { return Stream; } + void setUnderlyingStream(BinaryStreamRef Stream) { this->Stream = Stream; } private: BinaryStreamRef Stream; - Extractor E; + ContextType *Context = nullptr; }; -template +template class VarStreamArrayIterator - : public iterator_facade_base, - std::forward_iterator_tag, ValueType> { - typedef VarStreamArrayIterator IterType; - typedef VarStreamArray ArrayType; + : public iterator_facade_base< + VarStreamArrayIterator, + std::forward_iterator_tag, ValueType> { + typedef typename ExtractorType::ContextType ContextType; + typedef VarStreamArrayIterator IterType; + typedef VarStreamArray ArrayType; public: - VarStreamArrayIterator(const ArrayType &Array, const Extractor &E, + VarStreamArrayIterator(const ArrayType &Array, ContextType *Context, bool *HadError = nullptr) - : IterRef(Array.Stream), Array(&Array), HadError(HadError), Extract(E) { + : IterRef(Array.Stream), Context(Context), Array(&Array), + HadError(HadError) { if (IterRef.getLength() == 0) moveToEnd(); else { - auto EC = Extract(IterRef, ThisLen, ThisValue); + auto EC = ExtractorType::extract(IterRef, ThisLen, ThisValue, Context); if (EC) { consumeError(std::move(EC)); markError(); @@ -139,7 +131,6 @@ public: } } VarStreamArrayIterator() = default; - explicit VarStreamArrayIterator(const Extractor &E) : Extract(E) {} ~VarStreamArrayIterator() = default; bool operator==(const IterType &R) const { @@ -178,7 +169,7 @@ public: moveToEnd(); } else { // There is some data after the current record. - auto EC = Extract(IterRef, ThisLen, ThisValue); + auto EC = ExtractorType::extract(IterRef, ThisLen, ThisValue, Context); if (EC) { consumeError(std::move(EC)); markError(); @@ -205,11 +196,11 @@ private: ValueType ThisValue; BinaryStreamRef IterRef; + ContextType *Context{nullptr}; const ArrayType *Array{nullptr}; uint32_t ThisLen{0}; bool HasError{false}; bool *HadError{nullptr}; - Extractor Extract; }; template class FixedStreamArrayIterator; diff --git a/include/llvm/Support/BinaryStreamReader.h b/include/llvm/Support/BinaryStreamReader.h index d994fa0f49d..f30d82d81b2 100644 --- a/include/llvm/Support/BinaryStreamReader.h +++ b/include/llvm/Support/BinaryStreamReader.h @@ -172,11 +172,13 @@ public: /// \returns a success error code if the data was successfully read, otherwise /// returns an appropriate error code. template - Error readArray(VarStreamArray &Array, uint32_t Size) { + Error + readArray(VarStreamArray &Array, uint32_t Size, + typename VarStreamArray::ContextType *Context = nullptr) { BinaryStreamRef S; if (auto EC = readStreamRef(S, Size)) return EC; - Array = VarStreamArray(S, Array.getExtractor()); + Array = VarStreamArray(S, Context); return Error::success(); } diff --git a/lib/DebugInfo/CodeView/ModuleDebugFragmentVisitor.cpp b/lib/DebugInfo/CodeView/ModuleDebugFragmentVisitor.cpp index 8db17b94997..37cd887d783 100644 --- a/lib/DebugInfo/CodeView/ModuleDebugFragmentVisitor.cpp +++ b/lib/DebugInfo/CodeView/ModuleDebugFragmentVisitor.cpp @@ -68,9 +68,8 @@ Error llvm::codeview::visitModuleDebugFragment(const ModuleDebugFragment &R, const LineFragmentHeader *Header; if (auto EC = Reader.readObject(Header)) return EC; - VarStreamArrayExtractor E(Header); - LineInfoArray LineInfos(E); - if (auto EC = Reader.readArray(LineInfos, Reader.bytesRemaining())) + LineInfoArray LineInfos; + if (auto EC = Reader.readArray(LineInfos, Reader.bytesRemaining(), Header)) return EC; return V.visitLines(R.getRecordData(), Header, LineInfos); } diff --git a/unittests/Support/BinaryStreamTest.cpp b/unittests/Support/BinaryStreamTest.cpp index 1e646a6cf90..74c51e382d9 100644 --- a/unittests/Support/BinaryStreamTest.cpp +++ b/unittests/Support/BinaryStreamTest.cpp @@ -358,12 +358,14 @@ TEST_F(BinaryStreamTest, VarStreamArray) { struct StringExtractor { public: - Error operator()(BinaryStreamRef Stream, uint32_t &Len, StringRef &Item) { - if (Index == 0) + typedef uint32_t ContextType; + static Error extract(BinaryStreamRef Stream, uint32_t &Len, StringRef &Item, + uint32_t *Index) { + if (*Index == 0) Len = strlen("1. Test"); - else if (Index == 1) + else if (*Index == 1) Len = strlen("2. Longer Test"); - else if (Index == 2) + else if (*Index == 2) Len = strlen("3. Really Long Test"); else Len = strlen("4. Super Extra Longest Test Of All"); @@ -372,16 +374,14 @@ TEST_F(BinaryStreamTest, VarStreamArray) { return EC; Item = StringRef(reinterpret_cast(Bytes.data()), Bytes.size()); - ++Index; + ++(*Index); return Error::success(); } - - private: - uint32_t Index = 0; }; for (auto &Stream : Streams) { - VarStreamArray Array(*Stream.Input); + uint32_t Context = 0; + VarStreamArray Array(*Stream.Input, &Context); auto Iter = Array.begin(); ASSERT_EQ("1. Test", *Iter++); ASSERT_EQ("2. Longer Test", *Iter++); -- 2.40.0