Skip to content

Commit

Permalink
#5977: Late parser registration is working now
Browse files Browse the repository at this point in the history
  • Loading branch information
codereader committed Jun 19, 2022
1 parent 2ef2444 commit 813575c
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 10 deletions.
46 changes: 46 additions & 0 deletions radiantcore/decl/DeclarationManager.cpp
Expand Up @@ -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)
Expand Down Expand Up @@ -96,6 +99,49 @@ void DeclarationManager::onParserFinished(std::map<Type, NamedDeclarations>&& 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<std::mutex> 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<std::mutex> 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
Expand Down
8 changes: 6 additions & 2 deletions radiantcore/decl/DeclarationManager.h
Expand Up @@ -4,7 +4,6 @@
#include <map>
#include <vector>
#include <memory>
#include <thread>

namespace decl
{
Expand Down Expand Up @@ -39,7 +38,7 @@ class DeclarationManager :
std::map<Type, Declarations> _declarationsByType;
std::mutex _declarationLock;

std::vector<DeclarationBlockSyntax> _unrecognisedBlocks;
std::list<DeclarationBlockSyntax> _unrecognisedBlocks;
std::mutex _unrecognisedBlockLock;

public:
Expand All @@ -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<Type, NamedDeclarations>&& parsedDecls,
std::vector<DeclarationBlockSyntax>&& unrecognisedBlocks);

static void InsertDeclaration(NamedDeclarations& map, IDeclaration::Ptr&& declaration);

private:
void handleUnrecognisedBlocks();
};

}
8 changes: 1 addition & 7 deletions radiantcore/decl/DeclarationParser.cpp
Expand Up @@ -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
Expand Down
19 changes: 18 additions & 1 deletion test/DeclManager.cpp
Expand Up @@ -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<TestDeclarationParser>();

GlobalDeclarationManager().registerDeclType("testdecl", std::make_shared<TestDeclarationParser>());

// 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<TestDeclaration2Parser>());

// Everything should be registered now
checkKnownTestDecl2Names();
}

}

0 comments on commit 813575c

Please sign in to comment.