From 1c24a996b7f9f38021ac45f5f3f099cb40e9a52a Mon Sep 17 00:00:00 2001 From: Nicholas Wiersma Date: Fri, 19 Jun 2020 08:45:13 +0200 Subject: [PATCH] feature: add intersect and except (#3) --- .travis.yml | 1 + README.md | 46 ++++- example_test.go | 16 ++ except.go | 68 +++++++ except_test.go | 153 +++++++++++++++ internal/gen/gen.go | 55 +++++- intersect.go | 68 +++++++ intersect_test.go | 157 ++++++++++++++++ ops.gen.go | 444 ++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 994 insertions(+), 14 deletions(-) create mode 100644 except.go create mode 100644 except_test.go create mode 100644 intersect.go create mode 100644 intersect_test.go diff --git a/.travis.yml b/.travis.yml index 43c8706..43a01e2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,7 @@ cache: - $GOPATH/pkg/mod before_install: + - go generate ./... && git diff --exit-code; code=$?; (exit $code) - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $GOPATH/bin - go mod download - go get github.com/mattn/goveralls diff --git a/README.md b/README.md index 2135921..fe7ea7c 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ [![GitHub release](https://img.shields.io/github/release/hamba/slices.svg)](https://github.com/hamba/slices/releases) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/hamba/slices/master/LICENSE) -A fast Go slices codec +Go slice helper functions ## Overview @@ -61,15 +61,47 @@ fmt.Println(slice) // Outputs: [bar foo] ``` +### Intersect + +Intersect returns the intersection of 2 slices. + +Supports: string, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64 + +```go +slice := []string{"foo", "bar", "baz", "bat"} +other := []string{"bar", "baz", "test"} + +fmt.Println(slices.Intersect(slice, other)) +// Outputs: [bar baz] +``` + +### Except + +Except returns the all elements in the first slice that are not in the second. + +Supports: string, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64 + +```go +slice := []string{"foo", "bar", "baz", "bat"} +other := []string{"bar", "baz", "test"} + +fmt.Println(slices.Except(slice, other)) +// Outputs: [foo bat] +``` + ## Benchmark ``` -BenchmarkContains-8 36659943 30.0 ns/op 0 B/op 0 allocs/op -BenchmarkContainsNative-8 48539482 24.9 ns/op 0 B/op 0 allocs/op -BenchmarkGreaterOf-8 6257299 193 ns/op 80 B/op 3 allocs/op -BenchmarkGreaterOfNative-8 7963461 149 ns/op 64 B/op 2 allocs/op -BenchmarkLesserOf-8 6122317 192 ns/op 80 B/op 3 allocs/op -BenchmarkLesserOfNative-8 7947242 152 ns/op 64 B/op 2 allocs/op +BenchmarkContains-8 35621572 30.5 ns/op 0 B/op 0 allocs/op +BenchmarkContainsNative-8 50106157 23.9 ns/op 0 B/op 0 allocs/op +BenchmarkExcept-8 6070610 200 ns/op 96 B/op 2 allocs/op +BenchmarkExceptNative-8 5933550 193 ns/op 96 B/op 2 allocs/op +BenchmarkGreaterOf-8 6290626 189 ns/op 80 B/op 3 allocs/op +BenchmarkGreaterOfNative-8 8201284 149 ns/op 64 B/op 2 allocs/op +BenchmarkIntersect-8 6012298 196 ns/op 96 B/op 2 allocs/op +BenchmarkIntersectNative-8 6305799 198 ns/op 96 B/op 2 allocs/op +BenchmarkLesserOf-8 6449050 189 ns/op 80 B/op 3 allocs/op +BenchmarkLesserOfNative-8 8077785 149 ns/op 64 B/op 2 allocs/op ``` Always benchmark with your own workload. The result depends heavily on the data input. diff --git a/example_test.go b/example_test.go index b6604ce..fe12632 100644 --- a/example_test.go +++ b/example_test.go @@ -30,3 +30,19 @@ func ExampleLesserOf() { fmt.Println(slice) // Outputs: [foo baz bar] } + +func ExampleIntersect() { + slice := []string{"foo", "bar", "baz", "bat"} + other := []string{"bar", "baz", "test"} + + fmt.Println(slices.Intersect(slice, other)) + // Outputs: [bar baz] +} + +func ExampleExcept() { + slice := []string{"foo", "bar", "baz", "bat"} + other := []string{"bar", "baz", "test"} + + fmt.Println(slices.Except(slice, other)) + // Outputs: [foo bat] +} diff --git a/except.go b/except.go new file mode 100644 index 0000000..5b4ee4f --- /dev/null +++ b/except.go @@ -0,0 +1,68 @@ +package slices + +import ( + "unsafe" +) + +type exceptFn func(sptr, optr unsafe.Pointer) interface{} + +// Except returns a slice with the elements of slice that are not in other. +// When the slices different, slice is returned. +func Except(slice, other interface{}) interface{} { + fn, ok := exceptOf(slice, other) + if fn == nil { + panic("slice is not a supported slice type") + } + if !ok { + panic("other is not the same type as slice") + } + + sptr := noescape(ptrOf(slice)) + optr := noescape(ptrOf(other)) + return fn(sptr, optr) +} + +func exceptOf(slice, other interface{}) (exceptFn, bool) { + switch slice.(type) { + case []string: + _, ok := other.([]string) + return stringExcept, ok + case []int: + _, ok := other.([]int) + return intExcept, ok + case []int8: + _, ok := other.([]int8) + return int8Except, ok + case []int16: + _, ok := other.([]int16) + return int16Except, ok + case []int32: + _, ok := other.([]int32) + return int32Except, ok + case []int64: + _, ok := other.([]int64) + return int64Except, ok + case []uint: + _, ok := other.([]uint) + return uintExcept, ok + case []uint8: + _, ok := other.([]uint8) + return uint8Except, ok + case []uint16: + _, ok := other.([]uint16) + return uint16Except, ok + case []uint32: + _, ok := other.([]uint32) + return uint32Except, ok + case []uint64: + _, ok := other.([]uint64) + return uint64Except, ok + case []float32: + _, ok := other.([]float32) + return float32Except, ok + case []float64: + _, ok := other.([]float64) + return float64Except, ok + } + return nil, false +} diff --git a/except_test.go b/except_test.go new file mode 100644 index 0000000..6d30b9c --- /dev/null +++ b/except_test.go @@ -0,0 +1,153 @@ +package slices_test + +import ( + "testing" + + "github.com/hamba/slices" + "github.com/stretchr/testify/assert" +) + +func TestExcept(t *testing.T) { + tests := []struct { + name string + a interface{} + b interface{} + want interface{} + }{ + { + name: "string contains", + a: []string{"foo", "bar", "baz", "bat"}, + b: []string{"bar", "baz", "test"}, + want: []string{"foo", "bat"}, + }, + { + name: "int contains", + a: []int{1, 2, 3, 4}, + b: []int{2, 3, 5}, + want: []int{1, 4}, + }, + { + name: "int8 contains", + a: []int8{1, 2, 3, 4}, + b: []int8{2, 3, 5}, + want: []int8{1, 4}, + }, + { + name: "int16 contains", + a: []int16{1, 2, 3, 4}, + b: []int16{2, 3, 5}, + want: []int16{1, 4}, + }, + { + name: "int32 contains", + a: []int32{1, 2, 3, 4}, + b: []int32{2, 3, 5}, + want: []int32{1, 4}, + }, + { + name: "int64 contains", + a: []int64{1, 2, 3, 4}, + b: []int64{2, 3, 5}, + want: []int64{1, 4}, + }, + { + name: "uint contains", + a: []uint{1, 2, 3, 4}, + b: []uint{2, 3, 5}, + want: []uint{1, 4}, + }, + { + name: "uint8 contains", + a: []uint8{1, 2, 3, 4}, + b: []uint8{2, 3, 5}, + want: []uint8{1, 4}, + }, + { + name: "uint16 contains", + a: []uint16{1, 2, 3, 4}, + b: []uint16{2, 3, 5}, + want: []uint16{1, 4}, + }, + { + name: "uint32 contains", + a: []uint32{1, 2, 3, 4}, + b: []uint32{2, 3, 5}, + want: []uint32{1, 4}, + }, + { + name: "uint64 contains", + a: []uint64{1, 2, 3, 4}, + b: []uint64{2, 3, 5}, + want: []uint64{1, 4}, + }, + { + name: "float32 contains", + a: []float32{1, 2, 3, 4}, + b: []float32{2, 3, 5}, + want: []float32{1, 4}, + }, + { + name: "float64 contains", + a: []float64{1, 2, 3, 4}, + b: []float64{2, 3, 5}, + want: []float64{1, 4}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := slices.Except(tt.a, tt.b) + + assert.Equal(t, tt.want, got) + }) + } +} + +func TestExcept_ChecksSliceType(t *testing.T) { + assert.Panics(t, func() { + slices.Except("test", "test") + }) +} + +func TestExcept_ChecksValType(t *testing.T) { + assert.Panics(t, func() { + slices.Except([]string{"test"}, 1) + }) +} + +func BenchmarkExcept(b *testing.B) { + a := []string{"foo", "bar", "baz", "bat"} + c := []string{"bar", "baz", "test"} + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + slices.Except(a, c) + } +} + +func except(slice, other []string) interface{} { + s := make([]string, len(slice)) + copy(s, slice) + for i := 0; i < len(s); i++ { + for _, v := range other { + if v == s[i] { + s = append(s[:i], s[i+1:]...) + i-- + break + } + } + } + return s +} + +func BenchmarkExceptNative(b *testing.B) { + slice := []string{"foo", "bar", "baz", "bat"} + other := []string{"bar", "baz", "test"} + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + except(slice, other) + } +} diff --git a/internal/gen/gen.go b/internal/gen/gen.go index c7e1da3..7172ebf 100644 --- a/internal/gen/gen.go +++ b/internal/gen/gen.go @@ -38,7 +38,7 @@ func {{ $type }}Lesser(ptr unsafe.Pointer) func(i, j int) bool { {{end -}} // GreaterOf -{{- range $i, $type := .lesserOf}} +{{- range $i, $type := .greaterOf}} func {{ $type }}Greater(ptr unsafe.Pointer) func(i, j int) bool { return func(i, j int) bool { v := *(*[]{{ $type }})(ptr) @@ -46,19 +46,61 @@ func {{ $type }}Greater(ptr unsafe.Pointer) func(i, j int) bool { } } {{end -}} + +// Intersect +{{- range $i, $type := .intersect}} +func {{ $type }}Intersect(sptr, optr unsafe.Pointer) interface{} { + slice := make([]{{ $type }}, len(*(*[]{{ $type }})(sptr))) + copy(slice, *(*[]{{ $type }})(sptr)) + for i := 0; i < len(slice); i++ { + found := false + for _, v := range *(*[]{{ $type }})(optr) { + if v == slice[i] { + found = true + break + } + } + if !found { + slice = append(slice[:i], slice[i+1:]...) + i-- + } + } + return slice +} +{{end -}} + +// Except +{{- range $i, $type := .except}} +func {{ $type }}Except(sptr, optr unsafe.Pointer) interface{} { + s := make([]{{ $type }}, len(*(*[]{{ $type }})(sptr))) + copy(s, *(*[]{{ $type }})(sptr)) + for i := 0; i < len(s); i++ { + for _, v := range *(*[]{{ $type }})(optr) { + if v == s[i] { + s = append(s[:i], s[i+1:]...) + i-- + break + } + } + } + return s +} +{{end -}} + ` func main() { - base := template.New("gen") - parse, err := base.Parse(tmpl) + parse, err := template.New("gen").Parse(tmpl) if err != nil { log.Fatal(err) } - ops := map[string][]string { - "contains": {"bool", "string", "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64", "float32", "float64"}, - "lesserOf": {"string", "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64", "float32", "float64"}, + ops := map[string][]string{ + "contains": {"bool", "string", "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64", "float32", "float64"}, + "lesserOf": {"string", "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64", "float32", "float64"}, "greaterOf": {"string", "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64", "float32", "float64"}, + "intersect": {"string", "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64", "float32", "float64"}, + "except": {"string", "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64", "float32", "float64"}, } b := &bytes.Buffer{} @@ -66,7 +108,6 @@ func main() { log.Fatal(err) } - // gofmt source, err := format.Source(b.Bytes()) if err != nil { log.Fatal(err) diff --git a/intersect.go b/intersect.go new file mode 100644 index 0000000..29cf5fc --- /dev/null +++ b/intersect.go @@ -0,0 +1,68 @@ +package slices + +import ( + "unsafe" +) + +type intersectFn func(sptr, optr unsafe.Pointer) interface{} + +// Intersection returns a slice with the intersection of slice and other. +// When the slices are the same, slice is returned. +func Intersect(slice, other interface{}) interface{} { + fn, ok := intersectOf(slice, other) + if fn == nil { + panic("slice is not supported slice type") + } + if !ok { + panic("other is not the same type as slice") + } + + sptr := noescape(ptrOf(slice)) + optr := noescape(ptrOf(other)) + return fn(sptr, optr) +} + +func intersectOf(slice, other interface{}) (intersectFn, bool) { + switch slice.(type) { + case []string: + _, ok := other.([]string) + return stringIntersect, ok + case []int: + _, ok := other.([]int) + return intIntersect, ok + case []int8: + _, ok := other.([]int8) + return int8Intersect, ok + case []int16: + _, ok := other.([]int16) + return int16Intersect, ok + case []int32: + _, ok := other.([]int32) + return int32Intersect, ok + case []int64: + _, ok := other.([]int64) + return int64Intersect, ok + case []uint: + _, ok := other.([]uint) + return uintIntersect, ok + case []uint8: + _, ok := other.([]uint8) + return uint8Intersect, ok + case []uint16: + _, ok := other.([]uint16) + return uint16Intersect, ok + case []uint32: + _, ok := other.([]uint32) + return uint32Intersect, ok + case []uint64: + _, ok := other.([]uint64) + return uint64Intersect, ok + case []float32: + _, ok := other.([]float32) + return float32Intersect, ok + case []float64: + _, ok := other.([]float64) + return float64Intersect, ok + } + return nil, false +} diff --git a/intersect_test.go b/intersect_test.go new file mode 100644 index 0000000..d4b9e7c --- /dev/null +++ b/intersect_test.go @@ -0,0 +1,157 @@ +package slices_test + +import ( + "testing" + + "github.com/hamba/slices" + "github.com/stretchr/testify/assert" +) + +func TestIntersect(t *testing.T) { + tests := []struct { + name string + slice interface{} + other interface{} + want interface{} + }{ + { + name: "string contains", + slice: []string{"foo", "bar", "baz", "bat"}, + other: []string{"bar", "baz", "test"}, + want: []string{"bar", "baz"}, + }, + { + name: "int contains", + slice: []int{1, 2, 3, 4}, + other: []int{2, 3, 5}, + want: []int{2, 3}, + }, + { + name: "int8 contains", + slice: []int8{1, 2, 3, 4}, + other: []int8{2, 3, 5}, + want: []int8{2, 3}, + }, + { + name: "int16 contains", + slice: []int16{1, 2, 3, 4}, + other: []int16{2, 3, 5}, + want: []int16{2, 3}, + }, + { + name: "int32 contains", + slice: []int32{1, 2, 3, 4}, + other: []int32{2, 3, 5}, + want: []int32{2, 3}, + }, + { + name: "int64 contains", + slice: []int64{1, 2, 3, 4}, + other: []int64{2, 3, 5}, + want: []int64{2, 3}, + }, + { + name: "uint contains", + slice: []uint{1, 2, 3, 4}, + other: []uint{2, 3, 5}, + want: []uint{2, 3}, + }, + { + name: "uint8 contains", + slice: []uint8{1, 2, 3, 4}, + other: []uint8{2, 3, 5}, + want: []uint8{2, 3}, + }, + { + name: "uint16 contains", + slice: []uint16{1, 2, 3, 4}, + other: []uint16{2, 3, 5}, + want: []uint16{2, 3}, + }, + { + name: "uint32 contains", + slice: []uint32{1, 2, 3, 4}, + other: []uint32{2, 3, 5}, + want: []uint32{2, 3}, + }, + { + name: "uint64 contains", + slice: []uint64{1, 2, 3, 4}, + other: []uint64{2, 3, 5}, + want: []uint64{2, 3}, + }, + { + name: "float32 contains", + slice: []float32{1, 2, 3, 4}, + other: []float32{2, 3, 5}, + want: []float32{2, 3}, + }, + { + name: "float64 contains", + slice: []float64{1, 2, 3, 4}, + other: []float64{2, 3, 5}, + want: []float64{2, 3}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := slices.Intersect(tt.slice, tt.other) + + assert.Equal(t, tt.want, got) + }) + } +} + +func TestIntersect_ChecksSliceType(t *testing.T) { + assert.Panics(t, func() { + slices.Intersect("test", "test") + }) +} + +func TestIntersect_ChecksValType(t *testing.T) { + assert.Panics(t, func() { + slices.Intersect([]string{"test"}, 1) + }) +} + +func BenchmarkIntersect(b *testing.B) { + slice := []string{"foo", "bar", "baz", "bat"} + other := []string{"bar", "baz", "test"} + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + slices.Intersect(slice, other) + } +} + +func intersect(slice, other []string) interface{} { + s := make([]string, len(slice)) + copy(s, slice) + for i := 0; i < len(s); i++ { + found := false + for _, v := range other { + if v == s[i] { + found = true + break + } + } + if !found { + s = append(s[:i], s[i+1:]...) + i-- + } + } + return s +} + +func BenchmarkIntersectNative(b *testing.B) { + slice := []string{"foo", "bar", "baz", "bat"} + other := []string{"bar", "baz", "test"} + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + intersect(slice, other) + } +} diff --git a/ops.gen.go b/ops.gen.go index 03428a1..ed7f9a8 100644 --- a/ops.gen.go +++ b/ops.gen.go @@ -328,3 +328,447 @@ func float64Greater(ptr unsafe.Pointer) func(i, j int) bool { return v[i] > v[j] } } + +// Intersect +func stringIntersect(sptr, optr unsafe.Pointer) interface{} { + slice := make([]string, len(*(*[]string)(sptr))) + copy(slice, *(*[]string)(sptr)) + for i := 0; i < len(slice); i++ { + found := false + for _, v := range *(*[]string)(optr) { + if v == slice[i] { + found = true + break + } + } + if !found { + slice = append(slice[:i], slice[i+1:]...) + i-- + } + } + return slice +} + +func intIntersect(sptr, optr unsafe.Pointer) interface{} { + slice := make([]int, len(*(*[]int)(sptr))) + copy(slice, *(*[]int)(sptr)) + for i := 0; i < len(slice); i++ { + found := false + for _, v := range *(*[]int)(optr) { + if v == slice[i] { + found = true + break + } + } + if !found { + slice = append(slice[:i], slice[i+1:]...) + i-- + } + } + return slice +} + +func int8Intersect(sptr, optr unsafe.Pointer) interface{} { + slice := make([]int8, len(*(*[]int8)(sptr))) + copy(slice, *(*[]int8)(sptr)) + for i := 0; i < len(slice); i++ { + found := false + for _, v := range *(*[]int8)(optr) { + if v == slice[i] { + found = true + break + } + } + if !found { + slice = append(slice[:i], slice[i+1:]...) + i-- + } + } + return slice +} + +func int16Intersect(sptr, optr unsafe.Pointer) interface{} { + slice := make([]int16, len(*(*[]int16)(sptr))) + copy(slice, *(*[]int16)(sptr)) + for i := 0; i < len(slice); i++ { + found := false + for _, v := range *(*[]int16)(optr) { + if v == slice[i] { + found = true + break + } + } + if !found { + slice = append(slice[:i], slice[i+1:]...) + i-- + } + } + return slice +} + +func int32Intersect(sptr, optr unsafe.Pointer) interface{} { + slice := make([]int32, len(*(*[]int32)(sptr))) + copy(slice, *(*[]int32)(sptr)) + for i := 0; i < len(slice); i++ { + found := false + for _, v := range *(*[]int32)(optr) { + if v == slice[i] { + found = true + break + } + } + if !found { + slice = append(slice[:i], slice[i+1:]...) + i-- + } + } + return slice +} + +func int64Intersect(sptr, optr unsafe.Pointer) interface{} { + slice := make([]int64, len(*(*[]int64)(sptr))) + copy(slice, *(*[]int64)(sptr)) + for i := 0; i < len(slice); i++ { + found := false + for _, v := range *(*[]int64)(optr) { + if v == slice[i] { + found = true + break + } + } + if !found { + slice = append(slice[:i], slice[i+1:]...) + i-- + } + } + return slice +} + +func uintIntersect(sptr, optr unsafe.Pointer) interface{} { + slice := make([]uint, len(*(*[]uint)(sptr))) + copy(slice, *(*[]uint)(sptr)) + for i := 0; i < len(slice); i++ { + found := false + for _, v := range *(*[]uint)(optr) { + if v == slice[i] { + found = true + break + } + } + if !found { + slice = append(slice[:i], slice[i+1:]...) + i-- + } + } + return slice +} + +func uint8Intersect(sptr, optr unsafe.Pointer) interface{} { + slice := make([]uint8, len(*(*[]uint8)(sptr))) + copy(slice, *(*[]uint8)(sptr)) + for i := 0; i < len(slice); i++ { + found := false + for _, v := range *(*[]uint8)(optr) { + if v == slice[i] { + found = true + break + } + } + if !found { + slice = append(slice[:i], slice[i+1:]...) + i-- + } + } + return slice +} + +func uint16Intersect(sptr, optr unsafe.Pointer) interface{} { + slice := make([]uint16, len(*(*[]uint16)(sptr))) + copy(slice, *(*[]uint16)(sptr)) + for i := 0; i < len(slice); i++ { + found := false + for _, v := range *(*[]uint16)(optr) { + if v == slice[i] { + found = true + break + } + } + if !found { + slice = append(slice[:i], slice[i+1:]...) + i-- + } + } + return slice +} + +func uint32Intersect(sptr, optr unsafe.Pointer) interface{} { + slice := make([]uint32, len(*(*[]uint32)(sptr))) + copy(slice, *(*[]uint32)(sptr)) + for i := 0; i < len(slice); i++ { + found := false + for _, v := range *(*[]uint32)(optr) { + if v == slice[i] { + found = true + break + } + } + if !found { + slice = append(slice[:i], slice[i+1:]...) + i-- + } + } + return slice +} + +func uint64Intersect(sptr, optr unsafe.Pointer) interface{} { + slice := make([]uint64, len(*(*[]uint64)(sptr))) + copy(slice, *(*[]uint64)(sptr)) + for i := 0; i < len(slice); i++ { + found := false + for _, v := range *(*[]uint64)(optr) { + if v == slice[i] { + found = true + break + } + } + if !found { + slice = append(slice[:i], slice[i+1:]...) + i-- + } + } + return slice +} + +func float32Intersect(sptr, optr unsafe.Pointer) interface{} { + slice := make([]float32, len(*(*[]float32)(sptr))) + copy(slice, *(*[]float32)(sptr)) + for i := 0; i < len(slice); i++ { + found := false + for _, v := range *(*[]float32)(optr) { + if v == slice[i] { + found = true + break + } + } + if !found { + slice = append(slice[:i], slice[i+1:]...) + i-- + } + } + return slice +} + +func float64Intersect(sptr, optr unsafe.Pointer) interface{} { + slice := make([]float64, len(*(*[]float64)(sptr))) + copy(slice, *(*[]float64)(sptr)) + for i := 0; i < len(slice); i++ { + found := false + for _, v := range *(*[]float64)(optr) { + if v == slice[i] { + found = true + break + } + } + if !found { + slice = append(slice[:i], slice[i+1:]...) + i-- + } + } + return slice +} + +// Except +func stringExcept(sptr, optr unsafe.Pointer) interface{} { + s := make([]string, len(*(*[]string)(sptr))) + copy(s, *(*[]string)(sptr)) + for i := 0; i < len(s); i++ { + for _, v := range *(*[]string)(optr) { + if v == s[i] { + s = append(s[:i], s[i+1:]...) + i-- + break + } + } + } + return s +} + +func intExcept(sptr, optr unsafe.Pointer) interface{} { + s := make([]int, len(*(*[]int)(sptr))) + copy(s, *(*[]int)(sptr)) + for i := 0; i < len(s); i++ { + for _, v := range *(*[]int)(optr) { + if v == s[i] { + s = append(s[:i], s[i+1:]...) + i-- + break + } + } + } + return s +} + +func int8Except(sptr, optr unsafe.Pointer) interface{} { + s := make([]int8, len(*(*[]int8)(sptr))) + copy(s, *(*[]int8)(sptr)) + for i := 0; i < len(s); i++ { + for _, v := range *(*[]int8)(optr) { + if v == s[i] { + s = append(s[:i], s[i+1:]...) + i-- + break + } + } + } + return s +} + +func int16Except(sptr, optr unsafe.Pointer) interface{} { + s := make([]int16, len(*(*[]int16)(sptr))) + copy(s, *(*[]int16)(sptr)) + for i := 0; i < len(s); i++ { + for _, v := range *(*[]int16)(optr) { + if v == s[i] { + s = append(s[:i], s[i+1:]...) + i-- + break + } + } + } + return s +} + +func int32Except(sptr, optr unsafe.Pointer) interface{} { + s := make([]int32, len(*(*[]int32)(sptr))) + copy(s, *(*[]int32)(sptr)) + for i := 0; i < len(s); i++ { + for _, v := range *(*[]int32)(optr) { + if v == s[i] { + s = append(s[:i], s[i+1:]...) + i-- + break + } + } + } + return s +} + +func int64Except(sptr, optr unsafe.Pointer) interface{} { + s := make([]int64, len(*(*[]int64)(sptr))) + copy(s, *(*[]int64)(sptr)) + for i := 0; i < len(s); i++ { + for _, v := range *(*[]int64)(optr) { + if v == s[i] { + s = append(s[:i], s[i+1:]...) + i-- + break + } + } + } + return s +} + +func uintExcept(sptr, optr unsafe.Pointer) interface{} { + s := make([]uint, len(*(*[]uint)(sptr))) + copy(s, *(*[]uint)(sptr)) + for i := 0; i < len(s); i++ { + for _, v := range *(*[]uint)(optr) { + if v == s[i] { + s = append(s[:i], s[i+1:]...) + i-- + break + } + } + } + return s +} + +func uint8Except(sptr, optr unsafe.Pointer) interface{} { + s := make([]uint8, len(*(*[]uint8)(sptr))) + copy(s, *(*[]uint8)(sptr)) + for i := 0; i < len(s); i++ { + for _, v := range *(*[]uint8)(optr) { + if v == s[i] { + s = append(s[:i], s[i+1:]...) + i-- + break + } + } + } + return s +} + +func uint16Except(sptr, optr unsafe.Pointer) interface{} { + s := make([]uint16, len(*(*[]uint16)(sptr))) + copy(s, *(*[]uint16)(sptr)) + for i := 0; i < len(s); i++ { + for _, v := range *(*[]uint16)(optr) { + if v == s[i] { + s = append(s[:i], s[i+1:]...) + i-- + break + } + } + } + return s +} + +func uint32Except(sptr, optr unsafe.Pointer) interface{} { + s := make([]uint32, len(*(*[]uint32)(sptr))) + copy(s, *(*[]uint32)(sptr)) + for i := 0; i < len(s); i++ { + for _, v := range *(*[]uint32)(optr) { + if v == s[i] { + s = append(s[:i], s[i+1:]...) + i-- + break + } + } + } + return s +} + +func uint64Except(sptr, optr unsafe.Pointer) interface{} { + s := make([]uint64, len(*(*[]uint64)(sptr))) + copy(s, *(*[]uint64)(sptr)) + for i := 0; i < len(s); i++ { + for _, v := range *(*[]uint64)(optr) { + if v == s[i] { + s = append(s[:i], s[i+1:]...) + i-- + break + } + } + } + return s +} + +func float32Except(sptr, optr unsafe.Pointer) interface{} { + s := make([]float32, len(*(*[]float32)(sptr))) + copy(s, *(*[]float32)(sptr)) + for i := 0; i < len(s); i++ { + for _, v := range *(*[]float32)(optr) { + if v == s[i] { + s = append(s[:i], s[i+1:]...) + i-- + break + } + } + } + return s +} + +func float64Except(sptr, optr unsafe.Pointer) interface{} { + s := make([]float64, len(*(*[]float64)(sptr))) + copy(s, *(*[]float64)(sptr)) + for i := 0; i < len(s); i++ { + for _, v := range *(*[]float64)(optr) { + if v == s[i] { + s = append(s[:i], s[i+1:]...) + i-- + break + } + } + } + return s +}