“indirectly” stored Dictionary keys?

is there a way to use a Dictionary or Dictionary-like interface with indirectly-stored keys? meaning that Equatable.== and Hashable.hash(into:) must access some additional indirect storage, which due to heap fragmentation, cannot be allocated as a swift class.

// MemoryLayout<_IndirectPath>.stride == 40
struct _IndirectPath 
{
    enum Disambiguation 
    {
        case unique 
        case overloaded
        case casefolded
    }
    let package:Int
    let namespace:Int
    let scope:Int
    let name:Int
    let disambiguation:Disambiguation
}

in _IndirectPath, self.name is an index to a descriptor containing a String, so Equatable.== and Hashable.hash(into:) have to de-reference this string to perform comparisons.

packing everything into the struct, like in _DirectPath requires three additional words of storage (one for self.name and two for self.disambiguation).

// MemoryLayout<_IndirectPath>.stride == 64
struct _DirectPath 
{
    enum Disambiguation 
    {
        case unique 
        case overloaded(symbol:Int)
        case casefolded(symbol:Int, scope:Int)
    }
    let package:Int
    let namespace:Int
    let scope:[String]
    let name:String
    let disambiguation:Disambiguation
}

(note that the storage of self.scope is efficient because this array already has an owner)

So the first answer is “no, what you see is what you get, you’d need a Dictionary implementation that doesn’t go through Hashable”. But the second answer is “in order to provide these comparisons you’d have to provide the context in which these indexes are looked up”. Let’s say it’s a simple array of strings for simplicity. In that case, if you can guarantee that the strings in the array are unique, then you wouldn’t need to resolve the indexes to implement equality. So rather than reimplement Dictionary (something which, admittedly, it’d be nice for the Swift project to provide!), can you set up your data so that Equatable and Hashable do the right thing in the context where they’ll be used?

1 Like

therein lies the problem. the keys stored in the array are normalized URIs, and can be compared/hashed by index. but the URIs from the requests don’t live in the array, they live in their own storage allocated for the request.

I'm not sure that's a problem. Either the URIs can change, in which case they're not suitable for hashing, or they can't, in which case you can check for uniqueness (though maybe you aren't checking for uniqueness today).

they don’t change. the purpose of the dictionary lookup is to bootstrap the check for uniqueness. the reason indirection is needed is because the key space is very large, which means it’s not possible to store every combination of key component combinations; they have to be computed “on the fly”.

What are the values of that dictionary?

the values are very lightweight, just an integer index