Skip to content

Commit

Permalink
#5911: Move common VFS handling code to the base ThreadedDeclParser i…
Browse files Browse the repository at this point in the history
…mplementation. Subclasses just fill in the missing parsing routines.

Add a parseSynchronously() method to allow for parsing on the main thread (reloading entityDefs is using that).
FontLoader has been reverted to use a ThreadedDefLoader only, it's not really a decl parser.
EClassParser is now doing all the parsing business previously hosted in the EClassManager.
  • Loading branch information
codereader committed Mar 2, 2022
1 parent f5d9a92 commit cbcca64
Show file tree
Hide file tree
Showing 17 changed files with 525 additions and 279 deletions.
18 changes: 18 additions & 0 deletions include/idecltypes.h
@@ -1,5 +1,8 @@
#pragma once

#include <stdexcept>
#include <string>

namespace decl
{

Expand All @@ -14,4 +17,19 @@ enum class Type
Particle,
};

inline std::string getTypeName(Type type)
{
switch (type)
{
case Type::None: return "None";
case Type::Material: return "Material";
case Type::EntityDef: return "EntityDef";
case Type::SoundShader: return "SoundShader";
case Type::Model: return "Model";
case Type::Particle: return "Particle";
default:
throw std::runtime_error("Unhandled decl type");
}
}

}
9 changes: 4 additions & 5 deletions libs/debugging/ScopedDebugTimer.h
Expand Up @@ -92,7 +92,7 @@ class ScopedDebugTimer
: _op(name), _fps(showFps)
{
// Save start time
gettimeofday(&_s, NULL);
gettimeofday(&_s, nullptr);
}

/**
Expand All @@ -102,15 +102,14 @@ class ScopedDebugTimer
{
// Get the current time
timeval end;
gettimeofday(&end, NULL);
gettimeofday(&end, nullptr);

// Calculate duration
double duration = end - _s;

TemporaryThreadsafeStream stream = rMessage();
auto stream = rMessage();

stream << "[ScopedDebugTimer] \"" << _op << "\" in "
<< duration << " seconds";
stream << _op << " in " << duration << " seconds";

if (_fps)
{
Expand Down
68 changes: 61 additions & 7 deletions libs/parser/ThreadedDeclParser.h
@@ -1,7 +1,10 @@
#pragma once

#include "ifilesystem.h"
#include "itextstream.h"
#include "idecltypes.h"
#include "ThreadedDefLoader.h"
#include "debugging/ScopedDebugTimer.h"

namespace parser
{
Expand All @@ -18,16 +21,30 @@ class ThreadedDeclParser :
using LoadFunction = util::ThreadedDefLoader<ReturnType>::LoadFunction;

private:
decl::Type _declType;
std::string _baseDir;
std::string _extension;
std::size_t _depth;

protected:
// Construct a parser traversing all files matching the given extension in the given VFS path
// Subclasses need to implement the parse(std::istream) overload for this scenario
ThreadedDeclParser(decl::Type declType, const std::string& baseDir, const std::string& extension, std::size_t depth = 1) :
util::ThreadedDefLoader<typename ReturnType>(std::bind(&ThreadedDeclParser::doParse, this)),
_baseDir(baseDir),
_extension(extension),
_depth(depth),
_declType(declType)
{}

public:
// Legacy constructor
ThreadedDeclParser(const std::string& baseDir, const std::string& extension,
const LoadFunction& loadFunc) :
ThreadedDeclParser(baseDir, extension, 0, loadFunc)
{}

// Legacy constructor
ThreadedDeclParser(const std::string& baseDir, const std::string& extension, std::size_t depth,
const LoadFunction& loadFunc) :
util::ThreadedDefLoader<typename ReturnType>(loadFunc),
Expand All @@ -39,19 +56,39 @@ class ThreadedDeclParser :
virtual ~ThreadedDeclParser()
{}

// Bypass the threading, and just perform the parse routine
ReturnType parseSynchronously()
{
return doParse();
}

protected:
void loadFiles(const vfs::VirtualFileSystem::VisitorFunc& visitor)
virtual void onBeginParsing() {}
virtual ReturnType onFinishParsing() { return ReturnType(); }

// Main parse entry point, process all files
ReturnType doParse()
{
loadFiles(GlobalFileSystem(), visitor);
onBeginParsing();

processFiles();

return onFinishParsing();
}

void loadFiles(vfs::VirtualFileSystem& vfs, const vfs::VirtualFileSystem::VisitorFunc& visitor)
// Parse all decls found in the given stream. To be implemented by subclasses
virtual void parse(std::istream& stream, const vfs::FileInfo& fileInfo, const std::string& modDir)
{}

void processFiles()
{
// Accumulate all the files and sort them before calling the visitor
ScopedDebugTimer timer("[DeclParser] Parsed " + decl::getTypeName(_declType) + " declarations");

// Accumulate all the files and sort them before calling the protected parse() method
std::vector<vfs::FileInfo> _incomingFiles;
_incomingFiles.reserve(200);

vfs.forEachFile(_baseDir, _extension, [&](const vfs::FileInfo& info)
GlobalFileSystem().forEachFile(_baseDir, _extension, [&](const vfs::FileInfo& info)
{
_incomingFiles.push_back(info);
}, _depth);
Expand All @@ -62,8 +99,25 @@ class ThreadedDeclParser :
return a.name < b.name;
});

// Dispatch the sorted list to the visitor
std::for_each(_incomingFiles.begin(), _incomingFiles.end(), visitor);
// Dispatch the sorted list to the protected parse() method
for (const auto& fileInfo : _incomingFiles)
{
auto file = GlobalFileSystem().openTextFile(fileInfo.fullPath());

if (!file) continue;

try
{
// Parse entity defs from the file
std::istream stream(&file->getInputStream());
parse(stream, fileInfo, file->getModName());
}
catch (ParseException& e)
{
rError() << "[DeclParser] Failed to parse " << fileInfo.fullPath()
<< " (" << e.what() << ")" << std::endl;
}
}
}
};

Expand Down
1 change: 1 addition & 0 deletions radiantcore/CMakeLists.txt
Expand Up @@ -27,6 +27,7 @@ add_library(radiantcore MODULE
eclass/EntityClass.cpp
eclass/EClassColourManager.cpp
eclass/EClassManager.cpp
eclass/EClassParser.cpp
entity/AngleKey.cpp
entity/AttachmentData.cpp
entity/curve/CurveCatmullRom.cpp
Expand Down

0 comments on commit cbcca64

Please sign in to comment.