Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions benchmarks/go.mod
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
module github.com/alphadose/haxmap/benchmarks

go 1.19
go 1.23

replace github.com/alphadose/haxmap => ../
replace github.com/alphadose/haxmap v0.0.0-00010101000000-000000000000 => ../

require (
github.com/alphadose/haxmap v0.0.0-00010101000000-000000000000
github.com/cornelk/hashmap v1.0.8
github.com/puzpuzpuz/xsync/v2 v2.3.1
)

require golang.org/x/exp v0.0.0-20221031165847-c99f073a8326 // indirect
require (
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/zeebo/xxh3 v1.0.2 // indirect
golang.org/x/exp v0.0.0-20221031165847-c99f073a8326 // indirect
)
4 changes: 4 additions & 0 deletions benchmarks/go.sum
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
github.com/cornelk/hashmap v1.0.8 h1:nv0AWgw02n+iDcawr5It4CjQIAcdMMKRrs10HOJYlrc=
github.com/cornelk/hashmap v1.0.8/go.mod h1:RfZb7JO3RviW/rT6emczVuC/oxpdz4UsSB2LJSclR1k=
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/puzpuzpuz/xsync/v2 v2.3.1 h1:oAm/nI4ZC+FqOM7t2fnA7DaQVsuj4fO2KcTcNTS1Q9Y=
github.com/puzpuzpuz/xsync/v2 v2.3.1/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU=
github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
golang.org/x/exp v0.0.0-20221031165847-c99f073a8326 h1:QfTh0HpN6hlw6D3vu8DAwC8pBIwikq0AI1evdm+FksE=
golang.org/x/exp v0.0.0-20221031165847-c99f073a8326/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
2 changes: 2 additions & 0 deletions benchmarks/map_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"testing"

"github.com/alphadose/haxmap"

"github.com/cornelk/hashmap"
"github.com/puzpuzpuz/xsync/v2"
)
Expand All @@ -17,6 +18,7 @@ const (

func setupHaxMap() *haxmap.Map[uintptr, uintptr] {
m := haxmap.New[uintptr, uintptr](mapSize)
// m.SetHasher(customStringHasher)
for i := uintptr(0); i < epochs; i++ {
m.Set(i, i)
}
Expand Down
193 changes: 177 additions & 16 deletions e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type Animal struct {
}

func TestMapCreation(t *testing.T) {
m := New[int, int]()
m := New[int, int](0)
if m.Len() != 0 {
t.Errorf("new map should be empty but has %d items.", m.Len())
}
Expand All @@ -31,7 +31,7 @@ func TestMapCreation(t *testing.T) {

func TestOverwrite(t *testing.T) {
type customUint uint
m := New[customUint, string]()
m := New[customUint, string](0)
key := customUint(1)
cat := "cat"
tiger := "tiger"
Expand All @@ -52,6 +52,32 @@ func TestOverwrite(t *testing.T) {
}
}

func TestSetUint8(t *testing.T) {
m := New[uint8, string](0)

for i := 0; i < 10; i++ {
m.Set(uint8(i), strconv.Itoa(i))
}

for i := 1; i <= 10; i++ {
m.Del(uint8(i))
}

for i := 0; i < 10; i++ {
m.Set(uint8(i), strconv.Itoa(i))
}

for i := 0; i < 10; i++ {
id, ok := m.Get(uint8(i))
if !ok {
t.Error("ok should be true for item stored within the map.")
}
if id != strconv.Itoa(i) {
t.Error("item is not as expected.")
}
}
}

func TestSet(t *testing.T) {
m := New[int, string](4)

Expand All @@ -67,7 +93,7 @@ func TestSet(t *testing.T) {

// From bug https://github.com/alphadose/haxmap/issues/33
func TestSet2(t *testing.T) {
h := New[int, string]()
h := New[int, string](0)
for i := 1; i <= 10; i++ {
h.Set(i, strconv.Itoa(i))
}
Expand All @@ -89,7 +115,7 @@ func TestSet2(t *testing.T) {
}

func TestGet(t *testing.T) {
m := New[string, string]()
m := New[string, string](0)
cat := "cat"
key := "animal"

Expand All @@ -116,7 +142,7 @@ func TestGet(t *testing.T) {
}

func TestGrow(t *testing.T) {
m := New[uint, uint]()
m := New[uint, uint](0)
m.Grow(63)
d := m.metadata.Load()
log := int(math.Log2(64))
Expand All @@ -139,7 +165,7 @@ func TestGrow2(t *testing.T) {
}

func TestFillrate(t *testing.T) {
m := New[int, any]()
m := New[int, any](0)
for i := 0; i < 1000; i++ {
m.Set(i, nil)
}
Expand All @@ -152,7 +178,7 @@ func TestFillrate(t *testing.T) {
}

func TestDelete(t *testing.T) {
m := New[int, *Animal]()
m := New[int, *Animal](0)
cat := &Animal{"cat"}
tiger := &Animal{"tiger"}

Expand All @@ -177,7 +203,7 @@ func TestDelete(t *testing.T) {

// From bug https://github.com/alphadose/haxmap/issues/11
func TestDelete2(t *testing.T) {
m := New[int, string]()
m := New[int, string](0)
m.Set(1, "one")
m.Del(1) // delegate key 1
if m.Len() != 0 {
Expand All @@ -193,7 +219,7 @@ func TestDelete2(t *testing.T) {
// from https://pkg.go.dev/sync#Map.LoadOrStore
func TestGetOrSet(t *testing.T) {
var (
m = New[int, string]()
m = New[int, string](0)
data = "one"
)
if val, loaded := m.GetOrSet(1, data); loaded {
Expand All @@ -209,7 +235,7 @@ func TestGetOrSet(t *testing.T) {
}

func TestForEach(t *testing.T) {
m := New[int, *Animal]()
m := New[int, *Animal](0)

m.ForEach(func(i int, a *Animal) bool {
t.Errorf("map should be empty but got key -> %d and value -> %#v.", i, a)
Expand All @@ -236,7 +262,7 @@ func TestForEach(t *testing.T) {
}

func TestClear(t *testing.T) {
m := New[int, any]()
m := New[int, any](0)
for i := 0; i < 100; i++ {
m.Set(i, nil)
}
Expand All @@ -262,7 +288,7 @@ func TestClear(t *testing.T) {
func TestMapParallel(t *testing.T) {
max := 10
dur := 2 * time.Second
m := New[int, int]()
m := New[int, int](0)
do := func(t *testing.T, max int, d time.Duration, fn func(*testing.T, int)) <-chan error {
t.Helper()
done := make(chan error)
Expand Down Expand Up @@ -330,7 +356,7 @@ func TestMapParallel(t *testing.T) {
}

func TestMapConcurrentWrites(t *testing.T) {
blocks := New[string, struct{}]()
blocks := New[string, struct{}](0)

var wg sync.WaitGroup
for i := 0; i < 100; i++ {
Expand All @@ -355,7 +381,7 @@ func TestMapConcurrentWrites(t *testing.T) {

// Collision test case when hash key is 0 in value for all entries
func TestHash0Collision(t *testing.T) {
m := New[string, int]()
m := New[string, int](0)
staticHasher := func(key string) uintptr {
return 0
}
Expand Down Expand Up @@ -395,7 +421,7 @@ func TestCAS(t *testing.T) {
type custom struct {
val int
}
m := New[string, custom]()
m := New[string, custom](0)
m.Set("1", custom{val: 1})
if m.CompareAndSwap("1", custom{val: 420}, custom{val: 2}) {
t.Error("Invalid Compare and Swap")
Expand All @@ -415,7 +441,7 @@ func TestCAS(t *testing.T) {
// https://github.com/alphadose/haxmap/issues/18
// test swap
func TestSwap(t *testing.T) {
m := New[string, int]()
m := New[string, int](0)
m.Set("1", 1)
val, swapped := m.Swap("1", 2)
if !swapped {
Expand All @@ -432,3 +458,138 @@ func TestSwap(t *testing.T) {
t.Error("New value not set")
}
}

func TestUint8(t *testing.T) {
m := New[uint8, string](0)

m.Set(0, "cat")

val, ok := m.Get(0)
if !ok {
t.Error("Key doesnt exists")
}
if val != "cat" {
t.Error("New value not set")
}
}

func TestUint64(t *testing.T) {
m := New[uint64, string](0)

m.Set(0, "cat")

val, ok := m.Get(0)
if !ok {
t.Error("Key doesnt exists")
}
if val != "cat" {
t.Error("New value not set")
}
}

func TestUint32(t *testing.T) {
m := New[uint32, string](0)

m.Set(0, "cat")

val, ok := m.Get(0)
if !ok {
t.Error("Key doesnt exists")
}
if val != "cat" {
t.Error("New value not set")
}
}

func TestUintptr(t *testing.T) {
m := New[uintptr, string](0)

m.Set(0, "cat")

val, ok := m.Get(0)
if !ok {
t.Error("Key doesnt exists")
}
if val != "cat" {
t.Error("New value not set")
}

}

func TestString(t *testing.T) {
m := New[string, string](0)

m.Set("1", "cat")

val, ok := m.Get("1")
if !ok {
t.Error("Key doesnt exists")
}
if val != "cat" {
t.Error("New value not set")
}

}

func TestHashStability(t *testing.T) {
m := New[string, string](0)
key := "stability_test"
expectedValue := "value"
m.Set(key, expectedValue)

val, ok := m.Get(key)
if !ok {
t.Errorf("Expected key %s to exist in the map", key)
}
if val != expectedValue {
t.Errorf("Expected value %s for key %s, got %s", expectedValue, key, val)
}
}

func TestHashCollision(t *testing.T) {
m := New[string, string](0)

key1 := "collision_key_1"
key2 := "collision_key_2"

m.Set(key1, "value1")
m.Set(key2, "value2")

val1, ok1 := m.Get(key1)
if !ok1 || val1 != "value1" {
t.Errorf("Expected value for %s to be 'value1', got %v", key1, val1)
}

val2, ok2 := m.Get(key2)
if !ok2 || val2 != "value2" {
t.Errorf("Expected value for %s to be 'value2', got %v", key2, val2)
}
}

func TestHashUinptrCollision(t *testing.T) {
m := New[uintptr, int](0)
staticHasher := func(key uintptr) uintptr {
return 0
}
m.SetHasher(staticHasher)
m.Set(1, 1)
m.Set(2, 2)
_, ok := m.Get(1)
if !ok {
t.Error("1 not found")
}
_, ok = m.Get(2)
if !ok {
t.Error("2 not found")
}
}

func TestMapLargeLoad(t *testing.T) {
m := New[uintptr, int](0)
for i := 0; i < 1000000; i++ {
m.Set(uintptr(i), i)
}
if value, ok := m.Get(999999); !ok || value != 999999 {
t.Errorf("Expected 999999, got %v", value)
}
}
9 changes: 6 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
module github.com/alphadose/haxmap
go 1.23

go 1.18

require golang.org/x/exp v0.0.0-20221031165847-c99f073a8326 // indirect
require (
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/zeebo/xxh3 v1.0.2 // indirect
golang.org/x/exp v0.0.0-20221031165847-c99f073a8326 // indirect
)
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
golang.org/x/exp v0.0.0-20221031165847-c99f073a8326 h1:QfTh0HpN6hlw6D3vu8DAwC8pBIwikq0AI1evdm+FksE=
golang.org/x/exp v0.0.0-20221031165847-c99f073a8326/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
Loading