summaryrefslogtreecommitdiff
path: root/source/slang/slang-file-system.cpp
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2018-10-26 08:16:54 -0400
committerGitHub <noreply@github.com>2018-10-26 08:16:54 -0400
commitcb9d679a3a93c65c44904bf77811b9d74e431e23 (patch)
treebdc78bc01351f6eeed4714d01cd3aef6cf067109 /source/slang/slang-file-system.cpp
parentad47fe71defcc96a7bed87a4c3a40543978f0fb8 (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.cpp275
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