В Go нет недостатка хеш-таблиц. Вы всегда можете использовать встроенную map[Key]Val, с ошеломительной скоростью обладающую непревзойденным удобством! А изобилие типов Key, разрешенных к использованию, способно довести до изумления!
Вот только ни указатель, ни слайс не подходят... Невозможно подсунуть свои операции (равенства и хеширования). Но хоть со скоростью все хорошо! (извините, не удержался)
Итого, мне пришлось написать HashMap[K, V any], закрывающую проблемы.
------------------8<------------------
В это трудно поверить, но:
Без резервирования памяти (конфигурация R0), map[uint64]uint64 работает в 1.93 раза медленнее UintMap! И производит в 5.64 раза больше мусора!!
А с полным резервированием (R1), в 1.72 раза медленнее! И аж в 16.5 раз больше мусора!!!
Вдумайтесь! На коленке написанная хеш-таблица для целых чисел UintMap почти в два раза обгоняет ЖУТКО оптимизированную нативную map[uint64]uint64!! И существенно менее мусорит!!!
Но раз трудно поверить, то давайте проверим:
func MyUintMap() {
const N = umN
//R0| um := lib.NewUintMap(0)
um := lib.NewUintMap(N) //R1|
for i := uint64(0); i < N; i++ {
um.Findsert(i, i+N)
}
lib.Assert(um.Size() == N)
cnt := 0
for i := uint64(0); i < N; i++ {
if *um.Val(um.Find(i)) == i+N {
cnt++
}
if um.Find(i+N) == -1 {
cnt++
}
}
lib.Assert(cnt == N*2)
for i := uint64(0); i < N; i++ {
um.Delete(i)
}
lib.Assert(um.Size() == 0)
}
func GoUintMap() {
const N = umN
//R0| m := make(map[uint64]uint64)
m := make(map[uint64]uint64, N) //R1|
for i := uint64(0); i < N; i++ {
m[i] = i + N
}
lib.Assert(len(m) == N)
cnt := 0
for i := uint64(0); i < N; i++ {
if m[i] == i+N {
cnt++
}
if _, ok := m[i+N]; !ok {
cnt++
}
}
lib.Assert(cnt == N*2)
for i := uint64(0); i < N; i++ {
delete(m, i)
}
lib.Assert(len(m) == 0)
}
Здесь всего-то лишь вставка, два поиска и удаление. Запустите go test -bench=UintMap -benchmem и увидите сами. Вот только можно ли ругать Google за неэффективный map[uint64]uint64?
------------------8<------------------
Итоги?
Смело берите HashMap[K, V any] для слайсов и указателей!
Немного оптимизированная BytesMap -- лучший выбор для []byte.
Интересно оптимизированная UintMap -- это выбор для целых чисел. Разберитесь, что там "не так", и используйте за основу.