From ff2ae7e0c1b48fa222f14dc84f15d0178ed056a1 Mon Sep 17 00:00:00 2001 From: jsmall-nvidia Date: Wed, 8 Jun 2022 13:40:09 -0400 Subject: Improvements around Visual Studio versions/matching versions (#2267) * #include an absolute path didn't work - because paths were taken to always be relative. * Use TerminatedUnownedStringSlice for literals in output C++. * Remove Escape/Unescape functions used in slang-token-reader.cpp Add target type of 'host-cpp' etc to map to the target types. * Fix some corner cases around string encoding. * Added unit test for string escaping. Fixed some assorted escaping bugs. * Updated test output. * Added decode test. * Stop using hex output, to get around 'greedy' aspect. Use octal instead. * Added HostHostCallable Small changes to use ArtifactDesc/Info instead of large switches. * Fix C++ emit to handle arbitrary function export. * Add options handling for callable without an output being specified. * Can compile with COM interface. Added example using com interface. * Use the IR Ptr type instead of hack in C++ emit for interfaces. * Fix issue with outputting the COM call when ptr is used. * Fix crash issue on compilation failure. * Add support for __global. * Added `ActualGlobalRate` Added special handling around globals and COM interfaces. Tested out in cpu-com-example. * Fix typo in NodeBase. * Support for accessing globals by name working. * Check that actual global initialization is working. * Refactor the com replacement such that it doesn't need a cache or do anything special with GlobalVar. * Remove context. Only create replacement if needed. * Split out COM host-callable into a unit-test. * host-callable com testing on C++and llvm. * Comment around the COM ptr replacement. * Disable com test on vs 32 bit. Fix C++ prelude * Disable 32 bit targets testing com host-callable. * Use JSON parsing to locate VS version. * Need platform detection in C++prelude. * Fix com host callable test for LLVM. * WIP improments finding downstream compiler version. * Work around for not being able to include "targetConditionals.h" * Matching semantic versioning support. * DownstreamMatchVersion -> DownstreamCompilerMatchVersion Small improvements. --- source/core/slang-semantic-version.cpp | 153 +++++++++++++++++++++++++++++++++ source/core/slang-semantic-version.h | 46 ++++++++++ 2 files changed, 199 insertions(+) (limited to 'source/core') diff --git a/source/core/slang-semantic-version.cpp b/source/core/slang-semantic-version.cpp index 7f603fd9c..cc631d292 100644 --- a/source/core/slang-semantic-version.cpp +++ b/source/core/slang-semantic-version.cpp @@ -7,6 +7,8 @@ namespace Slang { +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! SemanticVersion !!!!!!!!!!!!!!!!!!!!!!!!!!!!! + SlangResult SemanticVersion::parse(const UnownedStringSlice& value, char separatorChar, SemanticVersion& outVersion) { outVersion.reset(); @@ -52,4 +54,155 @@ void SemanticVersion::append(StringBuilder& buf) const } } +/* static */SemanticVersion SemanticVersion::getEarliest(const ThisType* versions, Count count) +{ + if (count <= 0) + { + return SemanticVersion(); + } + + SemanticVersion bestVersion = versions[0]; + for (const auto version : makeConstArrayView(versions + 1, count - 1)) + { + if (version < bestVersion) + { + bestVersion = version; + } + } + return bestVersion; +} + +/* static */SemanticVersion SemanticVersion::getLatest(const ThisType* versions, Count count) +{ + if (count <= 0) + { + return SemanticVersion(); + } + + SemanticVersion bestVersion = versions[0]; + for (const auto version : makeConstArrayView(versions + 1, count - 1)) + { + if (version > bestVersion) + { + bestVersion = version; + } + } + return bestVersion; +} + + + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! MatchSemanticVersion !!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +/* static */SemanticVersion MatchSemanticVersion::findAnyBest(const SemanticVersion* versions, Count count, const ThisType& matchVersion) +{ + // If there aren't any we are done + if (count <= 0) + { + return SemanticVersion(); + } + + // If there is only one it must be the best + if (count == 1) + { + return versions[0]; + } + + // Define a version range [start, end) + SemanticVersion start, end; + + switch (matchVersion.m_kind) + { + case Kind::Past: + { + return SemanticVersion::getEarliest(versions, count); + } + case Kind::Unknown: + case Kind::Future: + { + // If it's unknown, we just get the latest + return SemanticVersion::getLatest(versions, count); + } + case Kind::Major: + { + start = SemanticVersion(matchVersion.m_version.m_major, 0, 0); + end = SemanticVersion(matchVersion.m_version.m_major + 1, 0, 0); + break; + } + case Kind::MajorMinor: + { + start = SemanticVersion(matchVersion.m_version.m_major, matchVersion.m_version.m_minor, 0); + end = SemanticVersion(matchVersion.m_version.m_major, matchVersion.m_version.m_minor + 1, 0); + break; + } + case Kind::MajorMinorPatch: + { + start = SemanticVersion(matchVersion.m_version); + end = SemanticVersion(matchVersion.m_version.m_major, matchVersion.m_version.m_minor, matchVersion.m_version.m_patch + 1); + break; + } + default: break; + } + + List sortedVersions; + sortedVersions.addRange(versions, count); + + // Sort into increasing values + sortedVersions.sort([&](const SemanticVersion& a, const SemanticVersion& b) -> bool { return a < b; }); + + Index startIndex = 0; + for (; startIndex < count && sortedVersions[startIndex] < start; ++startIndex); + + Index endIndex = startIndex; + for (; endIndex < count && sortedVersions[endIndex] < end; ++endIndex); + + // If we have a span of versions, get the last in the span + if (startIndex < endIndex) + { + // Get the last one + return sortedVersions[endIndex - 1]; + } + + // Get the next greatest if there is one + if (endIndex < count) + { + return sortedVersions[endIndex]; + } + + // Get the prior prior to the start + if (startIndex > 0) + { + return sortedVersions[startIndex - 1]; + } + + // All cases should be covered, but return the last one + return sortedVersions[count - 1]; +} + +void MatchSemanticVersion::append(StringBuilder& buf) const +{ + switch (m_kind) + { + default: + case Kind::Unknown: buf << "unknown"; break; + case Kind::Past: buf << "past"; break; + case Kind::Future: buf << "future"; break; + case Kind::Major: + { + buf << m_version.m_major; + break; + } + case Kind::MajorMinor: + { + buf << m_version.m_major << "." << m_version.m_minor; + break; + } + case Kind::MajorMinorPatch: + { + m_version.append(buf); + break; + } + } +} + } // namespace Slang diff --git a/source/core/slang-semantic-version.h b/source/core/slang-semantic-version.h index d33116de6..4d64627c2 100644 --- a/source/core/slang-semantic-version.h +++ b/source/core/slang-semantic-version.h @@ -47,6 +47,9 @@ struct SemanticVersion static SlangResult parse(const UnownedStringSlice& value, SemanticVersion& outVersion); static SlangResult parse(const UnownedStringSlice& value, char separatorChar, SemanticVersion& outVersion); + static ThisType getEarliest(const ThisType* versions, Count count); + static ThisType getLatest(const ThisType* versions, Count count); + void append(StringBuilder& buf) const; bool operator>(const ThisType& rhs) const { return toInteger() > rhs.toInteger(); } @@ -63,5 +66,48 @@ struct SemanticVersion uint16_t m_patch; }; +/* Adds to the semantic versioning information for an incomplete version that can be matched */ +struct MatchSemanticVersion +{ + typedef MatchSemanticVersion ThisType; + + enum class Kind + { + Unknown, ///< Not known + Past, ///< Some unknown past version + Future, ///< Some future unknown version + Major, ///< Major version is defined (minor is in effect undefined) + MajorMinor, ///< Major and minor version are defined + MajorMinorPatch, ///< All elements of semantic version are defined + }; + + /// True if has a complete version + bool hasCompleteVersion() const { return m_kind == Kind::MajorMinorPatch; } + /// True if has some version information + bool hasVersion() const { return Index(m_kind) >= Index(Kind::Major); } + + void set(Index major) { m_kind = Kind::Major; m_version = SemanticVersion(int(major), 0, 0); } + void set(Index major, Index minor) { m_kind = Kind::MajorMinor; m_version = SemanticVersion(int(major), int(minor), 0); } + void set(Index major, Index minor, Index patch) { m_kind = Kind::MajorMinorPatch; m_version = SemanticVersion(int(major), int(minor), int(patch)); } + + void append(StringBuilder& buf) const; + + static MatchSemanticVersion makeFuture() { MatchSemanticVersion version; version.m_kind = Kind::Future; return version; } + + /// Finds the 'best' version based on the versions passed. + /// Doesn't follow strict semantic rules as will attempt to return the closest 'any' in past or future + /// If none can be found, returns an empty semantic version + static SemanticVersion findAnyBest(const SemanticVersion* versions, Count count, const ThisType& matchVersion); + + MatchSemanticVersion():m_kind(Kind::Unknown) {} + MatchSemanticVersion(Kind kind, const SemanticVersion& version): + m_kind(kind), + m_version(version) + {} + + Kind m_kind; + SemanticVersion m_version; +}; + } #endif -- cgit v1.2.3