package flatset
import "bytes"
type ByteSet struct {
arena []byte
slots []bsSlot
mask uint32
count int
nSmall uint8
smLen [4 ]uint8
small [4 ][24 ]byte
}
type bsSlot struct {
hash uint32
off uint32
length uint32
filled bool
}
func bsHash(b []byte ) uint32 {
h := uint32 (2166136261 )
for _ , c := range b {
h ^= uint32 (c )
h *= 16777619
}
return h
}
func (s *ByteSet ) Add (b []byte ) bool {
if s .slots == nil {
for i := 0 ; i < int (s .nSmall ); i ++ {
if int (s .smLen [i ]) == len (b ) && bytes .Equal (s .small [i ][:s .smLen [i ]], b ) {
return false
}
}
if int (s .nSmall ) < len (s .small ) && len (b ) <= len (s .small [0 ]) {
copy (s .small [s .nSmall ][:], b )
s .smLen [s .nSmall ] = uint8 (len (b ))
s .nSmall ++
s .count ++
return true
}
s .slots = make ([]bsSlot , 16 )
s .mask = 15
for i := 0 ; i < int (s .nSmall ); i ++ {
s .insertNew (s .small [i ][:s .smLen [i ]])
}
}
if s .count *4 >= len (s .slots )*3 {
s .grow ()
}
h := bsHash (b )
i := h & s .mask
for s .slots [i ].filled {
if sl := s .slots [i ]; sl .hash == h && int (sl .length ) == len (b ) &&
bytes .Equal (s .arena [sl .off :sl .off +sl .length ], b ) {
return false
}
i = (i + 1 ) & s .mask
}
off := uint32 (len (s .arena ))
s .arena = append (s .arena , b ...)
s .slots [i ] = bsSlot {hash : h , off : off , length : uint32 (len (b )), filled : true }
s .count ++
return true
}
func (s *ByteSet ) Len () int { return s .count }
func (s *ByteSet ) insertNew (b []byte ) {
h := bsHash (b )
i := h & s .mask
for s .slots [i ].filled {
i = (i + 1 ) & s .mask
}
off := uint32 (len (s .arena ))
s .arena = append (s .arena , b ...)
s .slots [i ] = bsSlot {hash : h , off : off , length : uint32 (len (b )), filled : true }
}
func (s *ByteSet ) grow () {
old := s .slots
s .slots = make ([]bsSlot , len (old )*2 )
s .mask = uint32 (len (s .slots ) - 1 )
for _ , sl := range old {
if !sl .filled {
continue
}
i := sl .hash & s .mask
for s .slots [i ].filled {
i = (i + 1 ) & s .mask
}
s .slots [i ] = sl
}
}
type ByteMap struct {
arena []byte
slots []bmSlot
mask uint32
count int
}
type bmSlot struct {
hash uint32
off uint32
length uint32
val int
filled bool
}
func (m *ByteMap ) GetOrCreate (b []byte , create func () int ) int {
if m .slots == nil {
m .slots = make ([]bmSlot , 16 )
m .mask = 15
}
if m .count *4 >= len (m .slots )*3 {
m .grow ()
}
h := bsHash (b )
i := h & m .mask
for m .slots [i ].filled {
if sl := m .slots [i ]; sl .hash == h && int (sl .length ) == len (b ) &&
bytes .Equal (m .arena [sl .off :sl .off +sl .length ], b ) {
return sl .val
}
i = (i + 1 ) & m .mask
}
v := create ()
off := uint32 (len (m .arena ))
m .arena = append (m .arena , b ...)
m .slots [i ] = bmSlot {hash : h , off : off , length : uint32 (len (b )), val : v , filled : true }
m .count ++
return v
}
func (m *ByteMap ) Get (b []byte ) (int , bool ) {
if m .slots == nil {
return 0 , false
}
h := bsHash (b )
i := h & m .mask
for m .slots [i ].filled {
if sl := m .slots [i ]; sl .hash == h && int (sl .length ) == len (b ) &&
bytes .Equal (m .arena [sl .off :sl .off +sl .length ], b ) {
return sl .val , true
}
i = (i + 1 ) & m .mask
}
return 0 , false
}
func (m *ByteMap ) Len () int { return m .count }
func (m *ByteMap ) grow () {
old := m .slots
m .slots = make ([]bmSlot , len (old )*2 )
m .mask = uint32 (len (m .slots ) - 1 )
for _ , sl := range old {
if !sl .filled {
continue
}
i := sl .hash & m .mask
for m .slots [i ].filled {
i = (i + 1 ) & m .mask
}
m .slots [i ] = sl
}
}
The pages are generated with Golds v0.8.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .