Skip to content

Commit

Permalink
add slices and utils package
Browse files Browse the repository at this point in the history
  • Loading branch information
alimy committed Jun 23, 2024
1 parent 92ff535 commit c1d6c9e
Show file tree
Hide file tree
Showing 6 changed files with 198 additions and 0 deletions.
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/alimy/tryst
go 1.21

require (
github.com/RoaringBitmap/roaring v1.9.4
github.com/bytedance/sonic v1.11.8
github.com/goccy/go-json v0.10.3
github.com/hashicorp/golang-lru/v2 v2.0.7
Expand All @@ -11,12 +12,14 @@ require (
)

require (
github.com/bits-and-blooms/bitset v1.12.0 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mschoch/smat v0.2.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
)
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
github.com/RoaringBitmap/roaring v1.9.4 h1:yhEIoH4YezLYT04s1nHehNO64EKFTop/wBhxv2QzDdQ=
github.com/RoaringBitmap/roaring v1.9.4/go.mod h1:6AXUsoIEzDTFFQCe1RbGA6uFONMhvejWj5rqITANK90=
github.com/bits-and-blooms/bitset v1.12.0 h1:U/q1fAF7xXRhFCrhROzIfffYnu+dlS38vCZtmFVPHmA=
github.com/bits-and-blooms/bitset v1.12.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
github.com/bytedance/sonic v1.11.8 h1:Zw/j1KfiS+OYTi9lyB3bb0CFxPJVkM17k1wyDG32LRA=
github.com/bytedance/sonic v1.11.8/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
Expand All @@ -23,6 +27,8 @@ github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OH
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mschoch/smat v0.2.0 h1:8imxQsjDm8yFEAVBe7azKmKSgzSkZXDuKkSq9374khM=
github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOlotKw=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
Expand Down
17 changes: 17 additions & 0 deletions slices/help.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright 2024 Michael Li <alimy@gility.net>. All rights reserved.
// Use of this source code is governed by Apache License 2.0 that
// can be found in the LICENSE file.

package slices

import (
"hash/maphash"
)

// DistinctFn return distinc elements of S
func DistinctFn[S ~[]E, E any](s S, key func(e E) string) (res S) {
seed := maphash.MakeSeed()
return DistinctFunc(s, func(e E) int {
return int(maphash.String(seed, key(e)))
})
}
34 changes: 34 additions & 0 deletions slices/slices.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright 2024 Michael Li <alimy@gility.net>. All rights reserved.
// Use of this source code is governed by Apache License 2.0 that
// can be found in the LICENSE file.

package slices

import (
"github.com/RoaringBitmap/roaring"
)

type keyable interface {
Key() int
}

// Distinct return distinc elements of S
func Distinct[S ~[]E, E keyable](s S) S {
return DistinctFunc(s, func(e E) int {
return e.Key()
})
}

// DistinctFunc return distinc elements of S
func DistinctFunc[S ~[]E, E any](s S, key func(e E) int) (res S) {
res = make(S, 0, len(s))
x, bitmap := 0, roaring.New()
for _, e := range s {
x = key(e)
if !bitmap.ContainsInt(x) {
res = append(res, e)
bitmap.AddInt(x)
}
}
return
}
113 changes: 113 additions & 0 deletions slices/slices_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// Copyright 2024 Michael Li <alimy@gility.net>. All rights reserved.
// Use of this source code is governed by Apache License 2.0 that
// can be found in the LICENSE file.

package slices_test

import (
"cmp"
stdSlices "slices"
"testing"

"github.com/alimy/tryst/slices"
)

type aliasInt int

func (e aliasInt) Key() int {
return int(e)
}

func TestDistinct(t *testing.T) {
for _, d := range []struct {
input []aliasInt
expect []aliasInt
}{
{
input: []aliasInt{1, 2, 3, 1, 2, 3, 4, 5, 2, 6},
expect: []aliasInt{1, 2, 3, 4, 5, 6},
},
{
input: []aliasInt{0, 2, 3, 1, 2, 3, 4, 5, 2, 6, 1, 1, 3, 5, 6, 0, 1, 2, 3},
expect: []aliasInt{0, 1, 2, 3, 4, 5, 6},
},
} {
res := slices.Distinct(d.input)
if !eqAliasIntSlice(res, d.expect) {
t.Errorf("input:%v want:%v but got:%v", d.input, d.expect, res)
}
}
}

func TestDistinctFunc(t *testing.T) {
for _, d := range []struct {
input []int
expect []int
}{
{
input: []int{1, 2, 3, 1, 2, 3, 4, 5, 2, 6},
expect: []int{1, 2, 3, 4, 5, 6},
},
{
input: []int{0, 2, 3, 1, 2, 3, 4, 5, 2, 6, 1, 1, 3, 5, 6, 0, 1, 2, 3},
expect: []int{0, 1, 2, 3, 4, 5, 6},
},
} {
res := slices.DistinctFunc(d.input, func(e int) int {
return e
})
if !eqSlice(res, d.expect) {
t.Errorf("input:%v want:%v but got:%v", d.input, d.expect, res)
}
}
}

func TestDistinctFn(t *testing.T) {
for _, d := range []struct {
input []string
expect []string
}{
{
input: []string{"1", "2", "3", "1", "2", "3", "4", "5", "2", "6"},
expect: []string{"1", "2", "3", "4", "5", "6"},
},
{
input: []string{"abc", "bcd", "ccd", "abc", "ccd", "bcd", "a", "a", "b", "c"},
expect: []string{"abc", "bcd", "ccd", "a", "b", "c"},
},
} {
res := slices.DistinctFn(d.input, func(e string) string {
return e
})
if !eqSlice(res, d.expect) {
t.Errorf("input:%v want:%v but got:%v", d.input, d.expect, res)
}
}
}

func eqSlice[E cmp.Ordered](s1, s2 []E) bool {
if len(s1) != len(s2) {
return false
}
stdSlices.Sort(s1)
stdSlices.Sort(s2)
for i := 0; i < len(s1); i++ {
if s1[i] != s2[i] {
return false
}
}
return true
}

func eqAliasIntSlice(s1, s2 []aliasInt) bool {
t1, t2 := toIntSlice(s1), toIntSlice(s2)
return eqSlice(t1, t2)
}

func toIntSlice(s []aliasInt) []int {
res := make([]int, 0, len(s))
for _, e := range s {
res = append(res, int(e))
}
return res
}
25 changes: 25 additions & 0 deletions utils/str.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2024 Michael Li <alimy@gility.net>. All rights reserved.
// Use of this source code is governed by Apache License 2.0 that
// can be found in the LICENSE file.

package utils

import "unsafe"

// String convert bytes to string
func String(data []byte) (res string) {
if size := len(data); size > 0 {
res = unsafe.String(unsafe.SliceData(data), size)
}
return
}

// Bytes convert string to []byte
func Bytes(data string) (res []byte) {
if size := len(data); size > 0 {
res = unsafe.Slice(unsafe.StringData(data), size)
} else {
res = []byte{}
}
return
}

0 comments on commit c1d6c9e

Please sign in to comment.