summaryrefslogtreecommitdiff
path: root/source/slang/slang-file-system.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/slang-file-system.cpp')
-rw-r--r--source/slang/slang-file-system.cpp196
1 files changed, 127 insertions, 69 deletions
diff --git a/source/slang/slang-file-system.cpp b/source/slang/slang-file-system.cpp
index caaa9f56d..96dcc7558 100644
--- a/source/slang/slang-file-system.cpp
+++ b/source/slang/slang-file-system.cpp
@@ -38,7 +38,7 @@ static SlangResult _calcCombinedPath(SlangPathType fromPathType, const char* fro
/* !!!!!!!!!!!!!!!!!!!!!!!!!! IncludeFileSystem !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
-/* static */DefaultFileSystem DefaultFileSystem::s_singleton;
+/* static */OSFileSystem OSFileSystem::s_singleton;
template <typename T>
static ISlangFileSystemExt* _getInterface(T* ptr, const Guid& guid)
@@ -46,33 +46,43 @@ 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)
+ISlangUnknown* OSFileSystem::getInterface(const Guid& guid)
{
return _getInterface(this, guid);
}
-SlangResult DefaultFileSystem::getCanoncialPath(const char* path, ISlangBlob** canonicalPathOut)
+static String _fixPathDelimiters(const char* pathIn)
+{
+#if SLANG_WINDOWS_FAMILY
+ return pathIn;
+#else
+ // To allow windows style \ delimiters on other platforms, we convert to our standard delimiter
+ String path(pathIn);
+ return StringUtil::calcCharReplaced(pathIn, '\\', Path::PathDelimiter);
+#endif
+}
+
+SlangResult OSFileSystem::getCanoncialPath(const char* pathIn, ISlangBlob** canonicalPathOut)
{
String canonicalPath;
- SLANG_RETURN_ON_FAIL(Path::GetCanonical(path, canonicalPath));
+ SLANG_RETURN_ON_FAIL(Path::GetCanonical(_fixPathDelimiters(pathIn), canonicalPath));
*canonicalPathOut = StringUtil::createStringBlob(canonicalPath).detach();
return SLANG_OK;
}
-SlangResult DefaultFileSystem::calcCombinedPath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut)
+SlangResult OSFileSystem::calcCombinedPath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut)
{
+ // Don't need to fix delimiters - because combine path handles both path delimiter types
return _calcCombinedPath(fromPathType, fromPath, path, pathOut);
}
-SlangResult SLANG_MCALL DefaultFileSystem::getPathType(
- const char* path,
- SlangPathType* pathTypeOut)
+SlangResult SLANG_MCALL OSFileSystem::getPathType(const char* pathIn, SlangPathType* pathTypeOut)
{
- return Path::GetPathType(path, pathTypeOut);
+ return Path::GetPathType(_fixPathDelimiters(pathIn), pathTypeOut);
}
-SlangResult DefaultFileSystem::loadFile(char const* path, ISlangBlob** outBlob)
+SlangResult OSFileSystem::loadFile(char const* pathIn, ISlangBlob** outBlob)
{
// Default implementation that uses the `core` libraries facilities for talking to the OS filesystem.
//
@@ -80,6 +90,7 @@ SlangResult DefaultFileSystem::loadFile(char const* path, ISlangBlob** outBlob)
// a user could create a build of Slang that doesn't include any OS
// filesystem calls.
+ const String path = _fixPathDelimiters(pathIn);
if (!File::Exists(path))
{
return SLANG_E_NOT_FOUND;
@@ -139,11 +150,12 @@ CacheFileSystem::CacheFileSystem(ISlangFileSystem* fileSystem, CanonicalMode can
case CanonicalMode::Default:
case CanonicalMode::FileSystemExt:
{
- m_canonicalMode = m_fileSystemExt ? CanonicalMode::FileSystemExt : CanonicalMode::Hash;
+ m_canonicalMode = m_fileSystemExt ? CanonicalMode::FileSystemExt : CanonicalMode::SimplifyPathAndHash;
break;
}
default: break;
}
+
// It can't be default
SLANG_ASSERT(m_canonicalMode != CanonicalMode::Default);
}
@@ -156,32 +168,26 @@ CacheFileSystem::~CacheFileSystem()
}
}
-CacheFileSystem::PathInfo* CacheFileSystem::_getPathInfoFromCanonical(const String& canonicalPath)
+// Determines if we can simplify a path for a given mode
+static bool _canSimplifyPath(CacheFileSystem::CanonicalMode mode)
{
- // First see if we have it.. if not add it
- PathInfo** infoPtr = m_canonicalMap.TryGetValue(canonicalPath);
- if (infoPtr)
- {
- return *infoPtr;
- }
- else
+ typedef CacheFileSystem::CanonicalMode CanonicalMode;
+ switch (mode)
{
- // Create and add to canonical path
- PathInfo* pathInfo = new PathInfo(canonicalPath);
- m_canonicalMap.Add(canonicalPath, pathInfo);
- return pathInfo;
+ case CanonicalMode::SimplifyPath:
+ case CanonicalMode::SimplifyPathAndHash:
+ {
+ return true;
+ }
+ default:
+ {
+ return false;
+ }
}
}
-CacheFileSystem::PathInfo* CacheFileSystem::_getPathInfo(const String& relPath)
+SlangResult CacheFileSystem::_calcCanonicalPath(const String& path, String& outCanonicalPath, ComPtr<ISlangBlob>& outFileContents)
{
- PathInfo** infoPtr = m_pathMap.TryGetValue(relPath);
- if (infoPtr)
- {
- return *infoPtr;
- }
-
- PathInfo* pathInfo = nullptr;
switch (m_canonicalMode)
{
case CanonicalMode::FileSystemExt:
@@ -189,66 +195,118 @@ CacheFileSystem::PathInfo* CacheFileSystem::_getPathInfo(const String& relPath)
// 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;
- }
+ SLANG_RETURN_ON_FAIL(m_fileSystemExt->getCanoncialPath(path.Buffer(), canonicalBlob.writeRef()));
// Get the path as a string
- String canonicalPath = StringUtil::getString(canonicalBlob);
- pathInfo = _getPathInfoFromCanonical(canonicalPath);
- break;
+ outCanonicalPath = StringUtil::getString(canonicalBlob);
+ return SLANG_OK;
}
case CanonicalMode::Path:
{
- pathInfo = _getPathInfoFromCanonical(relPath);
- break;
+ outCanonicalPath = path;
+ return SLANG_OK;
}
- case CanonicalMode::SimplifiedPath:
+ case CanonicalMode::SimplifyPath:
{
- pathInfo = _getPathInfoFromCanonical(Path::Simplify(relPath.getUnownedSlice()));
- break;
+ outCanonicalPath = Path::Simplify(path);
+ // If it still has relative elements can't uniquely identify, so give up
+ return Path::IsRelative(outCanonicalPath) ? SLANG_FAIL : SLANG_OK;
}
+ case CanonicalMode::SimplifyPathAndHash:
case CanonicalMode::Hash:
{
// I can only see if this is the same file as already loaded by loading the file and doing a hash
- ComPtr<ISlangBlob> fileBlob;
- Result res = m_fileSystem->loadFile(relPath.Buffer(), fileBlob.writeRef());
- if (SLANG_FAILED(res) || fileBlob == nullptr)
+ Result res = m_fileSystem->loadFile(path.Buffer(), outFileContents.writeRef());
+ if (SLANG_FAILED(res) || outFileContents == nullptr)
{
- // Write in result as being null ptr so not tried again
- m_pathMap.Add(relPath, nullptr);
- return nullptr;
+ return SLANG_FAIL;
}
-
+
// Calculate the hash on the contents
- const uint64_t hash = GetHashCode64((const char*)fileBlob->getBufferPointer(), fileBlob->getBufferSize());
+ const uint64_t hash = GetHashCode64((const char*)outFileContents->getBufferPointer(), outFileContents->getBufferSize());
- String hashString = Path::GetFileName(relPath);
+ String hashString = Path::GetFileName(path);
hashString = hashString.ToLower();
hashString.append(':');
// The canonical name is.. combination of name and hash
hashString.append(hash, 16);
- // We'll use the 'hashString' as the canonical path
- pathInfo = _getPathInfoFromCanonical(hashString);
- // We have the contents, so store it on the PathInfo, along with the result
- if (pathInfo->m_loadFileResult == CompressedResult::Uninitialized)
- {
- // Save the contents of the saved file
- pathInfo->m_loadFileResult = toCompressedResult(res);
- pathInfo->m_fileBlob = fileBlob;
- }
+ outCanonicalPath = hashString;
+ return SLANG_OK;
+ }
+ }
- break;
+ return SLANG_FAIL;
+}
+
+CacheFileSystem::PathInfo* CacheFileSystem::_getOrCreateCanonicalCacheInfo(const String& path)
+{
+ // Use the path to produce canonicalPath information
+ ComPtr<ISlangBlob> fileContents;
+ String canonicalPath;
+
+ SlangResult res = _calcCanonicalPath(path, canonicalPath, fileContents);
+ if (SLANG_FAILED(res))
+ {
+ // Was not able to create a canonical path.. so mark in path map the problem
+ return nullptr;
+ }
+
+ // Now try looking up by canonical path. If not found, add a new result
+ PathInfo* pathInfo = nullptr;
+ if (!m_canonicalMap.TryGetValue(canonicalPath, pathInfo))
+ {
+ // Create with found canonicalPath
+ pathInfo = new PathInfo(canonicalPath);
+ m_canonicalMap.Add(canonicalPath, pathInfo);
+ }
+
+ // At this point they must have same canonicalPath
+ SLANG_ASSERT(pathInfo->getCanonicalPath() == canonicalPath);
+
+ // If we have the file contents (because of calcing canonical), and there isn't a read fileblob already
+ // store the data as if read, so doesn't get read again
+ if (fileContents && !pathInfo->m_fileBlob)
+ {
+ pathInfo->m_fileBlob = fileContents;
+ pathInfo->m_loadFileResult = CompressedResult::Ok;
+ }
+
+ return pathInfo;
+}
+
+CacheFileSystem::PathInfo* CacheFileSystem::_getOrCreateSimplifiedPathCacheInfo(const String& path)
+{
+ // If we can simplify the path, try looking up in path cache with simplified path (as long as it's different!)
+ if (_canSimplifyPath(m_canonicalMode))
+ {
+ const String simplifiedPath = Path::Simplify(path);
+ // Only lookup if the path is different - because otherwise will recurse forever...
+ if (simplifiedPath != path)
+ {
+ // This is a recursive call - and will ensure the simplified path is added to the cache
+ return _getOrCreatePathCacheInfo(simplifiedPath);
}
}
- // Add the relPath
- m_pathMap.Add(relPath, pathInfo);
+ return _getOrCreateCanonicalCacheInfo(path);
+}
+
+CacheFileSystem::PathInfo* CacheFileSystem::_getOrCreatePathCacheInfo(const String& path)
+{
+ // Lookup in path cache
+ PathInfo* pathInfo;
+ if (m_pathMap.TryGetValue(path, pathInfo))
+ {
+ // Found so done
+ return pathInfo;
+ }
+
+ // Try getting or creating taking into account possible path simplification
+ pathInfo = _getOrCreateSimplifiedPathCacheInfo(path);
+ // Always add the result to the path cache (even if null)
+ m_pathMap.Add(path, pathInfo);
return pathInfo;
}
@@ -256,7 +314,7 @@ SlangResult CacheFileSystem::loadFile(char const* pathIn, ISlangBlob** blobOut)
{
*blobOut = nullptr;
String path(pathIn);
- PathInfo* info = _getPathInfo(path);
+ PathInfo* info = _getOrCreatePathCacheInfo(path);
if (!info)
{
return SLANG_FAIL;
@@ -277,7 +335,7 @@ SlangResult CacheFileSystem::loadFile(char const* pathIn, ISlangBlob** blobOut)
SlangResult CacheFileSystem::getCanoncialPath(const char* path, ISlangBlob** canonicalPathOut)
{
- PathInfo* info = _getPathInfo(path);
+ PathInfo* info = _getOrCreatePathCacheInfo(path);
if (!info)
{
return SLANG_E_NOT_FOUND;
@@ -304,7 +362,7 @@ SlangResult CacheFileSystem::calcCombinedPath(SlangPathType fromPathType, const
SlangResult CacheFileSystem::getPathType(const char* pathIn, SlangPathType* pathTypeOut)
{
String path(pathIn);
- PathInfo* info = _getPathInfo(path);
+ PathInfo* info = _getOrCreatePathCacheInfo(path);
if (!info)
{
return SLANG_E_NOT_FOUND;