From 45d9961a6a86d184248ef84f6a07125b0c224f97 Mon Sep 17 00:00:00 2001 From: Ellie Hermaszewska Date: Wed, 16 Aug 2023 08:57:47 +0800 Subject: Use ankerl/unordered_dense as a hashmap implementation (#3036) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Correct namespace for getClockFrequency * missing const * Add missing assignment operator * Remove unused variables * Return correct modified variable * Use stable hash code for file system identity * terse static_assert * Structured binding for map iteration * Make (==) and getHashCode const on many structs * Add ConstIterator for LinkedList * Replace uses of ItemProxy::getValue with Dictionary::at * Extract list of loads from gradientsMap before updating it * Const correctness in type layout * Add unordered_dense hashmap submodule * Use wyhash or getHashCode in slang-hash.h * refactor slang-hash.h * Use ankerl/unordered_dense as a hashmap implementation Notable changes: - The subscript operator returns a reference directly to the value, rather than a lazy ItemProxy (pair of dict pointer and key) slang-profile time (95% over 10 runs): - Before: 6.3913906 (±0.0746) - After: 5.9276123 (±0.0964) * 64 bit hash for strings So they have the same hash as char buffers with the same contents * Narrowing warnings for gcc to match msvc * revert back to c++17 * Correct c++ version for msvc * Use path to unordered_dense which keeps tests happy * Do not assign to and read from map in same expression * Remove redundant map operations in primal-hoist * Split out stable hash functions into slang-stable-hash.h * 64 bit hash by default * regenerate vs projects * Correct return type from HashSetBase::getCount() * correct width for call to Dictionary::reserve * Use stable hash for obfuscated module ids * Signed int for reserve * clearer variable naming * Parameterize Dictionary on hash and equality functors * Allow heterogenous lookup for Dictionary * missing const * Use set over operator[] in some places * Remove unused function * s/at/getValue --- source/compiler-core/slang-source-loc.cpp | 1 - .../slang-visual-studio-compiler-util.cpp | 7 +- source/core/slang-dictionary.h | 637 ++++++--------------- source/core/slang-file-system.cpp | 19 +- source/core/slang-hash.h | 282 ++++----- source/core/slang-hex-dump-util.cpp | 10 +- source/core/slang-linked-list.h | 39 +- source/core/slang-memory-file-system.cpp | 10 +- source/core/slang-riff-file-system.cpp | 18 +- source/core/slang-smart-pointer.h | 2 +- source/core/slang-stable-hash.h | 99 ++++ source/core/slang-string.cpp | 18 + source/core/slang-string.h | 27 +- source/slang/slang-ast-base.h | 4 +- source/slang/slang-ast-builder.cpp | 12 +- source/slang/slang-ast-builder.h | 33 +- source/slang/slang-ast-dump.cpp | 5 +- source/slang/slang-ast-support-types.h | 2 +- source/slang/slang-check-decl.cpp | 26 +- source/slang/slang-check-impl.h | 6 +- source/slang/slang-compiler.cpp | 24 +- source/slang/slang-compiler.h | 4 +- source/slang/slang-doc-markdown-writer.cpp | 4 +- source/slang/slang-emit-c-like.cpp | 7 +- source/slang/slang-emit-source-writer.cpp | 31 +- source/slang/slang-emit-source-writer.h | 8 +- source/slang/slang-emit-spirv.cpp | 3 +- source/slang/slang-ir-any-value-marshalling.cpp | 2 +- source/slang/slang-ir-autodiff-fwd.cpp | 6 +- source/slang/slang-ir-autodiff-primal-hoist.cpp | 19 +- source/slang/slang-ir-autodiff-primal-hoist.h | 37 +- source/slang/slang-ir-autodiff-rev.cpp | 4 +- source/slang/slang-ir-autodiff-transpose.h | 25 +- source/slang/slang-ir-autodiff-unzip.cpp | 2 +- source/slang/slang-ir-autodiff-unzip.h | 7 +- source/slang/slang-ir-autodiff.cpp | 2 +- .../slang/slang-ir-eliminate-multilevel-break.cpp | 4 +- source/slang/slang-ir-eliminate-phis.cpp | 12 +- .../slang/slang-ir-generics-lowering-context.cpp | 2 +- source/slang/slang-ir-glsl-legalize.cpp | 4 +- source/slang/slang-ir-inline.cpp | 4 +- source/slang/slang-ir-link.cpp | 6 +- source/slang/slang-ir-lower-generic-function.cpp | 6 +- source/slang/slang-ir-lower-optional-type.cpp | 6 +- source/slang/slang-ir-lower-result-type.cpp | 6 +- source/slang/slang-ir-lower-tuple-types.cpp | 6 +- source/slang/slang-ir-obfuscate-loc.cpp | 11 +- source/slang/slang-ir-reachability.h | 10 +- source/slang/slang-ir-specialize-dispatch.cpp | 4 +- source/slang/slang-ir-specialize.cpp | 12 +- source/slang/slang-ir-spirv-snippet.cpp | 2 +- source/slang/slang-ir-spirv-snippet.h | 4 +- source/slang/slang-ir.h | 1 + source/slang/slang-language-server.cpp | 20 +- source/slang/slang-mangle.cpp | 2 +- source/slang/slang-parameter-binding.cpp | 48 +- source/slang/slang-preprocessor.cpp | 11 +- source/slang/slang-reflection-api.cpp | 4 +- source/slang/slang-repro.cpp | 45 +- source/slang/slang-repro.h | 3 +- source/slang/slang-serialize-ir.h | 2 +- source/slang/slang-serialize-source-loc.cpp | 3 +- source/slang/slang-type-layout.cpp | 48 +- source/slang/slang-type-layout.h | 9 +- source/slang/slang-workspace-version.cpp | 4 +- source/slang/slang.cpp | 33 +- 66 files changed, 783 insertions(+), 991 deletions(-) create mode 100644 source/core/slang-stable-hash.h (limited to 'source') diff --git a/source/compiler-core/slang-source-loc.cpp b/source/compiler-core/slang-source-loc.cpp index f9014e0d8..33f93074e 100644 --- a/source/compiler-core/slang-source-loc.cpp +++ b/source/compiler-core/slang-source-loc.cpp @@ -318,7 +318,6 @@ SlangResult SourceView::_findSourceMapLoc(SourceLoc loc, SourceLocType type, Han // view, which may be a parent to the current one. auto lookupSourceManager = m_sourceFile->getSourceManager(); - HandleSourceLoc handleLoc; SLANG_RETURN_ON_FAIL(_findLocWithSourceMap(lookupSourceManager, this, loc, type, outLoc)); return SLANG_OK; diff --git a/source/compiler-core/slang-visual-studio-compiler-util.cpp b/source/compiler-core/slang-visual-studio-compiler-util.cpp index 81e00d73e..14fad0aec 100644 --- a/source/compiler-core/slang-visual-studio-compiler-util.cpp +++ b/source/compiler-core/slang-visual-studio-compiler-util.cpp @@ -83,14 +83,17 @@ static void _addFile(const String& path, const ArtifactDesc& desc, IOSFileArtifa // Display full path of source files in diagnostics cmdLine.addArg("/FC"); - if (options.flags & CompileOptions::Flag::EnableExceptionHandling) + if (options.sourceLanguage == SLANG_SOURCE_LANGUAGE_CPP) { - if (options.sourceLanguage == SLANG_SOURCE_LANGUAGE_CPP) + if (options.flags & CompileOptions::Flag::EnableExceptionHandling) { // https://docs.microsoft.com/en-us/cpp/build/reference/eh-exception-handling-model?view=vs-2019 // Assumes c functions cannot throw cmdLine.addArg("/EHsc"); } + + // To maintain parity with the slang compiler headers which are shared + cmdLine.addArg("/std:c++17"); } if (options.flags & CompileOptions::Flag::Verbose) diff --git a/source/core/slang-dictionary.h b/source/core/slang-dictionary.h index 2c683abfe..c7c0c8e05 100644 --- a/source/core/slang-dictionary.h +++ b/source/core/slang-dictionary.h @@ -8,6 +8,7 @@ #include "slang-exception.h" #include "slang-math.h" #include "slang-hash.h" +#include "../../external/unordered_dense/include/ankerl/unordered_dense.h" namespace Slang { @@ -55,7 +56,7 @@ namespace Slang value = that.value; return *this; } - HashCode getHashCode() + HashCode getHashCode() const { return combineHash( Slang::getHashCode(key), @@ -75,495 +76,188 @@ namespace Slang const float kMaxLoadFactor = 0.7f; - template + template, typename KeyEqual = std::equal_to> class Dictionary { - friend class Iterator; - friend class ItemProxy; + using InnerMap = ankerl::unordered_dense::map< + TKey, + TValue, + Hash, + KeyEqual>; + using ThisType = Dictionary; + InnerMap map; public: - typedef TValue ValueType; - typedef TKey KeyType; - typedef Dictionary ThisType; - private: - inline int getProbeOffset(int /*probeId*/) const - { - // linear probing - return 1; - } - private: - int m_bucketCountMinusOne; - int m_count; - UIntSet m_marks; - KeyValuePair* m_hashMap; - void deallocateAll() - { - if (m_hashMap) - delete[] m_hashMap; - m_hashMap = nullptr; - } - inline bool isDeleted(int pos) const - { - return m_marks.contains((pos << 1) + 1); - } - inline bool isEmpty(int pos) const - { - return !m_marks.contains((pos << 1)); - } - inline void setDeleted(int pos, bool val) - { - if (val) - m_marks.add((pos << 1) + 1); - else - m_marks.remove((pos << 1) + 1); - } - inline void setEmpty(int pos, bool val) - { - if (val) - m_marks.remove((pos << 1)); - else - m_marks.add((pos << 1)); - } - struct FindPositionResult - { - int objectPosition; - int insertionPosition; + // + // Types + // + using Iterator = typename InnerMap::iterator; + using ConstIterator = typename InnerMap::const_iterator; + using KeyType = TKey; + using ValueType = TValue; - FindPositionResult() - { - objectPosition = -1; - insertionPosition = -1; - } - FindPositionResult(int objPos, int insertPos) - { - objectPosition = objPos; - insertionPosition = insertPos; - } - }; - template - inline int getHashPos(KeyType& key) const - { - SLANG_ASSERT(m_bucketCountMinusOne > 0); - const unsigned int hash = (unsigned int)getHashCode(key); - return (hash * 2654435761u) % (unsigned int)(m_bucketCountMinusOne); - } - template - FindPositionResult findPosition(const KeyType& key) const - { - int hashPos = getHashPos(const_cast(key)); - int insertPos = -1; - int numProbes = 0; - while (numProbes <= m_bucketCountMinusOne) - { - if (isEmpty(hashPos)) - { - if (insertPos == -1) - return FindPositionResult(-1, hashPos); - else - return FindPositionResult(-1, insertPos); - } - else if (isDeleted(hashPos)) - { - if (insertPos == -1) - insertPos = hashPos; - } - else if (m_hashMap[hashPos].key == key) - { - return FindPositionResult(hashPos, -1); - } - numProbes++; - hashPos = (hashPos + getProbeOffset(numProbes)) & m_bucketCountMinusOne; - } - if (insertPos != -1) - return FindPositionResult(-1, insertPos); - SLANG_ASSERT_FAILURE("Hash map is full. This indicates an error in Key::Equal or Key::getHashCode."); - } - TValue& _insert(KeyValuePair&& kvPair, int pos) - { - m_hashMap[pos] = _Move(kvPair); - setEmpty(pos, false); - setDeleted(pos, false); - return m_hashMap[pos].value; - } - void maybeRehash() - { - if (m_bucketCountMinusOne == -1 || m_count >= int(kMaxLoadFactor * m_bucketCountMinusOne)) - { - int newSize = (m_bucketCountMinusOne + 1) * 2; - if (newSize == 0) - { - newSize = 64; - } - reserve(newSize); - } - } + // + // Iterators + // - bool addIfNotExists(KeyValuePair&& kvPair) - { - maybeRehash(); - auto pos = findPosition(kvPair.key); - if (pos.objectPosition != -1) - return false; - else if (pos.insertionPosition != -1) - { - m_count++; - _insert(_Move(kvPair), pos.insertionPosition); - return true; - } - else - SLANG_ASSERT_FAILURE("Inconsistent find result returned. This is a bug in Dictionary implementation."); - } - void add(KeyValuePair&& kvPair) - { - if (!addIfNotExists(_Move(kvPair))) - SLANG_ASSERT_FAILURE("The key already exists in Dictionary."); - } - TValue& set(KeyValuePair&& kvPair) - { - maybeRehash(); - auto pos = findPosition(kvPair.key); - if (pos.objectPosition != -1) - return _insert(_Move(kvPair), pos.objectPosition); - else if (pos.insertionPosition != -1) - { - m_count++; - return _insert(_Move(kvPair), pos.insertionPosition); - } - else - SLANG_ASSERT_FAILURE("Inconsistent find result returned. This is a bug in Dictionary implementation."); - } - public: - class Iterator - { - private: - const Dictionary* dict; - int pos; - public: - KeyValuePair& operator*() const - { - return dict->m_hashMap[pos]; - } - KeyValuePair* operator->() const - { - return dict->m_hashMap + pos; - } - Iterator& operator++() - { - if (pos > dict->m_bucketCountMinusOne) - return *this; - pos++; - while (pos <= dict->m_bucketCountMinusOne && (dict->isDeleted(pos) || dict->isEmpty(pos))) - { - pos++; - } - return *this; - } - Iterator operator++(int) - { - Iterator rs = *this; - operator++(); - return rs; - } - bool operator!=(const Iterator& that) const - { - return pos != that.pos || dict != that.dict; - } - bool operator==(const Iterator& that) const - { - return pos == that.pos && dict == that.dict; - } - Iterator(const Dictionary* inDict, int inPos) - { - this->dict = inDict; - this->pos = inPos; - } - Iterator() - { - this->dict = nullptr; - this->pos = 0; - } - }; + auto begin() { return map.begin(); } + auto begin() const { return map.begin(); } + auto end() { return map.end(); } + auto end() const { return map.end(); } - Iterator begin() const - { - int pos = 0; - while (pos < m_bucketCountMinusOne + 1) - { - if (isEmpty(pos) || isDeleted(pos)) - pos++; - else - break; - } - return Iterator(this, pos); - } - Iterator end() const - { - return Iterator(this, m_bucketCountMinusOne + 1); - } - public: - void add(const TKey& key, const TValue& value) - { - add(KeyValuePair(key, value)); - } - void add(TKey&& key, TValue&& value) - { - add(KeyValuePair(_Move(key), _Move(value))); - } - bool addIfNotExists(const TKey& key, const TValue& value) - { - return addIfNotExists(KeyValuePair(key, value)); - } - bool addIfNotExists(TKey&& key, TValue&& value) - { - return addIfNotExists(KeyValuePair(_Move(key), _Move(value))); - } - void remove(const TKey& key) - { - if (m_count == 0) - return; - auto pos = findPosition(key); - if (pos.objectPosition != -1) - { - setDeleted(pos.objectPosition, true); - m_count--; - } - } - void clear() - { - m_count = 0; - m_marks.clear(); - } + // + // Modifiers + // - void reserve(int newSize) - { - if (newSize <= m_bucketCountMinusOne + 1) - return; + // Removes all values from the map + void clear() { map.clear(); } - Dictionary newDict; - newDict.m_bucketCountMinusOne = newSize - 1; - newDict.m_hashMap = new KeyValuePair[newSize]; - newDict.m_marks.resizeAndClear(newSize * 2); - if (m_hashMap) - { - for (auto& kvPair : *this) - { - newDict.add(_Move(kvPair)); - } - } - *this = _Move(newDict); - } + // Erases the value at the specified key if it exists + void remove(const TKey& key) { map.erase(key); } - TValue* tryGetValueOrAdd(const TKey& key, const TValue& value) - { - maybeRehash(); - auto pos = findPosition(key); - if (pos.objectPosition != -1) - { - return &m_hashMap[pos.objectPosition].value; - } - else if (pos.insertionPosition != -1) - { - // Make pair - KeyValuePair kvPair(_Move(key), _Move(value)); - m_count++; - _insert(_Move(kvPair), pos.insertionPosition); - return nullptr; - } - else - SLANG_ASSERT_FAILURE("Inconsistent find result returned. This is a bug in Dictionary implementation."); - } + // Reserves enough space for the specified number of values + void reserve(Index size) { map.reserve(std::size_t(size)); }; - /// This differs from tryGetValueOrAdd, in that it always returns the Value held in the Dictionary. - /// If there isn't already an entry for 'key', a value is added with defaultValue. - TValue& getOrAddValue(const TKey& key, const TValue& defaultValue) + // Swap with another map + void swapWith(ThisType& rhs) { std::swap(*this, rhs); } + + // + // Query capacity + // + + std::size_t getCount() const { return map.size(); } + + // + // Lookup + // + + // Returns true if the map contains an equivalent key + template + bool containsKey(const K& k) const { return map.contains(k); } + + // Returns a valid pointer to the requested element, or nullptr if it + // doesn't exist + template + const TValue* tryGetValue(const K& key) const { - maybeRehash(); - auto pos = findPosition(key); - if (pos.objectPosition != -1) - { - return m_hashMap[pos.objectPosition].value; - } - else if (pos.insertionPosition != -1) - { - // Make pair - KeyValuePair kvPair(_Move(key), _Move(defaultValue)); - m_count++; - return _insert(_Move(kvPair), pos.insertionPosition); - } - else - SLANG_ASSERT_FAILURE("Inconsistent find result returned. This is a bug in Dictionary implementation."); + auto i = map.find(key); + return i == map.end() ? nullptr : &(i->second); } - void set(const TKey& key, const TValue& value) + // Returns a valid pointer to the requested element, or nullptr if it + // doesn't exist + template + TValue* tryGetValue(const K& key) { - if (auto ptr = tryGetValueOrAdd(key, value)) - { - *ptr = value; - } + auto i = map.find(key); + return i == map.end() ? nullptr : std::addressof(i->second); } - template - bool containsKey(const KeyType& key) const + // Returns true and copies the element into 'value' if present. + // Otherwise returns false and value unmodified. + template + bool tryGetValue(const K& key, TValue& value) const { - if (m_bucketCountMinusOne == -1) + auto i = map.find(key); + if(i == map.end()) return false; - auto pos = findPosition(key); - return pos.objectPosition != -1; - } - template - bool tryGetValue(const KeyType& key, TValue& value) const - { - if (m_bucketCountMinusOne == -1) - return false; - auto pos = findPosition(key); - if (pos.objectPosition != -1) - { - value = m_hashMap[pos.objectPosition].value; - return true; - } - return false; - } - template - TValue* tryGetValue(const KeyType& key) const - { - if (m_bucketCountMinusOne == -1) - return nullptr; - auto pos = findPosition(key); - if (pos.objectPosition != -1) - { - return &m_hashMap[pos.objectPosition].value; - } - return nullptr; + value = i->second; + return true; } - class ItemProxy + // Returns a const reference to the value at the given key. Asserts if + // the value doesn't exist + const TValue& getValue(const TKey& key) const { - private: - const Dictionary* dict; - TKey key; - public: - ItemProxy(const TKey& _key, const Dictionary* _dict) - { - this->dict = _dict; - this->key = _key; - } - ItemProxy(TKey&& _key, const Dictionary* _dict) - { - this->dict = _dict; - this->key = _Move(_key); - } - TValue& getValue() const - { - auto pos = dict->findPosition(key); - if (pos.objectPosition != -1) - { - return dict->m_hashMap[pos.objectPosition].value; - } - else - SLANG_ASSERT_FAILURE("The key does not exist in dictionary."); - } - inline TValue& operator()() const - { - return getValue(); - } - operator TValue&() const - { - return getValue(); - } - TValue& operator=(const TValue& val) const - { - return ((Dictionary*)dict)->set(KeyValuePair(_Move(key), val)); - } - TValue& operator=(TValue&& val) const - { - return ((Dictionary*)dict)->set(KeyValuePair(_Move(key), _Move(val))); - } - }; - ItemProxy operator[](const TKey& key) const - { - return ItemProxy(key, this); + if(const auto x = tryGetValue(key)) + return *x; + SLANG_ASSERT_FAILURE("The key does not exist in dictionary."); } - ItemProxy operator[](TKey&& key) const - { - return ItemProxy(_Move(key), this); - } - int getCount() const + + // Returns a reference to the value at the given key. Asserts if the + // value doesn't exist + TValue& getValue(const TKey& key) { - return m_count; + if(const auto x = tryGetValue(key)) + return *x; + SLANG_ASSERT_FAILURE("The key does not exist in dictionary."); } - /// Swap this with rhs - void swapWith(ThisType& rhs); + // + // Combined Lookup and Insertion + // - private: - template - void init(const KeyValuePair& kvPair, Args... args) - { - add(kvPair); - init(args...); - } - public: - Dictionary() + // Tries to insert the given element, if a value was already present at + // the given key then returns a pointer to that element instead. + // Returns nullptr if insertion was successful. + TValue* tryGetValueOrAdd(const typename InnerMap::value_type& kvPair) { - m_bucketCountMinusOne = -1; - m_count = 0; - m_hashMap = nullptr; - } - template - Dictionary(Arg arg, Args... args) - { - init(arg, args...); - } - Dictionary(const Dictionary& other) - : m_bucketCountMinusOne(-1), m_count(0), m_hashMap(nullptr) - { - *this = other; - } - Dictionary(Dictionary&& other) - : m_bucketCountMinusOne(-1), m_count(0), m_hashMap(nullptr) - { - *this = (_Move(other)); + const auto& [iterator, inserted] = map.insert(kvPair); + return inserted ? nullptr : std::addressof(iterator->second); } - Dictionary& operator=(const Dictionary& other) + // Tries to insert the given element, if a value was already present at + // the given key then returns a pointer to that element instead. + // Returns nullptr if insertion was successful. + TValue* tryGetValueOrAdd(typename InnerMap::value_type&& kvPair) { - if (this == &other) - return *this; - deallocateAll(); - m_bucketCountMinusOne = other.m_bucketCountMinusOne; - m_count = other.m_count; - m_hashMap = new KeyValuePair[other.m_bucketCountMinusOne + 1]; - m_marks = other.m_marks; - for (int i = 0; i <= m_bucketCountMinusOne; i++) - m_hashMap[i] = other.m_hashMap[i]; - return *this; + const auto& [iterator, inserted] = map.insert(std::move(kvPair)); + return inserted ? nullptr : std::addressof(iterator->second); } - Dictionary& operator=(Dictionary&& other) + // Tries to insert the given element, if a value was already present at + // the given key then returns a pointer to that element instead. + // Returns nullptr if insertion was successful. + TValue* tryGetValueOrAdd(const TKey& key, const TValue& value) { return tryGetValueOrAdd({key, value}); } + + // Inserts the given value if it doesn't exist already + // Return a reference to the (possibly new) value in the map + TValue& getOrAddValue(const TKey& key, const TValue& defaultValue) { - if (this == &other) - return *this; - deallocateAll(); - m_bucketCountMinusOne = other.m_bucketCountMinusOne; - m_count = other.m_count; - m_hashMap = other.m_hashMap; - m_marks = _Move(other.m_marks); - other.m_hashMap = nullptr; - other.m_count = 0; - other.m_bucketCountMinusOne = -1; - return *this; + auto [iterator, inserted] = map.insert({key, defaultValue}); + return iterator->second; + } + + // Returns a reference to the value at the specified key, default + // initializing it if it doesn't already exist + TValue& operator[]( const TKey& key ) { return map[key]; } + // Returns a reference to the value at the specified key, default + // initializing it if it doesn't already exist + TValue& operator[]( TKey&& key ) { return map[std::move(key)]; } + + // + // Insertion + // + + // Returns true if the value was inserted, returns false if the map + // already has a value associated with this key + bool addIfNotExists(typename InnerMap::value_type&& kvPair) { return !tryGetValueOrAdd(std::move(kvPair)); } + // Returns true if the value was inserted, returns false if the map + // already has a value associated with this key + bool addIfNotExists(const typename InnerMap::value_type& kvPair) { return !tryGetValueOrAdd(kvPair); } + // Returns true if the value was inserted, returns false if the map + // already has a value associated with this key + bool addIfNotExists(const TKey& k, const TValue& v) { return addIfNotExists({k, v}); } + // Returns true if the value was inserted, returns false if the map + // already has a value associated with this key + bool addIfNotExists(TKey&& k, TValue&& v) { return addIfNotExists({std::move(k), std::move(v)}); } + + // Asserts if the key already exists in the dictionary + void add(typename InnerMap::value_type&& kvPair) + { + if (!addIfNotExists(std::move(kvPair))) + SLANG_ASSERT_FAILURE("The key already exists in Dictionary."); } - ~Dictionary() + // Asserts if the key already exists in the dictionary + void add(const typename InnerMap::value_type& kvPair) { - deallocateAll(); + if (!addIfNotExists(kvPair)) + SLANG_ASSERT_FAILURE("The key already exists in Dictionary."); } - }; + // Asserts if the key already exists in the dictionary + void add(const TKey& key, const TValue& value) { add({key, value}); } + // Asserts if the key already exists in the dictionary + void add(TKey&& key, TValue&& value) { add({std::move(key), std::move(value)}); } - // --------------------------------------------------------- - template - void Dictionary::swapWith(ThisType& rhs) - { - Swap(m_bucketCountMinusOne, rhs.m_bucketCountMinusOne); - Swap(m_count, rhs.m_count); - m_marks.swapWith(rhs.m_marks); - Swap(m_hashMap, rhs.m_hashMap); - } + // Inserts into the dictionary or assigns if the key already exists + void set(const TKey& key, const TValue& value) { map.insert_or_assign(key, value); } + }; /* We may want to rename this, as strictly speaking _Caps names are reserved */ class _DummyClass @@ -611,16 +305,18 @@ namespace Slang class Iterator { private: - typename DictionaryType::Iterator iter; + typename DictionaryType::ConstIterator iter; public: Iterator() = default; - T& operator*() const + const T& operator*() const { - return (*iter).key; + const auto& [k, v] = *iter; + return k; } - T* operator->() const + const T* operator->() const { - return &(*iter).key; + const auto& [k, v] = *iter; + return &k; } Iterator& operator++() { @@ -641,7 +337,7 @@ namespace Slang { return iter == that.iter; } - Iterator(const typename DictionaryType::Iterator& _iter) + Iterator(const typename DictionaryType::ConstIterator& _iter) { this->iter = _iter; } @@ -655,7 +351,7 @@ namespace Slang return Iterator(dict.end()); } public: - int getCount() const + auto getCount() const { return dict.getCount(); } @@ -849,16 +545,13 @@ namespace Slang } public: - typedef typename LinkedList>::Iterator Iterator; + using Iterator = typename LinkedList>::Iterator; + using ConstIterator = typename LinkedList>::ConstIterator; - typename LinkedList>::Iterator begin() const - { - return m_kvPairs.begin(); - } - typename LinkedList>::Iterator end() const - { - return m_kvPairs.end(); - } + Iterator begin() { return m_kvPairs.begin(); } + Iterator end() { return m_kvPairs.end(); } + ConstIterator begin() const { return m_kvPairs.begin(); } + ConstIterator end() const { return m_kvPairs.end(); } public: void add(const TKey& key, const TValue& value) diff --git a/source/core/slang-file-system.cpp b/source/core/slang-file-system.cpp index e6d84cac1..7c3cd83bb 100644 --- a/source/core/slang-file-system.cpp +++ b/source/core/slang-file-system.cpp @@ -319,11 +319,8 @@ CacheFileSystem::CacheFileSystem(ISlangFileSystem* fileSystem, UniqueIdentityMod CacheFileSystem::~CacheFileSystem() { - for (const auto& pair : m_uniqueIdentityMap) - { - PathInfo* pathInfo = pair.value; + for (const auto& [_, pathInfo] : m_uniqueIdentityMap) delete pathInfo; - } } void CacheFileSystem::setInnerFileSystem(ISlangFileSystem* fileSystem, UniqueIdentityMode uniqueIdentityMode, PathStyle pathStyle) @@ -374,11 +371,8 @@ void CacheFileSystem::setInnerFileSystem(ISlangFileSystem* fileSystem, UniqueIde void CacheFileSystem::clearCache() { - for (const auto& pair : m_uniqueIdentityMap) - { - PathInfo* pathInfo = pair.value; + for (const auto& [_, pathInfo] : m_uniqueIdentityMap) delete pathInfo; - } m_uniqueIdentityMap.clear(); m_pathMap.clear(); @@ -434,11 +428,10 @@ SlangResult CacheFileSystem::enumeratePathContents(const char* path, FileSystemC simplifiedPath = ""; } - for (auto& pair : m_pathMap) + for (const auto& [currentPath, pathInfo] : m_pathMap) { // NOTE! The currentPath can be a *non* simplified path (the m_pathMap is the cache of paths simplified and other to a file/directory) // Also note that there will always be the simplified version of the path in cache. - const String& currentPath = pair.key; // If it doesn't start with simplified path, then it can't be a hit if (!currentPath.startsWith(simplifiedPath)) @@ -468,8 +461,6 @@ SlangResult CacheFileSystem::enumeratePathContents(const char* path, FileSystemC // Let's check that fact... SLANG_ASSERT(foundPath[remaining.getLength()] == 0); - PathInfo* pathInfo = pair.value; - SlangPathType pathType; if (SLANG_FAILED(_getPathType(pathInfo, currentPath.getBuffer(), &pathType))) { @@ -548,7 +539,7 @@ SlangResult CacheFileSystem::_calcUniqueIdentity(const String& path, String& out } // Calculate the hash on the contents - const uint64_t hash = getHashCode64((const char*)outFileContents->getBufferPointer(), outFileContents->getBufferSize()); + const StableHashCode64 hash = getStableHashCode64((const char*)outFileContents->getBufferPointer(), outFileContents->getBufferSize()); String hashString = Path::getFileName(path); hashString = hashString.toLower(); @@ -556,7 +547,7 @@ SlangResult CacheFileSystem::_calcUniqueIdentity(const String& path, String& out hashString.append(':'); // The uniqueIdentity is a combination of name and hash - hashString.append(hash, 16); + hashString.append(hash); outUniqueIdentity = hashString; return SLANG_OK; diff --git a/source/core/slang-hash.h b/source/core/slang-hash.h index 5f6b1b060..49685ee65 100644 --- a/source/core/slang-hash.h +++ b/source/core/slang-hash.h @@ -1,196 +1,171 @@ #ifndef SLANG_CORE_HASH_H #define SLANG_CORE_HASH_H +#include "../../slang.h" #include "slang-math.h" -#include +#include "../../external/unordered_dense/include/ankerl/unordered_dense.h" +#include #include namespace Slang { - // Ideally Hash codes should be unsigned types - makes accumulation simpler (as overflow/underflow behavior are defined) - // Only downside is around multiply, where unsigned multiply can be slightly slower on some targets. - - // HashCode - size may vary by platform. Typically has 'best' combination of bits/performance. Should not be exposed externally as value from same input may change depending on compilation platform. - typedef unsigned int HashCode; + // + // Types + // // A fixed 64bit wide hash on all targets. typedef uint64_t HashCode64; + typedef HashCode64 HashCode; // A fixed 32bit wide hash on all targets. typedef uint32_t HashCode32; - SLANG_FORCE_INLINE HashCode32 toHash32(HashCode value) { return (sizeof(HashCode) == sizeof(int64_t)) ? (HashCode32(uint64_t(value) >> 32) ^ HashCode(value)) : HashCode32(value); } - SLANG_FORCE_INLINE HashCode64 toHash64(HashCode value) { return (sizeof(HashCode) == sizeof(int64_t)) ? HashCode(value) : ((HashCode64(value) << 32) | value); } - - SLANG_FORCE_INLINE HashCode getHashCode(int64_t value) - { - return (sizeof(HashCode) == sizeof(int64_t)) ? HashCode(value) : (HashCode(uint64_t(value) >> 32) ^ HashCode(value)); - } - SLANG_FORCE_INLINE HashCode getHashCode(uint64_t value) + // + // Some helpers to determine which hash to use for a type + // + + // Forward declare Hash + template struct Hash; + + template + constexpr static bool HasSlangHash = false; + template + constexpr static bool HasSlangHash< + T, + std::enable_if_t()).getHashCode()), + HashCode64>>> + = true; + + // Does the hashmap implementation provide a uniform hash for this type. + template + constexpr static bool HasWyhash = false; + template + constexpr static bool HasWyhash::is_avalanching> = true; + + // We want to have an associated type 'is_avalanching = void' iff we have a + // hash with good uniformity, the two specializations here add that member + // when appropriate (since we can't declare an associated type with + // constexpr if or something terse like that) + template + struct DetectAvalanchingHash {}; + template + struct DetectAvalanchingHash>> { - return (sizeof(HashCode) == sizeof(uint64_t)) ? HashCode(value) : (HashCode(value >> 32) ^ HashCode(value)); - } - - inline HashCode getHashCode(double key) - { - return getHashCode(DoubleAsInt64(key)); - } - inline HashCode getHashCode(float key) - { - return FloatAsInt(key); - } - inline HashCode getHashCode(const char* buffer) - { - if (!buffer) - return 0; - HashCode hash = 0; - auto str = buffer; - HashCode c = HashCode(*str++); - while (c) - { - hash = c + (hash << 6) + (hash << 16) - hash; - c = HashCode(*str++); - } - return hash; - } - inline HashCode getHashCode(char* buffer) - { - return getHashCode(const_cast(buffer)); - } - inline HashCode getHashCode(const char* buffer, size_t numChars) + using is_avalanching = void; + }; + // Have we marked 'getHashCode' as having good uniformity properties. + template + struct DetectAvalanchingHash> { - HashCode hash = 0; - for (size_t i = 0; i < numChars; ++i) - { - hash = HashCode(buffer[i]) + (hash << 6) + (hash << 16) - hash; - } - return hash; - } - - /* The 'Stable' hash code functions produce hashes that must be - - * The same result for the same inputs on all targets - * Rarely change - as their values can change the output of the Slang API/Serialization - - Hash value used from the 'Stable' functions can also be used as part of serialization - - so it is in effect part of the API. + using is_avalanching = void; + }; - In effect this means changing a 'Stable' algorithm will typically require doing a new release. - */ - inline HashCode32 getStableHashCode32(const char* buffer, size_t numChars) + // A helper for hashing according to the bit representation + template + struct BitCastHash : DetectAvalanchingHash { - HashCode32 hash = 0; - for (size_t i = 0; i < numChars; ++i) + auto operator()(const T& t) const { - hash = HashCode32(buffer[i]) + (hash << 6) + (hash << 16) - hash; + // Doesn't discard or invent bits + static_assert(sizeof(T) == sizeof(U)); + // Can we copy bytes to and fro + static_assert(std::is_trivially_copyable_v); + static_assert(std::is_trivially_copyable_v); + // Because we construct a U to memcpy into + static_assert(std::is_trivially_constructible_v); + + U u; + memcpy(&u, &t, sizeof(T)); + return Hash{}(u); } - return hash; - } + }; - inline HashCode64 getStableHashCode64(const char* buffer, size_t numChars) + // + // Our hashing functor which disptaches to the most appropriate hashing + // function for the type + // + + template + struct Hash : DetectAvalanchingHash { - // Use HashCode64 is assumed unsigned because hash requires wrap around behavior and int is undefined on over/underflows - HashCode64 hash = 0; - for (size_t i = 0; i < numChars; ++i) + auto operator()(const T& t) const { - hash = HashCode64(HashCode64(buffer[i])) + (hash << 6) + (hash << 16) - hash; + // Our preference is for any hash we've defined ourselves + if constexpr (HasSlangHash) + return t.getHashCode(); + // Otherwise fall back to any good hash provided by the hashmap + // library + else if constexpr (HasWyhash) + return ankerl::unordered_dense::hash{}(t); + // Otherwise fail + else + { + // !sizeof(T*) is a 'false' which is dependent on T (pending P2593R0) + static_assert(!sizeof(T*), "No hash implementation found for this type"); + // This is to avoid the return type being deduced as 'void' and creating further errors. + return HashCode64(0); + } } - return hash; - } + }; - // Hash functions with specific sized results - // TODO(JS): We might want to implement HashCode as just an alias a suitable Hash32/Hash32 based on target. - // For now just use Stable for 64bit. - SLANG_FORCE_INLINE HashCode64 getHashCode64(const char* buffer, size_t numChars) { return getStableHashCode64(buffer, numChars); } - SLANG_FORCE_INLINE HashCode32 getHashCode32(const char* buffer, size_t numChars) { return toHash32(getHashCode(buffer, numChars)); } + // Specializations for float and double which hash 0 and -0 to distinct values + template<> + struct Hash : BitCastHash {}; + template<> + struct Hash : BitCastHash {}; - template - class Hash - { - public: - }; - template<> - class Hash<1> - { - public: - template - static HashCode getHashCode(TKey& key) - { - return (HashCode)key; - } - }; - template<> - class Hash<0> - { - public: - template - static HashCode getHashCode(TKey& key) - { - return HashCode(key.getHashCode()); - } - }; - template - class PointerHash - {}; - template<> - class PointerHash<1> - { - public: - template - static HashCode getHashCode(TKey const& key) - { - return (HashCode)((PtrInt)key) >> 2; // sizeof(typename std::remove_pointer::type); - } - }; - template<> - class PointerHash<0> - { - public: - template - static HashCode getHashCode(TKey& key) - { - return Hash::value || std::is_enum::value>::getHashCode(key); - } - }; + // + // Utility functions for using hashes + // + // A wrapper for Hash template - HashCode getHashCode(const TKey& key) + auto getHashCode(const TKey& key) { - return PointerHash::value>::getHashCode(key); + return Hash{}(key); } - template - HashCode getHashCode(TKey& key) + inline HashCode64 getHashCode(const char* buffer, std::size_t len) { - return PointerHash::value>::getHashCode(key); + return ankerl::unordered_dense::detail::wyhash::hash(buffer, len); } - template - HashCode getHashCodeBytewise(const TKey& t) + template + HashCode64 hashObjectBytes(const T& t) { - static_assert(std::has_unique_object_representations_v); - return getHashCode(reinterpret_cast(&t), sizeof(TKey)); + static_assert(std::has_unique_object_representations_v, + "This type must have a unique object representation to use hashObjectBytes"); + return getHashCode(reinterpret_cast(&t), sizeof(t)); } - inline HashCode combineHash(HashCode left, HashCode right) + // Use in a struct to declare a uniform hash which doens't care about the + // structure of the members. +# define SLANG_BYTEWISE_HASHABLE \ + static constexpr bool kHasUniformHash = true; \ + ::Slang::HashCode64 getHashCode() const \ + { \ + return ::Slang::hashObjectBytes(*this); \ + } + + inline HashCode64 combineHash(HashCode64 h) { - return (left * 16777619) ^ right; + return h; } - inline HashCode combineHash(HashCode hash0, HashCode hash1, HashCode hash2) + inline HashCode32 combineHash(HashCode32 h) { - auto h = hash0; - h = combineHash(h, hash1); - h = combineHash(h, hash2); return h; } - inline HashCode combineHash(HashCode hash0, HashCode hash1, HashCode hash2, HashCode hash3) + // A left fold of a mixing operation + template + auto combineHash(H1 n, H2 m, Hs... args) { - auto h = hash0; - h = combineHash(h, hash1); - h = combineHash(h, hash2); - h = combineHash(h, hash3); - return h; + // TODO: restrict the types here more, currently we tend to throw + // unhashed integers in here along with proper hashes of objects. + static_assert(std::is_convertible_v || std::is_convertible_v); + static_assert(std::is_convertible_v || std::is_convertible_v); + return combineHash((n * 16777619) ^ m, args...); } struct Hasher @@ -209,17 +184,6 @@ namespace Slang m_hashCode = combineHash(m_hashCode, getHashCode(value)); } - /// Hash the given `object` and combine it into this hash state - template - void hashObject(T const& object) - { - // TODO: Eventually, we should replace `getHashCode` - // with a "hash into" operation that takes the value - // and a `Hasher`. - - m_hashCode = combineHash(m_hashCode, object->getHashCode()); - } - /// Combine the given `hash` code into the hash state. /// /// Note: users should prefer to use `hashValue` or `hashObject` diff --git a/source/core/slang-hex-dump-util.cpp b/source/core/slang-hex-dump-util.cpp index bbee0a199..3a78c256a 100644 --- a/source/core/slang-hex-dump-util.cpp +++ b/source/core/slang-hex-dump-util.cpp @@ -28,8 +28,8 @@ static const char s_hex[] = "0123456789abcdef"; SLANG_RETURN_ON_FAIL(helper.write(s_start.begin(), s_start.getLength())); SLANG_RETURN_ON_FAIL(helper.print(" %zu", dataCount)); - const HashCode32 hash = getStableHashCode32((const char*)data, dataCount); - SLANG_RETURN_ON_FAIL(helper.print(" %d\n", int(hash) )); + const StableHashCode32 hash = getStableHashCode32((const char*)data, dataCount); + SLANG_RETURN_ON_FAIL(helper.print(" %d\n", hash.hash )); SLANG_RETURN_ON_FAIL(dump(data, dataCount, maxBytesPerLine, writer)); @@ -216,7 +216,7 @@ static SlangResult _findLine(const UnownedStringSlice& find, UnownedStringSlice& UnownedStringSlice startLine, endLine; SLANG_RETURN_ON_FAIL(findStartAndEndLines(lines, startLine, endLine)); - HashCode32 hash; + StableHashCode32 hash; size_t size; { // Get the size and the hash @@ -228,13 +228,13 @@ static SlangResult _findLine(const UnownedStringSlice& find, UnownedStringSlice& } // Extract the size size = stringToInt(String(slices[1])); - hash = HashCode32(stringToInt(String(slices[2]))); + hash = StableHashCode32{stringToUInt(String(slices[2]))}; } SLANG_RETURN_ON_FAIL(parse(UnownedStringSlice(startLine.end(), endLine.begin()), outBytes)); // Calc the hash - const HashCode32 readHash = getStableHashCode32((const char*)outBytes.begin(), outBytes.getCount()); + const StableHashCode32 readHash = getStableHashCode32((const char*)outBytes.begin(), outBytes.getCount()); if (readHash != hash || size_t(outBytes.getCount()) != size) { diff --git a/source/core/slang-linked-list.h b/source/core/slang-linked-list.h index 41709c9d0..93b5e435c 100644 --- a/source/core/slang-linked-list.h +++ b/source/core/slang-linked-list.h @@ -4,6 +4,7 @@ #include "../../slang.h" #include "slang-allocator.h" +#include namespace Slang { @@ -28,6 +29,7 @@ public: }; LinkedNode* getPrevious() { return prev; }; LinkedNode* getNext() { return next; }; + const LinkedNode* getNext() const { return next; }; LinkedNode* insertAfter(const T& nData) { LinkedNode* n = new LinkedNode(list); @@ -88,37 +90,46 @@ private: int count; public: - class Iterator + template + class GenIterator { public: - LinkedNode* current, *next; - void setCurrent(LinkedNode* cur) + using Node = std::conditional_t, LinkedNode>; + Node* current, *next; + void setCurrent(Node* cur) { current = cur; if (current) next = current->getNext(); else - next = 0; + next = nullptr; } - Iterator() { current = next = nullptr; } - Iterator(LinkedNode* cur) { setCurrent(cur); } - T& operator*() const { return current->value; } - Iterator& operator++() + GenIterator() { current = next = nullptr; } + GenIterator(Node* cur) { setCurrent(cur); } + std::conditional_t + operator*() const { return current->value; } + GenIterator& operator++() { setCurrent(next); return *this; } - Iterator operator++(int) + GenIterator operator++(int) { - Iterator rs = *this; + GenIterator rs = *this; setCurrent(next); return rs; } - bool operator!=(const Iterator& iter) const { return current != iter.current; } - bool operator==(const Iterator& iter) const { return current == iter.current; } + bool operator!=(const GenIterator& iter) const { return current != iter.current; } + bool operator==(const GenIterator& iter) const { return current == iter.current; } }; - Iterator begin() const { return Iterator(head); } - Iterator end() const { return Iterator(0); } + + using Iterator = GenIterator; + Iterator begin() { return Iterator(head); } + Iterator end() { return Iterator(0); } + + using ConstIterator = GenIterator; + ConstIterator begin() const { return ConstIterator(head); } + ConstIterator end() const { return ConstIterator(0); } public: LinkedList() diff --git a/source/core/slang-memory-file-system.cpp b/source/core/slang-memory-file-system.cpp index eabd13072..b24abc20b 100644 --- a/source/core/slang-memory-file-system.cpp +++ b/source/core/slang-memory-file-system.cpp @@ -171,10 +171,9 @@ SlangResult MemoryFileSystem::enumeratePathContents(const char* path, FileSystem ImplicitDirectoryCollector collector(canonicalPath, true); // If it is a directory, we need to see if there is anything in it - for (const auto& pair : m_entries) + for (const auto& [_, childEntry] : m_entries) { - const Entry* childEntry = &pair.value; - collector.addPath(childEntry->m_type, childEntry->m_canonicalPath.getUnownedSlice()); + collector.addPath(childEntry.m_type, childEntry.m_canonicalPath.getUnownedSlice()); } return collector.enumerate(callback, userData); @@ -275,10 +274,9 @@ SlangResult MemoryFileSystem::remove(const char* path) ImplicitDirectoryCollector collector(canonicalPath); // If it is a directory, we need to see if there is anything in it - for (const auto& pair : m_entries) + for (const auto& [_, childEntry] : m_entries) { - const Entry* childEntry = &pair.value; - collector.addPath(childEntry->m_type, childEntry->m_canonicalPath.getUnownedSlice()); + collector.addPath(childEntry.m_type, childEntry.m_canonicalPath.getUnownedSlice()); if (collector.hasContent()) { // Directory is not empty diff --git a/source/core/slang-riff-file-system.cpp b/source/core/slang-riff-file-system.cpp index 9db330956..1fb867500 100644 --- a/source/core/slang-riff-file-system.cpp +++ b/source/core/slang-riff-file-system.cpp @@ -235,12 +235,10 @@ SlangResult RiffFileSystem::storeArchive(bool blobOwnsContent, ISlangBlob** outB container.addDataChunk(RiffFileSystemBinary::kHeaderFourCC, &header, sizeof(header)); } - for (const auto& pair : m_entries) + for (const auto& [_, srcEntry] : m_entries) { - const Entry* srcEntry = &pair.value; - // Ignore the root entry - if (srcEntry->m_canonicalPath == toSlice(".")) + if (srcEntry.m_canonicalPath == toSlice(".")) { continue; } @@ -250,22 +248,22 @@ SlangResult RiffFileSystem::storeArchive(bool blobOwnsContent, ISlangBlob** outB RiffFileSystemBinary::Entry dstEntry; dstEntry.uncompressedSize = 0; dstEntry.compressedSize = 0; - dstEntry.pathSize = uint32_t(srcEntry->m_canonicalPath.getLength() + 1); - dstEntry.pathType = srcEntry->m_type; + dstEntry.pathSize = uint32_t(srcEntry.m_canonicalPath.getLength() + 1); + dstEntry.pathType = srcEntry.m_type; - ISlangBlob* blob = srcEntry->m_contents; + ISlangBlob* blob = srcEntry.m_contents; - if (srcEntry->m_type == SLANG_PATH_TYPE_FILE) + if (srcEntry.m_type == SLANG_PATH_TYPE_FILE) { dstEntry.compressedSize = uint32_t(blob->getBufferSize()); - dstEntry.uncompressedSize = uint32_t(srcEntry->m_uncompressedSizeInBytes); + dstEntry.uncompressedSize = uint32_t(srcEntry.m_uncompressedSizeInBytes); } // Entry header container.write(&dstEntry, sizeof(dstEntry)); // Path - container.write(srcEntry->m_canonicalPath.getBuffer(), srcEntry->m_canonicalPath.getLength() + 1); + container.write(srcEntry.m_canonicalPath.getBuffer(), srcEntry.m_canonicalPath.getLength() + 1); // Add the contained data without copying if (blob) diff --git a/source/core/slang-smart-pointer.h b/source/core/slang-smart-pointer.h index 80e8adbf1..a161f1b83 100644 --- a/source/core/slang-smart-pointer.h +++ b/source/core/slang-smart-pointer.h @@ -153,7 +153,7 @@ namespace Slang releaseReference(old); } - HashCode getHashCode() + HashCode getHashCode() const { // Note: We need a `RefPtr` to hash the same as a `T*`, // so that a `T*` can be used as a key in a dictionary with diff --git a/source/core/slang-stable-hash.h b/source/core/slang-stable-hash.h new file mode 100644 index 000000000..30a47121e --- /dev/null +++ b/source/core/slang-stable-hash.h @@ -0,0 +1,99 @@ +#pragma once + +#include +#include +#include + +namespace Slang +{ + // + // Types + // + + struct StableHashCode64 + { + uint64_t hash; + explicit operator uint64_t() const { return hash; } + bool operator==(StableHashCode64 other) const { return other.hash == hash; }; + bool operator!=(StableHashCode64 other) const { return other.hash != hash; }; + }; + + struct StableHashCode32 + { + uint32_t hash; + explicit operator uint32_t() const { return hash; } + bool operator==(StableHashCode32 other) const { return other.hash == hash; }; + bool operator!=(StableHashCode32 other) const { return other.hash != hash; }; + }; + + /* The 'Stable' hash code functions produce hashes that must be + + * The same result for the same inputs on all targets + * Rarely change - as their values can change the output of the Slang API/Serialization + + Hash value used from the 'Stable' functions can also be used as part of serialization - + so it is in effect part of the API. + + In effect this means changing a 'Stable' algorithm will typically require doing a new release. + */ + inline StableHashCode64 getStableHashCode64(const char* buffer, size_t numChars) + { + uint64_t hash = 0; + for (size_t i = 0; i < numChars; ++i) + { + hash = uint64_t(buffer[i]) + (hash << 6) + (hash << 16) - hash; + } + return StableHashCode64{hash}; + } + + template + inline StableHashCode64 getStableHashCode64(const T& t) + { + static_assert(std::has_unique_object_representations_v); + return getStableHashCode64(reinterpret_cast(&t), sizeof(T)); + } + + inline StableHashCode32 getStableHashCode32(const char* buffer, size_t numChars) + { + uint32_t hash = 0; + for (size_t i = 0; i < numChars; ++i) + { + hash = uint32_t(buffer[i]) + (hash << 6) + (hash << 16) - hash; + } + return StableHashCode32{hash}; + } + + template + inline StableHashCode32 getStableHashCode32(const T& t) + { + static_assert(std::has_unique_object_representations_v); + return getStableHashCode32(reinterpret_cast(&t), sizeof(T)); + } + + inline StableHashCode64 combineStableHash(StableHashCode64 h) + { + return h; + } + + inline StableHashCode32 combineStableHash(StableHashCode32 h) + { + return h; + } + + // A left fold with a mixing operation + template + H combineStableHash(H n, H m, Hs... args) + { + return combineStableHash(H{(n.hash * 16777619) ^ m.hash}, args...); + } +} + +// > Please draw a small horse in ASCII art: +// +// ,~~. +// ( 9 )-_, +// (\___ )=='-' ) +// \ . ) ) / +// \ `-' / / +// ~'`~'`~'`~'`~ +// diff --git a/source/core/slang-string.cpp b/source/core/slang-string.cpp index dd2138c83..182c6261e 100644 --- a/source/core/slang-string.cpp +++ b/source/core/slang-string.cpp @@ -612,6 +612,24 @@ namespace Slang m_buffer->length += strnlen_s(data, kCount); } + void String::append(StableHashCode32 value) + { + const Index digits = 8; + // + null terminator + char* data = prepareForAppend(digits + 1); + auto count = intToAscii(data, value.hash, 16, digits); + m_buffer->length += count; + } + + void String::append(StableHashCode64 value) + { + const Index digits = 16; + // + null terminator + char* data = prepareForAppend(digits + 1); + auto count = intToAscii(data, value.hash, 16, digits); + m_buffer->length += count; + } + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! UnownedStringSlice !!!!!!!!!!!!!!!!!!!!!!!!!!!!! Index UnownedStringSlice::indexOf(char c) const diff --git a/source/core/slang-string.h b/source/core/slang-string.h index 65fd3a315..3f401b7bb 100644 --- a/source/core/slang-string.h +++ b/source/core/slang-string.h @@ -10,8 +10,10 @@ #include "slang-common.h" #include "slang-hash.h" #include "slang-secure-crt.h" +#include "slang-stable-hash.h" #include +#include namespace Slang { @@ -32,8 +34,10 @@ namespace Slang } } template - inline int intToAscii(char* buffer, IntType val, int radix) + inline int intToAscii(char* buffer, IntType val, int radix, int padTo = 0) { + static_assert(std::is_integral_v); + int i = 0; IntType sign; @@ -52,6 +56,9 @@ namespace Slang buffer[i++] = (char)(digit - 10 + 'A'); } while ((val /= radix) > 0); + while(i < padTo) + buffer[i++] = '0'; + if (sign < 0) buffer[i++] = '-'; @@ -189,7 +196,8 @@ namespace Slang /// Trims any horizonatl whitespace from start and returns as a substring UnownedStringSlice trimStart() const; - HashCode getHashCode() const + static constexpr bool kHasUniformHash = true; + HashCode64 getHashCode() const { return Slang::getHashCode(m_begin, size_t(m_end - m_begin)); } @@ -508,6 +516,10 @@ namespace Slang void append(float val, const char* format = "%g"); void append(double val, const char* format = "%g"); + // Padded hex representations + void append(StableHashCode32 val); + void append(StableHashCode64 val); + void append(char const* str); void append(char const* str, size_t len); void append(const char* textBegin, char const* textEnd); @@ -549,6 +561,14 @@ namespace Slang { append(val, radix); } + explicit String(StableHashCode32 val) + { + append(val); + } + explicit String(StableHashCode64 val) + { + append(val); + } explicit String(float val, const char* format = "%g") { append(val, format); @@ -869,7 +889,8 @@ namespace Slang return contains(str.begin()); } - HashCode getHashCode() const + static constexpr bool kHasUniformHash = true; + HashCode64 getHashCode() const { return Slang::getHashCode(StringRepresentation::asSlice(m_buffer)); } diff --git a/source/slang/slang-ast-base.h b/source/slang/slang-ast-base.h index 0eefbab0f..777098943 100644 --- a/source/slang/slang-ast-base.h +++ b/source/slang/slang-ast-base.h @@ -484,11 +484,11 @@ struct ValSet ValItem() = default; ValItem(Val* v) : val(v) {} - HashCode getHashCode() + HashCode getHashCode() const { return val ? val->getHashCode() : 0; } - bool operator==(ValItem other) + bool operator==(const ValItem other) const { if (val == other.val) return true; diff --git a/source/slang/slang-ast-builder.cpp b/source/slang/slang-ast-builder.cpp index a76f6e07f..4a3756c1f 100644 --- a/source/slang/slang-ast-builder.cpp +++ b/source/slang/slang-ast-builder.cpp @@ -210,19 +210,13 @@ void SharedASTBuilder::registerMagicDecl(Decl* decl, MagicTypeModifier* modifier Decl* SharedASTBuilder::findMagicDecl(const String& name) { - return m_magicDecls[name].getValue(); + return m_magicDecls.getValue(name); } Decl* SharedASTBuilder::tryFindMagicDecl(const String& name) { - if (m_magicDecls.containsKey(name)) - { - return m_magicDecls[name].getValue(); - } - else - { - return nullptr; - } + auto d = m_magicDecls.tryGetValue(name); + return d ? *d : nullptr; } // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ASTBuilder !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! diff --git a/source/slang/slang-ast-builder.h b/source/slang/slang-ast-builder.h index 2674ef1b2..338993552 100644 --- a/source/slang/slang-ast-builder.h +++ b/source/slang/slang-ast-builder.h @@ -57,7 +57,7 @@ public: Decl* findBuiltinRequirementDecl(BuiltinRequirementKind kind) { - return m_builtinRequirementDecls[kind].getValue(); + return m_builtinRequirementDecls.getValue(kind); } /// A name pool that can be used for lookup for findClassInfo etc. It is the same pool as the Session. @@ -154,6 +154,35 @@ struct ValKey HashCode getHashCode() const { return hashCode; } }; +// Add a specialization which can hash both ValKey and ValNodeDesc +template<> +struct Hash +{ + using is_transparent = void; + auto operator()(const ValKey& k) const + { + return k.getHashCode(); + } + auto operator()(const ValNodeDesc& k) const + { + return Hash{}(k); + } +}; + +// A functor which can compare ValKey for equality with ValNodeDesc +struct ValKeyEqual +{ + using is_transparent = void; + bool operator()(const Slang::ValKey& a, const Slang::ValKey& b) const + { + return a == b; + } + bool operator()(const Slang::ValNodeDesc& a, const Slang::ValKey& b) const + { + return b == a; + } +}; + class ASTBuilder : public RefObject { friend class SharedASTBuilder; @@ -176,7 +205,7 @@ public: /// A cache for AST nodes that are entirely defined by their node type, with /// no need for additional state. - Dictionary m_cachedNodes; + Dictionary, ValKeyEqual> m_cachedNodes; Dictionary> m_cachedGenericDefaultArgs; diff --git a/source/slang/slang-ast-dump.cpp b/source/slang/slang-ast-dump.cpp index 65718833b..d016d1c15 100644 --- a/source/slang/slang-ast-dump.cpp +++ b/source/slang/slang-ast-dump.cpp @@ -386,11 +386,8 @@ struct ASTDumpContext m_writer->emit(" { \n"); m_writer->indent(); - for (auto iter : dict) + for (const auto& [key, value] : dict) { - const auto& key = iter.key; - const auto& value = iter.value; - dump(key); m_writer->emit(" : "); dump(value); diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h index b1d3a34a2..5d7ca49cb 100644 --- a/source/slang/slang-ast-support-types.h +++ b/source/slang/slang-ast-support-types.h @@ -1413,7 +1413,7 @@ namespace Slang witnessTable, }; - Flavor getFlavor() + Flavor getFlavor() const { return m_flavor; } diff --git a/source/slang/slang-check-decl.cpp b/source/slang/slang-check-decl.cpp index 6385e5f57..8c9ca2936 100644 --- a/source/slang/slang-check-decl.cpp +++ b/source/slang/slang-check-decl.cpp @@ -2006,11 +2006,11 @@ namespace Slang // Once things are done, we will install the satisfying values // into the witness table for the requirements. // - for( auto p : mapRequiredToSatisfyingAccessorDeclRef ) + for( const auto& [key, value] : mapRequiredToSatisfyingAccessorDeclRef ) { witnessTable->add( - p.key.getDecl(), - RequirementWitness(p.value)); + key.getDecl(), + RequirementWitness(value)); } // // Note: the property declaration itself isn't something that @@ -2559,10 +2559,10 @@ namespace Slang // if (auto typeParamDecl = as(constraintDecl->sub.type)->getDeclRef().as().getDecl()) { - auto synTypeParamDecl = mapOrigToSynTypeParams[typeParamDecl]; + auto synTypeParamDecl = mapOrigToSynTypeParams.getValue(typeParamDecl); // Construct a DeclRefExpr from the type parameter. - auto synTypeParamDeclRef = makeDeclRef(synTypeParamDecl.getValue()); + auto synTypeParamDeclRef = makeDeclRef(synTypeParamDecl); auto synTypeParamDeclRefExpr = m_astBuilder->create(); synTypeParamDeclRefExpr->declRef = synTypeParamDeclRef; @@ -3262,9 +3262,9 @@ namespace Slang // difference between our synthetic property and a hand-written // one with the same behavior. // - for(auto p : mapRequiredAccessorToSynAccessor) + for(auto& [key, value] : mapRequiredAccessorToSynAccessor) { - witnessTable->add(p.key.getDecl(), RequirementWitness(makeDeclRef(p.value))); + witnessTable->add(key.getDecl(), RequirementWitness(makeDeclRef(value))); } witnessTable->add(requiredMemberDeclRef.getDecl(), RequirementWitness(makeDeclRef(synPropertyDecl))); @@ -3531,7 +3531,6 @@ namespace Slang { case SynthesisPattern::AllInductive: { - int paramIndex = 0; for (auto arg : synArgs) { auto memberExpr = m_astBuilder->create(); @@ -3541,8 +3540,6 @@ namespace Slang memberExpr->name = varMember->getName(); paramFields.add(memberExpr); inductiveArgMask.add(true); - - paramIndex++; } break; } @@ -5460,9 +5457,8 @@ namespace Slang _addTargetModifiers(newDecl, newTargets); bool hasConflict = false; - for (auto& pair : newTargets) + for (auto& [target, value] : newTargets) { - Name* target = pair.key; auto found = currentTargets.tryGetValue(target); if (found) { @@ -6666,10 +6662,10 @@ namespace Slang void SharedSemanticsContext::_addCandidateExtensionsFromModule(ModuleDecl* moduleDecl) { - for( auto& entry : moduleDecl->mapTypeToCandidateExtensions ) + for( auto& [entryKey, entryValue] : moduleDecl->mapTypeToCandidateExtensions ) { - auto& list = _getCandidateExtensionList(entry.key, m_mapTypeDeclToCandidateExtensions); - list.addRange(entry.value->candidateExtensions); + auto& list = _getCandidateExtensionList(entryKey, m_mapTypeDeclToCandidateExtensions); + list.addRange(entryValue->candidateExtensions); } } diff --git a/source/slang/slang-check-impl.h b/source/slang/slang-check-impl.h index 6cb719e43..8e37e7967 100644 --- a/source/slang/slang-check-impl.h +++ b/source/slang/slang-check-impl.h @@ -115,7 +115,7 @@ namespace Slang bool isValid() const { return type1.getRaw() != BasicTypeKey::invalid().getRaw() && type2.getRaw() != BasicTypeKey::invalid().getRaw(); } - HashCode getHashCode() + HashCode getHashCode() const { return combineHash(type1.getRaw(), type2.getRaw()); } @@ -125,11 +125,11 @@ namespace Slang { intptr_t operatorName; BasicTypeKey args[2]; - bool operator == (OperatorOverloadCacheKey key) + bool operator == (OperatorOverloadCacheKey key) const { return operatorName == key.operatorName && args[0] == key.args[0] && args[1] == key.args[1]; } - HashCode getHashCode() + HashCode getHashCode() const { return combineHash((int)(UInt64)(void*)(operatorName), args[0].getRaw(), args[1].getRaw()); } diff --git a/source/slang/slang-compiler.cpp b/source/slang/slang-compiler.cpp index f786512d1..eecb86242 100644 --- a/source/slang/slang-compiler.cpp +++ b/source/slang/slang-compiler.cpp @@ -1063,14 +1063,10 @@ namespace Slang sourceTarget = CodeGenTarget(TypeConvertUtil::getCompileTargetFromSourceLanguage((SlangSourceLanguage)sourceLanguage)); // If it's pass through we accumulate the preprocessor definitions. - for (auto& define : translationUnit->compileRequest->preprocessorDefinitions) - { - preprocessorDefinitions.add(define.key, define.value); - } - for (auto& define : translationUnit->preprocessorDefinitions) - { - preprocessorDefinitions.add(define.key, define.value); - } + for (const auto& define : translationUnit->compileRequest->preprocessorDefinitions) + preprocessorDefinitions.add(define); + for (const auto& define : translationUnit->preprocessorDefinitions) + preprocessorDefinitions.add(define); { /* TODO(JS): Not totally clear what options should be set here. If we are using the pass through - then using say the defines/includes @@ -1148,10 +1144,8 @@ namespace Slang // of downstream compilation. auto linkage = getLinkage(); - for (auto& define : linkage->preprocessorDefinitions) - { - preprocessorDefinitions.add(define.key, define.value); - } + for (const auto& define : linkage->preprocessorDefinitions) + preprocessorDefinitions.add(define); } @@ -1398,12 +1392,12 @@ namespace Slang Index i = 0; - for(auto& def : preprocessorDefinitions) + for(const auto& [defKey, defValue] : preprocessorDefinitions) { auto& define = dst[i]; - define.nameWithSig = allocator.allocate(def.key); - define.value = allocator.allocate(def.value); + define.nameWithSig = allocator.allocate(defKey); + define.value = allocator.allocate(defValue); ++i; } diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h index 040773546..f29dc8dae 100755 --- a/source/slang/slang-compiler.h +++ b/source/slang/slang-compiler.h @@ -1697,11 +1697,11 @@ namespace Slang { slang::TypeReflection* elementType; slang::ContainerType containerType; - bool operator==(ContainerTypeKey other) + bool operator==(ContainerTypeKey other) const { return elementType == other.elementType && containerType == other.containerType; } - Slang::HashCode getHashCode() + Slang::HashCode getHashCode() const { return Slang::combineHash( Slang::getHashCode(elementType), Slang::getHashCode(containerType)); diff --git a/source/slang/slang-doc-markdown-writer.cpp b/source/slang/slang-doc-markdown-writer.cpp index 0e7856f1f..de7695d18 100644 --- a/source/slang/slang-doc-markdown-writer.cpp +++ b/source/slang/slang-doc-markdown-writer.cpp @@ -1064,9 +1064,9 @@ void DocMarkdownWriter::writeAggType(const ASTMarkup::Entry& entry, AggTypeDeclB auto& memberDict = aggTypeDecl->getMemberDictionary(); List uniqueMethods; - for (const auto& pair : memberDict) + for (const auto& [_, decl] : memberDict) { - CallableDecl* callableDecl = as(pair.value); + CallableDecl* callableDecl = as(decl); if (callableDecl && isVisible(callableDecl)) { uniqueMethods.add(callableDecl); diff --git a/source/slang/slang-emit-c-like.cpp b/source/slang/slang-emit-c-like.cpp index 95c691d8b..337860771 100644 --- a/source/slang/slang-emit-c-like.cpp +++ b/source/slang/slang-emit-c-like.cpp @@ -3,6 +3,7 @@ #include "../core/slang-writer.h" #include "../compiler-core/slang-name.h" +#include "../core/slang-stable-hash.h" #include "slang-ir-bind-existentials.h" #include "slang-ir-dce.h" @@ -833,7 +834,7 @@ void CLikeSourceEmitter::appendScrubbedName(const UnownedStringSlice& name, Stri if (length > maxTokenLength) { // We are going to output with a prefix and a hash of the full name - const HashCode64 hash = getStableHashCode64(out.getBuffer(), length); + const auto hash = getStableHashCode64(out.getBuffer(), length); // Two hex chars per byte const Index hashSize = sizeof(hash) * 2; @@ -848,7 +849,7 @@ void CLikeSourceEmitter::appendScrubbedName(const UnownedStringSlice& name, Stri // Let's add a _ to separate from the rest of the name out.appendChar('_'); // Append the hash in hex - out.append(uint64_t(hash), 16); + out.append(hash); SLANG_ASSERT(out.getLength() <= maxTokenLength); } @@ -2497,7 +2498,7 @@ void CLikeSourceEmitter::defaultEmitInstExpr(IRInst* inst, const EmitOpInfo& inO if (stringLit) { auto slice = stringLit->getStringSlice(); - m_writer->emit(static_cast(getStableHashCode32(slice.begin(), slice.getLength()))); + m_writer->emit(getStableHashCode32(slice.begin(), slice.getLength()).hash); } else { diff --git a/source/slang/slang-emit-source-writer.cpp b/source/slang/slang-emit-source-writer.cpp index 4ff547119..fa362d874 100644 --- a/source/slang/slang-emit-source-writer.cpp +++ b/source/slang/slang-emit-source-writer.cpp @@ -186,38 +186,41 @@ void SourceWriter::emitName(Name* name) emitName(name, SourceLoc()); } -void SourceWriter::emit(IntegerLiteralValue value) +void SourceWriter::emitUInt64(uint64_t value) { - char buffer[32]; - sprintf(buffer, "%lld", (long long int)value); - emit(buffer); + emit(value); } -void SourceWriter::emit(UInt value) +void SourceWriter::emitInt64(int64_t value) { - char buffer[32]; - sprintf(buffer, "%llu", (unsigned long long)(value)); + emit(value); +} + +void SourceWriter::emit(Int32 value) +{ + char buffer[16]; + sprintf(buffer, "%" PRId32, value); emit(buffer); } -void SourceWriter::emitUInt64(uint64_t value) +void SourceWriter::emit(Int64 value) { char buffer[32]; - sprintf(buffer, "%llu", (unsigned long long)(value)); + sprintf(buffer, "%" PRId64, value); emit(buffer); } -void SourceWriter::emitInt64(int64_t value) +void SourceWriter::emit(UInt32 value) { char buffer[32]; - sprintf(buffer, "%lld", (long long int)value); + sprintf(buffer, "%" PRIu32, value); emit(buffer); } -void SourceWriter::emit(int value) +void SourceWriter::emit(UInt64 value) { - char buffer[16]; - sprintf(buffer, "%d", value); + char buffer[32]; + sprintf(buffer, "%" PRIu64, value); emit(buffer); } diff --git a/source/slang/slang-emit-source-writer.h b/source/slang/slang-emit-source-writer.h index 9a931bb98..84cdd06af 100644 --- a/source/slang/slang-emit-source-writer.h +++ b/source/slang/slang-emit-source-writer.h @@ -32,13 +32,15 @@ public: void emit(Name* name); void emit(const NameLoc& nameAndLoc); void emit(const StringSliceLoc& nameAndLoc); - void emit(IntegerLiteralValue value); void emitUInt64(uint64_t value); void emitInt64(int64_t value); - void emit(UInt value); - void emit(int value); + void emit(Int32 value); + void emit(UInt32 value); + void emit(Int64 value); + void emit(UInt64 value); + void emit(double value); void emitChar(char c); diff --git a/source/slang/slang-emit-spirv.cpp b/source/slang/slang-emit-spirv.cpp index 3947e8468..d93a50756 100644 --- a/source/slang/slang-emit-spirv.cpp +++ b/source/slang/slang-emit-spirv.cpp @@ -2533,8 +2533,7 @@ struct SPIRVEmitContext case SpvSnippet::ASMOperandType::ResultTypeId: if (operand.content != 0xFFFFFFFF) { - emitOperand(context.qualifiedResultTypes[(SpvStorageClass)operand.content] - .getValue()); + emitOperand(context.qualifiedResultTypes.getValue((SpvStorageClass)operand.content)); } else { diff --git a/source/slang/slang-ir-any-value-marshalling.cpp b/source/slang/slang-ir-any-value-marshalling.cpp index 35e063848..79aea9011 100644 --- a/source/slang/slang-ir-any-value-marshalling.cpp +++ b/source/slang/slang-ir-any-value-marshalling.cpp @@ -27,7 +27,7 @@ namespace Slang { IRType* originalType; IRIntegerValue anyValueSize; - bool operator ==(MarshallingFunctionKey other) + bool operator ==(MarshallingFunctionKey other) const { return originalType == other.originalType && anyValueSize == other.anyValueSize; } diff --git a/source/slang/slang-ir-autodiff-fwd.cpp b/source/slang/slang-ir-autodiff-fwd.cpp index 25051cb6d..c17d7d5c4 100644 --- a/source/slang/slang-ir-autodiff-fwd.cpp +++ b/source/slang/slang-ir-autodiff-fwd.cpp @@ -1608,10 +1608,8 @@ void insertTempVarForMutableParams(IRModule* module, IRFunc* func) if (inst->getOp() == kIROp_Return) { builder.setInsertBefore(inst); - for (auto& kv : mapParamToTempVar) - { - builder.emitStore(kv.key, builder.emitLoad(kv.value)); - } + for (const auto& [param, var] : mapParamToTempVar) + builder.emitStore(param, builder.emitLoad(var)); } } } diff --git a/source/slang/slang-ir-autodiff-primal-hoist.cpp b/source/slang/slang-ir-autodiff-primal-hoist.cpp index 898a86049..6ccf7caf4 100644 --- a/source/slang/slang-ir-autodiff-primal-hoist.cpp +++ b/source/slang/slang-ir-autodiff-primal-hoist.cpp @@ -108,7 +108,7 @@ static Dictionary createPrimalRecomputeBlocks( recomputeBlock->insertAtEnd(func); builder.addDecoration(recomputeBlock, kIROp_RecomputeBlockDecoration); recomputeBlockMap.add(primalBlock, recomputeBlock); - indexedBlockInfo[recomputeBlock] = indexedBlockInfo[primalBlock].getValue(); + indexedBlockInfo.set(recomputeBlock, indexedBlockInfo.getValue(primalBlock)); return recomputeBlock; }; @@ -188,7 +188,7 @@ static Dictionary createPrimalRecomputeBlocks( // Queue work for the subregion. auto loop = as(primalBlock->getTerminator()); auto bodyBlock = getLoopRegionBodyBlock(loop); - auto diffLoop = mapPrimalLoopToDiffLoop[loop].getValue(); + auto diffLoop = mapPrimalLoopToDiffLoop.getValue(loop); auto diffBodyBlock = getLoopRegionBodyBlock(diffLoop); auto bodyRecomputeBlock = createRecomputeBlock(bodyBlock); bodyRecomputeBlock->insertBefore(diffBodyBlock); @@ -499,11 +499,10 @@ RefPtr AutodiffCheckpointPolicyBase::processFunc( struct ImplicationParams { IRInst *condition, *induction, *block; - HashCode getHashCode() const { return getHashCodeBytewise(*this); } - // C++20: friend auto operator<=>(const ImplicationParams&, const ImplicationParams&) = default; - friend bool operator==(const ImplicationParams& x, const ImplicationParams& y) + SLANG_BYTEWISE_HASHABLE; + bool operator==(const ImplicationParams& other) const { - return x.condition == y.condition && x.induction == y.induction && x.block == y.block; + return condition == other.condition && induction == other.induction && block == other.block; } }; @@ -993,7 +992,7 @@ void applyCheckpointSet( predecessorSet.add(predecessor); auto primalPhiArg = as(predecessor->getTerminator())->getArg(ii); - auto recomputePredecessor = mapPrimalBlockToRecomputeBlock[predecessor].getValue(); + auto recomputePredecessor = mapPrimalBlockToRecomputeBlock.getValue(predecessor); // For now, find the primal phi argument in this predecessor, // and stick it into the recompute predecessor's branch inst. We @@ -1236,7 +1235,7 @@ static int getInstRegionNestLevel( IRBlock* defBlock, IRInst* inst) { - auto result = indexedBlockInfo[defBlock].getValue().getCount(); + auto result = indexedBlockInfo.getValue(defBlock).getCount(); // Loop counters are considered to not belong to the region started by the its loop. if (result > 0 && inst->findDecoration()) result--; @@ -1261,7 +1260,7 @@ static List maybeTrimIndices( { auto useInst = use->getUser(); auto useBlock = useInst->getParent(); - auto useBlockIndices = indexedBlockInfo[as(useBlock)].getValue(); + auto useBlockIndices = indexedBlockInfo.getValue(as(useBlock)); if (useBlockIndices.contains(index)) { found = true; @@ -1410,7 +1409,7 @@ RefPtr ensurePrimalAvailability( continue; } - auto defBlockIndices = indexedBlockInfo[defBlock].getValue(); + auto defBlockIndices = indexedBlockInfo.getValue(defBlock); IRBlock* varBlock = defaultVarBlock; if (isRecomputeInst) { diff --git a/source/slang/slang-ir-autodiff-primal-hoist.h b/source/slang/slang-ir-autodiff-primal-hoist.h index 96e4ea99b..d655d45a6 100644 --- a/source/slang/slang-ir-autodiff-primal-hoist.h +++ b/source/slang/slang-ir-autodiff-primal-hoist.h @@ -103,26 +103,21 @@ namespace Slang RefPtr applyMap(IRCloneEnv* env) { RefPtr newPrimalsInfo = new HoistedPrimalsInfo(); - - for (auto inst : this->storeSet) - if (env->mapOldValToNew.containsKey(inst)) - newPrimalsInfo->storeSet.add(env->mapOldValToNew[inst]); - - for (auto inst : this->recomputeSet) - if (env->mapOldValToNew.containsKey(inst)) - newPrimalsInfo->recomputeSet.add(env->mapOldValToNew[inst]); - - for (auto inst : this->invertSet) - if (env->mapOldValToNew.containsKey(inst)) - newPrimalsInfo->invertSet.add(env->mapOldValToNew[inst]); - - for (auto inst : this->instsToInvert) - if (env->mapOldValToNew.containsKey(inst)) - newPrimalsInfo->instsToInvert.add(env->mapOldValToNew[inst]); - for (auto kvpair : this->invertInfoMap) - if (env->mapOldValToNew.containsKey(kvpair.key)) - newPrimalsInfo->invertInfoMap[env->mapOldValToNew[kvpair.key]] = kvpair.value.applyMap(env); + const auto goSet = [&env](const auto& inSet, auto& outSet){ + for (auto inst : inSet) + if (const auto newKey = env->mapOldValToNew.tryGetValue(inst)) + outSet.add(*newKey); + }; + + goSet(this->storeSet, newPrimalsInfo->storeSet); + goSet(this->recomputeSet, newPrimalsInfo->recomputeSet); + goSet(this->invertSet, newPrimalsInfo->invertSet); + goSet(this->instsToInvert, newPrimalsInfo->instsToInvert); + + for (auto [key, value] : this->invertInfoMap) + if (const auto newKey = env->mapOldValToNew.tryGetValue(key)) + newPrimalsInfo->invertInfoMap.set(*newKey, value.applyMap(env)); return newPrimalsInfo; } @@ -141,8 +136,8 @@ namespace Slang for (auto inst : info->instsToInvert) instsToInvert.add(inst); - for (auto kvpair : info->invertInfoMap) - invertInfoMap[kvpair.key] = kvpair.value; + for (auto invertInfo : info->invertInfoMap) + invertInfoMap.add(invertInfo); } }; diff --git a/source/slang/slang-ir-autodiff-rev.cpp b/source/slang/slang-ir-autodiff-rev.cpp index fc8979551..532fb88ac 100644 --- a/source/slang/slang-ir-autodiff-rev.cpp +++ b/source/slang/slang-ir-autodiff-rev.cpp @@ -658,8 +658,8 @@ namespace Slang // Remove [KeepAlive] decorations for primal param replacement insts. static void _unlockPrimalParamReplacementInsts(ParameterBlockTransposeInfo& paramInfo) { - for (auto& kv : paramInfo.mapPrimalSpecificParamToReplacementInPropFunc) - kv.value->findDecoration()->removeAndDeallocate(); + for (const auto& [_, value] : paramInfo.mapPrimalSpecificParamToReplacementInPropFunc) + value->findDecoration()->removeAndDeallocate(); } // Transcribe a function definition. diff --git a/source/slang/slang-ir-autodiff-transpose.h b/source/slang/slang-ir-autodiff-transpose.h index 739ce6553..dad4ab192 100644 --- a/source/slang/slang-ir-autodiff-transpose.h +++ b/source/slang/slang-ir-autodiff-transpose.h @@ -571,7 +571,7 @@ struct DiffTransposePass // Keep track of first diff block, since this is where // we'll emit temporary vars to hold per-block derivatives. // - auto firstRevDiffBlock = revBlockMap[terminalDiffBlocks[0]].getValue(); + auto firstRevDiffBlock = revBlockMap.getValue(terminalDiffBlocks[0]); firstRevDiffBlockMap[revDiffFunc] = firstRevDiffBlock; // Move all diff vars to first block, and initialize them with zero. @@ -855,11 +855,14 @@ struct DiffTransposePass // function scope variable, since control flow can affect what blocks contribute to // for a specific inst. // - for (auto pair : gradientsMap) + List loads; + for (const auto& [key, _] : gradientsMap) { - if (auto loadInst = as(pair.key)) - accumulateGradientsForLoad(&builder, loadInst); + if (auto load = as(key)) + loads.add(load); } + for(const auto& load : loads) + accumulateGradientsForLoad(&builder, load); // Do the same thing with the phi parameters if the block. List phiParamRevGradInsts; @@ -903,16 +906,16 @@ struct DiffTransposePass // Also handle any remaining gradients for insts that appear in prior blocks. List externInsts; // Holds insts in a different block, same function. List globalInsts; // Holds insts in the global scope. - for (auto pair : gradientsMap) + for (const auto& [inst, _] : gradientsMap) { - auto instParent = pair.key->getParent(); + auto instParent = inst->getParent(); if (instParent != fwdBlock) { if (instParent->getParent() == fwdBlock->getParent()) - externInsts.add(pair.key); + externInsts.add(inst); if (as(instParent)) - globalInsts.add(pair.key); + globalInsts.add(inst); } } @@ -1357,7 +1360,7 @@ struct DiffTransposePass SLANG_ASSERT(!(afterBlockMap.containsKey(afterBlock) && \ afterBlockMap[afterBlock] != block->getTerminator())); - afterBlockMap[afterBlock] = block->getTerminator(); + afterBlockMap.set(afterBlock, block->getTerminator()); } } } @@ -2779,7 +2782,7 @@ struct DiffTransposePass { gradientsMap[fwdInst] = List(); } - gradientsMap[fwdInst].getValue().add(assignment); + gradientsMap.getValue(fwdInst).add(assignment); } List getRevGradients(IRInst* fwdInst) @@ -2789,7 +2792,7 @@ struct DiffTransposePass List popRevGradients(IRInst* fwdInst) { - List val = gradientsMap[fwdInst].getValue(); + List val = gradientsMap.getValue(fwdInst); gradientsMap.remove(fwdInst); return val; } diff --git a/source/slang/slang-ir-autodiff-unzip.cpp b/source/slang/slang-ir-autodiff-unzip.cpp index 1b14856e6..95ad0d921 100644 --- a/source/slang/slang-ir-autodiff-unzip.cpp +++ b/source/slang/slang-ir-autodiff-unzip.cpp @@ -331,7 +331,7 @@ IRFunc* DiffUnzipPass::extractPrimalFunc( for (auto param : func->getParams()) { if (paramInfo.primalFuncParams.contains(param)) - newPrimalParams.add(subEnv.mapOldValToNew[param].getValue()); + newPrimalParams.add(subEnv.mapOldValToNew.getValue(param)); } ExtractPrimalFuncContext context; diff --git a/source/slang/slang-ir-autodiff-unzip.h b/source/slang/slang-ir-autodiff-unzip.h index 2a5d73a01..4846fc840 100644 --- a/source/slang/slang-ir-autodiff-unzip.h +++ b/source/slang/slang-ir-autodiff-unzip.h @@ -159,11 +159,8 @@ struct DiffUnzipPass // { List workList; - for (auto blockRegionPair : indexRegionMap->map) - { - IRBlock* block = blockRegionPair.key; + for (auto [block, _] : indexRegionMap->map) workList.add(block); - } for (auto block : workList) { @@ -171,7 +168,7 @@ struct DiffUnzipPass indexRegionMap->map[as(primalMap[block])] = (IndexedRegion*)indexRegionMap->map[block]; if (diffMap.containsKey(block)) - indexRegionMap->map[as(diffMap[block])] = (IndexedRegion*)indexRegionMap->map[block]; + indexRegionMap->map.set(as(diffMap[block]), (IndexedRegion*)indexRegionMap->map[block]); } } diff --git a/source/slang/slang-ir-autodiff.cpp b/source/slang/slang-ir-autodiff.cpp index 2231e0ce7..cb710ac6b 100644 --- a/source/slang/slang-ir-autodiff.cpp +++ b/source/slang/slang-ir-autodiff.cpp @@ -1782,7 +1782,7 @@ bool finalizeAutoDiffPass(IRModule* module) // Remove auto-diff related decorations. stripAutoDiffDecorations(module); - return false; + return modified; } IRBlock* getBlock(IRInst* inst) diff --git a/source/slang/slang-ir-eliminate-multilevel-break.cpp b/source/slang/slang-ir-eliminate-multilevel-break.cpp index 8f7307f1b..65e388608 100644 --- a/source/slang/slang-ir-eliminate-multilevel-break.cpp +++ b/source/slang/slang-ir-eliminate-multilevel-break.cpp @@ -338,10 +338,8 @@ struct EliminateMultiLevelBreakContext // Once we have rewritten regions' break blocks with additional targetLevel parameter, all // original branches into that block without a parameter will now need to provide a default // value equal to the level of its corresponding region. - for (auto breakBlockKV : mapNewBreakBlockToRegionLevel) + for (auto [breakBlock, level] : mapNewBreakBlockToRegionLevel) { - auto breakBlock = breakBlockKV.key; - auto level = breakBlockKV.value; IRInst* levelInst = nullptr; List uses; for (auto use = breakBlock->firstUse; use; use = use->nextUse) diff --git a/source/slang/slang-ir-eliminate-phis.cpp b/source/slang/slang-ir-eliminate-phis.cpp index 48e95303f..c628b937e 100644 --- a/source/slang/slang-ir-eliminate-phis.cpp +++ b/source/slang/slang-ir-eliminate-phis.cpp @@ -140,11 +140,10 @@ struct PhiEliminationContext { IRBuilder builder(m_module); - for (auto instAlloc : m_registerAllocation.mapInstToRegister) + for (const auto& [inst, reg] : m_registerAllocation.mapInstToRegister) { - auto inst = instAlloc.key; IRInst* registerVar = nullptr; - m_mapRegToTempVar.tryGetValue(instAlloc.value, registerVar); + m_mapRegToTempVar.tryGetValue(reg, registerVar); SLANG_RELEASE_ASSERT(registerVar); switch (inst->getOp()) @@ -159,7 +158,7 @@ struct PhiEliminationContext m_registerAllocation.mapInstToRegister.tryGetValue(updateInst->getOldValue(), oldReg); // If the original value is not assigned to the same register as this inst, // we need to insert a copy. - if (instAlloc.value != oldReg) + if (reg != oldReg) { builder.emitStore(registerVar, updateInst->getOldValue()); } @@ -178,11 +177,10 @@ struct PhiEliminationContext { IRBuilder builder(m_module); - for (auto instAlloc : m_registerAllocation.mapInstToRegister) + for (const auto& [inst, reg] : m_registerAllocation.mapInstToRegister) { - auto inst = instAlloc.key; IRInst* registerVar = nullptr; - m_mapRegToTempVar.tryGetValue(instAlloc.value, registerVar); + m_mapRegToTempVar.tryGetValue(reg, registerVar); SLANG_RELEASE_ASSERT(registerVar); while (auto use = inst->firstUse) { diff --git a/source/slang/slang-ir-generics-lowering-context.cpp b/source/slang/slang-ir-generics-lowering-context.cpp index 609a9e298..325568040 100644 --- a/source/slang/slang-ir-generics-lowering-context.cpp +++ b/source/slang/slang-ir-generics-lowering-context.cpp @@ -88,7 +88,7 @@ namespace Slang IRInst* SharedGenericsLoweringContext::findInterfaceRequirementVal(IRInterfaceType* interfaceType, IRInst* requirementKey) { if (auto dict = mapInterfaceRequirementKeyValue.tryGetValue(interfaceType)) - return (*dict)[requirementKey].getValue(); + return dict->getValue(requirementKey); _builldInterfaceRequirementMap(interfaceType); return findInterfaceRequirementVal(interfaceType, requirementKey); } diff --git a/source/slang/slang-ir-glsl-legalize.cpp b/source/slang/slang-ir-glsl-legalize.cpp index a5bb299c5..5c4e1d037 100644 --- a/source/slang/slang-ir-glsl-legalize.cpp +++ b/source/slang/slang-ir-glsl-legalize.cpp @@ -2744,10 +2744,8 @@ void legalizeEntryPointForGLSL( // Let's fix the size array type globals now that we know the maximum index { - for (const auto& a : context.systemNameToGlobalMap) + for (const auto& [_, value] : context.systemNameToGlobalMap) { - const auto& value = a.value; - auto type = value.globalParam->getDataType(); // Strip out if there is one diff --git a/source/slang/slang-ir-inline.cpp b/source/slang/slang-ir-inline.cpp index db4bb50a8..e878c56f7 100644 --- a/source/slang/slang-ir-inline.cpp +++ b/source/slang/slang-ir-inline.cpp @@ -573,7 +573,7 @@ struct InliningPassBase // Insert a branch into the cloned first block at the end of `callerBlock`. builder->setInsertInto(callerBlock); - auto mainBlock = as(env->mapOldValToNew[callee->getFirstBlock()].getValue()); + auto mainBlock = as(env->mapOldValToNew.getValue(callee->getFirstBlock())); auto newBranch = builder->emitLoop(mainBlock, afterBlock, mainBlock); _setSourceLoc(newBranch, call, callSite); @@ -581,7 +581,7 @@ struct InliningPassBase bool isFirstBlock = true; for (auto calleeBlock : callee->getBlocks()) { - auto clonedBlock = env->mapOldValToNew[calleeBlock].getValue(); + auto clonedBlock = env->mapOldValToNew.getValue(calleeBlock); builder->setInsertInto(clonedBlock); // We will loop over the instructions of the each block, // and clone each of them appropriately. diff --git a/source/slang/slang-ir-link.cpp b/source/slang/slang-ir-link.cpp index 364613074..66fda8a86 100644 --- a/source/slang/slang-ir-link.cpp +++ b/source/slang/slang-ir-link.cpp @@ -595,10 +595,8 @@ IRGeneric* cloneGenericImpl( // Generic parameter list does not match, bail. if (clonedParam || originalParam) continue; - for (auto kv : paramMapping) - { - registerClonedValue(context, kv.key, kv.value); - } + for (const auto& [key, value] : paramMapping) + registerClonedValue(context, key, value); IRBuilder builderStorage = *builder; IRBuilder* decorBuilder = &builderStorage; diff --git a/source/slang/slang-ir-lower-generic-function.cpp b/source/slang/slang-ir-lower-generic-function.cpp index 3edc373c4..baedbbd22 100644 --- a/source/slang/slang-ir-lower-generic-function.cpp +++ b/source/slang/slang-ir-lower-generic-function.cpp @@ -370,10 +370,8 @@ namespace Slang void replaceLoweredInterfaceTypes() { - for (auto lowered : sharedContext->loweredInterfaceTypes) - { - lowered.key->replaceUsesWith(lowered.value); - } + for (const auto& [loweredKey, loweredValue] : sharedContext->loweredInterfaceTypes) + loweredKey->replaceUsesWith(loweredValue); sharedContext->mapInterfaceRequirementKeyValue.clear(); } diff --git a/source/slang/slang-ir-lower-optional-type.cpp b/source/slang/slang-ir-lower-optional-type.cpp index 91b108ffe..ba2584976 100644 --- a/source/slang/slang-ir-lower-optional-type.cpp +++ b/source/slang/slang-ir-lower-optional-type.cpp @@ -270,10 +270,8 @@ namespace Slang } // Replace all optional types with lowered struct types. - for (auto kv : loweredOptionalTypes) - { - kv.key->replaceUsesWith(kv.value->loweredType); - } + for (const auto& [key, value] : loweredOptionalTypes) + key->replaceUsesWith(value->loweredType); } }; diff --git a/source/slang/slang-ir-lower-result-type.cpp b/source/slang/slang-ir-lower-result-type.cpp index a10a9d343..ee69a4fed 100644 --- a/source/slang/slang-ir-lower-result-type.cpp +++ b/source/slang/slang-ir-lower-result-type.cpp @@ -291,10 +291,8 @@ namespace Slang } // Replace all result types with lowered struct types. - for (auto kv : loweredResultTypes) - { - kv.key->replaceUsesWith(kv.value->loweredType); - } + for (const auto& [key, value] : loweredResultTypes) + key->replaceUsesWith(value->loweredType); } }; diff --git a/source/slang/slang-ir-lower-tuple-types.cpp b/source/slang/slang-ir-lower-tuple-types.cpp index 1392ab453..caa031d85 100644 --- a/source/slang/slang-ir-lower-tuple-types.cpp +++ b/source/slang/slang-ir-lower-tuple-types.cpp @@ -170,10 +170,8 @@ namespace Slang } // Replace all tuple types with lowered struct types. - for (auto kv : loweredTuples) - { - kv.key->replaceUsesWith(kv.value->structType); - } + for (const auto& [key, value] : loweredTuples) + key->replaceUsesWith(value->structType); } }; diff --git a/source/slang/slang-ir-obfuscate-loc.cpp b/source/slang/slang-ir-obfuscate-loc.cpp index 860633106..9aef6f6a6 100644 --- a/source/slang/slang-ir-obfuscate-loc.cpp +++ b/source/slang/slang-ir-obfuscate-loc.cpp @@ -4,7 +4,7 @@ #include "../../slang.h" #include "../core/slang-random-generator.h" -#include "../core/slang-hash.h" +#include "../core/slang-stable-hash.h" #include "../core/slang-char-util.h" #include "../core/slang-castable.h" @@ -81,7 +81,7 @@ SlangResult obfuscateModuleLocs(IRModule* module, SourceManager* sourceManager) // Doing so would mean that we could use the obfuscated location ouput to output // the origin. - HashCode hash = 0; + StableHashCode32 hash{0}; List locPairs; @@ -124,10 +124,10 @@ SlangResult obfuscateModuleLocs(IRModule* module, SourceManager* sourceManager) const auto pathInfo = sourceView->getViewPathInfo(); const auto name = pathInfo.getName(); - const auto nameHash = getHashCode(pathInfo.getName().getUnownedSlice()); + const auto nameHash = getStableHashCode32(name.getBuffer(), name.getLength()); // Combine the name - hash = combineHash(hash, nameHash); + hash = combineStableHash(hash, nameHash); } // We *can't* just use the offset to produce the hash, because the source might have @@ -140,8 +140,7 @@ SlangResult obfuscateModuleLocs(IRModule* module, SourceManager* sourceManager) const auto lineIndex = sourceFile->calcLineIndexFromOffset(offset); const auto lineOffset = sourceFile->calcColumnOffset(lineIndex, offset); - hash = combineHash(hash, getHashCode(lineIndex)); - hash = combineHash(hash, getHashCode(lineOffset)); + hash = combineStableHash(hash, getStableHashCode32(lineIndex), getStableHashCode32(lineOffset)); } } } diff --git a/source/slang/slang-ir-reachability.h b/source/slang/slang-ir-reachability.h index f605abd41..74463b7fe 100644 --- a/source/slang/slang-ir-reachability.h +++ b/source/slang/slang-ir-reachability.h @@ -13,17 +13,17 @@ struct ReachabilityContext { IRBlock* first; IRBlock* second; - HashCode getHashCode() + bool operator == (const BlockPair& other) const + { + return first == other.first && second == other.second; + } + HashCode getHashCode() const { Hasher h; h.hashValue(first); h.hashValue(second); return h.getResult(); } - bool operator == (const BlockPair& other) - { - return first == other.first && second == other.second; - } }; Dictionary reachabilityResults; diff --git a/source/slang/slang-ir-specialize-dispatch.cpp b/source/slang/slang-ir-specialize-dispatch.cpp index 4b26ced32..d57e1ed96 100644 --- a/source/slang/slang-ir-specialize-dispatch.cpp +++ b/source/slang/slang-ir-specialize-dispatch.cpp @@ -333,10 +333,8 @@ void specializeDispatchFunctions(SharedGenericsLoweringContext* sharedContext) ensureWitnessTableSequentialIDs(sharedContext); // Generate specialized dispatch functions and fixup call sites. - for (auto kv : sharedContext->mapInterfaceRequirementKeyToDispatchMethods) + for (const auto& [_, dispatchFunc] : sharedContext->mapInterfaceRequirementKeyToDispatchMethods) { - auto dispatchFunc = kv.value; - // Generate a specialized `switch` statement based dispatch func, // from the witness tables present in the module. auto newDispatchFunc = specializeDispatchFunction(sharedContext, dispatchFunc); diff --git a/source/slang/slang-ir-specialize.cpp b/source/slang/slang-ir-specialize.cpp index 83e2cad70..b2cd5edc4 100644 --- a/source/slang/slang-ir-specialize.cpp +++ b/source/slang/slang-ir-specialize.cpp @@ -632,7 +632,7 @@ struct SpecializationContext int childrenCount = 0; for (auto child = dictInst->getFirstChild(); child; child = child->next) childrenCount++; - dict.reserve(1 << Math::Log2Ceil(childrenCount * 2)); + dict.reserve(Index{1} << Math::Log2Ceil(childrenCount * 2)); for (auto child : dictInst->getChildren()) { auto item = as(child); @@ -698,18 +698,18 @@ struct SpecializationContext builder.setInsertInto(moduleInst); auto dictInst = builder.emitIntrinsicInst(nullptr, dictOp, 0, nullptr); builder.setInsertInto(dictInst); - for (auto kv : dict) + for (const auto& [key, value] : dict) { - if (!kv.value->parent) + if (!value->parent) continue; - for (auto keyVal : kv.key.vals) + for (auto keyVal : key.vals) { if (!keyVal->parent) goto next; } { List args; - args.add(kv.value); - args.addRange(kv.key.vals); + args.add(value); + args.addRange(key.vals); builder.emitIntrinsicInst(nullptr, kIROp_SpecializationDictionaryItem, args.getCount(), args.getBuffer()); } next:; diff --git a/source/slang/slang-ir-spirv-snippet.cpp b/source/slang/slang-ir-spirv-snippet.cpp index 40a506d64..ecb8d1b5e 100644 --- a/source/slang/slang-ir-spirv-snippet.cpp +++ b/source/slang/slang-ir-spirv-snippet.cpp @@ -102,7 +102,7 @@ RefPtr SpvSnippet::parse(UnownedStringSlice definition) if (tokenReader.AdvanceIf("%")) { String instName = tokenReader.ReadToken().Content; - mapInstNameToIndex[instName] = (int)snippet->instructions.getCount(); + mapInstNameToIndex.set(instName, (int)snippet->instructions.getCount()); tokenReader.Read(Slang::Misc::TokenType::OpAssign); } SpvOp opCode; diff --git a/source/slang/slang-ir-spirv-snippet.h b/source/slang/slang-ir-spirv-snippet.h index 75edf0b38..c1497496d 100644 --- a/source/slang/slang-ir-spirv-snippet.h +++ b/source/slang/slang-ir-spirv-snippet.h @@ -76,7 +76,7 @@ struct SpvSnippet : public RefObject ASMType type; SpvWord intValues[4]; float floatValues[4]; - HashCode getHashCode() + HashCode getHashCode() const { HashCode result = (HashCode)type; for (int i = 0; i < 4; i++) @@ -96,7 +96,7 @@ struct SpvSnippet : public RefObject } return result; } - bool operator==(const ASMConstant& other) + bool operator==(const ASMConstant& other) const { if (type != other.type) return false; diff --git a/source/slang/slang-ir.h b/source/slang/slang-ir.h index 68ca403bd..b765f6aee 100644 --- a/source/slang/slang-ir.h +++ b/source/slang/slang-ir.h @@ -2034,6 +2034,7 @@ public: { hashCode = _getHashCode(); } + IRInstKey& operator=(const IRInstKey&) = default; HashCode getHashCode() const { return hashCode; } IRInst* getInst() const { return inst; } diff --git a/source/slang/slang-language-server.cpp b/source/slang/slang-language-server.cpp index bc12ad34f..5574b995d 100644 --- a/source/slang/slang-language-server.cpp +++ b/source/slang/slang-language-server.cpp @@ -1537,14 +1537,14 @@ void LanguageServer::publishDiagnostics() // Send updates to clear diagnostics for files that no longer have any messages. List filesToRemove; - for (auto& file : m_lastPublishedDiagnostics) + for (const auto& [filepath, _] : m_lastPublishedDiagnostics) { - if (!version->diagnostics.containsKey(file.key)) + if (!version->diagnostics.containsKey(filepath)) { PublishDiagnosticsParams args; - args.uri = URI::fromLocalFilePath(file.key.getUnownedSlice()).uri; + args.uri = URI::fromLocalFilePath(filepath.getUnownedSlice()).uri; m_connection->sendCall(UnownedStringSlice("textDocument/publishDiagnostics"), &args); - filesToRemove.add(file.key); + filesToRemove.add(filepath); } } for (auto& toRemove : filesToRemove) @@ -1552,17 +1552,17 @@ void LanguageServer::publishDiagnostics() m_lastPublishedDiagnostics.remove(toRemove); } // Send updates for any files whose diagnostic messages has changed since last update. - for (auto& list : version->diagnostics) + for (const auto& [listKey, listValue] : version->diagnostics) { - auto lastPublished = m_lastPublishedDiagnostics.tryGetValue(list.key); - if (!lastPublished || *lastPublished != list.value.originalOutput) + auto lastPublished = m_lastPublishedDiagnostics.tryGetValue(listKey); + if (!lastPublished || *lastPublished != listValue.originalOutput) { PublishDiagnosticsParams args; - args.uri = URI::fromLocalFilePath(list.key.getUnownedSlice()).uri; - for (auto& d : list.value.messages) + args.uri = URI::fromLocalFilePath(listKey.getUnownedSlice()).uri; + for (auto& d : listValue.messages) args.diagnostics.add(d); m_connection->sendCall(UnownedStringSlice("textDocument/publishDiagnostics"), &args); - m_lastPublishedDiagnostics[list.key] = list.value.originalOutput; + m_lastPublishedDiagnostics[listKey] = listValue.originalOutput; } } } diff --git a/source/slang/slang-mangle.cpp b/source/slang/slang-mangle.cpp index 6a3a17caa..59110ea05 100644 --- a/source/slang/slang-mangle.cpp +++ b/source/slang/slang-mangle.cpp @@ -681,7 +681,7 @@ namespace Slang String getHashedName(const UnownedStringSlice& mangledName) { - HashCode64 hash = getStableHashCode64(mangledName.begin(), mangledName.getLength()); + StableHashCode64 hash = getStableHashCode64(mangledName.begin(), mangledName.getLength()); StringBuilder builder; builder << "_Sh"; diff --git a/source/slang/slang-parameter-binding.cpp b/source/slang/slang-parameter-binding.cpp index c0389d1cd..f9e2433cf 100644 --- a/source/slang/slang-parameter-binding.cpp +++ b/source/slang/slang-parameter-binding.cpp @@ -676,8 +676,9 @@ RefPtr getTypeLayoutForGlobalShaderParameter( if(varDecl->hasModifier() && as(type)) { - return createTypeLayout( - layoutContext.with(rules->getShaderRecordConstantBufferRules()), + return createTypeLayoutWith( + layoutContext, + rules->getShaderRecordConstantBufferRules(), type); } @@ -686,8 +687,9 @@ RefPtr getTypeLayoutForGlobalShaderParameter( // qualifier before we move on to anything else. if( varDecl->hasModifier() && as(type) ) { - return createTypeLayout( - layoutContext.with(rules->getPushConstantBufferRules()), + return createTypeLayoutWith( + layoutContext, + rules->getPushConstantBufferRules(), type); } @@ -710,8 +712,9 @@ RefPtr getTypeLayoutForGlobalShaderParameter( // An "ordinary" global variable is implicitly a uniform // shader parameter. - return createTypeLayout( - layoutContext.with(rules->getConstantBufferRules(context->getTargetRequest())), + return createTypeLayoutWith( + layoutContext, + rules->getConstantBufferRules(context->getTargetRequest()), type); } @@ -1910,15 +1913,19 @@ static RefPtr processEntryPointVaryingParameter( case Stage::ClosestHit: case Stage::Miss: // `in out` or `out` parameter is payload - return createTypeLayout(context->layoutContext.with( - context->getRulesFamily()->getRayPayloadParameterRules()), - type); + return createTypeLayoutWith( + context->layoutContext, + context->getRulesFamily()->getRayPayloadParameterRules(), + type + ); case Stage::Callable: // `in out` or `out` parameter is payload - return createTypeLayout(context->layoutContext.with( - context->getRulesFamily()->getCallablePayloadParameterRules()), - type); + return createTypeLayoutWith( + context->layoutContext, + context->getRulesFamily()->getCallablePayloadParameterRules(), + type + ); } } @@ -1946,9 +1953,11 @@ static RefPtr processEntryPointVaryingParameter( case Stage::AnyHit: case Stage::ClosestHit: // `in` parameter is hit attributes - return createTypeLayout(context->layoutContext.with( - context->getRulesFamily()->getHitAttributesParameterRules()), - type); + return createTypeLayoutWith( + context->layoutContext, + context->getRulesFamily()->getHitAttributesParameterRules(), + type + ); } } @@ -2226,9 +2235,9 @@ static RefPtr computeEntryPointParameterTypeLayout( // a uniform shader parameter passed via the implicitly-defined // constant buffer (e.g., the `$Params` constant buffer seen in fxc/dxc output). // - return createTypeLayout( - context->layoutContext.with( - context->getRulesFamily()->getConstantBufferRules(context->getTargetRequest())), + return createTypeLayoutWith( + context->layoutContext, + context->getRulesFamily()->getConstantBufferRules(context->getTargetRequest()), paramType); } else @@ -3171,9 +3180,8 @@ void diagnoseGlobalUniform( static int _calcTotalNumUsedRegistersForLayoutResourceKind(ParameterBindingContext* bindingContext, LayoutResourceKind kind) { int numUsed = 0; - for (auto& pair : bindingContext->shared->globalSpaceUsedRangeSets) + for (auto& [_, rangeSet] : bindingContext->shared->globalSpaceUsedRangeSets) { - UsedRangeSet* rangeSet = pair.value; const auto& usedRanges = rangeSet->usedResourceRanges[kind]; for (const auto& usedRange : usedRanges.ranges) { diff --git a/source/slang/slang-preprocessor.cpp b/source/slang/slang-preprocessor.cpp index 4cc9bd113..aefbf7619 100644 --- a/source/slang/slang-preprocessor.cpp +++ b/source/slang/slang-preprocessor.cpp @@ -3864,11 +3864,8 @@ static Token ReadToken(Preprocessor* preprocessor) // clean up after an environment Environment::~Environment() { - for (auto pair : this->macros) - { - auto macro = pair.value; + for (const auto& [_, macro] : this->macros) delete macro; - } } // Add a simple macro definition from a string (e.g., for a @@ -4066,10 +4063,8 @@ TokenList preprocessSource( if(desc.defines) { - for (auto p : *desc.defines) - { - DefineMacro(&preprocessor, p.key, p.value); - } + for (const auto& [key, value] : *desc.defines) + DefineMacro(&preprocessor, key, value); } { diff --git a/source/slang/slang-reflection-api.cpp b/source/slang/slang-reflection-api.cpp index 9f83d325d..a52b7b886 100644 --- a/source/slang/slang-reflection-api.cpp +++ b/source/slang/slang-reflection-api.cpp @@ -2962,9 +2962,9 @@ SLANG_API const char* spReflection_getHashedString( return slice.begin(); } -SLANG_API int spComputeStringHash(const char* chars, size_t count) +SLANG_API SlangUInt32 spComputeStringHash(const char* chars, size_t count) { - return (int)getStableHashCode32(chars, count); + return SlangUInt32(getStableHashCode32(chars, count)); } SLANG_API SlangReflectionTypeLayout* spReflection_getGlobalParamsTypeLayout( diff --git a/source/slang/slang-repro.cpp b/source/slang/slang-repro.cpp index 7ddf2f304..de698cf46 100644 --- a/source/slang/slang-repro.cpp +++ b/source/slang/slang-repro.cpp @@ -57,7 +57,7 @@ namespace Slang { #define SLANG_STATE_TYPE_SIZE(x) uint32_t(sizeof(x)), // A function to calculate the hash related in list in part to how the types used are sized. Can catch crude breaking binary differences. -static HashCode32 _calcTypeHash() +static StableHashCode32 _calcTypeHash() { typedef ReproUtil Util; const uint32_t sizes[] = @@ -67,9 +67,9 @@ static HashCode32 _calcTypeHash() return getStableHashCode32((const char*)&sizes, sizeof(sizes)); } -static HashCode32 _getTypeHash() +static StableHashCode32 _getTypeHash() { - static HashCode32 s_hash = _calcTypeHash(); + static StableHashCode32 s_hash = _calcTypeHash(); return s_hash; } @@ -278,15 +278,11 @@ struct StoreContext OffsetBase& base = m_container->asBase(); Index index = 0; - for (const auto& srcDefine : srcDefines) + for (const auto& [srcDefineName, srcDefineVal] : srcDefines) { - // Do allocation before setting - const auto key = fromString(srcDefine.key); - const auto value = fromString(srcDefine.value); - auto& dstDefine = base[dstDefines[index]]; - dstDefine.first = key; - dstDefine.second = value; + dstDefine.first = fromString(srcDefineName); + dstDefine.second = fromString(srcDefineVal); index++; } @@ -447,7 +443,7 @@ static String _scrubName(const String& in) { const auto& srcTargetInfos = request->m_targetInfos; - if (RefPtr* infosPtr = srcTargetInfos.tryGetValue(srcTargetRequest)) + if (const RefPtr* infosPtr = srcTargetInfos.tryGetValue(srcTargetRequest)) { EndToEndCompileRequest::TargetInfo* infos = *infosPtr; @@ -456,13 +452,13 @@ static String _scrubName(const String& in) Offset32Array dstOutputStates = inOutContainer.newArray(entryPointOutputPaths.getCount()); Index index = 0; - for (const auto& pair : entryPointOutputPaths) + for (const auto& [key, value] : entryPointOutputPaths) { - Offset32Ptr outputPath = inOutContainer.newString(pair.value.getUnownedSlice()); + Offset32Ptr outputPath = inOutContainer.newString(value.getUnownedSlice()); auto& dstOutputState = base[dstOutputStates[index]]; - dstOutputState.entryPointIndex = int32_t(pair.key); + dstOutputState.entryPointIndex = int32_t(key); dstOutputState.outputPath = outputPath; index++; @@ -545,10 +541,10 @@ static String _scrubName(const String& in) Offset32Array pathMap = inOutContainer.newArray(srcFiles.getCount()); Index index = 0; - for (const auto& pair : srcFiles) + for (const auto& [key, value] : srcFiles) { - const auto path = context.fromString(pair.key); - const auto pathInfo = context.addPathInfo(pair.value); + const auto path = context.fromString(key); + const auto pathInfo = context.addPathInfo(value); PathAndPathInfo& dstInfo = base[pathMap[index]]; dstInfo.path = path; @@ -637,9 +633,9 @@ static String _scrubName(const String& in) auto dstSourceFiles = inOutContainer.newArray>(srcSourceFiles.getCount()); Index index = 0; - for (const auto& pair : srcSourceFiles) + for (const auto& [_, value] : srcSourceFiles) { - base[dstSourceFiles[index]] = pair.value; + base[dstSourceFiles[index]] = value; index++; } base[requestState]->sourceFiles = dstSourceFiles; @@ -873,9 +869,8 @@ struct LoadContext // Put all the path infos in the cache system { - for (const auto& pair : context.m_fileToPathInfoMap) + for (const auto& [_, pathInfo] : context.m_fileToPathInfoMap) { - CacheFileSystem::PathInfo* pathInfo = pair.value; SLANG_ASSERT(pathInfo->m_uniqueIdentity.getLength()); dstUniqueMap.add(pathInfo->m_uniqueIdentity, pathInfo); @@ -1069,10 +1064,8 @@ struct LoadContext } // Put all the path infos in the cache system { - for (const auto& pair : context.m_fileToPathInfoMap) + for (const auto& [_, pathInfo] : context.m_fileToPathInfoMap) { - CacheFileSystem::PathInfo* pathInfo = pair.value; - // TODO(JS): It's not 100% clear why we are ending up // with entries that don't have a unique identity. // For now we ignore adding to the unique map, because @@ -1105,7 +1098,7 @@ struct LoadContext Header header; header.m_chunk.type = kSlangStateFourCC; header.m_semanticVersion = g_semanticVersion; - header.m_typeHash = uint32_t(_getTypeHash()); + header.m_typeHash = _getTypeHash(); return RiffUtil::writeData(&header.m_chunk, sizeof(header),container.getData(), container.getDataCount(), stream); } @@ -1152,7 +1145,7 @@ struct LoadContext return SLANG_FAIL; } - if (header.m_typeHash != uint32_t(_getTypeHash())) + if (header.m_typeHash != _getTypeHash()) { sink->diagnose(SourceLoc(), Diagnostics::riffHashMismatch); return SLANG_FAIL; diff --git a/source/slang/slang-repro.h b/source/slang/slang-repro.h index bb0da53c5..03276d6d3 100644 --- a/source/slang/slang-repro.h +++ b/source/slang/slang-repro.h @@ -4,6 +4,7 @@ #include "../core/slang-riff.h" #include "../core/slang-string.h" +#include "../core/slang-stable-hash.h" // For TranslationUnitRequest #include "slang-compiler.h" @@ -35,7 +36,7 @@ struct ReproUtil { RiffHeader m_chunk; ///< The chunk RiffSemanticVersion m_semanticVersion; ///< The semantic version - uint32_t m_typeHash; ///< A hash based on the binary representation. If doesn't match then not binary compatible (extra check over semantic versioning) + StableHashCode32 m_typeHash; ///< A hash based on the binary representation. If doesn't match then not binary compatible (extra check over semantic versioning) }; struct FileState diff --git a/source/slang/slang-serialize-ir.h b/source/slang/slang-serialize-ir.h index 038335a60..a509db5c8 100644 --- a/source/slang/slang-serialize-ir.h +++ b/source/slang/slang-serialize-ir.h @@ -26,7 +26,7 @@ struct IRSerialWriter static Result writeContainer(const IRSerialData& data, SerialCompressionType compressionType, RiffContainer* container); /// Get an instruction index from an instruction - Ser::InstIndex getInstIndex(IRInst* inst) const { return inst ? Ser::InstIndex(m_instMap[inst]) : Ser::InstIndex(0); } + Ser::InstIndex getInstIndex(IRInst* inst) const { return inst ? Ser::InstIndex(m_instMap.getValue(inst)) : Ser::InstIndex(0); } /// Get a slice from an index UnownedStringSlice getStringSlice(Ser::StringIndex index) const { return m_stringSlicePool.getSlice(StringSlicePool::Handle(index)); } diff --git a/source/slang/slang-serialize-source-loc.cpp b/source/slang/slang-serialize-source-loc.cpp index 2ec732f93..afa6c1205 100644 --- a/source/slang/slang-serialize-source-loc.cpp +++ b/source/slang/slang-serialize-source-loc.cpp @@ -124,9 +124,8 @@ void SerialSourceLocWriter::write(SerialSourceLocData* outSourceLocData) // Okay we can now calculate the final source information - for (auto& pair : m_sourceFileMap) + for (const auto& [_, debugSourceFile] : m_sourceFileMap) { - Source* debugSourceFile = pair.value; SourceFile* sourceFile = debugSourceFile->m_sourceFile; SerialSourceLocData::SourceInfo sourceInfo; diff --git a/source/slang/slang-type-layout.cpp b/source/slang/slang-type-layout.cpp index bf3df4adc..cdf1f3694 100644 --- a/source/slang/slang-type-layout.cpp +++ b/source/slang/slang-type-layout.cpp @@ -1986,12 +1986,12 @@ RefPtr applyOffsetToTypeLayout( mapOldFieldToNew.add(oldField.Ptr(), newField.Ptr()); } - for (auto entry : oldStructTypeLayout->mapVarToLayout) + for (const auto& [entryKey, entryValue] : oldStructTypeLayout->mapVarToLayout) { VarLayout* newFieldLayout = nullptr; - if (mapOldFieldToNew.tryGetValue(entry.value.Ptr(), newFieldLayout)) + if (mapOldFieldToNew.tryGetValue(entryValue.Ptr(), newFieldLayout)) { - newStructTypeLayout->mapVarToLayout.add(entry.key, newFieldLayout); + newStructTypeLayout->mapVarToLayout.add(entryKey, newFieldLayout); } } @@ -2705,8 +2705,9 @@ static RefPtr _createParameterGroupTypeLayout( // We will first compute a layout for the element type of // the parameter group. // - auto elementTypeLayout = createTypeLayout( - context.with(elementTypeRules), + auto elementTypeLayout = createTypeLayoutWith( + context, + elementTypeRules, elementType); // Now we delegate to a routine that does the meat of @@ -2830,8 +2831,9 @@ createStructuredBufferTypeLayout( auto structuredBufferLayoutRules = context.getRulesFamily()->getStructuredBufferRules(context.targetReq); // Create and save type layout for the buffer contents. - auto elementTypeLayout = createTypeLayout( - context.with(structuredBufferLayoutRules), + auto elementTypeLayout = createTypeLayoutWith( + context, + structuredBufferLayoutRules, elementType); return createStructuredBufferTypeLayout( @@ -2849,7 +2851,7 @@ createStructuredBufferTypeLayout( /// together as a `TypeLayoutResult`. /// static TypeLayoutResult _createTypeLayout( - TypeLayoutContext const& context, + TypeLayoutContext& context, Type* type); /// Create layout information for the given `type`, obeying any layout modifiers on the given declaration. @@ -3131,10 +3133,8 @@ static RefPtr maybeAdjustLayoutForArrayElementType( mapOriginalFieldToAdjusted.add(originalField, adjustedField); } - for( auto p : originalStructTypeLayout->mapVarToLayout ) + for( auto [key, originalVal] : originalStructTypeLayout->mapVarToLayout ) { - VarDeclBase* key = p.key; - RefPtr originalVal = p.value; RefPtr adjustedVal; if( mapOriginalFieldToAdjusted.tryGetValue(originalVal, adjustedVal) ) { @@ -3436,7 +3436,7 @@ static bool _isDescriptorSlotLike( } static TypeLayoutResult createArrayLikeTypeLayout( - TypeLayoutContext const& context, + TypeLayoutContext& context, Type* type, Type* baseType, IntVal* arrayLength @@ -3607,23 +3607,23 @@ static TypeLayoutResult createArrayLikeTypeLayout( return TypeLayoutResult(typeLayout, arrayUniformInfo); } -static void _addLayout(TypeLayoutContext const& context, +static void _addLayout(TypeLayoutContext& context, Type* type, TypeLayout* layout) { // Add it *without info*. // The info can be added with _updateLayout - context.layoutMap[type] = TypeLayoutResult(layout, SimpleLayoutInfo()); + context.layoutMap.set(type, TypeLayoutResult(layout, SimpleLayoutInfo())); } -static void _addLayout(TypeLayoutContext const& context, +static void _addLayout(TypeLayoutContext& context, Type* type, const TypeLayoutResult& result) { context.layoutMap[type] = result; } -static TypeLayoutResult _updateLayout(TypeLayoutContext const& context, +static TypeLayoutResult _updateLayout(TypeLayoutContext& context, Type* type, const TypeLayoutResult& result) { @@ -3641,7 +3641,7 @@ static TypeLayoutResult _updateLayout(TypeLayoutContext const& context, } static TypeLayoutResult _createTypeLayout( - TypeLayoutContext const& context, + TypeLayoutContext& context, Type* type) { if (auto layoutResultPtr = context.layoutMap.tryGetValue(type)) @@ -4226,7 +4226,7 @@ static TypeLayoutResult _createTypeLayout( // auto anyValueRules = context.getRulesFamily()->getAnyValueRules(); RefPtr concreteTypeAnyValueLayout = - createTypeLayout(context.with(anyValueRules), concreteType); + createTypeLayoutWith(context, anyValueRules, concreteType); // We will look at the resource usage of the concrete type // to determine if it "fits" in the reserved space. @@ -4547,12 +4547,22 @@ RefPtr getSimpleVaryingParameterTypeLayout( } RefPtr createTypeLayout( - TypeLayoutContext const& context, + TypeLayoutContext& context, Type* type) { return _createTypeLayout(context, type).layout; } +RefPtr createTypeLayoutWith( + const TypeLayoutContext& context, + LayoutRulesImpl* rules, + Type* type) +{ + auto c = context.with(rules); + return createTypeLayout(c, type); +} + + void TypeLayout::removeResourceUsage(LayoutResourceKind kind) { Int infoCount = resourceInfos.getCount(); diff --git a/source/slang/slang-type-layout.h b/source/slang/slang-type-layout.h index c800d0931..af07f3e73 100644 --- a/source/slang/slang-type-layout.h +++ b/source/slang/slang-type-layout.h @@ -1264,7 +1264,14 @@ RefPtr getSimpleVaryingParameterTypeLayout( // Create a full type-layout object for a type, // according to the layout rules in `context`. RefPtr createTypeLayout( - TypeLayoutContext const& context, + TypeLayoutContext& context, + Type* type); + +// A wrapper for createTypeLayout which copies the context applying the +// provided rules with TypeLayoutContext::with +RefPtr createTypeLayoutWith( + const TypeLayoutContext& context, + LayoutRulesImpl* rules, Type* type); // diff --git a/source/slang/slang-workspace-version.cpp b/source/slang/slang-workspace-version.cpp index 2ac079047..ed568b470 100644 --- a/source/slang/slang-workspace-version.cpp +++ b/source/slang/slang-workspace-version.cpp @@ -299,9 +299,9 @@ RefPtr Workspace::createWorkspaceVersion() else { HashSet set; - for (auto& p : openedDocuments) + for (const auto& [docPath, _] : openedDocuments) { - auto dir = Path::getParentDirectory(p.key.getBuffer()); + auto dir = Path::getParentDirectory(docPath.getBuffer()); if (set.add(dir)) searchPathsRaw.add(dir.getBuffer()); } diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index 1edf62a38..71c705246 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -407,11 +407,8 @@ SlangResult Session::saveStdLib(SlangArchiveType archiveType, ISlangBlob** outBl SLANG_AST_BUILDER_RAII(m_builtinLinkage->getASTBuilder()); - for (auto& pair : m_builtinLinkage->mapNameToLoadedModules) + for (const auto& [moduleName, module] : m_builtinLinkage->mapNameToLoadedModules) { - const Name* moduleName = pair.key; - Module* module = pair.value; - // Set up options SerialContainerUtil::WriteOptions options; @@ -943,10 +940,8 @@ Linkage::Linkage(Session* session, ASTBuilder* astBuilder, Linkage* builtinLinka // Copy of the built in linkages modules if (builtinLinkage) { - for (const auto& pair : builtinLinkage->mapNameToLoadedModules) - { - mapNameToLoadedModules.add(pair.key, pair.value); - } + for (const auto& nameToMod : builtinLinkage->mapNameToLoadedModules) + mapNameToLoadedModules.add(nameToMod); } { @@ -1387,10 +1382,10 @@ void Linkage::buildHash(DigestBuilder& builder, SlangInt targetIndex) } // Add the preprocessor definitions to the hash - for (auto& key : preprocessorDefinitions) + for (const auto& [defName, defVal] : preprocessorDefinitions) { - builder.append(key.key); - builder.append(key.value); + builder.append(defName); + builder.append(defVal); } // Add the target specified by targetIndex @@ -2074,9 +2069,9 @@ static void _calcViewInitiatingHierarchy(SourceManager* sourceManager, ViewIniti // Order all the children, by their raw SourceLocs. This is desirable, so that a trivial traversal // will traverse children in the order they are initiated in the parent source. // This assumes they increase in SourceLoc implies an later within a source file - this is true currently. - for (auto& pair : outHierarchy) + for (auto& [_, value] : outHierarchy) { - pair.value.sort([](SourceView* a, SourceView* b) -> bool { return a->getInitiatingSourceLoc().getRaw() < b->getInitiatingSourceLoc().getRaw(); }); + value.sort([](SourceView* a, SourceView* b) -> bool { return a->getInitiatingSourceLoc().getRaw() < b->getInitiatingSourceLoc().getRaw(); }); } } @@ -2233,12 +2228,12 @@ void FrontEndCompileRequest::parseTranslationUnit( // Note! that a adding a define twice will cause an exception in debug builds // that may be desirable or not... Dictionary combinedPreprocessorDefinitions; - for(auto& def : getLinkage()->preprocessorDefinitions) - combinedPreprocessorDefinitions.add(def.key, def.value); - for(auto& def : preprocessorDefinitions) - combinedPreprocessorDefinitions.add(def.key, def.value); - for(auto& def : translationUnit->preprocessorDefinitions) - combinedPreprocessorDefinitions.add(def.key, def.value); + for(const auto& def : getLinkage()->preprocessorDefinitions) + combinedPreprocessorDefinitions.add(def); + for(const auto& def : preprocessorDefinitions) + combinedPreprocessorDefinitions.add(def); + for(const auto& def : translationUnit->preprocessorDefinitions) + combinedPreprocessorDefinitions.add(def); // Define standard macros, if not already defined. This style assumes using `#if __SOME_VAR` style, as in // -- cgit v1.2.3