diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2022-09-29 14:12:15 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-09-29 14:12:15 -0400 |
| commit | 9296405a2e15c07b5a8b7a002a2fa082232d559b (patch) | |
| tree | 9dd7bff82645e04f1dc53fbff8f5e366bda49cb9 /source/core/slang-memory-file-system.h | |
| parent | 8e0750fb193a8d2b9e8c3a0d81e367d6a9bdeb30 (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.h | 130 |
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 |
