diff --git a/go.mod b/go.mod index 5a229f3..f691838 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,11 @@ module github.com/miniLCT/gosb go 1.22.0 + +require github.com/stretchr/testify v1.9.0 + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..60ce688 --- /dev/null +++ b/go.sum @@ -0,0 +1,10 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +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/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/gogenerics/constraints/constraints.go b/gogenerics/constraints/constraints.go new file mode 100644 index 0000000..d7501e8 --- /dev/null +++ b/gogenerics/constraints/constraints.go @@ -0,0 +1,46 @@ +// Package constraints `golang.org/x/exp/constraints` is experimental and unreliable, +// so remove it from the import path +package constraints + +// Signed is a constraint that permits any signed integer type. +// If future releases of Go add new predeclared signed integer types, +// this constraint will be modified to include them. +type Signed interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 +} + +// Unsigned is a constraint that permits any unsigned integer type. +// If future releases of Go add new predeclared unsigned integer types, +// this constraint will be modified to include them. +type Unsigned interface { + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr +} + +// Integer is a constraint that permits any integer type. +// If future releases of Go add new predeclared integer types, +// this constraint will be modified to include them. +type Integer interface { + Signed | Unsigned +} + +// Float is a constraint that permits any floating-point type. +// If future releases of Go add new predeclared floating-point types, +// this constraint will be modified to include them. +type Float interface { + ~float32 | ~float64 +} + +// Complex is a constraint that permits any complex numeric type. +// If future releases of Go add new predeclared complex numeric types, +// this constraint will be modified to include them. +type Complex interface { + ~complex64 | ~complex128 +} + +// Ordered is a constraint that permits any ordered type: any type +// that supports the operators < <= >= >. +// If future releases of Go add new ordered types, +// this constraint will be modified to include them. +type Ordered interface { + Integer | Float | ~string +} diff --git a/gogenerics/constraints/func.go b/gogenerics/constraints/func.go new file mode 100644 index 0000000..d5a5977 --- /dev/null +++ b/gogenerics/constraints/func.go @@ -0,0 +1,27 @@ +package constraints + +type ( + // Call is Function Call + Call func() + + // Consumer is one input argument and no returns Function + Consumer[T any] func(T) + + // BiConsumer is two input arguments and no returns Function + BiConsumer[T, U any] func(T, U) + + // UFunc is Unary Function + UFunc[P, R any] func(P) R + + // BiFunc is Binary Function + BiFunc[P1, P2, R any] func(P1, P2) R + + // Cmp is Compare Function + Cmp[T any] BiFunc[T, T, int] + + // Eql is Equal Function + Eql[T any] BiFunc[T, T, bool] + + // Less is Less Function + Less[T any] BiFunc[T, T, bool] +) diff --git a/gogenerics/gnumerics/math.go b/gogenerics/gnumerics/math.go new file mode 100644 index 0000000..9cdc5c6 --- /dev/null +++ b/gogenerics/gnumerics/math.go @@ -0,0 +1,97 @@ +package gnumerics + +import "github.com/miniLCT/gosb/gogenerics/constraints" + +// Max returns the maximum of two values +func Max[T constraints.Ordered](a, b T) T { + if a > b { + return a + } + return b +} + +// MaxCollection returns the maximum value in a collection. Returns zero value when collection is empty +func MaxCollection[T constraints.Ordered](collection []T) T { + var maxC T + l := len(collection) + if l == 0 { + return maxC + } + + maxC = collection[0] + for i := 1; i < l; i++ { + c := collection[i] + if c > maxC { + maxC = c + } + } + return maxC +} + +// MaxBy returns the maximum value in a collection, using the given comparison function +// If several values are equivalent, the first one is returned +// Returns zero value when collection is empty +func MaxBy[T any](collection []T, cmp func(a T, b T) bool) T { + var maxC T + + l := len(collection) + if l == 0 { + return maxC + } + + maxC = collection[0] + for i := 1; i < l; i++ { + c := collection[i] + if cmp(c, maxC) { + maxC = c + } + } + return maxC +} + +// Min returns the minimum of two values. +func Min[T constraints.Ordered](a, b T) T { + if a < b { + return a + } + return b +} + +// MinCollection returns the minimum value in a collection. Returns zero value when collection is empty +func MinCollection[T constraints.Ordered](collection []T) T { + var minC T + l := len(collection) + if l == 0 { + return minC + } + + minC = collection[0] + for i := 1; i < l; i++ { + c := collection[i] + if c < minC { + minC = c + } + } + return minC +} + +// MinBy returns the minimum value in a collection, using the given comparison function +// If several values are equivalent, the first one is returned +// Returns zero value when collection is empty +func MinBy[T any](collection []T, cmp func(a T, b T) bool) T { + var minC T + + l := len(collection) + if l == 0 { + return minC + } + + minC = collection[0] + for i := 1; i < l; i++ { + c := collection[i] + if cmp(c, minC) { + minC = c + } + } + return minC +} diff --git a/gogenerics/gnumerics/math_test.go b/gogenerics/gnumerics/math_test.go new file mode 100644 index 0000000..703148e --- /dev/null +++ b/gogenerics/gnumerics/math_test.go @@ -0,0 +1,103 @@ +package gnumerics + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestMax(t *testing.T) { + t.Parallel() + assert := assert.New(t) + + resInt := Max(114, 514) + resFloat := Max(100.0, 99.9) + resString := Max("109", "11") + + assert.Equal(514, resInt) + assert.Equal(100.00, resFloat) + assert.Equal("11", resString) +} + +func TestMin(t *testing.T) { + t.Parallel() + assert := assert.New(t) + + resInt := Min(114, 514) + resFloat := Min(100.0, 99.9) + resString := Min("109", "11") + + assert.Equal(114, resInt) + assert.Equal(99.9, resFloat) + assert.Equal("109", resString) +} + +func TestMaxCollection(t *testing.T) { + t.Parallel() + assert := assert.New(t) + + resEmpty := MaxCollection([]int{}) + resInt1 := MaxCollection([]int{1}) + resInt2 := MaxCollection([]int64{1, 2, 3, 4, 5}) + resString := MaxCollection([]string{"11", "109", "100", "a"}) + resFloat := MaxCollection([]float64{-100.0, 99.9, 99.8}) + + assert.Equal(0, resEmpty) + assert.Equal(1, resInt1) + assert.Equal(int64(5), resInt2) + assert.Equal("a", resString) + assert.Equal(99.9, resFloat) +} + +func TestMinCollection(t *testing.T) { + t.Parallel() + assert := assert.New(t) + + resEmpty := MinCollection([]string{}) + resInt1 := MinCollection([]int{1}) + resInt2 := MinCollection([]int64{1, 2, 3, 4, 5}) + resString := MinCollection([]string{"11", "109", "100", "a"}) + resFloat := MinCollection([]float64{-100.0, 99.9, 99.8}) + + assert.Equal("", resEmpty) + assert.Equal(1, resInt1) + assert.Equal(int64(1), resInt2) + assert.Equal("100", resString) + assert.Equal(-100.0, resFloat) +} + +func TestMaxBy(t *testing.T) { + t.Parallel() + assert := assert.New(t) + res1 := MaxBy([]string{"hello", "the", "cruel", "woooooorld"}, func(a, b string) bool { + return len(a) > len(b) + }) + res2 := MaxBy([]string{"hello", "the", "cruel", "world"}, func(a, b string) bool { + return len(a) > len(b) + }) + res3 := MaxBy([]int{1, 92, -9, 123, -456}, func(a, b int) bool { + return a > b + }) + + assert.Equal("woooooorld", res1) + assert.Equal("hello", res2) + assert.Equal(123, res3) +} + +func TestMinBy(t *testing.T) { + t.Parallel() + assert := assert.New(t) + res1 := MinBy([]string{"hello", "the", "cruel", "woooooorld"}, func(a, b string) bool { + return len(a) < len(b) + }) + res2 := MinBy([]string{"hello", "thhhe", "cruel", "world"}, func(a, b string) bool { + return len(a) < len(b) + }) + res3 := MinBy([]int{1, 92, -9, 123, -456}, func(a, b int) bool { + return a < b + }) + + assert.Equal("the", res1) + assert.Equal("hello", res2) + assert.Equal(-456, res3) +}