-
-
Notifications
You must be signed in to change notification settings - Fork 23.5k
Reduce cross project includes by rewriting HashMapHasherDefault.
#106434
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
e0def9f to
d22d390
Compare
dc37fe6 to
b2a441d
Compare
|
I've done some experiments and unfortunately this PR alone doesn't reduce build time, because all the headers removed from |
Thanks for checking! I was guessing as much, for the same reasons you mentioned; almost everything ends up including |
de9c7e5 to
0677326
Compare
13699cc to
8c3514a
Compare
8c3514a to
a144bab
Compare
a144bab to
6cb89ec
Compare
| template <typename F, typename S> | ||
| struct HashMapHasherDefaultImpl<Pair<F, S>> { | ||
| static _FORCE_INLINE_ uint32_t hash(const Pair<F, S> &p_pair) { | ||
| uint64_t h1 = HashMapHasherDefault::hash(p_pair.first); | ||
| uint64_t h2 = HashMapHasherDefault::hash(p_pair.second); | ||
| return hash_one_uint64((h1 << 32) | h2); | ||
| } | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably be made into a hash function within the Pair template itself. Failing that, the type should be forward-declared.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is one of those cases where it really depends on perspective of which is the more 'fundamental' header. If it is hashfuncs, the functions should be declared on Pair. If it's Pair, they should be declared on hashfuncs. I deem Pair to be more fundamental.
That being said, forward-declaring Pair is much better than including it!
…ble to declare a default hashing function for any type. Remove cross-project includes from `hashfuncs.h`. Improve hashing function for `Color` (based on values instead of `String`). Move `Variant` comparison from `hash_map.h` to `dictionary.cpp` (`VariantComparatorDictionary`), where it's used. Remove now unnecessary `HashableHasher`.
6cb89ec to
ad60012
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work!
|
Thanks! |
Godot is plagued by long compile times because of unnecessary cross project includes.
Two of the main culprits in Core are
hashfuncs.handvariant.h.This PR eliminates cross project includes from
hashfuncs.h, to improve compile time and reduce type coupling.Explanation
HashMapHasherDefaultwas previously written by implementing astatic uint32_t hash(const T &)function for every knownVarianttype. AsVarianttypes grew, so did the includes forhashfuncs.h.I rewrote the struct by adding a type trait called
HashMapHasherDefaultImpl<T>. This type trait can be declared for any type, providing a hash function for default hashing, analogous toHashMapComparatorDefault.The type trait is specialized for primitives (like
doubleandint32_t).It is further specialized for
enumtypes by using the underlying type, which was also the previous behavior (through implicit conversion).It is also specialized for types that declare
uint32_t hash() const;, by calling this function. This behavior was previously implemented withHashableHasher, whose implementation claimed it is only possible to generalize this with c++20 concepts. I removed the now unnecessaryHashableHashertype.Using this specialization, hash functions are moved to the appropriate types. By this move, the includes from
hashfuncs.hcould be removed.The same trick was applied to
HashMapDefaultComparator, which previously had unnecessary specializations that all calledis_same. I generalized this assumption with type trait logic (SFINAE).Side effects
Colorwas previously hashed by converting toStringand hashing the string (through implicit conversion). This was slow. I optimized the conversion to hash with the components instead.hash_mappreviously needed aVariantinclude because it declared a function that assumedVariantkeys. I generalized the function to use a comparator, and moved the variant comparison method todictionary.cpp(the only place where it was used). This allowed me to deletehash_map.cpp.Color). Two types now need to define an explicit hashing function that did not need to declare it before.enum struct, which was not possible before. Previously, the enum needed to be implicitly convertible to its underlying type, to support being hashed byHashMapHasherDefault.ImageLoaderSVGremotely, to debug it I inserted the error code to the error message. It seems to have mysteriously disappeared, but I'd argue having the error code for the future is good anyway.