// Byte-keyed flat structures: a dedup set and a value-carrying map over // []byte keys that intern into one growable arena probed by an // open-addressing (offset, length) table -- N distinct keys cost O(log N) // arena and table growths rather than N heap strings (the per-insert // string allocation of map[string]... that these replace). Split from // flatset.go, which holds the integer-keyed twins.
package flatset import // ByteSet is a dedup set over byte keys that avoids the per-insert string // allocation of map[string]struct{}: keys append into one growable arena // probed through an open-addressing table keyed on (offset, length), so N // distinct keys cost O(log N) arena and table growths rather than N heap // strings. The first few short keys store inline (a per-group DISTINCT // set usually holds a handful), spilling into the table form on overflow // with identical semantics. type ByteSet struct { arena []byte slots []bsSlot mask uint32 count int nSmall uint8 smLen [4]uint8 small [4][24]byte } // bsSlot is one open-addressing slot; filled=false marks an empty slot. type bsSlot struct { hash uint32 off uint32 length uint32 filled bool } // bsHash is FNV-1a over the key bytes. func bsHash( []byte) uint32 { := uint32(2166136261) for , := range { ^= uint32() *= 16777619 } return } // Add reports whether b is newly seen, copying it into the inline store or // the arena on first sight. The caller may reuse b's backing immediately // after (the bytes are copied, never aliased). func ( *ByteSet) ( []byte) bool { if .slots == nil { for := 0; < int(.nSmall); ++ { if int(.smLen[]) == len() && bytes.Equal(.small[][:.smLen[]], ) { return false } } if int(.nSmall) < len(.small) && len() <= len(.small[0]) { copy(.small[.nSmall][:], ) .smLen[.nSmall] = uint8(len()) .nSmall++ .count++ return true } // Overflow (a fifth key, or one too long for a slot): spill the // inline keys into the table form; count already includes them. .slots = make([]bsSlot, 16) .mask = 15 for := 0; < int(.nSmall); ++ { .insertNew(.small[][:.smLen[]]) } } if .count*4 >= len(.slots)*3 { .grow() } := bsHash() := & .mask for .slots[].filled { if := .slots[]; .hash == && int(.length) == len() && bytes.Equal(.arena[.off:.off+.length], ) { return false } = ( + 1) & .mask } := uint32(len(.arena)) .arena = append(.arena, ...) .slots[] = bsSlot{hash: , off: , length: uint32(len()), filled: true} .count++ return true } // Len is the number of distinct keys added. func ( *ByteSet) () int { return .count } // insertNew appends a key known to be absent into the arena and table // without recounting it (the spill path: inline keys are already counted). func ( *ByteSet) ( []byte) { := bsHash() := & .mask for .slots[].filled { = ( + 1) & .mask } := uint32(len(.arena)) .arena = append(.arena, ...) .slots[] = bsSlot{hash: , off: , length: uint32(len()), filled: true} } // grow doubles the table and rehashes the filled slots. func ( *ByteSet) () { := .slots .slots = make([]bsSlot, len()*2) .mask = uint32(len(.slots) - 1) for , := range { if !.filled { continue } := .hash & .mask for .slots[].filled { = ( + 1) & .mask } .slots[] = } } // ByteMap is the value-carrying twin of ByteSet: a byte key maps to an // int through the same interned arena, so a group-by over a string key // pays O(log N) growths across N distinct groups instead of one heap // string per new group. type ByteMap struct { arena []byte slots []bmSlot mask uint32 count int } // bmSlot is one open-addressing slot; filled=false marks an empty slot. type bmSlot struct { hash uint32 off uint32 length uint32 val int filled bool } // GetOrCreate returns the int mapped to b, calling create to mint it on // first sight (create must not touch this map). b's backing may be reused // immediately after (the bytes are copied). func ( *ByteMap) ( []byte, func() int) int { if .slots == nil { .slots = make([]bmSlot, 16) .mask = 15 } if .count*4 >= len(.slots)*3 { .grow() } := bsHash() := & .mask for .slots[].filled { if := .slots[]; .hash == && int(.length) == len() && bytes.Equal(.arena[.off:.off+.length], ) { return .val } = ( + 1) & .mask } := () := uint32(len(.arena)) .arena = append(.arena, ...) .slots[] = bmSlot{hash: , off: , length: uint32(len()), val: , filled: true} .count++ return } // Get returns the int mapped to b; ok is false when absent. func ( *ByteMap) ( []byte) (int, bool) { if .slots == nil { return 0, false } := bsHash() := & .mask for .slots[].filled { if := .slots[]; .hash == && int(.length) == len() && bytes.Equal(.arena[.off:.off+.length], ) { return .val, true } = ( + 1) & .mask } return 0, false } // Len is the number of distinct keys mapped. func ( *ByteMap) () int { return .count } // grow doubles the table and rehashes the filled slots. func ( *ByteMap) () { := .slots .slots = make([]bmSlot, len()*2) .mask = uint32(len(.slots) - 1) for , := range { if !.filled { continue } := .hash & .mask for .slots[].filled { = ( + 1) & .mask } .slots[] = } }