diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2018-10-26 08:16:54 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-10-26 08:16:54 -0400 |
| commit | cb9d679a3a93c65c44904bf77811b9d74e431e23 (patch) | |
| tree | bdc78bc01351f6eeed4714d01cd3aef6cf067109 /source/slang/slang-file-system.cpp | |
| parent | ad47fe71defcc96a7bed87a4c3a40543978f0fb8 (diff) | |
Feature/file system cache (#692)
* First pass at caching file system.
* default-file-system -> slang-file-system
fix problem with location("build.linux") confusing windows build for now.
* Added CompressedResult
Fix problem in Result construction with it being unsigned
* Add support for Path simplification.
* Testing for Path::Simplify.
* Refactored CacheFileSystem - automatically handles ISlangFileSystem or ISlangFileSystemExt appropriately.
Removed WrapFileSystem - because wasn't possible to emulate some of the behavior if just loadFile is implemented.
Split out StringBlob - so that no need to convert between ISlangBlob and String repeatidly.
* Remove unwanted code in ~CompileRequest
Diffstat (limited to 'source/slang/slang-file-system.cpp')
| -rw-r--r-- | source/slang/slang-file-system.cpp | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/source/slang/slang-file-system.cpp b/source/slang/slang-file-system.cpp new file mode 100644 index 000000000..ef77dbf33 --- /dev/null +++ b/source/slang/slang-file-system.cpp @@ -0,0 +1,275 @@ +#include "slang-file-system.h" + +#include "../../slang-com-ptr.h" +#include "../core/slang-io.h" +#include "../core/slang-string-util.h" + +#include "compiler.h" + +namespace Slang +{ + +// Allocate static const storage for the various interface IDs that the Slang API needs to expose +static const Guid IID_ISlangUnknown = SLANG_UUID_ISlangUnknown; +static const Guid IID_ISlangFileSystem = SLANG_UUID_ISlangFileSystem; +static const Guid IID_ISlangFileSystemExt = SLANG_UUID_ISlangFileSystemExt; + +// Cacluate a relative path, just using Path:: string processing +static SlangResult _calcRelativePath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut) +{ + String relPath; + switch (fromPathType) + { + case SLANG_PATH_TYPE_FILE: + { + relPath = Path::Combine(Path::GetDirectoryName(fromPath), path); + break; + } + case SLANG_PATH_TYPE_DIRECTORY: + { + relPath = Path::Combine(fromPath, path); + break; + } + } + + *pathOut = StringUtil::createStringBlob(relPath).detach(); + return SLANG_OK; +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!!! IncludeFileSystem !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ + +/* static */DefaultFileSystem DefaultFileSystem::s_singleton; + +template <typename T> +static ISlangFileSystemExt* _getInterface(T* ptr, const Guid& guid) +{ + return (guid == IID_ISlangUnknown || guid == IID_ISlangFileSystem || guid == IID_ISlangFileSystemExt) ? static_cast<ISlangFileSystemExt*>(ptr) : nullptr; +} + +ISlangUnknown* DefaultFileSystem::getInterface(const Guid& guid) +{ + return _getInterface(this, guid); +} + +SlangResult DefaultFileSystem::getCanoncialPath(const char* path, ISlangBlob** canonicalPathOut) +{ + String canonicalPath; + SLANG_RETURN_ON_FAIL(Path::GetCanonical(path, canonicalPath)); + + *canonicalPathOut = StringUtil::createStringBlob(canonicalPath).detach(); + return SLANG_OK; +} + +SlangResult DefaultFileSystem::calcRelativePath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut) +{ + return _calcRelativePath(fromPathType, fromPath, path, pathOut); +} + +SlangResult SLANG_MCALL DefaultFileSystem::getPathType( + const char* path, + SlangPathType* pathTypeOut) +{ + return Path::GetPathType(path, pathTypeOut); +} + +SlangResult DefaultFileSystem::loadFile(char const* path, ISlangBlob** outBlob) +{ + // Default implementation that uses the `core` libraries facilities for talking to the OS filesystem. + // + // TODO: we might want to conditionally compile these in, so that + // a user could create a build of Slang that doesn't include any OS + // filesystem calls. + + if (!File::Exists(path)) + { + return SLANG_E_NOT_FOUND; + } + + try + { + String sourceString = File::ReadAllText(path); + *outBlob = StringUtil::createStringBlob(sourceString).detach(); + return SLANG_OK; + } + catch (...) + { + } + return SLANG_E_CANNOT_OPEN; +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CacheFileSystem !!!!!!!!!!!!!!!!!!!!!!!!!!! + +/* static */ const Result CacheFileSystem::s_compressedResultToResult[] = +{ + SLANG_E_UNINITIALIZED, + SLANG_OK, ///< Ok + SLANG_E_NOT_FOUND, ///< File not found + SLANG_E_CANNOT_OPEN, ///< CannotOpen, + SLANG_FAIL, ///< Fail +}; + +/* static */CacheFileSystem::CompressedResult CacheFileSystem::toCompressedResult(Result res) +{ + if (SLANG_SUCCEEDED(res)) + { + return CompressedResult::Ok; + } + switch (res) + { + case SLANG_E_CANNOT_OPEN: return CompressedResult::CannotOpen; + case SLANG_E_NOT_FOUND: return CompressedResult::NotFound; + default: return CompressedResult::Fail; + } +} + +ISlangUnknown* CacheFileSystem::getInterface(const Guid& guid) +{ + return _getInterface(this, guid); +} + +CacheFileSystem::CacheFileSystem(ISlangFileSystem* fileSystem, bool useSimplifyForCanonicalPath) : + m_fileSystem(fileSystem), + m_useSimplifyForCanonicalPath(useSimplifyForCanonicalPath) +{ + // Try to get the more sophisticated interface + fileSystem->queryInterface(IID_ISlangFileSystemExt, (void**)m_fileSystemExt.writeRef()); +} + +CacheFileSystem::~CacheFileSystem() +{ + for (const auto& pair : m_canonicalMap) + { + delete pair.Value; + } +} + +CacheFileSystem::PathInfo* CacheFileSystem::_getPathInfo(const String& relPath) +{ + PathInfo** infoPtr = m_pathMap.TryGetValue(relPath); + if (infoPtr) + { + return *infoPtr; + } + + String canonicalPath; + if (m_fileSystemExt) + { + // Try getting the canonical path + // Okay request from the underlying file system the canonical path + ComPtr<ISlangBlob> canonicalBlob; + if (SLANG_FAILED(m_fileSystemExt->getCanoncialPath(relPath.Buffer(), canonicalBlob.writeRef()))) + { + // Write in result as being null ptr so not tried again + m_pathMap.Add(relPath, nullptr); + return nullptr; + } + // Get the path as a string + canonicalPath = StringUtil::getString(canonicalBlob); + } + else + { + canonicalPath = m_useSimplifyForCanonicalPath ? Path::Simplify(relPath.getUnownedSlice()) : relPath; + } + + PathInfo* pathInfo; + infoPtr = m_canonicalMap.TryGetValue(canonicalPath); + if (infoPtr) + { + pathInfo = *infoPtr; + } + else + { + // Create and add to canonical path + pathInfo = new PathInfo(canonicalPath); + m_canonicalMap.Add(canonicalPath, pathInfo); + } + + // Add the relPath + m_pathMap.Add(relPath, pathInfo); + return pathInfo; +} + +SlangResult CacheFileSystem::loadFile(char const* pathIn, ISlangBlob** blobOut) +{ + *blobOut = nullptr; + String path(pathIn); + PathInfo* info = _getPathInfo(path); + if (!info) + { + return SLANG_FAIL; + } + + if (info->m_loadFileResult == CompressedResult::Uninitialized) + { + info->m_loadFileResult = toCompressedResult(m_fileSystem->loadFile(path.Buffer(), info->m_fileBlob.writeRef())); + } + + *blobOut = info->m_fileBlob; + if (*blobOut) + { + (*blobOut)->addRef(); + } + return toResult(info->m_loadFileResult); +} + +SlangResult CacheFileSystem::getCanoncialPath(const char* path, ISlangBlob** canonicalPathOut) +{ + PathInfo* info = _getPathInfo(path); + if (!info) + { + return SLANG_E_NOT_FOUND; + } + info->m_canonicalPath->addRef(); + *canonicalPathOut = info->m_canonicalPath; + return SLANG_OK; +} + +SlangResult CacheFileSystem::calcRelativePath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut) +{ + // Just defer to contained implementation + if (m_fileSystemExt) + { + return m_fileSystemExt->calcRelativePath(fromPathType, fromPath, path, pathOut); + } + else + { + // Just use the default implementation + return _calcRelativePath(fromPathType, fromPath, path, pathOut); + } +} + +SlangResult CacheFileSystem::getPathType(const char* pathIn, SlangPathType* pathTypeOut) +{ + String path(pathIn); + PathInfo* info = _getPathInfo(path); + if (!info) + { + return SLANG_E_NOT_FOUND; + } + + if (info->m_getPathTypeResult == CompressedResult::Uninitialized) + { + if (m_fileSystemExt) + { + info->m_getPathTypeResult = toCompressedResult(m_fileSystemExt->getPathType(pathIn, &info->m_pathType)); + } + else + { + // Okay try to load the file + if (info->m_loadFileResult == CompressedResult::Uninitialized) + { + info->m_loadFileResult = toCompressedResult(m_fileSystem->loadFile(path.Buffer(), info->m_fileBlob.writeRef())); + } + + // Make the getPathResult the same as the load result + info->m_getPathTypeResult = info->m_loadFileResult; + // Just set to file... the result is what matters in this case + info->m_pathType = SLANG_PATH_TYPE_FILE; + } + } + + *pathTypeOut = info->m_pathType; + return toResult(info->m_getPathTypeResult); +} + +}
\ No newline at end of file |
