From 813575cdf300fef91641f9ad99826ac7190367b8 Mon Sep 17 00:00:00 2001 From: codereader Date: Sun, 19 Jun 2022 10:54:24 +0200 Subject: [PATCH] #5977: Late parser registration is working now --- radiantcore/decl/DeclarationManager.cpp | 46 +++++++++++++++++++++++++ radiantcore/decl/DeclarationManager.h | 8 +++-- radiantcore/decl/DeclarationParser.cpp | 8 +---- test/DeclManager.cpp | 19 +++++++++- 4 files changed, 71 insertions(+), 10 deletions(-) diff --git a/radiantcore/decl/DeclarationManager.cpp b/radiantcore/decl/DeclarationManager.cpp index de7bd79667..a20d204cf0 100644 --- a/radiantcore/decl/DeclarationManager.cpp +++ b/radiantcore/decl/DeclarationManager.cpp @@ -18,6 +18,9 @@ void DeclarationManager::registerDeclType(const std::string& typeName, const IDe } _parsersByTypename.emplace(typeName, parser); + + // A new parser might be able to parse some of the unrecognised blocks + handleUnrecognisedBlocks(); } void DeclarationManager::unregisterDeclType(const std::string& typeName) @@ -96,6 +99,49 @@ void DeclarationManager::onParserFinished(std::map&& pa _unrecognisedBlocks.insert(_unrecognisedBlocks.end(), std::make_move_iterator(unrecognisedBlocks.begin()), std::make_move_iterator(unrecognisedBlocks.end())); } + + // We might have received a parser in the meantime + handleUnrecognisedBlocks(); +} + +void DeclarationManager::handleUnrecognisedBlocks() +{ + std::lock_guard lock(_unrecognisedBlockLock); + + // Check each of the unrecognised blocks + for (auto b = _unrecognisedBlocks.begin(); b != _unrecognisedBlocks.end();) + { + auto parser = _parsersByTypename.find(b->typeName); + + if (parser == _parsersByTypename.end()) + { + ++b; + continue; // still not recognised + } + + // We found a parser, handle it now + auto declaration = parser->second->parseFromBlock(*b); + _unrecognisedBlocks.erase(b++); + + // Insert into our main library + std::lock_guard declLock(_declarationLock); + + auto& namedDecls = _declarationsByType.try_emplace(declaration->getType(), Declarations()).first->second.decls; + + InsertDeclaration(namedDecls, std::move(declaration)); + } +} + +void DeclarationManager::InsertDeclaration(NamedDeclarations& map, IDeclaration::Ptr&& declaration) +{ + auto type = declaration->getType(); + auto result = map.try_emplace(declaration->getName(), std::move(declaration)); + + if (!result.second) + { + rWarning() << "[DeclParser]: " << getTypeName(type) << " " << + result.first->second->getName() << " has already been declared" << std::endl; + } } const std::string& DeclarationManager::getName() const diff --git a/radiantcore/decl/DeclarationManager.h b/radiantcore/decl/DeclarationManager.h index cf64f63c0a..2d9e6c477e 100644 --- a/radiantcore/decl/DeclarationManager.h +++ b/radiantcore/decl/DeclarationManager.h @@ -4,7 +4,6 @@ #include #include #include -#include namespace decl { @@ -39,7 +38,7 @@ class DeclarationManager : std::map _declarationsByType; std::mutex _declarationLock; - std::vector _unrecognisedBlocks; + std::list _unrecognisedBlocks; std::mutex _unrecognisedBlockLock; public: @@ -56,6 +55,11 @@ class DeclarationManager : // Invoked once a parser thread has finished. It will move its data over to here. void onParserFinished(std::map&& parsedDecls, std::vector&& unrecognisedBlocks); + + static void InsertDeclaration(NamedDeclarations& map, IDeclaration::Ptr&& declaration); + +private: + void handleUnrecognisedBlocks(); }; } diff --git a/radiantcore/decl/DeclarationParser.cpp b/radiantcore/decl/DeclarationParser.cpp index 2c1fed8a97..7bf8ac0252 100644 --- a/radiantcore/decl/DeclarationParser.cpp +++ b/radiantcore/decl/DeclarationParser.cpp @@ -77,13 +77,7 @@ void DeclarationParser::parseBlock(IDeclarationParser& parser, const Declaration auto& declMap = _parsedDecls.try_emplace(parser.getDeclType(), NamedDeclarations()).first->second; // Insert into map, emit a warning on duplicates - auto result = declMap.try_emplace(declaration->getName(), std::move(declaration)); - - if (!result.second) - { - rWarning() << "[DeclParser]: " << getTypeName(parser.getDeclType()) << " " << - result.first->second->getName() << " has already been declared" << std::endl; - } + DeclarationManager::InsertDeclaration(declMap, std::move(declaration)); } IDeclarationParser::Ptr DeclarationParser::getParserByType(Type declType) const diff --git a/test/DeclManager.cpp b/test/DeclManager.cpp index 0ed9979ec5..2c030a411f 100644 --- a/test/DeclManager.cpp +++ b/test/DeclManager.cpp @@ -178,11 +178,28 @@ TEST_F(DeclManagerTest, DeclTypeParserRegistration) } // Test that a parser coming late to the party is immediately fed with the buffered decl blocks -TEST_F(DeclManagerTest, LateDeclTypeRegistration) +TEST_F(DeclManagerTest, LateParserRegistration) { auto parser = std::make_shared(); + GlobalDeclarationManager().registerDeclType("testdecl", std::make_shared()); + + // Parse this folder, it contains decls of type testdecl and testdecl2 in the .decl files + GlobalDeclarationManager().registerDeclFolder(decl::Type::Material, "testdecls", ".decl"); + + // Let the testdecl parser finish its work + getAllDeclNames(decl::Type::Material); + auto foundTestDecl2Names = getAllDeclNames(decl::Type::Model); + EXPECT_FALSE(foundTestDecl2Names.count("decltable1") > 0); + EXPECT_FALSE(foundTestDecl2Names.count("decltable2") > 0); + EXPECT_FALSE(foundTestDecl2Names.count("decltable3") > 0); + + // Register the testdecl2 parser now, it should be used by the decl manager to parse the missing pieces + GlobalDeclarationManager().registerDeclType("testdecl2", std::make_shared()); + + // Everything should be registered now + checkKnownTestDecl2Names(); } }