diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2021-04-01 13:39:11 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-04-01 10:39:11 -0700 |
| commit | fa31d21ba92669a521a7768467246918e3947e02 (patch) | |
| tree | af98a593e24bc6309ac4d11a59562be4b22c93d7 /source/compiler-core/slang-downstream-compiler.cpp | |
| parent | 3f1632a1450a5879f337b4bd178e48880cd583f8 (diff) | |
Added compiler-core project (#1775)
* #include an absolute path didn't work - because paths were taken to always be relative.
* Split out compiler-core initially with just slang-source-loc.cpp
* More lexer, name, token to compiler-core.
* Split Lexer and Core diagnostics.
* Move slang-file-system to core.
* Add slang-file-system to core.
* More DownstreamCompiler into compiler-core
* Fix typo.
* Add compiler-core to bootstrap proj.
* Small fixes to premake
* For linux try with compiler-core
* Remove compiler-core from examples.
* Added NameConventionUtil to compiler-core
* Add global function to CharUtil to *hopefully* avoid linking issue.
* Hack to make linkage of CharUtil work on linux.
Diffstat (limited to 'source/compiler-core/slang-downstream-compiler.cpp')
| -rw-r--r-- | source/compiler-core/slang-downstream-compiler.cpp | 716 |
1 files changed, 716 insertions, 0 deletions
diff --git a/source/compiler-core/slang-downstream-compiler.cpp b/source/compiler-core/slang-downstream-compiler.cpp new file mode 100644 index 000000000..696376b49 --- /dev/null +++ b/source/compiler-core/slang-downstream-compiler.cpp @@ -0,0 +1,716 @@ +// slang-downstream-compiler.cpp +#include "slang-downstream-compiler.h" + +#include "../core/slang-common.h" +#include "../../slang-com-helper.h" +#include "../core/slang-string-util.h" + +#include "../core/slang-type-text-util.h" + +#include "../core/slang-io.h" +#include "../core/slang-shared-library.h" +#include "../core/slang-blob.h" + +#ifdef SLANG_VC +# include "windows/slang-win-visual-studio-util.h" +#endif + +#include "slang-visual-studio-compiler-util.h" +#include "slang-gcc-compiler-util.h" +#include "slang-nvrtc-compiler.h" + +namespace Slang +{ + +static DownstreamCompiler::Infos _calcInfos() +{ + typedef DownstreamCompiler::Info Info; + typedef DownstreamCompiler::SourceLanguageFlag SourceLanguageFlag; + typedef DownstreamCompiler::SourceLanguageFlags SourceLanguageFlags; + + DownstreamCompiler::Infos infos; + + infos.infos[int(SLANG_PASS_THROUGH_CLANG)] = Info(SourceLanguageFlag::CPP | SourceLanguageFlag::C); + infos.infos[int(SLANG_PASS_THROUGH_VISUAL_STUDIO)] = Info(SourceLanguageFlag::CPP | SourceLanguageFlag::C); + infos.infos[int(SLANG_PASS_THROUGH_GCC)] = Info(SourceLanguageFlag::CPP | SourceLanguageFlag::C); + + infos.infos[int(SLANG_PASS_THROUGH_NVRTC)] = Info(SourceLanguageFlag::CUDA); + + infos.infos[int(SLANG_PASS_THROUGH_DXC)] = Info(SourceLanguageFlag::HLSL); + infos.infos[int(SLANG_PASS_THROUGH_FXC)] = Info(SourceLanguageFlag::HLSL); + infos.infos[int(SLANG_PASS_THROUGH_GLSLANG)] = Info(SourceLanguageFlag::GLSL); + + return infos; +} + +/* static */DownstreamCompiler::Infos DownstreamCompiler::s_infos = _calcInfos(); + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DownstreamCompiler::Desc !!!!!!!!!!!!!!!!!!!!!!*/ + +void DownstreamCompiler::Desc::appendAsText(StringBuilder& out) const +{ + out << TypeTextUtil::getPassThroughAsHumanText(type); + + // Append the version if there is a version + if (majorVersion || minorVersion) + { + out << " "; + out << majorVersion; + out << "."; + out << minorVersion; + } +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DownstreamDiagnostic !!!!!!!!!!!!!!!!!!!!!!!!*/ + +/* static */UnownedStringSlice DownstreamDiagnostic::getSeverityText(Severity severity) +{ + switch (severity) + { + default: return UnownedStringSlice::fromLiteral("Unknown"); + case Severity::Info: return UnownedStringSlice::fromLiteral("Info"); + case Severity::Warning: return UnownedStringSlice::fromLiteral("Warning"); + case Severity::Error: return UnownedStringSlice::fromLiteral("Error"); + } +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DownstreamCompiler !!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ + + +/* static */bool DownstreamCompiler::canCompile(SlangPassThrough compiler, SlangSourceLanguage sourceLanguage) +{ + const auto& info = getInfo(compiler); + return (info.sourceLanguageFlags & (SourceLanguageFlags(1) << int(sourceLanguage))) != 0; +} + +/* static */SlangCompileTarget DownstreamCompiler::getCompileTarget(SlangSourceLanguage sourceLanguage) +{ + switch (sourceLanguage) + { + case SLANG_SOURCE_LANGUAGE_HLSL: return SLANG_HLSL; + case SLANG_SOURCE_LANGUAGE_GLSL: return SLANG_GLSL; + case SLANG_SOURCE_LANGUAGE_C: return SLANG_C_SOURCE; + case SLANG_SOURCE_LANGUAGE_CPP: return SLANG_CPP_SOURCE; + case SLANG_SOURCE_LANGUAGE_CUDA: return SLANG_CUDA_SOURCE; + default: return SLANG_TARGET_UNKNOWN; + } +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DownstreamDiagnostics !!!!!!!!!!!!!!!!!!!!!!*/ + +Index DownstreamDiagnostics::getCountBySeverity(Diagnostic::Severity severity) const +{ + Index count = 0; + for (const auto& msg : diagnostics) + { + count += Index(msg.severity == severity); + } + return count; +} + +Int DownstreamDiagnostics::countByStage(Diagnostic::Stage stage, Index counts[Int(Diagnostic::Severity::CountOf)]) const +{ + Int count = 0; + ::memset(counts, 0, sizeof(Index) * Int(Diagnostic::Severity::CountOf)); + for (const auto& diagnostic : diagnostics) + { + if (diagnostic.stage == stage) + { + count++; + counts[Index(diagnostic.severity)]++; + } + } + return count++; +} + +static void _appendCounts(const Index counts[Int(DownstreamDiagnostic::Severity::CountOf)], StringBuilder& out) +{ + typedef DownstreamDiagnostic::Severity Severity; + + for (Index i = 0; i < Int(Severity::CountOf); i++) + { + if (counts[i] > 0) + { + out << DownstreamDiagnostic::getSeverityText(Severity(i)) << "(" << counts[i] << ") "; + } + } +} + +static void _appendSimplified(const Index counts[Int(DownstreamDiagnostic::Severity::CountOf)], StringBuilder& out) +{ + typedef DownstreamDiagnostic::Severity Severity; + for (Index i = 0; i < Int(Severity::CountOf); i++) + { + if (counts[i] > 0) + { + out << DownstreamDiagnostic::getSeverityText(Severity(i)) << " "; + } + } +} + +void DownstreamDiagnostics::appendSummary(StringBuilder& out) const +{ + Index counts[Int(Diagnostic::Severity::CountOf)]; + if (countByStage(Diagnostic::Stage::Compile, counts) > 0) + { + out << "Compile: "; + _appendCounts(counts, out); + out << "\n"; + } + if (countByStage(Diagnostic::Stage::Link, counts) > 0) + { + out << "Link: "; + _appendCounts(counts, out); + out << "\n"; + } +} + +void DownstreamDiagnostics::appendSimplifiedSummary(StringBuilder& out) const +{ + Index counts[Int(Diagnostic::Severity::CountOf)]; + if (countByStage(Diagnostic::Stage::Compile, counts) > 0) + { + out << "Compile: "; + _appendSimplified(counts, out); + out << "\n"; + } + if (countByStage(Diagnostic::Stage::Link, counts) > 0) + { + out << "Link: "; + _appendSimplified(counts, out); + out << "\n"; + } +} + +void DownstreamDiagnostics::removeBySeverity(Diagnostic::Severity severity) +{ + Index count = diagnostics.getCount(); + for (Index i = 0; i < count; ++i) + { + if (diagnostics[i].severity == severity) + { + diagnostics.removeAt(i); + i--; + count--; + } + } +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CommandLineDownstreamCompileResult !!!!!!!!!!!!!!!!!!!!!!*/ + +SlangResult CommandLineDownstreamCompileResult::getHostCallableSharedLibrary(ComPtr<ISlangSharedLibrary>& outLibrary) +{ + if (m_hostCallableSharedLibrary) + { + outLibrary = m_hostCallableSharedLibrary; + return SLANG_OK; + } + + // Okay we want to load + // Try loading the shared library + SharedLibrary::Handle handle; + if (SLANG_FAILED(SharedLibrary::loadWithPlatformPath(m_moduleFilePath.getBuffer(), handle))) + { + return SLANG_FAIL; + } + // The shared library needs to keep temp files in scope + RefPtr<TemporarySharedLibrary> sharedLib(new TemporarySharedLibrary(handle, m_moduleFilePath)); + sharedLib->m_temporaryFileSet = m_temporaryFiles; + + m_hostCallableSharedLibrary = sharedLib; + outLibrary = m_hostCallableSharedLibrary; + return SLANG_OK; +} + +SlangResult CommandLineDownstreamCompileResult::getBinary(ComPtr<ISlangBlob>& outBlob) +{ + if (m_binaryBlob) + { + outBlob = m_binaryBlob; + return SLANG_OK; + } + + // Read the binary + try + { + // Read the contents of the binary + List<uint8_t> contents = File::readAllBytes(m_moduleFilePath); + + m_binaryBlob = new ScopeRefObjectBlob(ListBlob::moveCreate(contents), m_temporaryFiles); + outBlob = m_binaryBlob; + return SLANG_OK; + } + catch (const Slang::IOException&) + { + return SLANG_FAIL; + } +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CommandLineDownstreamCompiler !!!!!!!!!!!!!!!!!!!!!!*/ + +static bool _isContentsInFile(const DownstreamCompiler::CompileOptions& options) +{ + if (options.sourceContentsPath.getLength() <= 0) + { + return false; + } + + // We can see if we can load it + if (File::exists(options.sourceContentsPath)) + { + // Here we look for the file on the regular file system (as opposed to using the + // ISlangFileSystem. This is unfortunate but necessary - because when we call out + // to the compiler all it is able to (currently) see are files on the file system. + // + // Note that it could be coincidence that the filesystem has a file that's identical in + // contents/name. That being the case though, any includes wouldn't work for a generated + // file either from some specialized ISlangFileSystem, so this is probably as good as it gets + // until we can integrate directly to a C/C++ compiler through say a shared library where we can control + // file system access. + try + { + String readContents = File::readAllText(options.sourceContentsPath); + // We should see if they are the same + return options.sourceContents == readContents.getUnownedSlice(); + } + catch (const Slang::IOException&) + { + } + } + return false; +} + +SlangResult CommandLineDownstreamCompiler::compile(const CompileOptions& inOptions, RefPtr<DownstreamCompileResult>& out) +{ + // Copy the command line options + CommandLine cmdLine(m_cmdLine); + + CompileOptions options(inOptions); + + // Find all the files that will be produced + RefPtr<TemporaryFileSet> productFileSet(new TemporaryFileSet); + + if (options.modulePath.getLength() == 0 || options.sourceContents.getLength() != 0) + { + String modulePath = options.modulePath; + + // If there is no module path, generate one. + if (modulePath.getLength() == 0) + { + SLANG_RETURN_ON_FAIL(File::generateTemporary(UnownedStringSlice::fromLiteral("slang-generated"), modulePath)); + options.modulePath = modulePath; + } + + if (_isContentsInFile(options)) + { + options.sourceFiles.add(options.sourceContentsPath); + } + else + { + String compileSourcePath = modulePath; + + // NOTE: Strictly speaking producing filenames by modifying the generateTemporary path that may introduce a temp filename clash, but in practice is extraordinary unlikely + compileSourcePath.append("-src"); + + // Make the temporary filename have the appropriate extension. + if (options.sourceLanguage == SLANG_SOURCE_LANGUAGE_C) + { + compileSourcePath.append(".c"); + } + else + { + compileSourcePath.append(".cpp"); + } + + // Write it out + try + { + productFileSet->add(compileSourcePath); + + File::writeAllText(compileSourcePath, options.sourceContents); + } + catch (...) + { + return SLANG_FAIL; + } + + // Add it as a source file + options.sourceFiles.add(compileSourcePath); + } + + // There is no source contents + options.sourceContents = String(); + options.sourceContentsPath = String(); + } + + // Append command line args to the end of cmdLine using the target specific function for the specified options + SLANG_RETURN_ON_FAIL(calcArgs(options, cmdLine)); + + String moduleFilePath; + + { + StringBuilder builder; + SLANG_RETURN_ON_FAIL(calcModuleFilePath(options, builder)); + moduleFilePath = builder.ProduceString(); + } + + { + List<String> paths; + SLANG_RETURN_ON_FAIL(calcCompileProducts(options, DownstreamCompiler::ProductFlag::All, paths)); + productFileSet->add(paths); + } + + ExecuteResult exeRes; + +#if 0 + // Test + { + String line = ProcessUtil::getCommandLineString(cmdLine); + printf("%s", line.getBuffer()); + } +#endif + + SLANG_RETURN_ON_FAIL(ProcessUtil::execute(cmdLine, exeRes)); + +#if 0 + { + printf("stdout=\"%s\"\nstderr=\"%s\"\nret=%d\n", exeRes.standardOutput.getBuffer(), exeRes.standardError.getBuffer(), int(exeRes.resultCode)); + } +#endif + + DownstreamDiagnostics diagnostics; + SLANG_RETURN_ON_FAIL(parseOutput(exeRes, diagnostics)); + + + out = new CommandLineDownstreamCompileResult(diagnostics, moduleFilePath, productFileSet); + + return SLANG_OK; +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!! DownstreamCompiler::Desc !!!!!!!!!!!!!!!!!!!!!!*/ + +static DownstreamCompiler::Desc _calcCompiledWithDesc() +{ + DownstreamCompiler::Desc desc; + +#if SLANG_VC + desc = WinVisualStudioUtil::getDesc(WinVisualStudioUtil::getCompiledVersion()); +#elif SLANG_CLANG + desc.type = SLANG_PASS_THROUGH_CLANG; + desc.majorVersion = Int(__clang_major__); + desc.minorVersion = Int(__clang_minor__); +#elif SLANG_GCC + desc.type = SLANG_PASS_THROUGH_GCC; + desc.majorVersion = Int(__GNUC__); + desc.minorVersion = Int(__GNUC_MINOR__); +#else + // TODO(JS): Hmmm None is not quite the same as unknown. It works for now, but we might want to have a distinct enum for unknown. + desc.type = SLANG_PASS_THROUGH_NONE; +#endif + + return desc; +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!! DownstreamCompilerUtil !!!!!!!!!!!!!!!!!!!!!!*/ + +const DownstreamCompiler::Desc& DownstreamCompilerUtil::getCompiledWithDesc() +{ + static DownstreamCompiler::Desc s_desc = _calcCompiledWithDesc(); + return s_desc; +} + +/* static */DownstreamCompiler* DownstreamCompilerUtil::findCompiler(const DownstreamCompilerSet* set, MatchType matchType, const DownstreamCompiler::Desc& desc) +{ + List<DownstreamCompiler*> compilers; + set->getCompilers(compilers); + return findCompiler(compilers, matchType, desc); +} + +/* static */DownstreamCompiler* DownstreamCompilerUtil::findCompiler(const List<DownstreamCompiler*>& compilers, MatchType matchType, const DownstreamCompiler::Desc& desc) +{ + if (compilers.getCount() <= 0) + { + return nullptr; + } + + Int bestIndex = -1; + + const SlangPassThrough compilerType = desc.type; + + Int maxVersionValue = 0; + Int minVersionDiff = 0x7fffffff; + + Int descVersionValue = desc.getVersionValue(); + + // If we don't have version set, then anything 0 or above is good enough, and just take newest + if (descVersionValue == 0) + { + maxVersionValue = -1; + matchType = MatchType::Newest; + } + + for (Index i = 0; i < compilers.getCount(); ++i) + { + DownstreamCompiler* compiler = compilers[i]; + auto compilerDesc = compiler->getDesc(); + + if (compilerType == compilerDesc.type) + { + const Int versionValue = compilerDesc.getVersionValue(); + switch (matchType) + { + case MatchType::MinGreaterEqual: + { + auto diff = descVersionValue - versionValue; + if (diff >= 0 && diff < minVersionDiff) + { + bestIndex = i; + minVersionDiff = diff; + } + break; + } + case MatchType::MinAbsolute: + { + auto diff = descVersionValue - versionValue; + diff = (diff >= 0) ? diff : -diff; + if (diff < minVersionDiff) + { + bestIndex = i; + minVersionDiff = diff; + } + break; + } + case MatchType::Newest: + { + if (versionValue > maxVersionValue) + { + maxVersionValue = versionValue; + bestIndex = i; + } + break; + } + } + } + } + + return (bestIndex >= 0) ? compilers[bestIndex] : nullptr; +} + +/* static */DownstreamCompiler* DownstreamCompilerUtil::findClosestCompiler(const List<DownstreamCompiler*>& compilers, const DownstreamCompiler::Desc& desc) +{ + DownstreamCompiler* compiler; + + compiler = findCompiler(compilers, MatchType::MinGreaterEqual, desc); + if (compiler) + { + return compiler; + } + compiler = findCompiler(compilers, MatchType::MinAbsolute, desc); + if (compiler) + { + return compiler; + } + + // If we are gcc, we can try clang and vice versa + if (desc.type == SLANG_PASS_THROUGH_GCC || desc.type == SLANG_PASS_THROUGH_CLANG) + { + DownstreamCompiler::Desc compatible = desc; + compatible.type = (compatible.type == SLANG_PASS_THROUGH_CLANG) ? SLANG_PASS_THROUGH_GCC : SLANG_PASS_THROUGH_CLANG; + + compiler = findCompiler(compilers, MatchType::MinGreaterEqual, compatible); + if (compiler) + { + return compiler; + } + compiler = findCompiler(compilers, MatchType::MinAbsolute, compatible); + if (compiler) + { + return compiler; + } + } + + return nullptr; +} + +/* static */DownstreamCompiler* DownstreamCompilerUtil::findClosestCompiler(const DownstreamCompilerSet* set, const DownstreamCompiler::Desc& desc) +{ + DownstreamCompiler* compiler = set->getCompiler(desc); + if (compiler) + { + return compiler; + } + List<DownstreamCompiler*> compilers; + set->getCompilers(compilers); + return findClosestCompiler(compilers, desc); +} + +/* static */void DownstreamCompilerUtil::updateDefault(DownstreamCompilerSet* set, SlangSourceLanguage sourceLanguage) +{ + DownstreamCompiler* compiler = nullptr; + + switch (sourceLanguage) + { + case SLANG_SOURCE_LANGUAGE_CPP: + case SLANG_SOURCE_LANGUAGE_C: + { + compiler = findClosestCompiler(set, getCompiledWithDesc()); + break; + } + case SLANG_SOURCE_LANGUAGE_CUDA: + { + DownstreamCompiler::Desc desc; + desc.type = SLANG_PASS_THROUGH_NVRTC; + compiler = findCompiler(set, MatchType::Newest, desc); + break; + } + default: break; + } + + set->setDefaultCompiler(sourceLanguage, compiler); +} + +/* static */void DownstreamCompilerUtil::updateDefaults(DownstreamCompilerSet* set) +{ + for (Index i = 0; i < Index(SLANG_SOURCE_LANGUAGE_COUNT_OF); ++i) + { + updateDefault(set, SlangSourceLanguage(i)); + } +} + +static SlangResult _locateDXCCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set) +{ + // First try dxil, so it's loaded from the same path if it's there + ComPtr<ISlangSharedLibrary> dxil; + DefaultSharedLibraryLoader::load(loader, path, "dxil", dxil.writeRef()); + + ComPtr<ISlangSharedLibrary> sharedLibrary; + if (SLANG_SUCCEEDED(DefaultSharedLibraryLoader::load(loader, path, "dxcompiler", sharedLibrary.writeRef()))) + { + // Can we determine the version? + DownstreamCompiler::Desc desc(SLANG_PASS_THROUGH_DXC); + RefPtr<DownstreamCompiler> compiler(new SharedLibraryDownstreamCompiler(desc, sharedLibrary)); + + set->addCompiler(compiler); + } + return SLANG_OK; +} + +static SlangResult _locateFXCCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set) +{ + ComPtr<ISlangSharedLibrary> sharedLibrary; + if (SLANG_SUCCEEDED(DefaultSharedLibraryLoader::load(loader, path, "d3dcompiler_47", sharedLibrary.writeRef()))) + { + // Can we determine the version? + DownstreamCompiler::Desc desc(SLANG_PASS_THROUGH_FXC); + RefPtr<DownstreamCompiler> compiler(new SharedLibraryDownstreamCompiler(desc, sharedLibrary)); + set->addCompiler(compiler); + } + return SLANG_OK; +} + +static SlangResult _locateGlslangCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set) +{ +#if SLANG_UNIX_FAMILY + // On unix systems we need to ensure pthread is loaded first. + ComPtr<ISlangSharedLibrary> pthreadLibrary; + DefaultSharedLibraryLoader::load(loader, path, "pthread", pthreadLibrary.writeRef()); +#endif + ComPtr<ISlangSharedLibrary> sharedLibrary; + if (SLANG_SUCCEEDED(DefaultSharedLibraryLoader::load(loader, path, "slang-glslang", sharedLibrary.writeRef()))) + { + // Can we determine the version? + DownstreamCompiler::Desc desc(SLANG_PASS_THROUGH_GLSLANG); + RefPtr<DownstreamCompiler> compiler(new SharedLibraryDownstreamCompiler(desc, sharedLibrary)); + set->addCompiler(compiler); + } + return SLANG_OK; +} + +/* static */void DownstreamCompilerUtil::setDefaultLocators(DownstreamCompilerLocatorFunc outFuncs[int(SLANG_PASS_THROUGH_COUNT_OF)]) +{ + outFuncs[int(SLANG_PASS_THROUGH_VISUAL_STUDIO)] = &VisualStudioCompilerUtil::locateCompilers; + outFuncs[int(SLANG_PASS_THROUGH_CLANG)] = &GCCDownstreamCompilerUtil::locateClangCompilers; + outFuncs[int(SLANG_PASS_THROUGH_GCC)] = &GCCDownstreamCompilerUtil::locateGCCCompilers; + outFuncs[int(SLANG_PASS_THROUGH_NVRTC)] = &NVRTCDownstreamCompilerUtil::locateCompilers; + outFuncs[int(SLANG_PASS_THROUGH_DXC)] = &_locateDXCCompilers; + outFuncs[int(SLANG_PASS_THROUGH_FXC)] = &_locateFXCCompilers; + outFuncs[int(SLANG_PASS_THROUGH_GLSLANG)] = &_locateGlslangCompilers; +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DownstreamCompilerSet !!!!!!!!!!!!!!!!!!!!!!*/ + +void DownstreamCompilerSet::getCompilerDescs(List<DownstreamCompiler::Desc>& outCompilerDescs) const +{ + outCompilerDescs.clear(); + for (DownstreamCompiler* compiler : m_compilers) + { + outCompilerDescs.add(compiler->getDesc()); + } +} + +Index DownstreamCompilerSet::_findIndex(const DownstreamCompiler::Desc& desc) const +{ + const Index count = m_compilers.getCount(); + for (Index i = 0; i < count; ++i) + { + if (m_compilers[i]->getDesc() == desc) + { + return i; + } + } + return -1; +} + +DownstreamCompiler* DownstreamCompilerSet::getCompiler(const DownstreamCompiler::Desc& compilerDesc) const +{ + const Index index = _findIndex(compilerDesc); + return index >= 0 ? m_compilers[index] : nullptr; +} + +void DownstreamCompilerSet::getCompilers(List<DownstreamCompiler*>& outCompilers) const +{ + outCompilers.clear(); + outCompilers.addRange((DownstreamCompiler*const*)m_compilers.begin(), m_compilers.getCount()); +} + +bool DownstreamCompilerSet::hasCompiler(SlangPassThrough compilerType) const +{ + for (DownstreamCompiler* compiler : m_compilers) + { + const auto& desc = compiler->getDesc(); + if (desc.type == compilerType) + { + return true; + } + } + return false; +} + + +void DownstreamCompilerSet::remove(SlangPassThrough compilerType) +{ + for (Index i = 0; i < m_compilers.getCount(); ++i) + { + DownstreamCompiler* compiler = m_compilers[i]; + if (compiler->getDesc().type == compilerType) + { + m_compilers.fastRemoveAt(i); + i--; + } + } +} + +void DownstreamCompilerSet::addCompiler(DownstreamCompiler* compiler) +{ + const Index index = _findIndex(compiler->getDesc()); + if (index >= 0) + { + m_compilers[index] = compiler; + } + else + { + m_compilers.add(compiler); + } +} + +} |
