Skip to content

Commit

Permalink
Get rid of hash function in MapOf factory functions (#108)
Browse files Browse the repository at this point in the history
Also upgrades library version to v3
  • Loading branch information
puzpuzpuz authored Oct 22, 2023
1 parent 92b8269 commit f7bf836
Show file tree
Hide file tree
Showing 24 changed files with 429 additions and 643 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build-32-bit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
go-version: [1.21.x]
go-version: [1.19.x, 1.20.x, 1.21.x]
name: Build with Go ${{ matrix.go-version }} 32-bit
steps:
- uses: actions/checkout@v3
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
go-version: [1.21.x]
go-version: [1.19.x, 1.20.x, 1.21.x]
name: Build with Go ${{ matrix.go-version }}
steps:
- uses: actions/checkout@v3
Expand Down
28 changes: 9 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[![GoDoc reference](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/puzpuzpuz/xsync/v2)
[![GoReport](https://goreportcard.com/badge/github.com/puzpuzpuz/xsync/v2)](https://goreportcard.com/report/github.com/puzpuzpuz/xsync/v2)
[![GoDoc reference](https://img.shields.io/badge/godoc-reference-blue.svg)](https://pkg.go.dev/github.com/puzpuzpuz/xsync/v3)
[![GoReport](https://goreportcard.com/badge/github.com/puzpuzpuz/xsync/v3)](https://goreportcard.com/report/github.com/puzpuzpuz/xsync/v3)
[![codecov](https://codecov.io/gh/puzpuzpuz/xsync/branch/main/graph/badge.svg)](https://codecov.io/gh/puzpuzpuz/xsync)

# xsync
Expand All @@ -16,15 +16,15 @@ Also, a non-scientific, unfair benchmark comparing Java's [j.u.c.ConcurrentHashM

## Usage

The latest xsync major version is v2, so `/v2` suffix should be used when importing the library:
The latest xsync major version is v3, so `/v3` suffix should be used when importing the library:

```go
import (
"github.com/puzpuzpuz/xsync/v2"
"github.com/puzpuzpuz/xsync/v3"
)
```

*Note for v1 users*: v1 support is discontinued, so please upgrade to v2. While the API has some breaking changes, the migration should be trivial.
*Note for v1 users*: v1 support is discontinued, so please upgrade to v3. While the API has some breaking changes, the migration should be trivial.

### Counter

Expand All @@ -35,7 +35,7 @@ c := xsync.NewCounter()
// increment and decrement the counter
c.Inc()
c.Dec()
// read the current value
// read the current value
v := c.Value()
```

Expand All @@ -58,10 +58,10 @@ CLHT is built around idea to organize the hash table in cache-line-sized buckets

One important difference with `sync.Map` is that only string keys are supported. That's because Golang standard library does not expose the built-in hash functions for `interface{}` values.

`MapOf[K, V]` is an implementation with parametrized value type. It is available for Go 1.18 or later. While it's still a CLHT-inspired hash map, `MapOf`'s design is quite different from `Map`. As a result, less GC pressure and less atomic operations on reads.
`MapOf[K, V]` is an implementation with parametrized value type. While it's still a CLHT-inspired hash map, `MapOf`'s design is quite different from `Map`. As a result, less GC pressure and less atomic operations on reads.

```go
m := xsync.NewMapOf[string]()
m := xsync.NewMapOf[string, string]()
m.Store("foo", "bar")
v, ok := m.Load("foo")
```
Expand All @@ -73,17 +73,7 @@ type Point struct {
x int32
y int32
}
m := NewTypedMapOf[Point, int](func(seed maphash.Seed, p Point) uint64 {
// provide a hash function when creating the MapOf;
// we recommend using the hash/maphash package for the function
var h maphash.Hash
h.SetSeed(seed)
binary.Write(&h, binary.LittleEndian, p.x)
hash := h.Sum64()
h.Reset()
binary.Write(&h, binary.LittleEndian, p.y)
return 31*hash + h.Sum64()
})
m := NewMapOf[Point, int]()
m.Store(Point{42, 42}, 42)
v, ok := m.Load(point{42, 42})
```
Expand Down
4 changes: 2 additions & 2 deletions counter.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func (c *Counter) Add(delta int64) {
t, ok := ptokenPool.Get().(*ptoken)
if !ok {
t = new(ptoken)
t.idx = fastrand()
t.idx = runtime_fastrand()
}
for {
stripe := &c.stripes[t.idx&c.mask]
Expand All @@ -71,7 +71,7 @@ func (c *Counter) Add(delta int64) {
break
}
// Give a try with another randomly selected stripe.
t.idx = fastrand()
t.idx = runtime_fastrand()
}
ptokenPool.Put(t)
}
Expand Down
2 changes: 1 addition & 1 deletion counter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"sync/atomic"
"testing"

. "github.com/puzpuzpuz/xsync/v2"
. "github.com/puzpuzpuz/xsync/v3"
)

func TestCounterInc(t *testing.T) {
Expand Down
33 changes: 2 additions & 31 deletions example_test.go
Original file line number Diff line number Diff line change
@@ -1,42 +1,13 @@
//go:build go1.18
// +build go1.18

package xsync_test

import (
"encoding/binary"
"fmt"
"hash/maphash"
"time"

"github.com/puzpuzpuz/xsync/v2"
"github.com/puzpuzpuz/xsync/v3"
)

func ExampleNewTypedMapOf() {
type Person struct {
GivenName string
FamilyName string
YearOfBirth int16
}
age := xsync.NewTypedMapOf[Person, int](func(seed maphash.Seed, p Person) uint64 {
var h maphash.Hash
h.SetSeed(seed)
h.WriteString(p.GivenName)
hash := h.Sum64()
h.Reset()
h.WriteString(p.FamilyName)
hash = 31*hash + h.Sum64()
h.Reset()
binary.Write(&h, binary.LittleEndian, p.YearOfBirth)
return 31*hash + h.Sum64()
})
Y := time.Now().Year()
age.Store(Person{"Ada", "Lovelace", 1815}, Y-1815)
age.Store(Person{"Charles", "Babbage", 1791}, Y-1791)
}

func ExampleMapOf_Compute() {
counts := xsync.NewIntegerMapOf[int, int]()
counts := xsync.NewMapOf[int, int]()

// Store a new value.
v, ok := counts.Compute(42, func(oldValue int, loaded bool) (newValue int, delete bool) {
Expand Down
12 changes: 0 additions & 12 deletions export_mapof_test.go

This file was deleted.

34 changes: 26 additions & 8 deletions export_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package xsync

import "hash/maphash"

const (
EntriesPerMapBucket = entriesPerMapBucket
MapLoadFactor = mapLoadFactor
Expand All @@ -11,7 +9,8 @@ const (
)

type (
BucketPadded = bucketPadded
BucketPadded = bucketPadded
BucketOfPadded = bucketOfPadded
)

type MapStats struct {
Expand Down Expand Up @@ -50,14 +49,33 @@ func DisableAssertions() {
assertionsEnabled = false
}

func HashString(seed maphash.Seed, s string) uint64 {
return hashString(seed, s)
}

func Fastrand() uint32 {
return fastrand()
return runtime_fastrand()
}

func NextPowOf2(v uint32) uint32 {
return nextPowOf2(v)
}

func MakeSeed() uint64 {
return makeSeed()
}

func HashString(s string, seed uint64) uint64 {
return hashString(s, seed)
}

func MakeHasher[T comparable]() func(T, uint64) uint64 {
return makeHasher[T]()
}

func CollectMapOfStats[K comparable, V any](m *MapOf[K, V]) MapStats {
return MapStats{m.stats()}
}

func NewMapOfPresizedWithHasher[K comparable, V any](
hasher func(K, uint64) uint64,
sizeHint int,
) *MapOf[K, V] {
return newMapOfPresized[K, V](hasher, sizeHint)
}
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module github.com/puzpuzpuz/xsync/v2
module github.com/puzpuzpuz/xsync/v3

go 1.20
go 1.18
Loading

0 comments on commit f7bf836

Please sign in to comment.