GCC Code Coverage Report


Directory: ../
File: src/typechecker/StructManager.cpp
Date: 2024-12-24 01:17:15
Exec Total Coverage
Lines: 137 141 97.2%
Functions: 11 11 100.0%
Branches: 155 267 58.1%

Line Branch Exec Source
1 // Copyright (c) 2021-2024 ChilliBits. All rights reserved.
2
3 #include "StructManager.h"
4
5 #include <ast/ASTNodes.h>
6 #include <exception/SemanticError.h>
7 #include <symboltablebuilder/Scope.h>
8 #include <symboltablebuilder/SymbolTableBuilder.h>
9 #include <typechecker/TypeMatcher.h>
10 #include <util/CodeLoc.h>
11 #include <util/CustomHashFunctions.h>
12
13 namespace spice::compiler {
14
15 // Static member initialization
16 std::unordered_map<uint64_t, Struct *> StructManager::lookupCache = {};
17
18 540 Struct *StructManager::insert(Scope *insertScope, Struct &spiceStruct, std::vector<Struct *> *nodeStructList) {
19 // Open a new manifestation list. Which gets filled by the substantiated manifestations of the struct
20
3/6
✓ Branch 1 taken 540 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 540 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 540 times.
✗ Branch 8 not taken.
540 const std::string structId = spiceStruct.name + ":" + spiceStruct.declNode->codeLoc.toPrettyLineAndColumn();
21
2/4
✓ Branch 2 taken 540 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 540 times.
✗ Branch 6 not taken.
540 insertScope->structs.insert({structId, StructManifestationList()});
22
23 // Save substantiation in declaration node
24
1/2
✓ Branch 1 taken 540 times.
✗ Branch 2 not taken.
540 Struct *substantiation = insertSubstantiation(insertScope, spiceStruct, spiceStruct.declNode);
25
1/2
✓ Branch 1 taken 540 times.
✗ Branch 2 not taken.
540 nodeStructList->push_back(substantiation);
26
27 540 return substantiation;
28 540 }
29
30 854 Struct *StructManager::insertSubstantiation(Scope *insertScope, Struct &newManifestation, const ASTNode *declNode) {
31
1/2
✓ Branch 1 taken 854 times.
✗ Branch 2 not taken.
854 const std::string signature = newManifestation.getSignature();
32
33 #ifndef NDEBUG
34 // Make sure that the manifestation does not exist already
35
5/8
✓ Branch 1 taken 854 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 854 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 854 times.
✗ Branch 8 not taken.
✓ Branch 12 taken 1204 times.
✓ Branch 13 taken 854 times.
2058 for (const auto &val : insertScope->structs | std::views::values)
36
2/4
✓ Branch 1 taken 1204 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1204 times.
1204 assert(!val.contains(signature));
37 #endif
38
39 // Retrieve the matching manifestation list of the scope
40
3/6
✓ Branch 1 taken 854 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 854 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 854 times.
✗ Branch 8 not taken.
854 const std::string structId = newManifestation.name + ":" + declNode->codeLoc.toPrettyLineAndColumn();
41
2/4
✓ Branch 1 taken 854 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 854 times.
854 assert(insertScope->structs.contains(structId));
42
1/2
✓ Branch 1 taken 854 times.
✗ Branch 2 not taken.
854 StructManifestationList &manifestationList = insertScope->structs.at(structId);
43
44 // Add substantiated struct
45 854 newManifestation.manifestationIndex = manifestationList.size();
46
1/2
✓ Branch 1 taken 854 times.
✗ Branch 2 not taken.
854 manifestationList.emplace(signature, newManifestation);
47
1/2
✓ Branch 1 taken 854 times.
✗ Branch 2 not taken.
1708 return &manifestationList.at(signature);
48 854 }
49
50 /**
51 * Check if there is a struct in this scope, fulfilling all given requirements and if found, return it.
52 * If more than one struct matches the requirement, an error gets thrown
53 *
54 * @param matchScope Scope to match against
55 * @param qt Struct name requirement
56 * @param reqTemplateTypes Template types to substantiate generic types
57 * @param node Instantiation AST node for printing error messages
58 * @return Matched struct or nullptr
59 */
60 16465 Struct *StructManager::match(Scope *matchScope, const std::string &qt, const QualTypeList &reqTemplateTypes,
61 const ASTNode *node) {
62 // Do cache lookup
63
1/2
✓ Branch 1 taken 16465 times.
✗ Branch 2 not taken.
16465 const uint64_t cacheKey = getCacheKey(matchScope, qt, reqTemplateTypes);
64
3/4
✓ Branch 1 taken 16465 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 15536 times.
✓ Branch 4 taken 929 times.
16465 if (lookupCache.contains(cacheKey))
65
1/2
✓ Branch 1 taken 15536 times.
✗ Branch 2 not taken.
15536 return lookupCache.at(cacheKey);
66
67 // Copy the registry to prevent iterating over items, that are created within the loop
68
1/2
✓ Branch 1 taken 929 times.
✗ Branch 2 not taken.
929 StructRegistry structRegistry = matchScope->structs;
69 // Loop over struct registry to find structs, that match the requirements of the instantiation
70 929 std::vector<Struct *> matches;
71
2/2
✓ Branch 7 taken 1329 times.
✓ Branch 8 taken 929 times.
2258 for (const auto &[structId, m] : structRegistry) {
72 // Copy the manifestation list to prevent iterating over items, that are created within the loop
73
1/2
✓ Branch 1 taken 1329 times.
✗ Branch 2 not taken.
1329 const StructManifestationList manifestations = m;
74
2/2
✓ Branch 7 taken 1897 times.
✓ Branch 8 taken 679 times.
2576 for (const auto &[mangledName, presetStruct] : manifestations) {
75 // Skip generic substantiations to prevent double matching of a struct
76
3/4
✓ Branch 1 taken 1897 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 568 times.
✓ Branch 4 taken 1329 times.
1897 if (presetStruct.isGenericSubstantiation())
77 933 continue;
78
79 // Copy the struct to be able to substantiate types
80
1/2
✓ Branch 1 taken 1329 times.
✗ Branch 2 not taken.
1329 Struct candidate = presetStruct;
81
82 // Check name requirement
83
2/2
✓ Branch 1 taken 436 times.
✓ Branch 2 taken 893 times.
1329 if (!matchName(candidate, qt))
84 436 break; // Leave the whole manifestation list, because all manifestations in this list have the same name
85
86 // Prepare mapping table from generic type name to concrete type
87 893 TypeMapping &typeMapping = candidate.typeMapping;
88 893 typeMapping.clear();
89
1/2
✓ Branch 2 taken 893 times.
✗ Branch 3 not taken.
893 typeMapping.reserve(candidate.templateTypes.size());
90
91 // Check template types requirement
92
3/4
✓ Branch 1 taken 893 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 892 times.
893 if (!matchTemplateTypes(candidate, reqTemplateTypes, typeMapping, node))
93 1 continue; // Leave this manifestation and continue with the next one
94
95 // Map field types from generic to concrete
96
1/2
✓ Branch 1 taken 892 times.
✗ Branch 2 not taken.
892 substantiateFieldTypes(candidate, typeMapping, node);
97
98 // We found a match! -> Set the actual candidate and its entry to used
99 892 candidate.used = true;
100 892 candidate.entry->used = true;
101
102 // Check if it needs to be substantiated
103
2/2
✓ Branch 1 taken 364 times.
✓ Branch 2 taken 528 times.
892 if (presetStruct.templateTypes.empty()) {
104
5/10
✓ Branch 1 taken 364 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 364 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 364 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 364 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 364 times.
✗ Branch 12 not taken.
364 assert(matchScope->structs.contains(structId) && matchScope->structs.at(structId).contains(mangledName));
105
3/6
✓ Branch 1 taken 364 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 364 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 364 times.
✗ Branch 8 not taken.
364 matches.push_back(&matchScope->structs.at(structId).at(mangledName));
106 364 matches.back()->used = true;
107 364 continue; // Match was successful -> match the next struct
108 }
109
110 // Check if we already have this manifestation and can simply re-use it
111
4/6
✓ Branch 1 taken 528 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 528 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 214 times.
✓ Branch 8 taken 314 times.
528 if (manifestations.contains(candidate.getSignature())) {
112
4/8
✓ Branch 1 taken 214 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 214 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 214 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 214 times.
✗ Branch 11 not taken.
214 matches.push_back(&matchScope->structs.at(structId).at(candidate.getSignature()));
113 214 break; // Leave the whole manifestation list to not double-match the manifestation
114 }
115
116 // Insert the substantiated version if required
117
1/2
✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
314 Struct *substantiatedStruct = insertSubstantiation(matchScope, candidate, presetStruct.declNode);
118
2/4
✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 314 times.
✗ Branch 5 not taken.
314 substantiatedStruct->genericPreset = &matchScope->structs.at(structId).at(mangledName);
119
2/4
✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 314 times.
✗ Branch 5 not taken.
314 substantiatedStruct->declNode->getStructManifestations()->push_back(substantiatedStruct);
120
121 // Copy struct entry
122
1/2
✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
314 const std::string newSignature = substantiatedStruct->getSignature();
123
1/2
✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
314 matchScope->lookupStrict(substantiatedStruct->name)->used = true;
124
1/2
✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
314 substantiatedStruct->entry = matchScope->symbolTable.copySymbol(substantiatedStruct->name, newSignature);
125
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 314 times.
314 assert(substantiatedStruct->entry != nullptr);
126
127 // Copy struct scope
128
1/2
✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
314 const std::string oldScopeName = STRUCT_SCOPE_PREFIX + presetStruct.name;
129
1/2
✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
314 const std::string newScopeName = STRUCT_SCOPE_PREFIX + newSignature;
130
1/2
✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
314 substantiatedStruct->scope = matchScope->copyChildScope(oldScopeName, newScopeName);
131
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 314 times.
314 assert(substantiatedStruct->scope != nullptr);
132 314 substantiatedStruct->scope->isGenericScope = false;
133
134 // Attach the template types to the new struct entry
135
1/2
✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
314 QualType entryType = substantiatedStruct->entry->getQualType()
136
2/4
✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 314 times.
✗ Branch 5 not taken.
628 .getWithTemplateTypes(substantiatedStruct->getTemplateTypes())
137
1/2
✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
314 .getWithBodyScope(substantiatedStruct->scope);
138
1/2
✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
314 substantiatedStruct->entry->updateType(entryType, true);
139
140 // Replace symbol types of field entries with concrete types
141
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 314 times.
314 assert(substantiatedStruct->scope != nullptr);
142 314 const size_t fieldCount = substantiatedStruct->fieldTypes.size();
143
1/2
✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
314 const size_t explicitFieldsStartIdx = substantiatedStruct->scope->getFieldCount() - fieldCount;
144
2/2
✓ Branch 0 taken 738 times.
✓ Branch 1 taken 314 times.
1052 for (size_t i = 0; i < fieldCount; i++) {
145 // Replace field type with concrete template type
146
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 738 times.
738 SymbolTableEntry *fieldEntry = substantiatedStruct->scope->lookupField(explicitFieldsStartIdx + i);
147
3/6
✓ Branch 0 taken 738 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 738 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 738 times.
✗ Branch 6 not taken.
738 assert(fieldEntry != nullptr && fieldEntry->isField());
148
1/2
✓ Branch 1 taken 738 times.
✗ Branch 2 not taken.
738 QualType &fieldType = substantiatedStruct->fieldTypes.at(i);
149
1/2
✓ Branch 1 taken 738 times.
✗ Branch 2 not taken.
738 QualType baseType = fieldType.getBase();
150
151 // Set the body scope of fields that are of type <candidate-struct>*
152
4/6
✓ Branch 1 taken 738 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 738 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✓ Branch 7 taken 720 times.
738 if (baseType.matches(substantiatedStruct->entry->getQualType(), false, true, true))
153
2/4
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
18 fieldType = fieldType.replaceBaseType(baseType.getWithBodyScope(substantiatedStruct->scope));
154
155
1/2
✓ Branch 1 taken 738 times.
✗ Branch 2 not taken.
738 fieldEntry->updateType(fieldType, /*overwriteExistingType=*/true);
156
157 // Instantiate structs
158
3/4
✓ Branch 1 taken 738 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 254 times.
✓ Branch 4 taken 484 times.
738 if (baseType.is(TY_STRUCT))
159
1/2
✓ Branch 1 taken 254 times.
✗ Branch 2 not taken.
254 baseType.getStruct(node);
160 }
161
162 // Instantiate implemented interfaces if required
163
2/2
✓ Branch 5 taken 102 times.
✓ Branch 6 taken 314 times.
416 for (QualType &interfaceType : substantiatedStruct->interfaceTypes) {
164 // Skip non-generic interfaces
165
2/4
✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 102 times.
102 if (!interfaceType.hasAnyGenericParts())
166 continue;
167
168 // Build template types
169
2/4
✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 102 times.
✗ Branch 5 not taken.
102 QualTypeList templateTypes = interfaceType.getTemplateTypes();
170
1/2
✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
102 TypeMatcher::substantiateTypesWithTypeMapping(templateTypes, typeMapping, node);
171
172 // Instantiate interface
173
1/2
✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
102 Scope *interfaceMatchScope = interfaceType.getBodyScope()->parent;
174
2/4
✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 102 times.
✗ Branch 5 not taken.
102 Interface *spiceInterface = InterfaceManager::match(interfaceMatchScope, interfaceType.getSubType(), templateTypes, node);
175
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
102 assert(spiceInterface != nullptr);
176
177
1/2
✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
102 interfaceType = spiceInterface->entry->getQualType();
178 102 }
179
180 // Add to matched structs
181
1/2
✓ Branch 1 taken 314 times.
✗ Branch 2 not taken.
314 matches.push_back(substantiatedStruct);
182
3/3
✓ Branch 4 taken 314 times.
✓ Branch 5 taken 365 times.
✓ Branch 6 taken 650 times.
1329 }
183 1329 }
184
185 // If no matches were found, return a nullptr
186
2/2
✓ Branch 1 taken 37 times.
✓ Branch 2 taken 892 times.
929 if (matches.empty())
187 37 return nullptr;
188
189 // Check if more than one struct matches the requirements
190
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 892 times.
892 if (matches.size() > 1)
191 throw SemanticError(node, STRUCT_AMBIGUITY, "Multiple structs match the requested signature");
192
193 // Insert into cache
194
1/2
✓ Branch 2 taken 892 times.
✗ Branch 3 not taken.
892 lookupCache[cacheKey] = matches.front();
195
196 892 return matches.front();
197 929 }
198
199 /**
200 * Checks if the matching candidate fulfills the name requirement
201 *
202 * @param candidate Matching candidate struct
203 * @param reqName Requested struct name
204 * @return Fulfilled or not
205 */
206 1329 bool StructManager::matchName(const Struct &candidate, const std::string &reqName) { return candidate.name == reqName; }
207
208 /**
209 * Checks if the matching candidate fulfills the template types requirement
210 *
211 * @param candidate Matching candidate struct
212 * @param reqTemplateTypes Requested struct template types
213 * @param typeMapping Generic type mapping
214 * @param node Instantiation AST node for printing error messages
215 * @return Fulfilled or not
216 */
217 893 bool StructManager::matchTemplateTypes(Struct &candidate, const QualTypeList &reqTemplateTypes, TypeMapping &typeMapping,
218 const ASTNode *node) {
219 // Check if the number of types match
220 893 const size_t typeCount = reqTemplateTypes.size();
221
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 892 times.
893 if (typeCount != candidate.templateTypes.size())
222 1 return false;
223
224 // Give the type matcher a way to retrieve instances of GenericType by their name
225 2540 TypeMatcher::ResolverFct genericTypeResolver = [&](const std::string &genericTypeName) {
226 756 return getGenericTypeOfCandidateByName(candidate, genericTypeName);
227 892 };
228
229 // Loop over all template types
230
2/2
✓ Branch 0 taken 756 times.
✓ Branch 1 taken 892 times.
1648 for (size_t i = 0; i < typeCount; i++) {
231
1/2
✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
756 const QualType &reqType = reqTemplateTypes.at(i);
232
1/2
✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
756 QualType &candidateType = candidate.templateTypes.at(i);
233
234 // Check if the requested template type matches the candidate template type. The type mapping may be extended
235
2/4
✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 756 times.
756 if (!TypeMatcher::matchRequestedToCandidateType(candidateType, reqType, typeMapping, genericTypeResolver, false))
236 return false;
237
238 // Substantiate the candidate param type, based on the type mapping
239
2/4
✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 756 times.
✗ Branch 4 not taken.
756 if (candidateType.hasAnyGenericParts())
240
1/2
✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
756 TypeMatcher::substantiateTypeWithTypeMapping(candidateType, typeMapping, node);
241 }
242
243 892 return true;
244 892 }
245
246 /**
247 * Come up with the concrete field types, by applying the type mapping onto the generic field types
248 *
249 * @param candidate Candidate struct
250 * @param typeMapping Generic type mapping
251 * @param node Instantiation AST node for printing error messages
252 */
253 892 void StructManager::substantiateFieldTypes(Struct &candidate, const TypeMapping &typeMapping, const ASTNode *node) {
254 // Loop over all implicit fields and substantiate the generic ones
255 892 const size_t fieldCount = candidate.scope->getFieldCount() - candidate.fieldTypes.size();
256
2/2
✓ Branch 0 taken 194 times.
✓ Branch 1 taken 892 times.
1086 for (size_t i = 0; i < fieldCount; i++) {
257
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 194 times.
194 SymbolTableEntry *fieldEntry = candidate.scope->lookupField(i);
258
1/2
✓ Branch 1 taken 194 times.
✗ Branch 2 not taken.
194 QualType fieldType = fieldEntry->getQualType();
259
3/4
✓ Branch 1 taken 194 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 148 times.
✓ Branch 4 taken 46 times.
194 if (fieldType.hasAnyGenericParts()) {
260
1/2
✓ Branch 1 taken 148 times.
✗ Branch 2 not taken.
148 TypeMatcher::substantiateTypeWithTypeMapping(fieldType, typeMapping, node);
261
1/2
✓ Branch 1 taken 148 times.
✗ Branch 2 not taken.
148 fieldEntry->updateType(fieldType, true);
262 }
263 }
264
265 // Loop over all explicit field types and substantiate the generic ones
266
2/2
✓ Branch 5 taken 2016 times.
✓ Branch 6 taken 892 times.
2908 for (QualType &fieldType : candidate.fieldTypes)
267
3/4
✓ Branch 1 taken 2016 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 836 times.
✓ Branch 4 taken 1180 times.
2016 if (fieldType.hasAnyGenericParts())
268
1/2
✓ Branch 1 taken 836 times.
✗ Branch 2 not taken.
836 TypeMatcher::substantiateTypeWithTypeMapping(fieldType, typeMapping, node);
269 892 }
270
271 /**
272 * Searches the candidate template types for a generic type object with a certain name and return it
273 *
274 * @param candidate Matching candidate struct
275 * @param templateTypeName Template type name
276 * @return Generic type object
277 */
278 756 const GenericType *StructManager::getGenericTypeOfCandidateByName(const Struct &candidate, const std::string &templateTypeName) {
279
1/2
✓ Branch 5 taken 986 times.
✗ Branch 6 not taken.
986 for (const GenericType &templateType : candidate.templateTypes) {
280
3/4
✓ Branch 1 taken 986 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 156 times.
✓ Branch 4 taken 830 times.
986 if (!templateType.is(TY_GENERIC))
281 156 continue;
282
3/4
✓ Branch 1 taken 830 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 756 times.
✓ Branch 5 taken 74 times.
830 if (templateType.getSubType() == templateTypeName)
283 756 return &templateType;
284 }
285 return nullptr;
286 }
287
288 /**
289 * Calculate the cache key for the struct lookup cache
290 *
291 * @param scope Scope to match against
292 * @param name Struct name requirement
293 * @param templateTypes Template types to substantiate generic types
294 * @return Cache key
295 */
296 16465 uint64_t StructManager::getCacheKey(Scope *scope, const std::string &name, const QualTypeList &templateTypes) {
297 9820 const auto pred = [](size_t acc, const QualType &val) {
298 // Combine the previous hash value with the current element's hash, adjusted by a prime number to reduce collisions
299 9820 return acc * 31 + std::hash<QualType>{}(val);
300 };
301 // Calculate the cache key
302 16465 const uint64_t scopeHash = std::hash<Scope *>{}(scope);
303 16465 const uint64_t hashName = std::hash<std::string>{}(name);
304 16465 const uint64_t hashTemplateTypes = std::accumulate(templateTypes.begin(), templateTypes.end(), 0u, pred);
305 16465 return scopeHash ^ (hashName << 1) ^ (hashTemplateTypes << 2);
306 }
307
308 /**
309 * Clear all statics
310 */
311 390 void StructManager::clear() { lookupCache.clear(); }
312
313 } // namespace spice::compiler
314