summaryrefslogtreecommitdiff
path: root/source/core/slang-memory-file-system.h
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2022-09-29 14:12:15 -0400
committerGitHub <noreply@github.com>2022-09-29 14:12:15 -0400
commit9296405a2e15c07b5a8b7a002a2fa082232d559b (patch)
tree9dd7bff82645e04f1dc53fbff8f5e366bda49cb9 /source/core/slang-memory-file-system.h
parent8e0750fb193a8d2b9e8c3a0d81e367d6a9bdeb30 (diff)
Split out MemoryFileSystem (#2422)
* #include an absolute path didn't work - because paths were taken to always be relative. * Remove ref count for Entry in RiffFileSystem. Free up backing Entry types (to work around Dictionary not doing this). * Some small improvements to RiffFileSystem. * Add testing for file systems. * Split out MemoryFileSystem. * Add some documentation around different FileSystems. * Small tiry up - removing unused headers, fixing some comments. Use StringBlob::moveCreate where appropriate. * Small improvement to MemoryFileSystem. Improve documentation comments a little.
Diffstat (limited to 'source/core/slang-memory-file-system.h')
-rw-r--r--source/core/slang-memory-file-system.h130
1 files changed, 130 insertions, 0 deletions
diff --git a/source/core/slang-memory-file-system.h b/source/core/slang-memory-file-system.h
new file mode 100644
index 000000000..72bacf2bd
--- /dev/null
+++ b/source/core/slang-memory-file-system.h
@@ -0,0 +1,130 @@
+#ifndef SLANG_CORE_MEMORY_FILE_SYSTEM_H
+#define SLANG_CORE_MEMORY_FILE_SYSTEM_H
+
+#include "slang-basic.h"
+
+#include "../../slang-com-ptr.h"
+#include "slang-com-object.h"
+
+namespace Slang
+{
+
+/* MemoryFileSystem is an implementation of ISlangMutableFileSystem that stores file contents in 'blobs' (typically) in memory.
+
+A derived class can change how the contents of the contents blob is interpretted (so for example the RiffFileSystem is implemented
+such that the Entry.m_contents is the files contents compressed).
+
+The implementation uses a map to store the file/directory based on their canonical path. This makes access relatively fast and simple -
+an access only requires a path being converted into a canonical path, and then a lookup. Whilst this makes typical access fast, it means
+doing an enumeration of a directory slower as it requires traversing all entries to find which are in the path.
+
+This is in contrast with an implementation that held items in directories 'objects'. In that scenario the path through the hierarchy
+would need to be traversed to find the item. Finding all of the items in a directory is very fast - it's all the items held
+in the the directory 'object'.
+
+The implementation allows for 'implicit' directories. If we have a file "a/b" it's existance *implicitly* implies the existance of the
+directory 'a'. This is similar to how archive file formats such as zip works.
+
+TODO(JS):
+* We may want to make saveFile take a blob, or have a version that does. Doing so would allow the application to handle memory management
+around the blob.
+*/
+class MemoryFileSystem : public ISlangMutableFileSystem, public ComBaseObject
+{
+public:
+
+ // ISlangUnknown
+ SLANG_COM_BASE_IUNKNOWN_ALL
+
+ // ISlangCastable
+ virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE;
+
+ // ISlangFileSystem
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadFile(char const* path, ISlangBlob** outBlob) SLANG_OVERRIDE;
+
+ // ISlangFileSystemExt
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL getFileUniqueIdentity(const char* path, ISlangBlob** uniqueIdentityOut) SLANG_OVERRIDE;
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcCombinedPath(SlangPathType fromPathType, const char* fromPath, const char* path, ISlangBlob** pathOut) SLANG_OVERRIDE;
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL getPathType(const char* path, SlangPathType* pathTypeOut) SLANG_OVERRIDE;
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL getSimplifiedPath(const char* path, ISlangBlob** outSimplifiedPath) SLANG_OVERRIDE;
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL getCanonicalPath(const char* path, ISlangBlob** outCanonicalPath) SLANG_OVERRIDE;
+ virtual SLANG_NO_THROW void SLANG_MCALL clearCache() SLANG_OVERRIDE {}
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL enumeratePathContents(const char* path, FileSystemContentsCallBack callback, void* userData) SLANG_OVERRIDE;
+ virtual SLANG_NO_THROW OSPathKind SLANG_MCALL getOSPathKind() SLANG_OVERRIDE { return OSPathKind::None; }
+
+ // ISlangModifyableFileSystem
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL saveFile(const char* path, const void* data, size_t size) SLANG_OVERRIDE;
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL remove(const char* path) SLANG_OVERRIDE;
+ virtual SLANG_NO_THROW SlangResult SLANG_MCALL createDirectory(const char* path) SLANG_OVERRIDE;
+
+protected:
+
+ struct Entry
+ {
+ void reset()
+ {
+ m_type = SLANG_PATH_TYPE_FILE;
+ m_canonicalPath = String();
+ m_uncompressedSizeInBytes = 0;
+ m_contents.setNull();
+ }
+
+ void initDirectory(const String& canonicalPath)
+ {
+ m_type = SLANG_PATH_TYPE_DIRECTORY;
+ m_canonicalPath = canonicalPath;
+ m_uncompressedSizeInBytes = 0;
+ m_contents.setNull();
+ }
+ void initFile(const String& canonicalPath, size_t uncompressedSize, ISlangBlob* blob)
+ {
+ m_type = SLANG_PATH_TYPE_FILE;
+ m_canonicalPath = canonicalPath;
+ setContents(uncompressedSize, blob);
+ }
+ void initFile(const String& canonicalPath)
+ {
+ m_type = SLANG_PATH_TYPE_FILE;
+ m_canonicalPath = canonicalPath;
+ m_contents.setNull();
+ m_uncompressedSizeInBytes = 0;
+ }
+ void setContents(size_t uncompressedSize, ISlangBlob* blob)
+ {
+ SLANG_ASSERT(m_type == SLANG_PATH_TYPE_FILE);
+ SLANG_ASSERT(blob);
+ m_uncompressedSizeInBytes = uncompressedSize;
+ m_contents = blob;
+ }
+
+ SlangPathType m_type;
+ String m_canonicalPath;
+
+ /// The size as seen on the file system. Might be different from the size of m_contents
+ /// if it's actually being stored in some other representation (such as compressed)
+ size_t m_uncompressedSizeInBytes;
+ ComPtr<ISlangBlob> m_contents; ///< Can be compressed or not
+ };
+
+ void* getInterface(const Guid& guid);
+ void* getObject(const Guid& guid);
+
+ SlangResult _calcCanonicalPath(const char* path, StringBuilder& out);
+ Entry* _getEntryFromPath(const char* path, String* outPath = nullptr);
+ Entry* _getEntryFromCanonicalPath(const String& canonicalPath);
+ /// Creates or returns a file entry for the given path.
+ /// If created the entry is empty.
+ SlangResult _requireFile(const char* path, Entry** outEntry);
+ /// Given the path returns the entry if it's a file, or returns an error
+ SlangResult _loadFile(const char* path, Entry** outEntry);
+
+ /// Clear, ensures any backing memory is also freed
+ void _clear() { m_entries = Dictionary<String, Entry>(); }
+
+ // Maps canonical paths to an entries (which could be files or directories)
+ Dictionary<String, Entry> m_entries;
+};
+
+}
+
+#endif