From cb9d679a3a93c65c44904bf77811b9d74e431e23 Mon Sep 17 00:00:00 2001 From: jsmall-nvidia Date: Fri, 26 Oct 2018 08:16:54 -0400 Subject: 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 --- source/core/core.vcxproj | 2 +- source/core/core.vcxproj.filters | 4 +- source/core/slang-io.cpp | 99 +++++++++++++++++++++++++++++++++++++++ source/core/slang-io.h | 11 +++++ source/core/slang-string-util.cpp | 37 +++++++++++++++ source/core/slang-string-util.h | 41 ++++++++++++++++ 6 files changed, 191 insertions(+), 3 deletions(-) (limited to 'source/core') diff --git a/source/core/core.vcxproj b/source/core/core.vcxproj index d1ed4715f..2d0c67342 100644 --- a/source/core/core.vcxproj +++ b/source/core/core.vcxproj @@ -213,7 +213,7 @@ - + diff --git a/source/core/core.vcxproj.filters b/source/core/core.vcxproj.filters index 7936ca11b..1548217b4 100644 --- a/source/core/core.vcxproj.filters +++ b/source/core/core.vcxproj.filters @@ -130,8 +130,8 @@ - + Source Files - + \ No newline at end of file diff --git a/source/core/slang-io.cpp b/source/core/slang-io.cpp index 2b443a62b..f1948200c 100644 --- a/source/core/slang-io.cpp +++ b/source/core/slang-io.cpp @@ -123,6 +123,105 @@ namespace Slang return sb.ProduceString(); } + /* static */ bool Path::IsDriveSpecification(const UnownedStringSlice& element) + { + switch (element.size()) + { + case 0: + { + // We'll just assume it is + return true; + } + case 2: + { + // Look for a windows like drive spec + const char firstChar = element[0]; + return element[1] == ':' && ((firstChar >= 'a' && firstChar <= 'z') || (firstChar >= 'A' && firstChar <= 'Z')); + } + default: return false; + } + + } + + /* static */void Path::Split(const UnownedStringSlice& path, List& splitOut) + { + splitOut.Clear(); + + const char* start = path.begin(); + const char* end = path.end(); + + while (start < end) + { + const char* cur = start; + // Find the split + while (cur < end && !IsDelimiter(*cur)) cur++; + + splitOut.Add(UnownedStringSlice(start, cur)); + + // Next + start = cur + 1; + } + + // Okay if the end is empty. And we aren't with a spec like // or c:/ , then drop the final slash + if (splitOut.Count() > 1 && splitOut.Last().size() == 0) + { + if (splitOut.Count() == 2 && IsDriveSpecification(splitOut[0])) + { + return; + } + // Remove the last + splitOut.RemoveLast(); + } + } + + /* static */String Path::Simplify(const UnownedStringSlice& path) + { + List split; + Split(path, split); + + // Strictly speaking we could do something about case on platforms like window, but here we won't worry about that + for (int i = 0; i < int(split.Count()); i++) + { + const UnownedStringSlice& cur = split[i]; + if (cur == "." && split.Count() > 1) + { + // Just remove it + split.RemoveAt(i); + i--; + } + else if (cur == ".." && i > 0) + { + // Can we remove this and the one before ? + UnownedStringSlice& before = split[i - 1]; + if (before == ".." || (i == 1 && IsDriveSpecification(before))) + { + // Can't do it + continue; + } + split.RemoveRange(i - 1, 2); + i -= 2; + } + } + + // If its empty it must be . + if (split.Count() == 0) + { + split.Add(UnownedStringSlice::fromLiteral(".")); + } + + // Reconstruct the string + StringBuilder builder; + for (int i = 0; i < int(split.Count()); i++) + { + if (i > 0) + { + builder.Append(PathDelimiter); + } + builder.Append(split[i]); + } + return builder; + } + bool Path::CreateDir(const String & path) { #if defined(_WIN32) diff --git a/source/core/slang-io.h b/source/core/slang-io.h index ff287254c..3703aee08 100644 --- a/source/core/slang-io.h +++ b/source/core/slang-io.h @@ -32,6 +32,17 @@ namespace Slang static String Combine(const String & path1, const String & path2, const String & path3); static bool CreateDir(const String & path); + /// Accept either style of delimiter + SLANG_FORCE_INLINE static bool IsDelimiter(char c) { return c == '/' || c == '\\'; } + + static bool IsDriveSpecification(const UnownedStringSlice& element); + + /// Splits the path into it's individual bits + static void Split(const UnownedStringSlice& path, List& splitOut); + /// Strips .. and . as much as it can + static String Simplify(const UnownedStringSlice& path); + static String Simplify(const String& path) { return Simplify(path.getUnownedSlice()); } + static SlangResult GetPathType(const String & path, SlangPathType* pathTypeOut); static SlangResult GetCanonical(const String & path, String& canonicalPathOut); diff --git a/source/core/slang-string-util.cpp b/source/core/slang-string-util.cpp index 29f8dc0ca..6d0d896a1 100644 --- a/source/core/slang-string-util.cpp +++ b/source/core/slang-string-util.cpp @@ -2,6 +2,19 @@ namespace Slang { +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! StringBlob !!!!!!!!!!!!!!!!!!!!!!!!!!! + +// 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_ISlangBlob = SLANG_UUID_ISlangBlob; + +/* static */ISlangUnknown* StringBlob::getInterface(const Guid& guid) +{ + return (guid == IID_ISlangUnknown || guid == IID_ISlangBlob) ? static_cast(this) : nullptr; +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! StringUtil !!!!!!!!!!!!!!!!!!!!!!!!!!! + /* static */void StringUtil::split(const UnownedStringSlice& in, char splitChar, List& slicesOut) { slicesOut.Clear(); @@ -74,4 +87,28 @@ namespace Slang { return builder; } +/* static */String StringUtil::getString(ISlangBlob* blob) +{ + if (blob) + { + size_t size = blob->getBufferSize(); + if (size > 0) + { + const char* contents = (const char*)blob->getBufferPointer(); + // Check it has terminating 0, if not we must construct as if it does + if (contents[size - 1] == 0) + { + size--; + } + return String(contents, contents + size); + } + } + return String(); +} + +ComPtr StringUtil::createStringBlob(const String& string) +{ + return ComPtr(new StringBlob(string)); +} + } // namespace Slang diff --git a/source/core/slang-string-util.h b/source/core/slang-string-util.h index fc3258490..47d92f2fe 100644 --- a/source/core/slang-string-util.h +++ b/source/core/slang-string-util.h @@ -6,8 +6,41 @@ #include +#include "../../slang-com-helper.h" +#include "../../slang-com-ptr.h" + namespace Slang { +/** A blob that uses a `String` for its storage. +*/ +class StringBlob : public ISlangBlob +{ +public: + // ISlangUnknown + SLANG_IUNKNOWN_ALL + + // ISlangBlob + SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE { return m_string.Buffer(); } + SLANG_NO_THROW size_t SLANG_MCALL getBufferSize() SLANG_OVERRIDE { return m_string.Length(); } + + /// Get the contained string + SLANG_FORCE_INLINE const String& getString() const { return m_string; } + + explicit StringBlob(String const& string) + : m_string(string) + {} + + /// Need virtual dtor, because BlobBase is derived from and release impl used is the one in the base class (that doesn't know the derived type) + /// Alternatively could be implemented by always using SLANG_IUNKNOWN_RELEASE in derived types - this would make derived types slightly smaller/faster + virtual ~StringBlob() {} + +protected: + ISlangUnknown* getInterface(const Guid& guid); + + String m_string; + uint32_t m_refCount = 0; +}; + struct StringUtil { /// Split in, by specified splitChar into slices out @@ -22,6 +55,14 @@ struct StringUtil /// Create a string from the format string applying args (like sprintf) static String makeStringWithFormat(const char* format, ...); + + /// Given a string held in a blob, returns as a String + /// Returns an empty string if blob is nullptr + static String getString(ISlangBlob* blob); + + /// Create a blob from a string + static ComPtr createStringBlob(const String& string); + }; } // namespace Slang -- cgit v1.2.3