Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get rid of hash function in MapOf factory functions #108

Merged
merged 1 commit into from
Oct 22, 2023
Merged
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
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