I was looking at the SymbolTable code in LLD COFF and ELF recently, and I’m confused by the use of CachedHashStringRef.
From what I understand, a CachedHashStringRef combines a StringRef with a computed hash. There’s no caching going on in the CachedHashStringRef itself; that is, if you construct CachedHashStringRef("foo"), and then construct a second CachedHashStringRef("foo") again later, you'll compute the hash for "foo" twice . Instead, once you've constructed a CachedHashStringRef from a StringRef, you can pass that around instead of the StringRef to avoid needing to recompute the hash for it.
LLD COFF's symbol table structure is a DenseMap<CachedHashStringRef, Symbol *> named symMap . (ELF's is similar, except it maps to a vector index instead of a Symbol * directly for symbol order determinism reasons.) The only accesses to symMap are either iterating over its values or doing a lookup. In the two cases where a map lookup is done , the input to the function doing the lookup is just a StringRef, and a CachedHashStringRef is constructed to perform the lookup. What's the advantage of using a CachedHashStringRef in that case, as opposed to just having a DenseMap<StringRef, Symbol *> directly? With that, the DenseMap would be performing the hash computation for each lookup operation, but the CachedHashStringRef construction we have right now is doing the same hash computation anyway, so I don't understand the benefit of using it here.