From 9d1e807ec27bf1219459e304bf55c981e773e86d Mon Sep 17 00:00:00 2001 From: Gert Drapers <1533850+gertd@users.noreply.github.com> Date: Wed, 30 Sep 2026 13:24:56 +0200 Subject: [PATCH] update golang-set to v3.0.0 --- .github/workflows/ci.yaml | 2 +- go.mod | 19 +- go.sum | 28 + internal/golang-set/v2/LICENSE | 22 - internal/golang-set/v2/README.md | 11 - internal/golang-set/v2/bench_helper_test.go | 49 - internal/golang-set/v2/bench_test.go | 840 --------- internal/golang-set/v2/helper.go | 11 - internal/golang-set/v2/helper_1_21.go | 9 - internal/golang-set/v2/iterator.go | 58 - .../golang-set/v2/iterator_example_test.go | 60 - internal/golang-set/v2/set.go | 286 --- internal/golang-set/v2/set123_test.go | 38 - internal/golang-set/v2/set_test.go | 1678 ----------------- internal/golang-set/v2/sorted.go | 42 - internal/golang-set/v2/sorted_test.go | 61 - internal/golang-set/v2/threadsafe.go | 362 ---- internal/golang-set/v2/threadsafe_test.go | 803 -------- internal/golang-set/v2/threadunsafe.go | 408 ---- internal/golang-set/v2/threadunsafe_test.go | 164 -- makefile | 4 +- model/inverse.go | 2 +- model/model.go | 2 +- model/validate.go | 2 +- 24 files changed, 44 insertions(+), 4917 deletions(-) delete mode 100644 internal/golang-set/v2/LICENSE delete mode 100644 internal/golang-set/v2/README.md delete mode 100644 internal/golang-set/v2/bench_helper_test.go delete mode 100644 internal/golang-set/v2/bench_test.go delete mode 100644 internal/golang-set/v2/helper.go delete mode 100644 internal/golang-set/v2/helper_1_21.go delete mode 100644 internal/golang-set/v2/iterator.go delete mode 100644 internal/golang-set/v2/iterator_example_test.go delete mode 100644 internal/golang-set/v2/set.go delete mode 100644 internal/golang-set/v2/set123_test.go delete mode 100644 internal/golang-set/v2/set_test.go delete mode 100644 internal/golang-set/v2/sorted.go delete mode 100644 internal/golang-set/v2/sorted_test.go delete mode 100644 internal/golang-set/v2/threadsafe.go delete mode 100644 internal/golang-set/v2/threadsafe_test.go delete mode 100644 internal/golang-set/v2/threadunsafe.go delete mode 100644 internal/golang-set/v2/threadunsafe_test.go diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index d10a44d..dc21f87 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -13,7 +13,7 @@ on: env: PRE_RELEASE: ${{ github.ref == 'refs/heads/main' && 'development' || '' }} - GO_LANGCI_LINT_VERSION: v2.13.1 + GO_LANGCI_LINT_VERSION: v2.14.0 jobs: test: diff --git a/go.mod b/go.mod index 9f32be1..4377172 100644 --- a/go.mod +++ b/go.mod @@ -2,12 +2,13 @@ module github.com/aserto-dev/azm go 1.26.0 -toolchain go1.26.7 +toolchain go1.27.1 require ( github.com/antlr4-go/antlr/v4 v4.13.1 github.com/aserto-dev/errors v0.34.1 github.com/aserto-dev/go-directory v0.34.2 + github.com/deckarep/golang-set/v3 v3.0.0 github.com/hashicorp/go-multierror v1.1.1 github.com/mitchellh/hashstructure/v2 v2.0.2 github.com/nsf/jsondiff v0.0.0-20260207060731-8e8d90c4c0ac @@ -15,22 +16,22 @@ require ( github.com/rs/zerolog v1.35.1 github.com/samber/lo v1.53.0 github.com/stretchr/testify v1.12.1 - google.golang.org/grpc v1.83.1 + google.golang.org/grpc v1.84.0 google.golang.org/protobuf v1.36.12 gopkg.in/yaml.v3 v3.0.1 ) require ( - github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.31.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/mattn/go-colorable v0.1.15 // indirect github.com/mattn/go-isatty v0.0.24 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect go.yaml.in/yaml/v3 v3.0.5 // indirect - golang.org/x/exp v0.0.0-20260824195058-e88cd73687aa // indirect - golang.org/x/net v0.58.0 // indirect - golang.org/x/sys v0.47.0 // indirect - golang.org/x/text v0.41.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20260819154853-08b0e4226688 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260819154853-08b0e4226688 // indirect + golang.org/x/exp v0.0.0-20260908205506-85c1c2202aba // indirect + golang.org/x/net v0.59.0 // indirect + golang.org/x/sys v0.48.0 // indirect + golang.org/x/text v0.42.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260928230214-8a89bd6388cc // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260928230214-8a89bd6388cc // indirect ) diff --git a/go.sum b/go.sum index 165296e..515a47a 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/aserto-dev/go-directory v0.34.2 h1:LHfQ+NBY/+Lvy7sFXvD0qg3uhpo18uAXAv github.com/aserto-dev/go-directory v0.34.2/go.mod h1:QQsDn8SPkaD7tB50niinLzdYa8KtFbHWVQon91oklzw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/deckarep/golang-set/v3 v3.0.0 h1:Jn/HhA4IIh0odCMtBuiW2Gith2AlgO4+J/x7YgpGywQ= +github.com/deckarep/golang-set/v3 v3.0.0/go.mod h1:n8bXs6b+vTxST3g+6yxlve6cVvnHr+kmWzQ/K6FXdks= github.com/go-logr/logr v1.4.4 h1:tG4xh9yMsRCAiodLVTxyrkzSZ9+o0L1Kg/+cPVcbP/8= github.com/go-logr/logr v1.4.4/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= @@ -18,6 +20,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0 h1:/Tnpcb2E0Pz/tN9s3bfEY2Q8ePCEX9iuS+cneUwncnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.30.0/go.mod h1:zOBXOsUaBSjKgmH4OGzV1esUpR3oUSCPYVd2cUBjKYY= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.31.0 h1:Bd7KaOxzULLxtZ/K5s1aLbWhR0+5RToO65TXHsf3bqQ= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.31.0/go.mod h1:nN7ts3dFXKtCZWc//yfkpcQNKJABg16/uDVAZpLDalo= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -45,32 +49,56 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/otel v1.45.0 h1:pdrWmLHofpubmArBv1LgFSv1Z0Ie/ppdZzu+kUN5EeU= go.opentelemetry.io/otel v1.45.0/go.mod h1:XZxIqPapzEYnhNSScF5DIqXhm/rYi0FzCe2XddAwZfQ= +go.opentelemetry.io/otel v1.46.0 h1:FHt5/CDyVxi/8IM1CH7VE/rRgq3kLHa2mSTVMO8AWyc= go.opentelemetry.io/otel/metric v1.45.0 h1:7Eg1uH7CJ5cXv9is6tnBe1FI6rj1nwUdbFypRm3br/M= go.opentelemetry.io/otel/metric v1.45.0/go.mod h1:HAPbm1nd3p1PmFH7v2dR+6BjXxw+Lq4a2+pndMAm08s= +go.opentelemetry.io/otel/metric v1.46.0 h1:yBnkXvgV7AXFILZc5K6IZe/CBFF3OS7BJ8ov6/lj0K8= go.opentelemetry.io/otel/sdk v1.45.0 h1:4VVSMgQ83dUgW2aoX5f6JgLvHwIvzcuLnF9lUdCSpCw= go.opentelemetry.io/otel/sdk v1.45.0/go.mod h1:Sr40LgXV7DsKMMJMKOhUWOgMWTfAaqvm2kF0g7ilwuA= +go.opentelemetry.io/otel/sdk v1.46.0 h1:h5CNQQjEbuQXY/JfZtgt3i7HVFV3aHPO2OAwO2eTYPI= go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI= go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA= go.opentelemetry.io/otel/trace v1.45.0 h1:l/mP6Uv7oNO7/TblbhpbgMidxhq1uO/rPsikOyVhxag= go.opentelemetry.io/otel/trace v1.45.0/go.mod h1:qoJJA2xNMnxRrdISU/kLtfUH2wNeQbiv+jhs/CxI8bc= +go.opentelemetry.io/otel/trace v1.46.0 h1:OULy7ccdJnZtJ0UDYFOIGaCmiWzJ8Vi2G/Rsu60qs1c= go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw= go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg= golang.org/x/exp v0.0.0-20260824195058-e88cd73687aa h1:QSyA8ishJCyT21kER9KwNt0b7BM3iRK4x9QXhjN5Fdk= golang.org/x/exp v0.0.0-20260824195058-e88cd73687aa/go.mod h1:zeBbvyFKDaLwa7CH/zI8KXt7gTl14SF7sO08Pl5jBCM= +golang.org/x/exp v0.0.0-20260908205506-85c1c2202aba h1:Ck8QetSgk912qxWLMCKxd0in+aiyBQyDSMae6e/xmpU= +golang.org/x/exp v0.0.0-20260908205506-85c1c2202aba/go.mod h1:50RgIsmK7OwqzTTeqcSXQW8SswW0o8fRcDxmqGluJ8E= golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To= golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU= +golang.org/x/net v0.59.0 h1:5zfYln+w5XCxwrnMMJPufRgNoXEaGxl0wo5GqPXyues= +golang.org/x/net v0.59.0/go.mod h1:2DA/G1UfVbCpQPeWTmMPGY7Cs2PkBkwu743bVX5PIVg= golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo= +golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og= golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8= golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M= +golang.org/x/text v0.42.0 h1:JbOZXgfeCPU9gacVtYliJqOhD+zhrEqK4LfdpmlUZqI= +golang.org/x/text v0.42.0/go.mod h1:ojzP1Z+2QtioaF8DTtO8K5q7JWVVYwZKenzujK0Zd0E= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= google.golang.org/genproto/googleapis/api v0.0.0-20260819154853-08b0e4226688 h1:ax2KzoSRIZU/M0cIxri3pKxy99vniH1PVxWC6si/eZI= google.golang.org/genproto/googleapis/api v0.0.0-20260819154853-08b0e4226688/go.mod h1:1RJ9BQGyNdZwkGc1eTqkErfRZ6RJyYPHZo73BZ1vQqI= +google.golang.org/genproto/googleapis/api v0.0.0-20260921155816-b14227669459 h1:GS9OIt/j7c8bvBjYNgnKQysVfmV7e4jM0H8ZK95G4t8= +google.golang.org/genproto/googleapis/api v0.0.0-20260921155816-b14227669459/go.mod h1:PX5/4vemwVoXtwEcRDWwcR1/r0qrosfx3qoVADMwnVE= +google.golang.org/genproto/googleapis/api v0.0.0-20260928230214-8a89bd6388cc h1:rZHRz0ogq4Pid1IKtA/ivHi8XONVF5tqUQXA2TtgpkE= +google.golang.org/genproto/googleapis/api v0.0.0-20260928230214-8a89bd6388cc/go.mod h1:K/n0XLazCJHjD73YuMyNJsN38BPPy1kfFnKxUXaThFU= google.golang.org/genproto/googleapis/rpc v0.0.0-20260819154853-08b0e4226688 h1:cYNAzI2sUwhmCcoj9TxvihSrqsxt6uIkj3rDRhSDmW4= google.golang.org/genproto/googleapis/rpc v0.0.0-20260819154853-08b0e4226688/go.mod h1:DjtHYE8FKJLivXcBEjGwndXfIC23G0VpXiXKqG179uA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260918162117-cecb64721679 h1:KmqdJU4vrNcxy/6qdg3JduZtalEXrJLspVltnR1cE+8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260918162117-cecb64721679/go.mod h1:OaIUM3+LpYcK2GXM4FTmhWoIq371Owdr+Cc7/BsYHHc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260921155816-b14227669459 h1:b0xCahf3FK2m2Cv0p4vTozGPWncCvLfwV86UNg8xWU8= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260921155816-b14227669459/go.mod h1:OaIUM3+LpYcK2GXM4FTmhWoIq371Owdr+Cc7/BsYHHc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260928230214-8a89bd6388cc h1:4bNTbnb44EqGVy9HaQxSY2jnafSUdgV3qHtedvNpDKg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260928230214-8a89bd6388cc/go.mod h1:OaIUM3+LpYcK2GXM4FTmhWoIq371Owdr+Cc7/BsYHHc= google.golang.org/grpc v1.83.1 h1:HIO0+BEtBP6soyqvqC8sNUjZ7bTs+0hFQuFF+RAy++Y= google.golang.org/grpc v1.83.1/go.mod h1:kDyl6SKsiHKt0uylY5gtn5cEjkrIOhQOGDgIc4JGwzQ= +google.golang.org/grpc v1.84.0 h1:soMyaPJ8pAak5PIQ0DGBUir0XRo2fRoMqhNWMLlLxO0= +google.golang.org/grpc v1.84.0/go.mod h1:ljCht0DrxQrXBDRTZp52Qxh3Ffk8CdYm2sj4O2QN2C0= google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc= google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= diff --git a/internal/golang-set/v2/LICENSE b/internal/golang-set/v2/LICENSE deleted file mode 100644 index efd4827..0000000 --- a/internal/golang-set/v2/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Open Source Initiative OSI - The MIT License (MIT):Licensing - -The MIT License (MIT) -Copyright (c) 2013 - 2022 Ralph Caraveo (deckarep@gmail.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/internal/golang-set/v2/README.md b/internal/golang-set/v2/README.md deleted file mode 100644 index 1cd82b4..0000000 --- a/internal/golang-set/v2/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Private fork of [deckarep/golang-set/v2](https://github.com/deckarep/golang-set) - -Removed all the mongodb driver dependencies and implementation - -From original ci.yaml - -``` -go test -v -race ./... -go vet ./... -go test -bench=. -``` diff --git a/internal/golang-set/v2/bench_helper_test.go b/internal/golang-set/v2/bench_helper_test.go deleted file mode 100644 index 793785e..0000000 --- a/internal/golang-set/v2/bench_helper_test.go +++ /dev/null @@ -1,49 +0,0 @@ -package mapset - -import ( - "fmt" - "math/rand" -) - -func nrand(n int) []int { - is := make([]int, n) - for i := range is { - is[i] = rand.Int() - } - return is -} - -func buildRandomSet(n int, safe bool) Set[int] { - if safe { - return NewSet(nrand(n)...) - } else { - return NewThreadUnsafeSet(nrand(n)...) - } -} - -func buildCaseName(n int, safe bool) string { - var settype string - if safe { - settype = "Safe" - } else { - settype = "Unsafe" - } - - return fmt.Sprintf("%s(%d)", settype, n) -} - -type benchCase struct { - n int - safe bool -} - -func buildBenchCases(ns ...int) []benchCase { - cases := []benchCase{} - for _, n := range ns { - cases = append(cases, benchCase{n, true}) - } - for _, n := range ns { - cases = append(cases, benchCase{n, false}) - } - return cases -} diff --git a/internal/golang-set/v2/bench_test.go b/internal/golang-set/v2/bench_test.go deleted file mode 100644 index 318216c..0000000 --- a/internal/golang-set/v2/bench_test.go +++ /dev/null @@ -1,840 +0,0 @@ -/* -Open Source Initiative OSI - The MIT License (MIT):Licensing - -The MIT License (MIT) -Copyright (c) 2013 - 2022 Ralph Caraveo (deckarep@gmail.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -package mapset - -import ( - "testing" -) - -func BenchmarkNewSet(b *testing.B) { - nums := nrand(1000) - b.ResetTimer() - for i := 0; i < b.N; i++ { - _ = NewSet(nums...) - } -} - -func BenchmarkNewThreadUnsafeSet(b *testing.B) { - nums := nrand(1000) - b.ResetTimer() - for i := 0; i < b.N; i++ { - _ = NewThreadUnsafeSet(nums...) - } -} - -func benchAdd(b *testing.B, n int, newSet func(...int) Set[int]) { - nums := nrand(n) - b.ResetTimer() - for i := 0; i < b.N; i++ { - s := newSet() - for _, v := range nums { - s.Add(v) - } - } -} - -func BenchmarkAddSafe(b *testing.B) { - benchAdd(b, 1000, NewSet[int]) -} - -func BenchmarkAddUnsafe(b *testing.B) { - benchAdd(b, 1000, NewThreadUnsafeSet[int]) -} - -func benchAppend(b *testing.B, n int, newSet func(...int) Set[int]) { - nums := nrand(n) - b.ResetTimer() - for i := 0; i < b.N; i++ { - s := newSet() - s.Append(nums...) - } -} - -func BenchmarkAppendSafe(b *testing.B) { - benchAppend(b, 1000, NewSet[int]) -} - -func BenchmarkAppendUnsafe(b *testing.B) { - benchAppend(b, 1000, NewThreadUnsafeSet[int]) -} - -func benchAppendFrom(b *testing.B, n int, s, t Set[int]) { - s.Append(nrand(n)...) - t.Append(nrand(n)...) - - b.ReportAllocs() - for i := 0; i < b.N; i++ { - _ = s.AppendFrom(t) - } -} - -func BenchmarkAppendFromSafe(b *testing.B) { - benchAppendFrom(b, 1000, NewSet[int](), NewSet[int]()) -} - -func BenchmarkAppendFromUnsafe(b *testing.B) { - benchAppendFrom(b, 1000, NewThreadUnsafeSet[int](), NewThreadUnsafeSet[int]()) -} - -func benchRemove(b *testing.B, s Set[int]) { - nums := nrand(b.N) - for _, v := range nums { - s.Add(v) - } - - b.ResetTimer() - for _, v := range nums { - s.Remove(v) - } -} - -func BenchmarkRemoveSafe(b *testing.B) { - benchRemove(b, NewSet[int]()) -} - -func BenchmarkRemoveUnsafe(b *testing.B) { - benchRemove(b, NewThreadUnsafeSet[int]()) -} - -func benchCardinality(b *testing.B, s Set[int]) { - for i := 0; i < b.N; i++ { - s.Cardinality() - } -} - -func BenchmarkCardinalitySafe(b *testing.B) { - benchCardinality(b, NewSet[int]()) -} - -func BenchmarkCardinalityUnsafe(b *testing.B) { - benchCardinality(b, NewThreadUnsafeSet[int]()) -} - -func benchClear(b *testing.B, s Set[int]) { - b.ResetTimer() - for i := 0; i < b.N; i++ { - s.Clear() - } -} - -func BenchmarkClearSafe(b *testing.B) { - benchClear(b, NewSet[int]()) -} - -func BenchmarkClearUnsafe(b *testing.B) { - benchClear(b, NewThreadUnsafeSet[int]()) -} - -func benchClone(b *testing.B, n int, s Set[int]) { - nums := nrand(n) - for _, v := range nums { - s.Add(v) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - s.Clone() - } -} - -func BenchmarkClone1Safe(b *testing.B) { - benchClone(b, 1, NewSet[int]()) -} - -func BenchmarkClone1Unsafe(b *testing.B) { - benchClone(b, 1, NewThreadUnsafeSet[int]()) -} - -func BenchmarkClone10Safe(b *testing.B) { - benchClone(b, 10, NewSet[int]()) -} - -func BenchmarkClone10Unsafe(b *testing.B) { - benchClone(b, 10, NewThreadUnsafeSet[int]()) -} - -func BenchmarkClone100Safe(b *testing.B) { - benchClone(b, 100, NewSet[int]()) -} - -func BenchmarkClone100Unsafe(b *testing.B) { - benchClone(b, 100, NewThreadUnsafeSet[int]()) -} - -func benchContains(b *testing.B, n int, s Set[int]) { - nums := nrand(n) - for _, v := range nums { - s.Add(v) - } - - nums[n-1] = -1 // Definitely not in s - - b.ResetTimer() - for i := 0; i < b.N; i++ { - s.Contains(nums...) - } -} - -func BenchmarkContains1Safe(b *testing.B) { - benchContains(b, 1, NewSet[int]()) -} - -func BenchmarkContains1Unsafe(b *testing.B) { - benchContains(b, 1, NewThreadUnsafeSet[int]()) -} - -func BenchmarkContains10Safe(b *testing.B) { - benchContains(b, 10, NewSet[int]()) -} - -func BenchmarkContains10Unsafe(b *testing.B) { - benchContains(b, 10, NewThreadUnsafeSet[int]()) -} - -func BenchmarkContains100Safe(b *testing.B) { - benchContains(b, 100, NewSet[int]()) -} - -func BenchmarkContains100Unsafe(b *testing.B) { - benchContains(b, 100, NewThreadUnsafeSet[int]()) -} - -func benchContainsOne(b *testing.B, n int, s Set[int]) { - nums := nrand(n) - for _, v := range nums { - s.Add(v) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - s.ContainsOne(-1) - } -} - -func BenchmarkContainsOne1Safe(b *testing.B) { - benchContainsOne(b, 1, NewSet[int]()) -} - -func BenchmarkContainsOne1Unsafe(b *testing.B) { - benchContainsOne(b, 1, NewThreadUnsafeSet[int]()) -} - -func BenchmarkContainsOne10Safe(b *testing.B) { - benchContainsOne(b, 10, NewSet[int]()) -} - -func BenchmarkContainsOne10Unsafe(b *testing.B) { - benchContainsOne(b, 10, NewThreadUnsafeSet[int]()) -} - -func BenchmarkContainsOne100Safe(b *testing.B) { - benchContainsOne(b, 100, NewSet[int]()) -} - -func BenchmarkContainsOne100Unsafe(b *testing.B) { - benchContainsOne(b, 100, NewThreadUnsafeSet[int]()) -} - -// In this scenario, Contains argument escapes to the heap, while ContainsOne does not. -func benchContainsComparison(b *testing.B, n int, s Set[int]) { - nums := nrand(n) - for _, v := range nums { - s.Add(v) - } - - b.Run("Contains", func(b *testing.B) { - b.ReportAllocs() - for i := 0; i < b.N; i++ { - for _, v := range nums { - s.Contains(v) // 1 allocation, v is moved to the heap - } - } - }) - b.Run("Contains slice", func(b *testing.B) { - b.ReportAllocs() - for i := 0; i < b.N; i++ { - for i := range nums { - s.Contains(nums[i : i+1]...) // no allocations, using heap-allocated slice - } - } - }) - b.Run("ContainsOne", func(b *testing.B) { - b.ReportAllocs() - for i := 0; i < b.N; i++ { - for _, v := range nums { - s.ContainsOne(v) // no allocations, using stack-allocated v - } - } - }) -} - -func BenchmarkContainsComparison1Unsafe(b *testing.B) { - benchContainsComparison(b, 1, NewThreadUnsafeSet[int]()) -} - -func BenchmarkContainsComparison1Safe(b *testing.B) { - benchContainsComparison(b, 1, NewSet[int]()) -} - -func BenchmarkContainsComparison10Unsafe(b *testing.B) { - benchContainsComparison(b, 10, NewThreadUnsafeSet[int]()) -} - -func BenchmarkContainsComparison10Safe(b *testing.B) { - benchContainsComparison(b, 10, NewSet[int]()) -} - -func BenchmarkContainsComparison100Unsafe(b *testing.B) { - benchContainsComparison(b, 100, NewThreadUnsafeSet[int]()) -} - -func BenchmarkContainsComparison100Safe(b *testing.B) { - benchContainsComparison(b, 100, NewSet[int]()) -} - -func benchEqual(b *testing.B, n int, s, t Set[int]) { - nums := nrand(n) - for _, v := range nums { - s.Add(v) - t.Add(v) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - s.Equal(t) - } -} - -func BenchmarkEqual1Safe(b *testing.B) { - benchEqual(b, 1, NewSet[int](), NewSet[int]()) -} - -func BenchmarkEqual1Unsafe(b *testing.B) { - benchEqual(b, 1, NewThreadUnsafeSet[int](), NewThreadUnsafeSet[int]()) -} - -func BenchmarkEqual10Safe(b *testing.B) { - benchEqual(b, 10, NewSet[int](), NewSet[int]()) -} - -func BenchmarkEqual10Unsafe(b *testing.B) { - benchEqual(b, 10, NewThreadUnsafeSet[int](), NewThreadUnsafeSet[int]()) -} - -func BenchmarkEqual100Safe(b *testing.B) { - benchEqual(b, 100, NewSet[int](), NewSet[int]()) -} - -func BenchmarkEqual100Unsafe(b *testing.B) { - benchEqual(b, 100, NewThreadUnsafeSet[int](), NewThreadUnsafeSet[int]()) -} - -func benchDifference(b *testing.B, n int, s, t Set[int]) { - nums := nrand(n) - for _, v := range nums { - s.Add(v) - } - for _, v := range nums[:n/2] { - t.Add(v) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - s.Difference(t) - } -} - -func benchIsSubset(b *testing.B, n int, s, t Set[int]) { - nums := nrand(n) - for _, v := range nums { - s.Add(v) - t.Add(v) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - s.IsSubset(t) - } -} - -func BenchmarkIsSubset1Safe(b *testing.B) { - benchIsSubset(b, 1, NewSet[int](), NewSet[int]()) -} - -func BenchmarkIsSubset1Unsafe(b *testing.B) { - benchIsSubset(b, 1, NewThreadUnsafeSet[int](), NewThreadUnsafeSet[int]()) -} - -func BenchmarkIsSubset10Safe(b *testing.B) { - benchIsSubset(b, 10, NewSet[int](), NewSet[int]()) -} - -func BenchmarkIsSubset10Unsafe(b *testing.B) { - benchIsSubset(b, 10, NewThreadUnsafeSet[int](), NewThreadUnsafeSet[int]()) -} - -func BenchmarkIsSubset100Safe(b *testing.B) { - benchIsSubset(b, 100, NewSet[int](), NewSet[int]()) -} - -func BenchmarkIsSubset100Unsafe(b *testing.B) { - benchIsSubset(b, 100, NewThreadUnsafeSet[int](), NewThreadUnsafeSet[int]()) -} - -func benchIsSuperset(b *testing.B, n int, s, t Set[int]) { - nums := nrand(n) - for _, v := range nums { - s.Add(v) - t.Add(v) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - s.IsSuperset(t) - } -} - -func BenchmarkIsSuperset1Safe(b *testing.B) { - benchIsSuperset(b, 1, NewSet[int](), NewSet[int]()) -} - -func BenchmarkIsSuperset1Unsafe(b *testing.B) { - benchIsSuperset(b, 1, NewThreadUnsafeSet[int](), NewThreadUnsafeSet[int]()) -} - -func BenchmarkIsSuperset10Safe(b *testing.B) { - benchIsSuperset(b, 10, NewSet[int](), NewSet[int]()) -} - -func BenchmarkIsSuperset10Unsafe(b *testing.B) { - benchIsSuperset(b, 10, NewThreadUnsafeSet[int](), NewThreadUnsafeSet[int]()) -} - -func BenchmarkIsSuperset100Safe(b *testing.B) { - benchIsSuperset(b, 100, NewSet[int](), NewSet[int]()) -} - -func BenchmarkIsSuperset100Unsafe(b *testing.B) { - benchIsSuperset(b, 100, NewThreadUnsafeSet[int](), NewThreadUnsafeSet[int]()) -} - -func benchIsProperSubset(b *testing.B, n int, s, t Set[int]) { - nums := nrand(n) - for _, v := range nums { - s.Add(v) - t.Add(v) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - s.IsProperSubset(t) - } -} - -func BenchmarkIsProperSubset1Safe(b *testing.B) { - benchIsProperSubset(b, 1, NewSet[int](), NewSet[int]()) -} - -func BenchmarkIsProperSubset1Unsafe(b *testing.B) { - benchIsProperSubset(b, 1, NewThreadUnsafeSet[int](), NewThreadUnsafeSet[int]()) -} - -func BenchmarkIsProperSubset10Safe(b *testing.B) { - benchIsProperSubset(b, 10, NewSet[int](), NewSet[int]()) -} - -func BenchmarkIsProperSubset10Unsafe(b *testing.B) { - benchIsProperSubset(b, 10, NewThreadUnsafeSet[int](), NewThreadUnsafeSet[int]()) -} - -func BenchmarkIsProperSubset100Safe(b *testing.B) { - benchIsProperSubset(b, 100, NewSet[int](), NewSet[int]()) -} - -func BenchmarkIsProperSubset100Unsafe(b *testing.B) { - benchIsProperSubset(b, 100, NewThreadUnsafeSet[int](), NewThreadUnsafeSet[int]()) -} - -func benchIsProperSuperset(b *testing.B, n int, s, t Set[int]) { - nums := nrand(n) - for _, v := range nums { - s.Add(v) - t.Add(v) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - s.IsProperSuperset(t) - } -} - -func BenchmarkIsProperSuperset1Safe(b *testing.B) { - benchIsProperSuperset(b, 1, NewSet[int](), NewSet[int]()) -} - -func BenchmarkIsProperSuperset1Unsafe(b *testing.B) { - benchIsProperSuperset(b, 1, NewThreadUnsafeSet[int](), NewThreadUnsafeSet[int]()) -} - -func BenchmarkIsProperSuperset10Safe(b *testing.B) { - benchIsProperSuperset(b, 10, NewSet[int](), NewSet[int]()) -} - -func BenchmarkIsProperSuperset10Unsafe(b *testing.B) { - benchIsProperSuperset(b, 10, NewThreadUnsafeSet[int](), NewThreadUnsafeSet[int]()) -} - -func BenchmarkIsProperSuperset100Safe(b *testing.B) { - benchIsProperSuperset(b, 100, NewSet[int](), NewSet[int]()) -} - -func BenchmarkIsProperSuperset100Unsafe(b *testing.B) { - benchIsProperSuperset(b, 100, NewThreadUnsafeSet[int](), NewThreadUnsafeSet[int]()) -} - -func BenchmarkDifference1Safe(b *testing.B) { - benchDifference(b, 1, NewSet[int](), NewSet[int]()) -} - -func BenchmarkDifference1Unsafe(b *testing.B) { - benchDifference(b, 1, NewThreadUnsafeSet[int](), NewThreadUnsafeSet[int]()) -} - -func BenchmarkDifference10Safe(b *testing.B) { - benchDifference(b, 10, NewSet[int](), NewSet[int]()) -} - -func BenchmarkDifference10Unsafe(b *testing.B) { - benchDifference(b, 10, NewThreadUnsafeSet[int](), NewThreadUnsafeSet[int]()) -} - -func BenchmarkDifference100Safe(b *testing.B) { - benchDifference(b, 100, NewSet[int](), NewSet[int]()) -} - -func BenchmarkDifference100Unsafe(b *testing.B) { - benchDifference(b, 100, NewThreadUnsafeSet[int](), NewThreadUnsafeSet[int]()) -} - -func benchIntersect(b *testing.B, n int, s, t Set[int]) { - nums := nrand(int(float64(n) * float64(1.5))) - for _, v := range nums[:n] { - s.Add(v) - } - for _, v := range nums[n/2:] { - t.Add(v) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - s.Intersect(t) - } -} - -func BenchmarkIntersect1Safe(b *testing.B) { - benchIntersect(b, 1, NewSet[int](), NewSet[int]()) -} - -func BenchmarkIntersect1Unsafe(b *testing.B) { - benchIntersect(b, 1, NewThreadUnsafeSet[int](), NewThreadUnsafeSet[int]()) -} - -func BenchmarkIntersect10Safe(b *testing.B) { - benchIntersect(b, 10, NewSet[int](), NewSet[int]()) -} - -func BenchmarkIntersect10Unsafe(b *testing.B) { - benchIntersect(b, 10, NewThreadUnsafeSet[int](), NewThreadUnsafeSet[int]()) -} - -func BenchmarkIntersect100Safe(b *testing.B) { - benchIntersect(b, 100, NewSet[int](), NewSet[int]()) -} - -func BenchmarkIntersect100Unsafe(b *testing.B) { - benchIntersect(b, 100, NewThreadUnsafeSet[int](), NewThreadUnsafeSet[int]()) -} - -func benchSymmetricDifference(b *testing.B, n int, s, t Set[int]) { - nums := nrand(int(float64(n) * float64(1.5))) - for _, v := range nums[:n] { - s.Add(v) - } - for _, v := range nums[n/2:] { - t.Add(v) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - s.SymmetricDifference(t) - } -} - -func BenchmarkSymmetricDifference1Safe(b *testing.B) { - benchSymmetricDifference(b, 1, NewSet[int](), NewSet[int]()) -} - -func BenchmarkSymmetricDifference1Unsafe(b *testing.B) { - benchSymmetricDifference(b, 1, NewThreadUnsafeSet[int](), NewThreadUnsafeSet[int]()) -} - -func BenchmarkSymmetricDifference10Safe(b *testing.B) { - benchSymmetricDifference(b, 10, NewSet[int](), NewSet[int]()) -} - -func BenchmarkSymmetricDifference10Unsafe(b *testing.B) { - benchSymmetricDifference(b, 10, NewThreadUnsafeSet[int](), NewThreadUnsafeSet[int]()) -} - -func BenchmarkSymmetricDifference100Safe(b *testing.B) { - benchSymmetricDifference(b, 100, NewSet[int](), NewSet[int]()) -} - -func BenchmarkSymmetricDifference100Unsafe(b *testing.B) { - benchSymmetricDifference(b, 100, NewThreadUnsafeSet[int](), NewThreadUnsafeSet[int]()) -} - -func benchUnion(b *testing.B, n int, s, t Set[int]) { - nums := nrand(n) - for _, v := range nums[:n/2] { - s.Add(v) - } - for _, v := range nums[n/2:] { - t.Add(v) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - s.Union(t) - } -} - -func BenchmarkUnion1Safe(b *testing.B) { - benchUnion(b, 1, NewSet[int](), NewSet[int]()) -} - -func BenchmarkUnion1Unsafe(b *testing.B) { - benchUnion(b, 1, NewThreadUnsafeSet[int](), NewThreadUnsafeSet[int]()) -} - -func BenchmarkUnion10Safe(b *testing.B) { - benchUnion(b, 10, NewSet[int](), NewSet[int]()) -} - -func BenchmarkUnion10Unsafe(b *testing.B) { - benchUnion(b, 10, NewThreadUnsafeSet[int](), NewThreadUnsafeSet[int]()) -} - -func BenchmarkUnion100Safe(b *testing.B) { - benchUnion(b, 100, NewSet[int](), NewSet[int]()) -} - -func BenchmarkUnion100Unsafe(b *testing.B) { - benchUnion(b, 100, NewThreadUnsafeSet[int](), NewThreadUnsafeSet[int]()) -} - -func benchEach(b *testing.B, n int, s Set[int]) { - nums := nrand(n) - for _, v := range nums { - s.Add(v) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - s.Each(func(elem int) bool { - return false - }) - } -} - -func BenchmarkEach1Safe(b *testing.B) { - benchEach(b, 1, NewSet[int]()) -} - -func BenchmarkEach1Unsafe(b *testing.B) { - benchEach(b, 1, NewThreadUnsafeSet[int]()) -} - -func BenchmarkEach10Safe(b *testing.B) { - benchEach(b, 10, NewSet[int]()) -} - -func BenchmarkEach10Unsafe(b *testing.B) { - benchEach(b, 10, NewThreadUnsafeSet[int]()) -} - -func BenchmarkEach100Safe(b *testing.B) { - benchEach(b, 100, NewSet[int]()) -} - -func BenchmarkEach100Unsafe(b *testing.B) { - benchEach(b, 100, NewThreadUnsafeSet[int]()) -} - -func benchIter(b *testing.B, n int, s Set[int]) { - nums := nrand(n) - for _, v := range nums { - s.Add(v) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - c := s.Iter() - for range c { - - } - } -} - -func BenchmarkIter1Safe(b *testing.B) { - benchIter(b, 1, NewSet[int]()) -} - -func BenchmarkIter1Unsafe(b *testing.B) { - benchIter(b, 1, NewThreadUnsafeSet[int]()) -} - -func BenchmarkIter10Safe(b *testing.B) { - benchIter(b, 10, NewSet[int]()) -} - -func BenchmarkIter10Unsafe(b *testing.B) { - benchIter(b, 10, NewThreadUnsafeSet[int]()) -} - -func BenchmarkIter100Safe(b *testing.B) { - benchIter(b, 100, NewSet[int]()) -} - -func BenchmarkIter100Unsafe(b *testing.B) { - benchIter(b, 100, NewThreadUnsafeSet[int]()) -} - -func benchIterator(b *testing.B, n int, s Set[int]) { - nums := nrand(n) - for _, v := range nums { - s.Add(v) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - c := s.Iterator().C - for range c { - - } - } -} - -func BenchmarkIterator1Safe(b *testing.B) { - benchIterator(b, 1, NewSet[int]()) -} - -func BenchmarkIterator1Unsafe(b *testing.B) { - benchIterator(b, 1, NewThreadUnsafeSet[int]()) -} - -func BenchmarkIterator10Safe(b *testing.B) { - benchIterator(b, 10, NewSet[int]()) -} - -func BenchmarkIterator10Unsafe(b *testing.B) { - benchIterator(b, 10, NewThreadUnsafeSet[int]()) -} - -func BenchmarkIterator100Safe(b *testing.B) { - benchIterator(b, 100, NewSet[int]()) -} - -func BenchmarkIterator100Unsafe(b *testing.B) { - benchIterator(b, 100, NewThreadUnsafeSet[int]()) -} - -func benchString(b *testing.B, n int, s Set[int]) { - nums := nrand(n) - for _, v := range nums { - s.Add(v) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - _ = s.String() - } -} - -func BenchmarkString1Safe(b *testing.B) { - benchString(b, 1, NewSet[int]()) -} - -func BenchmarkString1Unsafe(b *testing.B) { - benchString(b, 1, NewThreadUnsafeSet[int]()) -} - -func BenchmarkString10Safe(b *testing.B) { - benchString(b, 10, NewSet[int]()) -} - -func BenchmarkString10Unsafe(b *testing.B) { - benchString(b, 10, NewThreadUnsafeSet[int]()) -} - -func BenchmarkString100Safe(b *testing.B) { - benchString(b, 100, NewSet[int]()) -} - -func BenchmarkString100Unsafe(b *testing.B) { - benchString(b, 100, NewThreadUnsafeSet[int]()) -} - -func benchToSlice(b *testing.B, s Set[int]) { - nums := nrand(b.N) - for _, v := range nums { - s.Add(v) - } - - b.ResetTimer() - for i := 0; i < b.N; i++ { - s.ToSlice() - } -} - -func BenchmarkToSliceSafe(b *testing.B) { - benchToSlice(b, NewSet[int]()) -} - -func BenchmarkToSliceUnsafe(b *testing.B) { - benchToSlice(b, NewThreadUnsafeSet[int]()) -} - -func BenchmarkMarshalJSON(b *testing.B) { - for _, c := range buildBenchCases(1, 10, 100) { - s := buildRandomSet(c.n, c.safe) - b.Run(buildCaseName(c.n, c.safe), func(b *testing.B) { - for i := 0; i < b.N; i++ { - _, _ = s.MarshalJSON() - } - }) - } -} diff --git a/internal/golang-set/v2/helper.go b/internal/golang-set/v2/helper.go deleted file mode 100644 index fcaf0d6..0000000 --- a/internal/golang-set/v2/helper.go +++ /dev/null @@ -1,11 +0,0 @@ -//go:build !go1.21 - -package mapset - -func mapclone[T comparable](m map[T]struct{}) map[T]struct{} { - c := make(map[T]struct{}, len(m)) - for k := range m { - c[k] = struct{}{} - } - return c -} diff --git a/internal/golang-set/v2/helper_1_21.go b/internal/golang-set/v2/helper_1_21.go deleted file mode 100644 index 0b32a46..0000000 --- a/internal/golang-set/v2/helper_1_21.go +++ /dev/null @@ -1,9 +0,0 @@ -//go:build go1.21 - -package mapset - -import "maps" - -func mapclone[T comparable](m map[T]struct{}) map[T]struct{} { - return maps.Clone(m) -} diff --git a/internal/golang-set/v2/iterator.go b/internal/golang-set/v2/iterator.go deleted file mode 100644 index fc14e70..0000000 --- a/internal/golang-set/v2/iterator.go +++ /dev/null @@ -1,58 +0,0 @@ -/* -Open Source Initiative OSI - The MIT License (MIT):Licensing - -The MIT License (MIT) -Copyright (c) 2013 - 2022 Ralph Caraveo (deckarep@gmail.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -package mapset - -// Iterator defines an iterator over a Set, its C channel can be used to range over the Set's -// elements. -type Iterator[T comparable] struct { - C <-chan T - stop chan struct{} -} - -// Stop stops the Iterator, no further elements will be received on C, C will be closed. -func (i *Iterator[T]) Stop() { - // Allows for Stop() to be called multiple times - // (close() panics when called on already closed channel) - defer func() { - recover() - }() - - close(i.stop) - - // Exhaust any remaining elements. - for range i.C { - } -} - -// newIterator returns a new Iterator instance together with its item and stop channels. -func newIterator[T comparable]() (*Iterator[T], chan<- T, <-chan struct{}) { - itemChan := make(chan T) - stopChan := make(chan struct{}) - return &Iterator[T]{ - C: itemChan, - stop: stopChan, - }, itemChan, stopChan -} diff --git a/internal/golang-set/v2/iterator_example_test.go b/internal/golang-set/v2/iterator_example_test.go deleted file mode 100644 index a974935..0000000 --- a/internal/golang-set/v2/iterator_example_test.go +++ /dev/null @@ -1,60 +0,0 @@ -/* -Open Source Initiative OSI - The MIT License (MIT):Licensing - -The MIT License (MIT) -Copyright (c) 2013 - 2022 Ralph Caraveo (deckarep@gmail.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -package mapset - -import ( - "testing" -) - -type yourType struct { - name string -} - -func Test_ExampleIterator(t *testing.T) { - - s := NewSet( - []*yourType{ - {name: "Alise"}, - {name: "Bob"}, - {name: "John"}, - {name: "Nick"}, - }..., - ) - - var found *yourType - it := s.Iterator() - - for elem := range it.C { - if elem.name == "John" { - found = elem - it.Stop() - } - } - - if found == nil || found.name != "John" { - t.Fatalf("expected iterator to have found `John` record but got nil or something else") - } -} diff --git a/internal/golang-set/v2/set.go b/internal/golang-set/v2/set.go deleted file mode 100644 index 61f7539..0000000 --- a/internal/golang-set/v2/set.go +++ /dev/null @@ -1,286 +0,0 @@ -/* -Open Source Initiative OSI - The MIT License (MIT):Licensing - -The MIT License (MIT) -Copyright (c) 2013 - 2022 Ralph Caraveo (deckarep@gmail.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -// Package mapset implements a simple and set collection. -// Items stored within it are unordered and unique. It supports -// typical set operations: membership testing, intersection, union, -// difference, symmetric difference and cloning. -// -// Package mapset provides two implementations of the Set -// interface. The default implementation is safe for concurrent -// access, but a non-thread-safe implementation is also provided for -// programs that can benefit from the slight speed improvement and -// that can enforce mutual exclusion through other means. -package mapset - -// import "go.mongodb.org/mongo-driver/bson/bsontype" - -// Set is the primary interface provided by the mapset package. It -// represents an unordered set of data and a large number of -// operations that can be applied to that set. -type Set[T comparable] interface { - // Add adds an element to the set. Returns whether - // the item was added. - Add(val T) bool - - // Append multiple elements to the set. Returns - // the number of elements added. - Append(val ...T) int - - // AppendFrom elements from another set into this set. (shorthand of s.Append(other.ToSlice()...)) - // Returns the number of elements added. - AppendFrom(other Set[T]) int - - // Cardinality returns the number of elements in the set. - Cardinality() int - - // Clear removes all elements from the set, leaving - // the empty set. - Clear() - - // Clone returns a clone of the set using the same - // implementation, duplicating all keys. - Clone() Set[T] - - // Contains returns whether the given items - // are all in the set. - Contains(val ...T) bool - - // ContainsOne returns whether the given item - // is in the set. - // - // Contains may cause the argument to escape to the heap. - // See: https://github.com/deckarep/golang-set/issues/118 - ContainsOne(val T) bool - - // ContainsAny returns whether at least one of the - // given items are in the set. - ContainsAny(val ...T) bool - - // ContainsAnyElement returns whether at least one of the - // given element are in the set. - ContainsAnyElement(other Set[T]) bool - - // Difference returns the difference between this set - // and other. The returned set will contain - // all elements of this set that are not also - // elements of other. - // - // Note that the argument to Difference - // must be of the same type as the receiver - // of the method. Otherwise, Difference will - // panic. - Difference(other Set[T]) Set[T] - - // Equal determines if two sets are equal to each - // other. If they have the same cardinality - // and contain the same elements, they are - // considered equal. The order in which - // the elements were added is irrelevant. - // - // Note that the argument to Equal must be - // of the same type as the receiver of the - // method. Otherwise, Equal will panic. - Equal(other Set[T]) bool - - // Intersect returns a new set containing only the elements - // that exist only in both sets. - // - // Note that the argument to Intersect - // must be of the same type as the receiver - // of the method. Otherwise, Intersect will - // panic. - Intersect(other Set[T]) Set[T] - - // IsEmpty determines if there are elements in the set. - IsEmpty() bool - - // IsProperSubset determines if every element in this set is in - // the other set but the two sets are not equal. - // - // Note that the argument to IsProperSubset - // must be of the same type as the receiver - // of the method. Otherwise, IsProperSubset - // will panic. - IsProperSubset(other Set[T]) bool - - // IsProperSuperset determines if every element in the other set - // is in this set but the two sets are not - // equal. - // - // Note that the argument to IsSuperset - // must be of the same type as the receiver - // of the method. Otherwise, IsSuperset will - // panic. - IsProperSuperset(other Set[T]) bool - - // IsSubset determines if every element in this set is in - // the other set. - // - // Note that the argument to IsSubset - // must be of the same type as the receiver - // of the method. Otherwise, IsSubset will - // panic. - IsSubset(other Set[T]) bool - - // IsSuperset determines if every element in the other set - // is in this set. - // - // Note that the argument to IsSuperset - // must be of the same type as the receiver - // of the method. Otherwise, IsSuperset will - // panic. - IsSuperset(other Set[T]) bool - - // Each iterates over elements and executes the passed func against each element. - // If passed func returns true, stop iteration at the time. - Each(func(T) bool) - - // Filter iterates over elements and executes the passed func against each element. - // If passed func returns true, the element will be added to the returned set. - Filter(func(T) bool) Set[T] - - // Iter returns a channel of elements that you can - // range over. - Iter() <-chan T - - // Iterator returns an Iterator object that you can - // use to range over the set. - Iterator() *Iterator[T] - - // Remove removes a single element from the set. - Remove(i T) - - // RemoveAll removes multiple elements from the set. - RemoveAll(i ...T) - - // String provides a convenient string representation - // of the current state of the set. - String() string - - // SymmetricDifference returns a new set with all elements which are - // in either this set or the other set but not in both. - // - // Note that the argument to SymmetricDifference - // must be of the same type as the receiver - // of the method. Otherwise, SymmetricDifference - // will panic. - SymmetricDifference(other Set[T]) Set[T] - - // Union returns a new set with all elements in both sets. - // - // Note that the argument to Union must be of the - // same type as the receiver of the method. - // Otherwise, Union will panic. - Union(other Set[T]) Set[T] - - // Pop removes and returns an arbitrary item from the set. - Pop() (T, bool) - - // PopN removes and returns up to n arbitrary items from the set. - // It returns a slice of the removed items and the actual number of items removed. - // If the set is empty or n is less than or equal to 0s, it returns an empty slice and 0. - // If n is greater than the set's size, all items are - PopN(n int) ([]T, int) - - // ToSlice returns the members of the set as a slice. - ToSlice() []T - - // MarshalJSON will marshal the set into a JSON-based representation. - MarshalJSON() ([]byte, error) - - // UnmarshalJSON will unmarshal a JSON-based byte slice into a full Set datastructure. - // For this to work, set subtypes must implement the Marshal/Unmarshal interface. - UnmarshalJSON(b []byte) error - - // MarshalBSONValue will marshal the set into a BSON-based representation. - // MarshalBSONValue() (bsontype.Type, []byte, error) - - // UnmarshalBSONValue will unmarshal a BSON-based byte slice into a full Set datastructure. - // For this to work, set subtypes must implement the Marshal/Unmarshal interface. - // UnmarshalBSONValue(bt bsontype.Type, b []byte) error -} - -// NewSet creates and returns a new set with the given elements. -// Operations on the resulting set are thread-safe. -func NewSet[T comparable](vs ...T) Set[T] { - s := newThreadSafeSetWithSize[T](len(vs)) - s.uss.append(vs...) - return s -} - -// NewSetWithSize creates and returns a reference to an empty set with a specified -// capacity. Operations on the resulting set are thread-safe. -func NewSetWithSize[T comparable](cardinality int) Set[T] { - return newThreadSafeSetWithSize[T](cardinality) -} - -// NewThreadUnsafeSet creates and returns a new set with the given elements. -// Operations on the resulting set are not thread-safe. -func NewThreadUnsafeSet[T comparable](vs ...T) Set[T] { - s := newThreadUnsafeSetWithSize[T](len(vs)) - s.append(vs...) - return s -} - -// NewThreadUnsafeSetWithSize creates and returns a reference to an empty set with -// a specified capacity. Operations on the resulting set are not thread-safe. -func NewThreadUnsafeSetWithSize[T comparable](cardinality int) Set[T] { - return newThreadUnsafeSetWithSize[T](cardinality) -} - -// NewSetFromMapKeys creates and returns a new set with the given keys of the map. -// Operations on the resulting set are thread-safe. -func NewSetFromMapKeys[T comparable, V any](val map[T]V) Set[T] { - s := newThreadSafeSetWithSize[T](len(val)) - - for k := range val { - s.uss.add(k) - } - - return s -} - -// NewThreadUnsafeSetFromMapKeys creates and returns a new set with the given keys of the map. -// Operations on the resulting set are not thread-safe. -func NewThreadUnsafeSetFromMapKeys[T comparable, V any](val map[T]V) Set[T] { - s := newThreadUnsafeSetWithSize[T](len(val)) - - for k := range val { - s.add(k) - } - - return s -} - -// Elements returns an iterator that yields the elements of the set. Starting -// with Go 1.23, users can use a for loop to iterate over it. -func Elements[T comparable](s Set[T]) func(func(element T) bool) { - return func(yield func(element T) bool) { - s.Each(func(t T) bool { - return !yield(t) - }) - } -} diff --git a/internal/golang-set/v2/set123_test.go b/internal/golang-set/v2/set123_test.go deleted file mode 100644 index df36506..0000000 --- a/internal/golang-set/v2/set123_test.go +++ /dev/null @@ -1,38 +0,0 @@ -//go:build go1.23 -// +build go1.23 - -package mapset - -import ( - "testing" -) - -func Test_Elements123(t *testing.T) { - a := NewSet[string]() - - a.Add("Z") - a.Add("Y") - a.Add("X") - a.Add("W") - - b := NewSet[string]() - for elem := range Elements(a) { - b.Add(elem) - } - - if !a.Equal(b) { - t.Error("The sets are not equal after iterating (Each) through the first set") - } - - var count int - for range Elements(a) { - if count == 2 { - break - } - count++ - } - - if count != 2 { - t.Error("Iteration should stop on the way") - } -} diff --git a/internal/golang-set/v2/set_test.go b/internal/golang-set/v2/set_test.go deleted file mode 100644 index 3d10ec3..0000000 --- a/internal/golang-set/v2/set_test.go +++ /dev/null @@ -1,1678 +0,0 @@ -/* -Open Source Initiative OSI - The MIT License (MIT):Licensing - -The MIT License (MIT) -Copyright (c) 2013 - 2022 Ralph Caraveo (deckarep@gmail.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -package mapset - -import ( - "testing" -) - -func makeSetInt(ints []int) Set[int] { - s := NewSet[int]() - for _, i := range ints { - s.Add(i) - } - return s -} - -func makeUnsafeSetInt(ints []int) Set[int] { - s := NewThreadUnsafeSet[int]() - for _, i := range ints { - s.Add(i) - } - return s -} - -func makeSetIntWithAppend(ints ...int) Set[int] { - s := NewSet[int]() - s.Append(ints...) - return s -} - -func makeUnsafeSetIntWithAppend(ints ...int) Set[int] { - s := NewThreadUnsafeSet[int]() - s.Append(ints...) - return s -} - -func assertEqual[T comparable](a, b Set[T], t *testing.T) { - if !a.Equal(b) { - t.Errorf("%v != %v\n", a, b) - } -} - -func Test_NewSet(t *testing.T) { - a := NewSet[int]() - if a.Cardinality() != 0 { - t.Error("NewSet should start out as an empty set") - } - - assertEqual(NewSet([]int{}...), NewSet[int](), t) - assertEqual(NewSet([]int{1}...), NewSet(1), t) - assertEqual(NewSet([]int{1, 2}...), NewSet(1, 2), t) - assertEqual(NewSet([]string{"a"}...), NewSet("a"), t) - assertEqual(NewSet([]string{"a", "b"}...), NewSet("a", "b"), t) -} - -func Test_NewUnsafeSet(t *testing.T) { - a := NewThreadUnsafeSet[int]() - - if a.Cardinality() != 0 { - t.Error("NewSet should start out as an empty set") - } -} - -func Test_AddSet(t *testing.T) { - a := makeSetInt([]int{1, 2, 3}) - - if a.Cardinality() != 3 { - t.Error("AddSet does not have a size of 3 even though 3 items were added to a new set") - } -} - -func Test_AddUnsafeSet(t *testing.T) { - a := makeUnsafeSetInt([]int{1, 2, 3}) - - if a.Cardinality() != 3 { - t.Error("AddSet does not have a size of 3 even though 3 items were added to a new set") - } -} - -func Test_AppendSet(t *testing.T) { - a := makeSetIntWithAppend(1, 2, 3) - - if a.Cardinality() != 3 { - t.Error("AppendSet does not have a size of 3 even though 3 items were added to a new set") - } -} - -func Test_AppendUnsafeSet(t *testing.T) { - a := makeUnsafeSetIntWithAppend(1, 2, 3) - - if a.Cardinality() != 3 { - t.Error("AppendSet does not have a size of 3 even though 3 items were added to a new set") - } -} - -func Test_AddSetNoDuplicate(t *testing.T) { - a := makeSetInt([]int{7, 5, 3, 7}) - - if a.Cardinality() != 3 { - t.Error("AddSetNoDuplicate set should have 3 elements since 7 is a duplicate") - } - - if !(a.Contains(7) && a.Contains(5) && a.Contains(3)) { - t.Error("AddSetNoDuplicate set should have a 7, 5, and 3 in it.") - } -} - -func Test_AddUnsafeSetNoDuplicate(t *testing.T) { - a := makeUnsafeSetInt([]int{7, 5, 3, 7}) - - if a.Cardinality() != 3 { - t.Error("AddSetNoDuplicate set should have 3 elements since 7 is a duplicate") - } - - if !(a.Contains(7) && a.Contains(5) && a.Contains(3)) { - t.Error("AddSetNoDuplicate set should have a 7, 5, and 3 in it.") - } -} - -func Test_AppendSetNoDuplicate(t *testing.T) { - a := makeSetIntWithAppend(7, 5, 3, 7) - - if a.Cardinality() != 3 { - t.Error("AppendSetNoDuplicate set should have 3 elements since 7 is a duplicate") - } - - if !(a.Contains(7) && a.Contains(5) && a.Contains(3)) { - t.Error("AppendSetNoDuplicate set should have a 7, 5, and 3 in it.") - } -} - -func Test_AppendUnsafeSetNoDuplicate(t *testing.T) { - a := makeUnsafeSetIntWithAppend(7, 5, 3, 7) - - if a.Cardinality() != 3 { - t.Error("AppendSetNoDuplicate set should have 3 elements since 7 is a duplicate") - } - - if !(a.Contains(7) && a.Contains(5) && a.Contains(3)) { - t.Error("AppendSetNoDuplicate set should have a 7, 5, and 3 in it.") - } -} - -func Test_AppendFrom(t *testing.T) { - a := NewSet("Z", "Y", "X", "W") - num := a.AppendFrom(NewSet("A", "B", "X", "W")) - - if !a.Equal(NewSet("Z", "Y", "X", "W", "A", "B")) { - t.Error("Added set is not correct") - } - if num != 2 { - t.Errorf("Number of added elements is not correct. num: %d", num) - } -} - -func Test_UnsafeAppendFrom(t *testing.T) { - a := NewThreadUnsafeSet("Z", "Y", "X", "W") - num := a.AppendFrom(NewThreadUnsafeSet("A", "B", "X", "W")) - - if !a.Equal(NewThreadUnsafeSet("Z", "Y", "X", "W", "A", "B")) { - t.Error("Added set is not correct") - } - if num != 2 { - t.Errorf("Number of added elements is not correct. num: %d", num) - } -} - -func Test_RemoveSet(t *testing.T) { - a := makeSetInt([]int{6, 3, 1}) - - a.Remove(3) - - if a.Cardinality() != 2 { - t.Error("RemoveSet should only have 2 items in the set") - } - - if !(a.Contains(6) && a.Contains(1)) { - t.Error("RemoveSet should have only items 6 and 1 in the set") - } - - a.Remove(6) - a.Remove(1) - - if a.Cardinality() != 0 { - t.Error("RemoveSet should be an empty set after removing 6 and 1") - } -} - -func Test_RemoveAllSet(t *testing.T) { - a := makeSetInt([]int{6, 3, 1, 8, 9}) - - a.RemoveAll(3, 1) - - if a.Cardinality() != 3 { - t.Error("RemoveAll should only have 2 items in the set") - } - - if !a.Contains(6, 8, 9) { - t.Error("RemoveAll should have only items (6,8,9) in the set") - } - - a.RemoveAll(6, 8, 9) - - if a.Cardinality() != 0 { - t.Error("RemoveSet should be an empty set after removing 6 and 1") - } -} - -func Test_RemoveUnsafeSet(t *testing.T) { - a := makeUnsafeSetInt([]int{6, 3, 1}) - - a.Remove(3) - - if a.Cardinality() != 2 { - t.Error("RemoveSet should only have 2 items in the set") - } - - if !(a.Contains(6) && a.Contains(1)) { - t.Error("RemoveSet should have only items 6 and 1 in the set") - } - - a.Remove(6) - a.Remove(1) - - if a.Cardinality() != 0 { - t.Error("RemoveSet should be an empty set after removing 6 and 1") - } -} - -func Test_RemoveAllUnsafeSet(t *testing.T) { - a := makeUnsafeSetInt([]int{6, 3, 1, 8, 9}) - - a.RemoveAll(3, 1) - - if a.Cardinality() != 3 { - t.Error("RemoveAll should only have 2 items in the set") - } - - if !a.Contains(6, 8, 9) { - t.Error("RemoveAll should have only items (6,8,9) in the set") - } - - a.RemoveAll(6, 8, 9) - - if a.Cardinality() != 0 { - t.Error("RemoveSet should be an empty set after removing 6 and 1") - } -} - -func Test_ContainsSet(t *testing.T) { - a := NewSet[int]() - - a.Add(71) - - if !a.Contains(71) { - t.Error("ContainsSet should contain 71") - } - - a.Remove(71) - - if a.Contains(71) { - t.Error("ContainsSet should not contain 71") - } - - a.Add(13) - a.Add(7) - a.Add(1) - - if !(a.Contains(13) && a.Contains(7) && a.Contains(1)) { - t.Error("ContainsSet should contain 13, 7, 1") - } -} - -func Test_ContainsUnsafeSet(t *testing.T) { - a := NewThreadUnsafeSet[int]() - - a.Add(71) - - if !a.Contains(71) { - t.Error("ContainsSet should contain 71") - } - - a.Remove(71) - - if a.Contains(71) { - t.Error("ContainsSet should not contain 71") - } - - a.Add(13) - a.Add(7) - a.Add(1) - - if !(a.Contains(13) && a.Contains(7) && a.Contains(1)) { - t.Error("ContainsSet should contain 13, 7, 1") - } -} - -func Test_ContainsMultipleSet(t *testing.T) { - a := makeSetInt([]int{8, 6, 7, 5, 3, 0, 9}) - - if !a.Contains(8, 6, 7, 5, 3, 0, 9) { - t.Error("ContainsAll should contain Jenny's phone number") - } - - if a.Contains(8, 6, 11, 5, 3, 0, 9) { - t.Error("ContainsAll should not have all of these numbers") - } -} - -func Test_ContainsMultipleUnsafeSet(t *testing.T) { - a := makeUnsafeSetInt([]int{8, 6, 7, 5, 3, 0, 9}) - - if !a.Contains(8, 6, 7, 5, 3, 0, 9) { - t.Error("ContainsAll should contain Jenny's phone number") - } - - if a.Contains(8, 6, 11, 5, 3, 0, 9) { - t.Error("ContainsAll should not have all of these numbers") - } -} - -func Test_ContainsOneSet(t *testing.T) { - a := NewSet[int]() - - a.Add(71) - - if !a.ContainsOne(71) { - t.Error("ContainsSet should contain 71") - } - - a.Remove(71) - - if a.ContainsOne(71) { - t.Error("ContainsSet should not contain 71") - } - - a.Add(13) - a.Add(7) - a.Add(1) - - if !(a.ContainsOne(13) && a.ContainsOne(7) && a.ContainsOne(1)) { - t.Error("ContainsSet should contain 13, 7, 1") - } -} - -func Test_ContainsOneUnsafeSet(t *testing.T) { - a := NewThreadUnsafeSet[int]() - - a.Add(71) - - if !a.ContainsOne(71) { - t.Error("ContainsSet should contain 71") - } - - a.Remove(71) - - if a.ContainsOne(71) { - t.Error("ContainsSet should not contain 71") - } - - a.Add(13) - a.Add(7) - a.Add(1) - - if !(a.ContainsOne(13) && a.ContainsOne(7) && a.ContainsOne(1)) { - t.Error("ContainsSet should contain 13, 7, 1") - } -} - -func Test_ContainsAnySet(t *testing.T) { - a := NewSet[int]() - - a.Add(71) - - if !a.ContainsAny(71) { - t.Error("ContainsSet should contain 71") - } - - if !a.ContainsAny(71, 10) { - t.Error("ContainsSet should contain 71 or 10") - } - - a.Remove(71) - - if a.ContainsAny(71) { - t.Error("ContainsSet should not contain 71") - } - - if a.ContainsAny(71, 10) { - t.Error("ContainsSet should not contain 71 or 10") - } - - a.Add(13) - a.Add(7) - a.Add(1) - - if !a.ContainsAny(13, 17, 10) { - t.Error("ContainsSet should contain 13, 17, or 10") - } -} - -func Test_ContainsAnyElement(t *testing.T) { - a := NewSet[int]() - a.Add(1) - a.Add(3) - a.Add(5) - - b := NewSet[int]() - a.Add(2) - a.Add(4) - a.Add(6) - - if ret := a.ContainsAnyElement(b); ret { - t.Errorf("set a not contain any element in set b") - } - - a.Add(10) - - if ret := a.ContainsAnyElement(b); ret { - t.Errorf("set a not contain any element in set b") - } - - b.Add(10) - - if ret := a.ContainsAnyElement(b); !ret { - t.Errorf("set a contain 10") - } -} - -func Test_ClearSet(t *testing.T) { - a := makeSetInt([]int{2, 5, 9, 10}) - - a.Clear() - - if a.Cardinality() != 0 { - t.Error("ClearSet should be an empty set") - } -} - -func Test_ClearUnsafeSet(t *testing.T) { - a := makeUnsafeSetInt([]int{2, 5, 9, 10}) - - a.Clear() - - if a.Cardinality() != 0 { - t.Error("ClearSet should be an empty set") - } -} - -func Test_CardinalitySet(t *testing.T) { - a := NewSet[int]() - - if a.Cardinality() != 0 { - t.Error("set should be an empty set") - } - - a.Add(1) - - if a.Cardinality() != 1 { - t.Error("set should have a size of 1") - } - - a.Remove(1) - - if a.Cardinality() != 0 { - t.Error("set should be an empty set") - } - - a.Add(9) - - if a.Cardinality() != 1 { - t.Error("set should have a size of 1") - } - - a.Clear() - - if a.Cardinality() != 0 { - t.Error("set should have a size of 1") - } -} - -func Test_CardinalityUnsafeSet(t *testing.T) { - a := NewThreadUnsafeSet[int]() - - if a.Cardinality() != 0 { - t.Error("set should be an empty set") - } - - a.Add(1) - - if a.Cardinality() != 1 { - t.Error("set should have a size of 1") - } - - a.Remove(1) - - if a.Cardinality() != 0 { - t.Error("set should be an empty set") - } - - a.Add(9) - - if a.Cardinality() != 1 { - t.Error("set should have a size of 1") - } - - a.Clear() - - if a.Cardinality() != 0 { - t.Error("set should have a size of 1") - } -} - -func Test_SetIsSubset(t *testing.T) { - a := makeSetInt([]int{1, 2, 3, 5, 7}) - - b := NewSet[int]() - b.Add(3) - b.Add(5) - b.Add(7) - - if !b.IsSubset(a) { - t.Error("set b should be a subset of set a") - } - - b.Add(72) - - if b.IsSubset(a) { - t.Error("set b should not be a subset of set a because it contains 72 which is not in the set of a") - } -} - -func Test_SetIsProperSubset(t *testing.T) { - a := makeSetInt([]int{1, 2, 3, 5, 7}) - b := makeSetInt([]int{7, 5, 3, 2, 1}) - - if !a.IsSubset(b) { - t.Error("set a should be a subset of set b") - } - if a.IsProperSubset(b) { - t.Error("set a should not be a proper subset of set b (they're equal)") - } - - b.Add(72) - - if !a.IsSubset(b) { - t.Error("set a should be a subset of set b") - } - if !a.IsProperSubset(b) { - t.Error("set a should be a proper subset of set b") - } -} - -func Test_UnsafeSetIsSubset(t *testing.T) { - a := makeUnsafeSetInt([]int{1, 2, 3, 5, 7}) - - b := NewThreadUnsafeSet[int]() - b.Add(3) - b.Add(5) - b.Add(7) - - if !b.IsSubset(a) { - t.Error("set b should be a subset of set a") - } - - b.Add(72) - - if b.IsSubset(a) { - t.Error("set b should not be a subset of set a because it contains 72 which is not in the set of a") - } -} - -func Test_UnsafeSetIsProperSubset(t *testing.T) { - a := makeUnsafeSetInt([]int{1, 2, 3, 5, 7}) - b := NewThreadUnsafeSet[int]() - b.Add(7) - b.Add(1) - b.Add(5) - b.Add(3) - b.Add(2) - - if !a.IsSubset(b) { - t.Error("set a should be a subset of set b") - } - if a.IsProperSubset(b) { - t.Error("set a should not be a proper subset of set b (they're equal)") - } - - b.Add(72) - - if !a.IsSubset(b) { - t.Error("set a should be a subset of set b") - } - if !a.IsProperSubset(b) { - t.Error("set a should be a proper subset of set b because set b has 72") - } -} - -func Test_SetIsSuperset(t *testing.T) { - a := NewSet[int]() - a.Add(9) - a.Add(5) - a.Add(2) - a.Add(1) - a.Add(11) - - b := NewSet[int]() - b.Add(5) - b.Add(2) - b.Add(11) - - if !a.IsSuperset(b) { - t.Error("set a should be a superset of set b") - } - - b.Add(42) - - if a.IsSuperset(b) { - t.Error("set a should not be a superset of set b because set b has a 42") - } -} - -func Test_SetIsProperSuperset(t *testing.T) { - a := NewSet[int]() - a.Add(5) - a.Add(2) - a.Add(11) - - b := NewSet[int]() - b.Add(2) - b.Add(5) - b.Add(11) - - if !a.IsSuperset(b) { - t.Error("set a should be a superset of set b") - } - if a.IsProperSuperset(b) { - t.Error("set a should not be a proper superset of set b (they're equal)") - } - - a.Add(9) - - if !a.IsSuperset(b) { - t.Error("set a should be a superset of set b") - } - if !a.IsProperSuperset(b) { - t.Error("set a not be a proper superset of set b because set a has a 9") - } - - b.Add(42) - - if a.IsSuperset(b) { - t.Error("set a should not be a superset of set b because set b has a 42") - } - if a.IsProperSuperset(b) { - t.Error("set a should not be a proper superset of set b because set b has a 42") - } -} - -func Test_UnsafeSetIsSuperset(t *testing.T) { - a := NewThreadUnsafeSet[int]() - a.Add(9) - a.Add(5) - a.Add(2) - a.Add(1) - a.Add(11) - - b := NewThreadUnsafeSet[int]() - b.Add(5) - b.Add(2) - b.Add(11) - - if !a.IsSuperset(b) { - t.Error("set a should be a superset of set b") - } - - b.Add(42) - - if a.IsSuperset(b) { - t.Error("set a should not be a superset of set b because set a has a 42") - } -} - -func Test_UnsafeSetIsProperSuperset(t *testing.T) { - a := NewThreadUnsafeSet[int]() - a.Add(5) - a.Add(2) - a.Add(11) - - b := NewThreadUnsafeSet[int]() - b.Add(2) - b.Add(5) - b.Add(11) - - if !a.IsSuperset(b) { - t.Error("set a should be a superset of set b") - } - if a.IsProperSuperset(b) { - t.Error("set a should not be a proper superset of set b (they're equal)") - } - - a.Add(9) - - if !a.IsSuperset(b) { - t.Error("set a should be a superset of set b") - } - if !a.IsProperSuperset(b) { - t.Error("set a not be a proper superset of set b because set a has a 9") - } - - b.Add(42) - - if a.IsSuperset(b) { - t.Error("set a should not be a superset of set b because set b has a 42") - } - if a.IsProperSuperset(b) { - t.Error("set a should not be a proper superset of set b because set b has a 42") - } -} - -func Test_SetUnion(t *testing.T) { - a := NewSet[int]() - - b := NewSet[int]() - b.Add(1) - b.Add(2) - b.Add(3) - b.Add(4) - b.Add(5) - - c := a.Union(b) - - if c.Cardinality() != 5 { - t.Error("set c is unioned with an empty set and therefore should have 5 elements in it") - } - - d := NewSet[int]() - d.Add(10) - d.Add(14) - d.Add(0) - - e := c.Union(d) - if e.Cardinality() != 8 { - t.Error("set e should have 8 elements in it after being unioned with set c to d") - } - - f := NewSet[int]() - f.Add(14) - f.Add(3) - - g := f.Union(e) - if g.Cardinality() != 8 { - t.Error("set g should still have 8 elements in it after being unioned with set f that has duplicates") - } -} - -func Test_UnsafeSetUnion(t *testing.T) { - a := NewThreadUnsafeSet[int]() - - b := NewThreadUnsafeSet[int]() - b.Add(1) - b.Add(2) - b.Add(3) - b.Add(4) - b.Add(5) - - c := a.Union(b) - - if c.Cardinality() != 5 { - t.Error("set c is unioned with an empty set and therefore should have 5 elements in it") - } - - d := NewThreadUnsafeSet[int]() - d.Add(10) - d.Add(14) - d.Add(0) - - e := c.Union(d) - if e.Cardinality() != 8 { - t.Error("set e should have 8 elements in it after being unioned with set c to d") - } - - f := NewThreadUnsafeSet[int]() - f.Add(14) - f.Add(3) - - g := f.Union(e) - if g.Cardinality() != 8 { - t.Error("set g should still have 8 elements in it after being unioned with set f that has duplicates") - } -} - -func Test_SetIntersect(t *testing.T) { - a := NewSet[int]() - a.Add(1) - a.Add(3) - a.Add(5) - - b := NewSet[int]() - a.Add(2) - a.Add(4) - a.Add(6) - - c := a.Intersect(b) - - if c.Cardinality() != 0 { - t.Error("set c should be the empty set because there is no common items to intersect") - } - - a.Add(10) - b.Add(10) - - d := a.Intersect(b) - - if !(d.Cardinality() == 1 && d.Contains(10)) { - t.Error("set d should have a size of 1 and contain the item 10") - } -} - -func Test_UnsafeSetIntersect(t *testing.T) { - a := NewThreadUnsafeSet[int]() - a.Add(1) - a.Add(3) - a.Add(5) - - b := NewThreadUnsafeSet[int]() - a.Add(2) - a.Add(4) - a.Add(6) - - c := a.Intersect(b) - - if c.Cardinality() != 0 { - t.Error("set c should be the empty set because there is no common items to intersect") - } - - a.Add(10) - b.Add(10) - - d := a.Intersect(b) - - if !(d.Cardinality() == 1 && d.Contains(10)) { - t.Error("set d should have a size of 1 and contain the item 10") - } -} - -func Test_SetDifference(t *testing.T) { - a := NewSet[int]() - a.Add(1) - a.Add(2) - a.Add(3) - - b := NewSet[int]() - b.Add(1) - b.Add(3) - b.Add(4) - b.Add(5) - b.Add(6) - b.Add(99) - - c := a.Difference(b) - - if !(c.Cardinality() == 1 && c.Contains(2)) { - t.Error("the difference of set a to b is the set of 1 item: 2") - } -} - -func Test_UnsafeSetDifference(t *testing.T) { - a := NewThreadUnsafeSet[int]() - a.Add(1) - a.Add(2) - a.Add(3) - - b := NewThreadUnsafeSet[int]() - b.Add(1) - b.Add(3) - b.Add(4) - b.Add(5) - b.Add(6) - b.Add(99) - - c := a.Difference(b) - - if !(c.Cardinality() == 1 && c.Contains(2)) { - t.Error("the difference of set a to b is the set of 1 item: 2") - } -} - -func Test_SetSymmetricDifference(t *testing.T) { - a := NewSet[int]() - a.Add(1) - a.Add(2) - a.Add(3) - a.Add(45) - - b := NewSet[int]() - b.Add(1) - b.Add(3) - b.Add(4) - b.Add(5) - b.Add(6) - b.Add(99) - - c := a.SymmetricDifference(b) - - if !(c.Cardinality() == 6 && c.Contains(2) && c.Contains(45) && c.Contains(4) && c.Contains(5) && c.Contains(6) && c.Contains(99)) { - t.Error("the symmetric difference of set a to b is the set of 6 items: 2, 45, 4, 5, 6, 99") - } -} - -func Test_UnsafeSetSymmetricDifference(t *testing.T) { - a := NewThreadUnsafeSet[int]() - a.Add(1) - a.Add(2) - a.Add(3) - a.Add(45) - - b := NewThreadUnsafeSet[int]() - b.Add(1) - b.Add(3) - b.Add(4) - b.Add(5) - b.Add(6) - b.Add(99) - - c := a.SymmetricDifference(b) - - if !(c.Cardinality() == 6 && c.Contains(2) && c.Contains(45) && c.Contains(4) && c.Contains(5) && c.Contains(6) && c.Contains(99)) { - t.Error("the symmetric difference of set a to b is the set of 6 items: 2, 45, 4, 5, 6, 99") - } -} - -func Test_SetEqual(t *testing.T) { - a := NewSet[int]() - b := NewSet[int]() - - if !a.Equal(b) { - t.Error("Both a and b are empty sets, and should be equal") - } - - a.Add(10) - - if a.Equal(b) { - t.Error("a should not be equal to b because b is empty and a has item 1 in it") - } - - b.Add(10) - - if !a.Equal(b) { - t.Error("a is now equal again to b because both have the item 10 in them") - } - - b.Add(8) - b.Add(3) - b.Add(47) - - if a.Equal(b) { - t.Error("b has 3 more elements in it so therefore should not be equal to a") - } - - a.Add(8) - a.Add(3) - a.Add(47) - - if !a.Equal(b) { - t.Error("a and b should be equal with the same number of elements") - } -} - -func Test_UnsafeSetEqual(t *testing.T) { - a := NewThreadUnsafeSet[int]() - b := NewThreadUnsafeSet[int]() - - if !a.Equal(b) { - t.Error("Both a and b are empty sets, and should be equal") - } - - a.Add(10) - - if a.Equal(b) { - t.Error("a should not be equal to b because b is empty and a has item 1 in it") - } - - b.Add(10) - - if !a.Equal(b) { - t.Error("a is now equal again to b because both have the item 10 in them") - } - - b.Add(8) - b.Add(3) - b.Add(47) - - if a.Equal(b) { - t.Error("b has 3 more elements in it so therefore should not be equal to a") - } - - a.Add(8) - a.Add(3) - a.Add(47) - - if !a.Equal(b) { - t.Error("a and b should be equal with the same number of elements") - } -} - -func Test_SetClone(t *testing.T) { - a := NewSet[int]() - a.Add(1) - a.Add(2) - - b := a.Clone() - - if !a.Equal(b) { - t.Error("Clones should be equal") - } - - a.Add(3) - if a.Equal(b) { - t.Error("a contains one more element, they should not be equal") - } - - c := a.Clone() - c.Remove(1) - - if a.Equal(c) { - t.Error("C contains one element less, they should not be equal") - } -} - -func Test_UnsafeSetClone(t *testing.T) { - a := NewThreadUnsafeSet[int]() - a.Add(1) - a.Add(2) - - b := a.Clone() - - if !a.Equal(b) { - t.Error("Clones should be equal") - } - - a.Add(3) - if a.Equal(b) { - t.Error("a contains one more element, they should not be equal") - } - - c := a.Clone() - c.Remove(1) - - if a.Equal(c) { - t.Error("C contains one element less, they should not be equal") - } -} - -func Test_Each(t *testing.T) { - a := NewSet[string]() - - a.Add("Z") - a.Add("Y") - a.Add("X") - a.Add("W") - - b := NewSet[string]() - a.Each(func(elem string) bool { - b.Add(elem) - return false - }) - - if !a.Equal(b) { - t.Error("The sets are not equal after iterating (Each) through the first set") - } - - var count int - a.Each(func(elem string) bool { - if count == 2 { - return true - } - count++ - return false - }) - if count != 2 { - t.Error("Iteration should stop on the way") - } -} - -func Test_Filter(t *testing.T) { - a := NewSet[string]() - a.Add("Z") - a.Add("Y") - a.Add("X") - a.Add("W") - - // Returning true keeps the element; returning false drops it. - keepFromX := a.Filter(func(elem string) bool { - return elem >= "X" - }) - - expected := NewSet("Z", "Y", "X") - if !keepFromX.Equal(expected) { - t.Errorf("Expected %v, got %v", expected, keepFromX) - } - - // Source set must be unmodified. - if a.Cardinality() != 4 { - t.Errorf("Expected source cardinality 4, got %d", a.Cardinality()) - } - - // Returning true for all elements should clone the set. - all := a.Filter(func(string) bool { return true }) - if !all.Equal(a) { - t.Errorf("Expected clone of source, got %v", all) - } - if all == a { - t.Error("Expected Filter to return a new Set, not the same reference") - } - - // Returning false for all elements should yield an empty set. - none := a.Filter(func(string) bool { return false }) - if none.Cardinality() != 0 { - t.Errorf("Expected empty set, got %v", none) - } - - // Filter on an empty set returns an empty set. - empty := NewSet[string]() - emptyOut := empty.Filter(func(string) bool { return true }) - if emptyOut.Cardinality() != 0 { - t.Errorf("Expected empty set from empty source, got %v", emptyOut) - } -} - -func Test_UnsafeFilter(t *testing.T) { - a := NewThreadUnsafeSet[int]() - a.Add(1) - a.Add(2) - a.Add(3) - a.Add(4) - - evens := a.Filter(func(elem int) bool { - return elem%2 == 0 - }) - - expected := NewThreadUnsafeSet(2, 4) - if !evens.Equal(expected) { - t.Errorf("Expected %v, got %v", expected, evens) - } - - // Source set must be unmodified. - if a.Cardinality() != 4 { - t.Errorf("Expected source cardinality 4, got %d", a.Cardinality()) - } - - // Drop everything. - none := a.Filter(func(int) bool { return false }) - if none.Cardinality() != 0 { - t.Errorf("Expected empty set, got %v", none) - } - - // Empty source. - empty := NewThreadUnsafeSet[int]() - emptyOut := empty.Filter(func(int) bool { return true }) - if emptyOut.Cardinality() != 0 { - t.Errorf("Expected empty set from empty source, got %v", emptyOut) - } -} - -func Test_FilterVisitsAllElements(t *testing.T) { - a := NewSet(1, 2, 3, 4, 5) - - visited := NewSet[int]() - a.Filter(func(elem int) bool { - visited.Add(elem) - return false - }) - - if !visited.Equal(a) { - t.Errorf("Filter did not visit every element: visited %v, expected %v", visited, a) - } -} - -func Test_Iter(t *testing.T) { - a := NewSet[string]() - - a.Add("Z") - a.Add("Y") - a.Add("X") - a.Add("W") - - b := NewSet[string]() - for val := range a.Iter() { - b.Add(val) - } - - if !a.Equal(b) { - t.Error("The sets are not equal after iterating (Iter) through the first set") - } -} - -func Test_UnsafeIter(t *testing.T) { - a := NewThreadUnsafeSet[string]() - - a.Add("Z") - a.Add("Y") - a.Add("X") - a.Add("W") - - b := NewThreadUnsafeSet[string]() - for val := range a.Iter() { - b.Add(val) - } - - if !a.Equal(b) { - t.Error("The sets are not equal after iterating (Iter) through the first set") - } -} - -func Test_Iterator(t *testing.T) { - a := NewSet[string]() - - a.Add("Z") - a.Add("Y") - a.Add("X") - a.Add("W") - - b := NewSet[string]() - for val := range a.Iterator().C { - b.Add(val) - } - - if !a.Equal(b) { - t.Error("The sets are not equal after iterating (Iterator) through the first set") - } -} - -func Test_UnsafeIterator(t *testing.T) { - a := NewThreadUnsafeSet[string]() - - a.Add("Z") - a.Add("Y") - a.Add("X") - a.Add("W") - - b := NewThreadUnsafeSet[string]() - for val := range a.Iterator().C { - b.Add(val) - } - - if !a.Equal(b) { - t.Error("The sets are not equal after iterating (Iterator) through the first set") - } -} - -func Test_IteratorStop(t *testing.T) { - a := NewSet[string]() - - a.Add("Z") - a.Add("Y") - a.Add("X") - a.Add("W") - - it := a.Iterator() - it.Stop() - for range it.C { - t.Error("The iterating (Iterator) did not stop after Stop() has been called") - } -} - -func Test_PopSafe(t *testing.T) { - a := NewSet[string]() - - a.Add("a") - a.Add("b") - a.Add("c") - a.Add("d") - - aPop := func() (v string) { - v, _ = a.Pop() - return - } - - captureSet := NewSet[string]() - captureSet.Add(aPop()) - captureSet.Add(aPop()) - captureSet.Add(aPop()) - captureSet.Add(aPop()) - finalNil := aPop() - - if captureSet.Cardinality() != 4 { - t.Error("unexpected captureSet cardinality; should be 4") - } - - if a.Cardinality() != 0 { - t.Error("unepxected a cardinality; should be zero") - } - - if !captureSet.Contains("c", "a", "d", "b") { - t.Error("unexpected result set; should be a,b,c,d (any order is fine") - } - - if finalNil != "" { - t.Error("when original set is empty, further pops should result in nil") - } -} - -func Test_PopUnsafe(t *testing.T) { - a := NewThreadUnsafeSet[string]() - - a.Add("a") - a.Add("b") - a.Add("c") - a.Add("d") - - aPop := func() (v string) { - v, _ = a.Pop() - return - } - - captureSet := NewThreadUnsafeSet[string]() - captureSet.Add(aPop()) - captureSet.Add(aPop()) - captureSet.Add(aPop()) - captureSet.Add(aPop()) - finalNil := aPop() - - if captureSet.Cardinality() != 4 { - t.Error("unexpected captureSet cardinality; should be 4") - } - - if a.Cardinality() != 0 { - t.Error("unepxected a cardinality; should be zero") - } - - if !captureSet.Contains("c", "a", "d", "b") { - t.Error("unexpected result set; should be a,b,c,d (any order is fine") - } - - if finalNil != "" { - t.Error("when original set is empty, further pops should result in nil") - } -} - -func Test_PopNSafe(t *testing.T) { - a := NewSet[string]() - a.Add("a") - a.Add("b") - a.Add("c") - a.Add("d") - - // Test pop with n <= 0 - items, count := a.PopN(0) - if count != 0 { - t.Errorf("expected 0 items popped, got %d", count) - } - items, count = a.PopN(-1) - if count != 0 { - t.Errorf("expected 0 items popped, got %d", count) - } - - captureSet := NewSet[string]() - - // Test pop 2 items - items, count = a.PopN(2) - if count != 2 { - t.Errorf("expected 2 items popped, got %d", count) - } - if len(items) != 2 { - t.Errorf("expected 2 items in slice, got %d", len(items)) - } - if a.Cardinality() != 2 { - t.Errorf("expected 2 items remaining, got %d", a.Cardinality()) - } - captureSet.Append(items...) - - // Test pop more than remaining - items, count = a.PopN(3) - if count != 2 { - t.Errorf("expected 2 items popped, got %d", count) - } - if a.Cardinality() != 0 { - t.Errorf("expected 0 items remaining, got %d", a.Cardinality()) - } - captureSet.Append(items...) - - // Test pop from empty set - items, count = a.PopN(1) - if count != 0 { - t.Errorf("expected 0 items popped, got %d", count) - } - if len(items) != 0 { - t.Errorf("expected empty slice, got %d items", len(items)) - } - - if !captureSet.Contains("c", "a", "d", "b") { - t.Error("unexpected result set; should be a,b,c,d (any order is fine") - } -} - -func Test_PopNUnsafe(t *testing.T) { - a := NewThreadUnsafeSet[string]() - a.Add("a") - a.Add("b") - a.Add("c") - a.Add("d") - - // Test pop with n <= 0 - items, count := a.PopN(0) - if count != 0 { - t.Errorf("expected 0 items popped, got %d", count) - } - items, count = a.PopN(-1) - if count != 0 { - t.Errorf("expected 0 items popped, got %d", count) - } - - captureSet := NewThreadUnsafeSet[string]() - - // Test pop 2 items - items, count = a.PopN(2) - if count != 2 { - t.Errorf("expected 2 items popped, got %d", count) - } - if len(items) != 2 { - t.Errorf("expected 2 items in slice, got %d", len(items)) - } - if a.Cardinality() != 2 { - t.Errorf("expected 2 items remaining, got %d", a.Cardinality()) - } - captureSet.Append(items...) - - // Test pop more than remaining - items, count = a.PopN(3) - if count != 2 { - t.Errorf("expected 2 items popped, got %d", count) - } - if a.Cardinality() != 0 { - t.Errorf("expected 0 items remaining, got %d", a.Cardinality()) - } - captureSet.Append(items...) - - // Test pop from empty set - items, count = a.PopN(1) - if count != 0 { - t.Errorf("expected 0 items popped, got %d", count) - } - if len(items) != 0 { - t.Errorf("expected empty slice, got %d items", len(items)) - } - - if !captureSet.Contains("c", "a", "d", "b") { - t.Error("unexpected result set; should be a,b,c,d (any order is fine") - } -} - -func Test_EmptySetProperties(t *testing.T) { - empty := NewSet[string]() - - a := NewSet[string]() - a.Add("1") - a.Add("foo") - a.Add("bar") - - b := NewSet[string]() - b.Add("one") - b.Add("two") - b.Add("3") - b.Add("4") - - if !empty.IsSubset(a) || !empty.IsSubset(b) { - t.Error("The empty set is supposed to be a subset of all sets") - } - - if !a.IsSuperset(empty) || !b.IsSuperset(empty) { - t.Error("All sets are supposed to be a superset of the empty set") - } - - if !empty.IsSubset(empty) || !empty.IsSuperset(empty) { - t.Error("The empty set is supposed to be a subset and a superset of itself") - } - - c := a.Union(empty) - if !c.Equal(a) { - t.Error("The union of any set with the empty set is supposed to be equal to itself") - } - - c = a.Intersect(empty) - if !c.Equal(empty) { - t.Error("The intersection of any set with the empty set is supposed to be the empty set") - } - - if empty.Cardinality() != 0 { - t.Error("Cardinality of the empty set is supposed to be zero") - } -} - -func Test_ToSliceUnthreadsafe(t *testing.T) { - s := makeUnsafeSetInt([]int{1, 2, 3}) - setAsSlice := s.ToSlice() - if len(setAsSlice) != s.Cardinality() { - t.Errorf("Set length is incorrect: %v", len(setAsSlice)) - } - - for _, i := range setAsSlice { - if !s.Contains(i) { - t.Errorf("Set is missing element: %v", i) - } - } -} - -func Test_NewSetFromMapKey_Ints(t *testing.T) { - m := map[int]int{ - 5: 5, - 2: 3, - } - - s := NewSetFromMapKeys(m) - - if len(m) != s.Cardinality() { - t.Errorf("Length of Set is not the same as the map. Expected: %d. Actual: %d", len(m), s.Cardinality()) - } - - for k := range m { - if !s.Contains(k) { - t.Errorf("Element %d not found in map: %v", k, m) - } - } -} - -func Test_NewSetFromMapKey_Strings(t *testing.T) { - m := map[int]int{ - 5: 5, - 2: 3, - } - - s := NewSetFromMapKeys(m) - - if len(m) != s.Cardinality() { - t.Errorf("Length of Set is not the same as the map. Expected: %d. Actual: %d", len(m), s.Cardinality()) - } - - for k := range m { - if !s.Contains(k) { - t.Errorf("Element %d not found in map: %v", k, m) - } - } -} - -func Test_NewThreadUnsafeSetFromMapKey_Ints(t *testing.T) { - m := map[int]int{ - 5: 5, - 2: 3, - } - - s := NewThreadUnsafeSetFromMapKeys(m) - - if len(m) != s.Cardinality() { - t.Errorf("Length of Set is not the same as the map. Expected: %d. Actual: %d", len(m), s.Cardinality()) - } - - for k := range m { - if !s.Contains(k) { - t.Errorf("Element %d not found in map: %v", k, m) - } - } -} - -func Test_NewThreadUnsafeSetFromMapKey_Strings(t *testing.T) { - m := map[int]int{ - 5: 5, - 2: 3, - } - - s := NewThreadUnsafeSetFromMapKeys(m) - - if len(m) != s.Cardinality() { - t.Errorf("Length of Set is not the same as the map. Expected: %d. Actual: %d", len(m), s.Cardinality()) - } - - for k := range m { - if !s.Contains(k) { - t.Errorf("Element %d not found in map: %v", k, m) - } - } -} - -func Test_Elements(t *testing.T) { - a := NewSet[string]() - - a.Add("Z") - a.Add("Y") - a.Add("X") - a.Add("W") - - b := NewSet[string]() - Elements(a)(func(elem string) bool { - b.Add(elem) - return true - }) - - if !a.Equal(b) { - t.Error("The sets are not equal after iterating (Each) through the first set") - } - - var count int - Elements(a)(func(elem string) bool { - if count == 2 { - return false - } - count++ - return true - }) - - if count != 2 { - t.Error("Iteration should stop on the way") - } -} - -func Test_Example(t *testing.T) { - /* - requiredClasses := NewSet() - requiredClasses.Add("Cooking") - requiredClasses.Add("English") - requiredClasses.Add("Math") - requiredClasses.Add("Biology") - - scienceSlice := []interface{}{"Biology", "Chemistry"} - scienceClasses := NewSet(scienceSlice) - - electiveClasses := NewSet() - electiveClasses.Add("Welding") - electiveClasses.Add("Music") - electiveClasses.Add("Automotive") - - bonusClasses := NewSet() - bonusClasses.Add("Go Programming") - bonusClasses.Add("Python Programming") - - //Show me all the available classes I can take - allClasses := requiredClasses.Union(scienceClasses).Union(electiveClasses).Union(bonusClasses) - fmt.Println(allClasses) //Set{English, Chemistry, Automotive, Cooking, Math, Biology, Welding, Music, Go Programming} - - //Is cooking considered a science class? - fmt.Println(scienceClasses.Contains("Cooking")) //false - - //Show me all classes that are not science classes, since I hate science. - fmt.Println(allClasses.Difference(scienceClasses)) //Set{English, Automotive, Cooking, Math, Welding, Music, Go Programming} - - //Which science classes are also required classes? - fmt.Println(scienceClasses.Intersect(requiredClasses)) //Set{Biology} - - //How many bonus classes do you offer? - fmt.Println(bonusClasses.Cardinality()) //2 - - //Do you have the following classes? Welding, Automotive and English? - fmt.Println(allClasses.ContainsAll("Welding", "Automotive", "English")) - */ -} diff --git a/internal/golang-set/v2/sorted.go b/internal/golang-set/v2/sorted.go deleted file mode 100644 index 8ee2e70..0000000 --- a/internal/golang-set/v2/sorted.go +++ /dev/null @@ -1,42 +0,0 @@ -//go:build go1.21 -// +build go1.21 - -/* -Open Source Initiative OSI - The MIT License (MIT):Licensing - -The MIT License (MIT) -Copyright (c) 2013 - 2023 Ralph Caraveo (deckarep@gmail.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -package mapset - -import ( - "cmp" - "slices" -) - -// Sorted returns a sorted slice of a set of any ordered type in ascending order. -// When sorting floating-point numbers, NaNs are ordered before other values. -func Sorted[E cmp.Ordered](set Set[E]) []E { - s := set.ToSlice() - slices.Sort(s) - return s -} diff --git a/internal/golang-set/v2/sorted_test.go b/internal/golang-set/v2/sorted_test.go deleted file mode 100644 index 9edc685..0000000 --- a/internal/golang-set/v2/sorted_test.go +++ /dev/null @@ -1,61 +0,0 @@ -//go:build go1.21 -// +build go1.21 - -/* -Open Source Initiative OSI - The MIT License (MIT):Licensing - -The MIT License (MIT) -Copyright (c) 2013 - 2022 Ralph Caraveo (deckarep@gmail.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -package mapset - -import ( - "testing" -) - -func Test_Sorted(t *testing.T) { - test := func(t *testing.T, ctor func(vals ...string) Set[string]) { - set := ctor("apple", "banana", "pear") - sorted := Sorted(set) - - if len(sorted) != set.Cardinality() { - t.Errorf("Length of slice is not the same as the set. Expected: %d. Actual: %d", set.Cardinality(), len(sorted)) - } - - if sorted[0] != "apple" { - t.Errorf("Element 0 was not equal to apple: %s", sorted[0]) - } - if sorted[1] != "banana" { - t.Errorf("Element 1 was not equal to banana: %s", sorted[1]) - } - if sorted[2] != "pear" { - t.Errorf("Element 2 was not equal to pear: %s", sorted[2]) - } - } - - t.Run("Safe", func(t *testing.T) { - test(t, NewSet[string]) - }) - t.Run("Unsafe", func(t *testing.T) { - test(t, NewThreadUnsafeSet[string]) - }) -} diff --git a/internal/golang-set/v2/threadsafe.go b/internal/golang-set/v2/threadsafe.go deleted file mode 100644 index 6df9d8f..0000000 --- a/internal/golang-set/v2/threadsafe.go +++ /dev/null @@ -1,362 +0,0 @@ -/* -Open Source Initiative OSI - The MIT License (MIT):Licensing - -The MIT License (MIT) -Copyright (c) 2013 - 2022 Ralph Caraveo (deckarep@gmail.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -package mapset - -import ( - "sync" - // "go.mongodb.org/mongo-driver/bson/bsontype" -) - -type threadSafeSet[T comparable] struct { - sync.RWMutex - uss *threadUnsafeSet[T] -} - -// unused. -// func newThreadSafeSet[T comparable]() *threadSafeSet[T] { -// return &threadSafeSet[T]{ -// uss: newThreadUnsafeSet[T](), -// } -// } - -func newThreadSafeSetWithSize[T comparable](cardinality int) *threadSafeSet[T] { - return &threadSafeSet[T]{ - uss: newThreadUnsafeSetWithSize[T](cardinality), - } -} - -func (t *threadSafeSet[T]) Add(v T) bool { - t.Lock() - ret := t.uss.Add(v) - t.Unlock() - return ret -} - -func (t *threadSafeSet[T]) Append(v ...T) int { - t.Lock() - ret := t.uss.Append(v...) - t.Unlock() - return ret -} - -func (t *threadSafeSet[T]) AppendFrom(other Set[T]) int { - o := other.(*threadSafeSet[T]) - - t.Lock() // Write Lock - o.RLock() // Read Lock - defer t.Unlock() - defer o.RUnlock() - - return t.uss.AppendFrom(o.uss) -} - -func (t *threadSafeSet[T]) Contains(v ...T) bool { - t.RLock() - ret := t.uss.Contains(v...) - t.RUnlock() - - return ret -} - -func (t *threadSafeSet[T]) ContainsOne(v T) bool { - t.RLock() - ret := t.uss.ContainsOne(v) - t.RUnlock() - - return ret -} - -func (t *threadSafeSet[T]) ContainsAny(v ...T) bool { - t.RLock() - ret := t.uss.ContainsAny(v...) - t.RUnlock() - - return ret -} - -func (t *threadSafeSet[T]) ContainsAnyElement(other Set[T]) bool { - o := other.(*threadSafeSet[T]) - - t.RLock() - o.RLock() - - ret := t.uss.ContainsAnyElement(o.uss) - - t.RUnlock() - o.RUnlock() - return ret -} - -func (t *threadSafeSet[T]) IsEmpty() bool { - return t.Cardinality() == 0 -} - -func (t *threadSafeSet[T]) IsSubset(other Set[T]) bool { - o := other.(*threadSafeSet[T]) - - t.RLock() - o.RLock() - - ret := t.uss.IsSubset(o.uss) - t.RUnlock() - o.RUnlock() - return ret -} - -func (t *threadSafeSet[T]) IsProperSubset(other Set[T]) bool { - o := other.(*threadSafeSet[T]) - - t.RLock() - defer t.RUnlock() - o.RLock() - defer o.RUnlock() - - return t.uss.IsProperSubset(o.uss) -} - -func (t *threadSafeSet[T]) IsSuperset(other Set[T]) bool { - return other.IsSubset(t) -} - -func (t *threadSafeSet[T]) IsProperSuperset(other Set[T]) bool { - return other.IsProperSubset(t) -} - -func (t *threadSafeSet[T]) Union(other Set[T]) Set[T] { - o := other.(*threadSafeSet[T]) - - t.RLock() - o.RLock() - - unsafeUnion := t.uss.Union(o.uss).(*threadUnsafeSet[T]) - ret := &threadSafeSet[T]{uss: unsafeUnion} - t.RUnlock() - o.RUnlock() - return ret -} - -func (t *threadSafeSet[T]) Intersect(other Set[T]) Set[T] { - o := other.(*threadSafeSet[T]) - - t.RLock() - o.RLock() - - unsafeIntersection := t.uss.Intersect(o.uss).(*threadUnsafeSet[T]) - ret := &threadSafeSet[T]{uss: unsafeIntersection} - t.RUnlock() - o.RUnlock() - return ret -} - -func (t *threadSafeSet[T]) Difference(other Set[T]) Set[T] { - o := other.(*threadSafeSet[T]) - - t.RLock() - o.RLock() - - unsafeDifference := t.uss.Difference(o.uss).(*threadUnsafeSet[T]) - ret := &threadSafeSet[T]{uss: unsafeDifference} - t.RUnlock() - o.RUnlock() - return ret -} - -func (t *threadSafeSet[T]) SymmetricDifference(other Set[T]) Set[T] { - o := other.(*threadSafeSet[T]) - - t.RLock() - o.RLock() - - unsafeDifference := t.uss.SymmetricDifference(o.uss).(*threadUnsafeSet[T]) - ret := &threadSafeSet[T]{uss: unsafeDifference} - t.RUnlock() - o.RUnlock() - return ret -} - -func (t *threadSafeSet[T]) Clear() { - t.Lock() - t.uss.Clear() - t.Unlock() -} - -func (t *threadSafeSet[T]) Remove(v T) { - t.Lock() - delete(*t.uss, v) - t.Unlock() -} - -func (t *threadSafeSet[T]) RemoveAll(i ...T) { - t.Lock() - t.uss.RemoveAll(i...) - t.Unlock() -} - -func (t *threadSafeSet[T]) Cardinality() int { - t.RLock() - defer t.RUnlock() - return len(*t.uss) -} - -func (t *threadSafeSet[T]) Each(cb func(T) bool) { - t.RLock() - defer t.RUnlock() - for elem := range *t.uss { - if cb(elem) { - break - } - } -} - -func (t *threadSafeSet[T]) Filter(cb func(T) bool) Set[T] { - t.RLock() - defer t.RUnlock() - mappedSet := newThreadSafeSetWithSize[T](t.uss.Cardinality()) - for elem := range *t.uss { - if cb(elem) { - mappedSet.uss.add(elem) - } - } - return mappedSet -} - -func (t *threadSafeSet[T]) Iter() <-chan T { - ch := make(chan T) - go func() { - t.RLock() - - for elem := range *t.uss { - ch <- elem - } - close(ch) - t.RUnlock() - }() - - return ch -} - -func (t *threadSafeSet[T]) Iterator() *Iterator[T] { - iterator, ch, stopCh := newIterator[T]() - - go func() { - t.RLock() - L: - for elem := range *t.uss { - select { - case <-stopCh: - break L - case ch <- elem: - } - } - close(ch) - t.RUnlock() - }() - - return iterator -} - -func (t *threadSafeSet[T]) Equal(other Set[T]) bool { - o := other.(*threadSafeSet[T]) - - t.RLock() - o.RLock() - - ret := t.uss.Equal(o.uss) - t.RUnlock() - o.RUnlock() - return ret -} - -func (t *threadSafeSet[T]) Clone() Set[T] { - t.RLock() - - unsafeClone := t.uss.Clone().(*threadUnsafeSet[T]) - ret := &threadSafeSet[T]{uss: unsafeClone} - t.RUnlock() - return ret -} - -func (t *threadSafeSet[T]) String() string { - t.RLock() - ret := t.uss.String() - t.RUnlock() - return ret -} - -func (t *threadSafeSet[T]) Pop() (T, bool) { - t.Lock() - defer t.Unlock() - return t.uss.Pop() -} - -func (t *threadSafeSet[T]) PopN(n int) ([]T, int) { - t.Lock() - defer t.Unlock() - return t.uss.PopN(n) -} - -func (t *threadSafeSet[T]) ToSlice() []T { - t.RLock() - l := len(*t.uss) - keys := make([]T, 0, l) - for elem := range *t.uss { - keys = append(keys, elem) - } - t.RUnlock() - return keys -} - -func (t *threadSafeSet[T]) MarshalJSON() ([]byte, error) { - t.RLock() - b, err := t.uss.MarshalJSON() - t.RUnlock() - - return b, err -} - -func (t *threadSafeSet[T]) UnmarshalJSON(p []byte) error { - t.Lock() - err := t.uss.UnmarshalJSON(p) - t.Unlock() - - return err -} - -// func (t *threadSafeSet[T]) MarshalBSONValue() (bsontype.Type, []byte, error) { -// t.RLock() -// bt, b, err := t.uss.MarshalBSONValue() -// t.RUnlock() - -// return bt, b, err -// } - -// func (t *threadSafeSet[T]) UnmarshalBSONValue(bt bsontype.Type, p []byte) error { -// t.Lock() -// err := t.uss.UnmarshalBSONValue(bt, p) -// t.Unlock() - -// return err -// } diff --git a/internal/golang-set/v2/threadsafe_test.go b/internal/golang-set/v2/threadsafe_test.go deleted file mode 100644 index ffece10..0000000 --- a/internal/golang-set/v2/threadsafe_test.go +++ /dev/null @@ -1,803 +0,0 @@ -/* -Open Source Initiative OSI - The MIT License (MIT):Licensing - -The MIT License (MIT) -Copyright (c) 2013 - 2022 Ralph Caraveo (deckarep@gmail.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -package mapset - -import ( - "encoding/json" - "fmt" - "math/rand" - "runtime" - "sync" - "sync/atomic" - "testing" - // "go.mongodb.org/mongo-driver/bson" -) - -const N = 1000 - -func Test_AddConcurrent(t *testing.T) { - runtime.GOMAXPROCS(2) - - s := NewSet[int]() - ints := rand.Perm(N) - - var wg sync.WaitGroup - wg.Add(len(ints)) - for i := 0; i < len(ints); i++ { - go func(i int) { - s.Add(i) - wg.Done() - }(i) - } - - wg.Wait() - for _, i := range ints { - if !s.Contains(i) { - t.Errorf("Set is missing element: %v", i) - } - } -} - -func Test_AppendConcurrent(t *testing.T) { - runtime.GOMAXPROCS(2) - - s := NewSet[int]() - ints := rand.Perm(N) - - n := len(ints) >> 1 - var wg sync.WaitGroup - wg.Add(n) - for i := 0; i < n; i++ { - go func(i int) { - s.Append(i, N-i-1) - wg.Done() - }(i) - } - - wg.Wait() - for _, i := range ints { - if !s.Contains(i) { - t.Errorf("Set is missing element: %v", i) - } - } -} - -func Test_CardinalityConcurrent(t *testing.T) { - runtime.GOMAXPROCS(2) - - s := NewSet[int]() - - var wg sync.WaitGroup - wg.Add(1) - go func() { - elems := s.Cardinality() - for i := 0; i < N; i++ { - newElems := s.Cardinality() - if newElems < elems { - t.Errorf("Cardinality shrunk from %v to %v", elems, newElems) - } - } - wg.Done() - }() - - for i := 0; i < N; i++ { - s.Add(rand.Int()) - } - wg.Wait() -} - -func Test_ClearConcurrent(t *testing.T) { - runtime.GOMAXPROCS(2) - - s := NewSet[int]() - ints := rand.Perm(N) - - var wg sync.WaitGroup - wg.Add(len(ints)) - for i := 0; i < len(ints); i++ { - go func() { - s.Clear() - wg.Done() - }() - go func(i int) { - s.Add(i) - }(i) - } - - wg.Wait() -} - -func Test_CloneConcurrent(t *testing.T) { - runtime.GOMAXPROCS(2) - - s := NewSet[int]() - ints := rand.Perm(N) - - for _, v := range ints { - s.Add(v) - } - - var wg sync.WaitGroup - wg.Add(len(ints)) - for i := range ints { - go func(i int) { - s.Remove(i) - wg.Done() - }(i) - } - s.Clone() - wg.Wait() -} - -func Test_ContainsConcurrent(t *testing.T) { - runtime.GOMAXPROCS(2) - - s := NewSet[int]() - ints := rand.Perm(N) - integers := make([]int, 0) - for _, v := range ints { - s.Add(v) - integers = append(integers, v) - } - - var wg sync.WaitGroup - for range ints { - wg.Add(1) - go func() { - s.Contains(integers...) - wg.Done() - }() - } - wg.Wait() -} - -func Test_ContainsOneConcurrent(t *testing.T) { - runtime.GOMAXPROCS(2) - - s := NewSet[int]() - ints := rand.Perm(N) - for _, v := range ints { - s.Add(v) - } - - var wg sync.WaitGroup - for _, v := range ints { - number := v - wg.Add(1) - go func() { - s.ContainsOne(number) - wg.Done() - }() - } - wg.Wait() -} - -func Test_ContainsAnyConcurrent(t *testing.T) { - runtime.GOMAXPROCS(2) - - s := NewSet[int]() - ints := rand.Perm(N) - integers := make([]int, 0) - for _, v := range ints { - if v%N == 0 { - s.Add(v) - } - integers = append(integers, v) - } - - var wg sync.WaitGroup - for range ints { - wg.Add(1) - go func() { - s.ContainsAny(integers...) - wg.Done() - }() - } - wg.Wait() -} - -func Test_ContainsAnyElementConcurrent(t *testing.T) { - runtime.GOMAXPROCS(2) - - s, ss := NewSet[int](), NewSet[int]() - ints := rand.Perm(N) - for _, v := range ints { - s.Add(v) - ss.Add(v) - } - - var wg sync.WaitGroup - for range ints { - wg.Add(1) - go func() { - s.ContainsAnyElement(ss) - wg.Done() - }() - } - wg.Wait() -} - -func Test_DifferenceConcurrent(t *testing.T) { - runtime.GOMAXPROCS(2) - - s, ss := NewSet[int](), NewSet[int]() - ints := rand.Perm(N) - for _, v := range ints { - s.Add(v) - ss.Add(v) - } - - var wg sync.WaitGroup - for range ints { - wg.Add(1) - go func() { - s.Difference(ss) - wg.Done() - }() - } - wg.Wait() -} - -func Test_EqualConcurrent(t *testing.T) { - runtime.GOMAXPROCS(2) - - s, ss := NewSet[int](), NewSet[int]() - ints := rand.Perm(N) - for _, v := range ints { - s.Add(v) - ss.Add(v) - } - - var wg sync.WaitGroup - for range ints { - wg.Add(1) - go func() { - s.Equal(ss) - wg.Done() - }() - } - wg.Wait() -} - -func Test_IntersectConcurrent(t *testing.T) { - runtime.GOMAXPROCS(2) - - s, ss := NewSet[int](), NewSet[int]() - ints := rand.Perm(N) - for _, v := range ints { - s.Add(v) - ss.Add(v) - } - - var wg sync.WaitGroup - for range ints { - wg.Add(1) - go func() { - s.Intersect(ss) - wg.Done() - }() - } - wg.Wait() -} - -func Test_IsEmptyConcurrent(t *testing.T) { - runtime.GOMAXPROCS(2) - - s := NewSet[int]() - - var wg sync.WaitGroup - wg.Add(1) - go func() { - for i := 0; i < N; i++ { - size := s.Cardinality() - if s.IsEmpty() && size > 0 { - t.Errorf("Is Empty should be return false") - } - } - wg.Done() - }() - - for i := 0; i < N; i++ { - s.Add(rand.Int()) - } - wg.Wait() -} - -func Test_IsSubsetConcurrent(t *testing.T) { - runtime.GOMAXPROCS(2) - - s, ss := NewSet[int](), NewSet[int]() - ints := rand.Perm(N) - for _, v := range ints { - s.Add(v) - ss.Add(v) - } - - var wg sync.WaitGroup - for range ints { - wg.Add(1) - go func() { - s.IsSubset(ss) - wg.Done() - }() - } - wg.Wait() -} - -func Test_IsProperSubsetConcurrent(t *testing.T) { - runtime.GOMAXPROCS(2) - - s, ss := NewSet[int](), NewSet[int]() - ints := rand.Perm(N) - for _, v := range ints { - s.Add(v) - ss.Add(v) - } - - var wg sync.WaitGroup - for range ints { - wg.Add(1) - go func() { - s.IsProperSubset(ss) - wg.Done() - }() - } - wg.Wait() -} - -func Test_IsSupersetConcurrent(t *testing.T) { - runtime.GOMAXPROCS(2) - - s, ss := NewSet[int](), NewSet[int]() - ints := rand.Perm(N) - for _, v := range ints { - s.Add(v) - ss.Add(v) - } - - var wg sync.WaitGroup - for range ints { - wg.Add(1) - go func() { - s.IsSuperset(ss) - wg.Done() - }() - } - wg.Wait() -} - -func Test_IsProperSupersetConcurrent(t *testing.T) { - runtime.GOMAXPROCS(2) - - s, ss := NewSet[int](), NewSet[int]() - ints := rand.Perm(N) - for _, v := range ints { - s.Add(v) - ss.Add(v) - } - - var wg sync.WaitGroup - for range ints { - wg.Add(1) - go func() { - s.IsProperSuperset(ss) - wg.Done() - }() - } - wg.Wait() -} - -func Test_EachConcurrent(t *testing.T) { - runtime.GOMAXPROCS(2) - concurrent := 10 - - s := NewSet[int]() - ints := rand.Perm(N) - for _, v := range ints { - s.Add(v) - } - - var count int64 - wg := new(sync.WaitGroup) - wg.Add(concurrent) - for n := 0; n < concurrent; n++ { - go func() { - defer wg.Done() - s.Each(func(elem int) bool { - atomic.AddInt64(&count, 1) - return false - }) - }() - } - wg.Wait() - - if count != int64(N*concurrent) { - t.Errorf("%v != %v", count, int64(N*concurrent)) - } -} - -func Test_FilterConcurrent(t *testing.T) { - runtime.GOMAXPROCS(2) - concurrent := 10 - - s := NewSet[int]() - ints := rand.Perm(N) - for _, v := range ints { - s.Add(v) - } - - var count int64 - wg := new(sync.WaitGroup) - wg.Add(concurrent) - for n := 0; n < concurrent; n++ { - go func() { - defer wg.Done() - mapped := s.Filter(func(elem int) bool { - atomic.AddInt64(&count, 1) - return elem%2 == 0 - }) - // Every retained element must be even and present in the source. - mapped.Each(func(elem int) bool { - if elem%2 != 0 { - t.Errorf("Filter produced odd element %d", elem) - } - if !s.Contains(elem) { - t.Errorf("Filter produced element %d not in source", elem) - } - return false - }) - }() - } - wg.Wait() - - if count != int64(N*concurrent) { - t.Errorf("%v != %v", count, int64(N*concurrent)) - } -} - -func Test_IterConcurrent(t *testing.T) { - runtime.GOMAXPROCS(2) - - s := NewSet[int]() - ints := rand.Perm(N) - for _, v := range ints { - s.Add(v) - } - - cs := make([]<-chan int, 0) - for range ints { - cs = append(cs, s.Iter()) - } - - c := make(chan interface{}) - go func() { - for n := 0; n < len(ints)*N; { - for _, d := range cs { - select { - case <-d: - n++ - c <- nil - default: - } - } - } - close(c) - }() - - for range c { - } -} - -func Test_RemoveConcurrent(t *testing.T) { - runtime.GOMAXPROCS(2) - - s := NewSet[int]() - ints := rand.Perm(N) - for _, v := range ints { - s.Add(v) - } - - var wg sync.WaitGroup - wg.Add(len(ints)) - for _, v := range ints { - go func(i int) { - s.Remove(i) - wg.Done() - }(v) - } - wg.Wait() - - if s.Cardinality() != 0 { - t.Errorf("Expected cardinality 0; got %v", s.Cardinality()) - } -} - -func Test_StringConcurrent(t *testing.T) { - runtime.GOMAXPROCS(2) - - s := NewSet[int]() - ints := rand.Perm(N) - for _, v := range ints { - s.Add(v) - } - - var wg sync.WaitGroup - wg.Add(len(ints)) - for range ints { - go func() { - _ = s.String() - wg.Done() - }() - } - wg.Wait() -} - -func Test_SymmetricDifferenceConcurrent(t *testing.T) { - runtime.GOMAXPROCS(2) - - s, ss := NewSet[int](), NewSet[int]() - ints := rand.Perm(N) - for _, v := range ints { - s.Add(v) - ss.Add(v) - } - - var wg sync.WaitGroup - for range ints { - wg.Add(1) - go func() { - s.SymmetricDifference(ss) - wg.Done() - }() - } - wg.Wait() -} - -func Test_ToSlice(t *testing.T) { - runtime.GOMAXPROCS(2) - - s := NewSet[int]() - ints := rand.Perm(N) - - var wg sync.WaitGroup - wg.Add(len(ints)) - for i := 0; i < len(ints); i++ { - go func(i int) { - s.Add(i) - wg.Done() - }(i) - } - - wg.Wait() - setAsSlice := s.ToSlice() - if len(setAsSlice) != s.Cardinality() { - t.Errorf("Set length is incorrect: %v", len(setAsSlice)) - } - - for _, i := range setAsSlice { - if !s.Contains(i) { - t.Errorf("Set is missing element: %v", i) - } - } -} - -// Test_ToSliceDeadlock - fixes issue: https://github.com/deckarep/golang-set/issues/36 -// This code reveals the deadlock however it doesn't happen consistently. -func Test_ToSliceDeadlock(t *testing.T) { - runtime.GOMAXPROCS(2) - - var wg sync.WaitGroup - set := NewSet[int]() - workers := 10 - wg.Add(workers) - for i := 1; i <= workers; i++ { - go func() { - for j := 0; j < 1000; j++ { - set.Add(1) - set.ToSlice() - } - wg.Done() - }() - } - wg.Wait() -} - -func Test_UnmarshalJSON(t *testing.T) { - s := []byte(`["test", "1", "2", "3"]`) //,["4,5,6"]]`) - expected := NewSet( - []string{ - string(json.Number("1")), - string(json.Number("2")), - string(json.Number("3")), - "test", - }..., - ) - - actual := NewSet[string]() - err := json.Unmarshal(s, actual) - if err != nil { - t.Errorf("Error should be nil: %v", err) - } - - if !expected.Equal(actual) { - t.Errorf("Expected no difference, got: %v", expected.Difference(actual)) - } -} - -func Test_MarshalJSON(t *testing.T) { - expected := NewSet( - []string{ - string(json.Number("1")), - "test", - }..., - ) - - b, err := json.Marshal( - NewSet( - []string{ - "1", - "test", - }..., - ), - ) - if err != nil { - t.Errorf("Error should be nil: %v", err) - } - - actual := NewSet[string]() - err = json.Unmarshal(b, actual) - if err != nil { - t.Errorf("Error should be nil: %v", err) - } - - if !expected.Equal(actual) { - t.Errorf("Expected no difference, got: %v", expected.Difference(actual)) - } -} - -// Test_DeadlockOnEachCallbackWhenPanic ensures that should a panic occur within the context -// of the Each callback, progress can still be made on recovery. This is an edge case -// that was called out on issue: https://github.com/deckarep/golang-set/issues/163. -func Test_DeadlockOnEachCallbackWhenPanic(t *testing.T) { - numbers := []int{1, 2, 3, 4} - widgets := NewSet[*int]() - widgets.Append(&numbers[0], &numbers[1], nil, &numbers[2]) - - panicOccured := false - - doWork := func(s Set[*int]) (err error) { - defer func() { - if r := recover(); r != nil { - panicOccured = true - err = fmt.Errorf("failed to do work: %v", r) - } - }() - - s.Each(func(n *int) bool { - // NOTE: this will throw a panic once we get to the nil element. - _ = *n * 2 - return false - }) - - return nil - } - - card := widgets.Cardinality() - if widgets.Cardinality() != 4 { - t.Errorf("Expected widgets to have 4 elements, but has %d", card) - } - - doWork(widgets) - - if !panicOccured { - t.Error("Expected a panic to occur followed by recover for test to be valid") - } - - widgets.Add(&numbers[3]) - - card = widgets.Cardinality() - if widgets.Cardinality() != 5 { - t.Errorf("Expected widgets to have 5 elements, but has %d", card) - } -} - -// func Test_UnmarshalBSONValue(t *testing.T) { -// tp, s, initErr := bson.MarshalValue( -// bson.A{"1", "2", "3", "test"}, -// ) - -// if initErr != nil { -// t.Errorf("Init Error should be nil: %v", initErr) - -// return -// } - -// if tp != bson.TypeArray { -// t.Errorf("Encoded Type should be bson.Array, got: %v", tp) - -// return -// } - -// expected := NewSet("1", "2", "3", "test") -// actual := NewSet[string]() -// err := bson.UnmarshalValue(bson.TypeArray, s, actual) -// if err != nil { -// t.Errorf("Error should be nil: %v", err) -// } - -// if !expected.Equal(actual) { -// t.Errorf("Expected no difference, got: %v", expected.Difference(actual)) -// } -// } - -// func TestThreadUnsafeSet_UnmarshalBSONValue(t *testing.T) { -// tp, s, initErr := bson.MarshalValue( -// bson.A{int64(1), int64(2), int64(3)}, -// ) - -// if initErr != nil { -// t.Errorf("Init Error should be nil: %v", initErr) - -// return -// } - -// if tp != bson.TypeArray { -// t.Errorf("Encoded Type should be bson.Array, got: %v", tp) - -// return -// } - -// expected := NewThreadUnsafeSet[int64](1, 2, 3) -// actual := NewThreadUnsafeSet[int64]() -// err := actual.UnmarshalBSONValue(bson.TypeArray, []byte(s)) -// if err != nil { -// t.Errorf("Error should be nil: %v", err) -// } -// if !expected.Equal(actual) { -// t.Errorf("Expected no difference, got: %v", expected.Difference(actual)) -// } -// } - -// func Test_MarshalBSONValue(t *testing.T) { -// expected := NewSet("1", "test") - -// _, b, err := bson.MarshalValue( -// NewSet("1", "test"), -// ) -// if err != nil { -// t.Errorf("Error should be nil: %v", err) -// } - -// actual := NewSet[string]() -// err = bson.UnmarshalValue(bson.TypeArray, b, actual) -// if err != nil { -// t.Errorf("Error should be nil: %v", err) -// } - -// if !expected.Equal(actual) { -// t.Errorf("Expected no difference, got: %v", expected.Difference(actual)) -// } -// } diff --git a/internal/golang-set/v2/threadunsafe.go b/internal/golang-set/v2/threadunsafe.go deleted file mode 100644 index fdbbc5f..0000000 --- a/internal/golang-set/v2/threadunsafe.go +++ /dev/null @@ -1,408 +0,0 @@ -/* -Open Source Initiative OSI - The MIT License (MIT):Licensing - -The MIT License (MIT) -Copyright (c) 2013 - 2022 Ralph Caraveo (deckarep@gmail.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -package mapset - -import ( - "encoding/json" - "fmt" - "strings" - // "go.mongodb.org/mongo-driver/bson" - // "go.mongodb.org/mongo-driver/bson/bsontype" -) - -type threadUnsafeSet[T comparable] map[T]struct{} - -// Assert concrete type:threadUnsafeSet adheres to Set interface. -var _ Set[string] = (*threadUnsafeSet[string])(nil) - -func newThreadUnsafeSet[T comparable]() *threadUnsafeSet[T] { - t := make(threadUnsafeSet[T]) - return &t -} - -func newThreadUnsafeSetWithSize[T comparable](cardinality int) *threadUnsafeSet[T] { - t := make(threadUnsafeSet[T], cardinality) - return &t -} - -func (s *threadUnsafeSet[T]) Add(v T) bool { - prevLen := s.Cardinality() - s.add(v) - return prevLen != s.Cardinality() -} - -// private version of Add which doesn't return a value -func (s *threadUnsafeSet[T]) add(v T) { - (*s)[v] = struct{}{} -} - -func (s *threadUnsafeSet[T]) Append(vs ...T) int { - prevLen := s.Cardinality() - s.append(vs...) - return s.Cardinality() - prevLen -} - -// private version of Append which doesn't return a value -func (s *threadUnsafeSet[T]) append(vs ...T) { - for i := range vs { - s.add(vs[i]) - } -} - -func (s *threadUnsafeSet[T]) AppendFrom(other Set[T]) int { - o := other.(*threadUnsafeSet[T]) - - prevLen := s.Cardinality() - for elem := range *o { - s.add(elem) - } - return s.Cardinality() - prevLen -} - -func (s *threadUnsafeSet[T]) Cardinality() int { - return len(*s) -} - -func (s *threadUnsafeSet[T]) Clear() { - // Constructions like this are optimised by compiler, and replaced by - // mapclear() function, defined in - // https://github.com/golang/go/blob/29bbca5c2c1ad41b2a9747890d183b6dd3a4ace4/src/runtime/map.go#L993) - for key := range *s { - delete(*s, key) - } -} - -func (s *threadUnsafeSet[T]) Clone() Set[T] { - t := threadUnsafeSet[T](mapclone(*s)) - return &t -} - -func (s *threadUnsafeSet[T]) Contains(v ...T) bool { - for _, val := range v { - if !s.contains(val) { - return false - } - } - return true -} - -func (s *threadUnsafeSet[T]) ContainsOne(v T) bool { - return s.contains(v) -} - -func (s *threadUnsafeSet[T]) ContainsAny(v ...T) bool { - for _, val := range v { - if s.contains(val) { - return true - } - } - return false -} - -func (s *threadUnsafeSet[T]) ContainsAnyElement(other Set[T]) bool { - o := other.(*threadUnsafeSet[T]) - - // loop over smaller set - if s.Cardinality() < other.Cardinality() { - for elem := range *s { - if o.contains(elem) { - return true - } - } - } else { - for elem := range *o { - if s.contains(elem) { - return true - } - } - } - return false -} - -// private version of Contains for a single element v -func (s *threadUnsafeSet[T]) contains(v T) (ok bool) { - _, found := (*s)[v] - return found -} - -func (s *threadUnsafeSet[T]) Difference(other Set[T]) Set[T] { - o := other.(*threadUnsafeSet[T]) - - diff := make(threadUnsafeSet[T], s.Cardinality()) - for elem := range *s { - if !o.contains(elem) { - diff.add(elem) - } - } - return &diff -} - -func (s *threadUnsafeSet[T]) Each(cb func(T) bool) { - for elem := range *s { - if cb(elem) { - break - } - } -} - -func (s *threadUnsafeSet[T]) Filter(cb func(T) bool) Set[T] { - mappedSet := newThreadUnsafeSetWithSize[T](s.Cardinality()) - for elem := range *s { - if cb(elem) { - mappedSet.add(elem) - } - } - return mappedSet -} - -func (s *threadUnsafeSet[T]) Equal(other Set[T]) bool { - o := other.(*threadUnsafeSet[T]) - - if s.Cardinality() != other.Cardinality() { - return false - } - for elem := range *s { - if !o.contains(elem) { - return false - } - } - return true -} - -func (s *threadUnsafeSet[T]) Intersect(other Set[T]) Set[T] { - o := other.(*threadUnsafeSet[T]) - - var intersection threadUnsafeSet[T] - // loop over smaller set - if s.Cardinality() < other.Cardinality() { - intersection = make(threadUnsafeSet[T], s.Cardinality()) - for elem := range *s { - if o.contains(elem) { - intersection.add(elem) - } - } - } else { - intersection = make(threadUnsafeSet[T], o.Cardinality()) - for elem := range *o { - if s.contains(elem) { - intersection.add(elem) - } - } - } - return &intersection -} - -func (s *threadUnsafeSet[T]) IsEmpty() bool { - return s.Cardinality() == 0 -} - -func (s *threadUnsafeSet[T]) IsProperSubset(other Set[T]) bool { - return s.Cardinality() < other.Cardinality() && s.IsSubset(other) -} - -func (s *threadUnsafeSet[T]) IsProperSuperset(other Set[T]) bool { - return s.Cardinality() > other.Cardinality() && s.IsSuperset(other) -} - -func (s *threadUnsafeSet[T]) IsSubset(other Set[T]) bool { - o := other.(*threadUnsafeSet[T]) - if s.Cardinality() > other.Cardinality() { - return false - } - for elem := range *s { - if !o.contains(elem) { - return false - } - } - return true -} - -func (s *threadUnsafeSet[T]) IsSuperset(other Set[T]) bool { - return other.IsSubset(s) -} - -func (s *threadUnsafeSet[T]) Iter() <-chan T { - ch := make(chan T) - go func() { - for elem := range *s { - ch <- elem - } - close(ch) - }() - - return ch -} - -func (s *threadUnsafeSet[T]) Iterator() *Iterator[T] { - iterator, ch, stopCh := newIterator[T]() - - go func() { - L: - for elem := range *s { - select { - case <-stopCh: - break L - case ch <- elem: - } - } - close(ch) - }() - - return iterator -} - -// Pop returns a popped item in case set is not empty, or nil-value of T -// if set is already empty -func (s *threadUnsafeSet[T]) Pop() (v T, ok bool) { - for item := range *s { - delete(*s, item) - return item, true - } - return v, false -} - -func (s *threadUnsafeSet[T]) PopN(n int) (items []T, count int) { - if n <= 0 || len(*s) == 0 { - return make([]T, 0), 0 - } - sn := s.Cardinality() - if n > sn { - n = sn - } - - items = make([]T, 0, sn) - for item := range *s { - if count >= n { - break - } - delete(*s, item) - items = append(items, item) - count++ - } - return items, count -} - -func (s threadUnsafeSet[T]) Remove(v T) { - delete(s, v) -} - -func (s threadUnsafeSet[T]) RemoveAll(i ...T) { - for _, elem := range i { - delete(s, elem) - } -} - -func (s threadUnsafeSet[T]) String() string { - items := make([]string, 0, len(s)) - - for elem := range s { - items = append(items, fmt.Sprintf("%v", elem)) - } - return fmt.Sprintf("Set{%s}", strings.Join(items, ", ")) -} - -func (s *threadUnsafeSet[T]) SymmetricDifference(other Set[T]) Set[T] { - o := other.(*threadUnsafeSet[T]) - - // maximum number of elements is the sum of s and o cardinalities (when s and o are disjoint) - n := s.Cardinality() + o.Cardinality() - sd := make(threadUnsafeSet[T], n) - for elem := range *s { - if !o.contains(elem) { - sd.add(elem) - } - } - for elem := range *o { - if !s.contains(elem) { - sd.add(elem) - } - } - return &sd -} - -func (s threadUnsafeSet[T]) ToSlice() []T { - keys := make([]T, 0, s.Cardinality()) - for elem := range s { - keys = append(keys, elem) - } - - return keys -} - -func (s threadUnsafeSet[T]) Union(other Set[T]) Set[T] { - o := other.(*threadUnsafeSet[T]) - - // maximum number of elements is the sum of s and o cardinalities (when s and o are disjoint) - n := s.Cardinality() + o.Cardinality() - unionedSet := make(threadUnsafeSet[T], n) - - for elem := range s { - unionedSet.add(elem) - } - for elem := range *o { - unionedSet.add(elem) - } - return &unionedSet -} - -// MarshalJSON creates a JSON array from the set, it marshals all elements -func (s threadUnsafeSet[T]) MarshalJSON() ([]byte, error) { - return json.Marshal(s.ToSlice()) -} - -// UnmarshalJSON recreates a set from a JSON array, it only decodes -// primitive types. Numbers are decoded as json.Number. -func (s *threadUnsafeSet[T]) UnmarshalJSON(b []byte) error { - var i []T - err := json.Unmarshal(b, &i) - if err != nil { - return err - } - s.append(i...) - - return nil -} - -// MarshalBSON creates a BSON array from the set. -// func (s threadUnsafeSet[T]) MarshalBSONValue() (bsontype.Type, []byte, error) { -// return bson.MarshalValue(s.ToSlice()) -// } - -// UnmarshalBSON recreates a set from a BSON array. -// func (s threadUnsafeSet[T]) UnmarshalBSONValue(bt bsontype.Type, b []byte) error { -// if bt != bson.TypeArray { -// return fmt.Errorf("must use BSON Array to unmarshal Set") -// } - -// var i []T -// err := bson.UnmarshalValue(bt, b, &i) -// if err != nil { -// return err -// } -// s.append(i...) - -// return nil -// } diff --git a/internal/golang-set/v2/threadunsafe_test.go b/internal/golang-set/v2/threadunsafe_test.go deleted file mode 100644 index c670305..0000000 --- a/internal/golang-set/v2/threadunsafe_test.go +++ /dev/null @@ -1,164 +0,0 @@ -/* -Open Source Initiative OSI - The MIT License (MIT):Licensing - -The MIT License (MIT) -Copyright (c) 2013 - 2022 Ralph Caraveo (deckarep@gmail.com) - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -package mapset - -import ( - "encoding/json" - "testing" -) - -func TestThreadUnsafeSet_MarshalJSON(t *testing.T) { - expected := NewThreadUnsafeSet[int64](1, 2, 3) - actual := newThreadUnsafeSet[int64]() - - // test Marshal from Set method - b, err := expected.MarshalJSON() - if err != nil { - t.Errorf("Error should be nil: %v", err) - } - - err = json.Unmarshal(b, actual) - if err != nil { - t.Errorf("Error should be nil: %v", err) - } - - if !expected.Equal(actual) { - t.Errorf("Expected no difference, got: %v", expected.Difference(actual)) - } - - // test Marshal from json package - b, err = json.Marshal(expected) - if err != nil { - t.Errorf("Error should be nil: %v", err) - } - - err = json.Unmarshal(b, actual) - if err != nil { - t.Errorf("Error should be nil: %v", err) - } - - if !expected.Equal(actual) { - t.Errorf("Expected no difference, got: %v", expected.Difference(actual)) - } -} - -func TestThreadUnsafeSet_UnmarshalJSON(t *testing.T) { - expected := NewThreadUnsafeSet[int64](1, 2, 3) - actual := NewThreadUnsafeSet[int64]() - - // test Unmarshal from Set method - err := actual.UnmarshalJSON([]byte(`[1, 2, 3]`)) - if err != nil { - t.Errorf("Error should be nil: %v", err) - } - if !expected.Equal(actual) { - t.Errorf("Expected no difference, got: %v", expected.Difference(actual)) - } - - // test Unmarshal from json package - actual = NewThreadUnsafeSet[int64]() - err = json.Unmarshal([]byte(`[1, 2, 3]`), actual) - if err != nil { - t.Errorf("Error should be nil: %v", err) - } - if !expected.Equal(actual) { - t.Errorf("Expected no difference, got: %v", expected.Difference(actual)) - } -} - -func TestThreadUnsafeSet_MarshalJSON_Struct(t *testing.T) { - expected := &testStruct{"test", NewThreadUnsafeSet("a")} - - b, err := json.Marshal(&testStruct{"test", NewThreadUnsafeSet("a")}) - if err != nil { - t.Errorf("Error should be nil: %v", err) - } - - actual := &testStruct{} - err = json.Unmarshal(b, actual) - if err != nil { - t.Errorf("Error should be nil: %v", err) - } - - if !expected.Set.Equal(actual.Set) { - t.Errorf("Expected no difference, got: %v", expected.Set.Difference(actual.Set)) - } -} -func TestThreadUnsafeSet_UnmarshalJSON_Struct(t *testing.T) { - expected := &testStruct{"test", NewThreadUnsafeSet("a", "b", "c")} - actual := &testStruct{} - - err := json.Unmarshal([]byte(`{"other":"test", "set":["a", "b", "c"]}`), actual) - if err != nil { - t.Errorf("Error should be nil: %v", err) - } - if !expected.Set.Equal(actual.Set) { - t.Errorf("Expected no difference, got: %v", expected.Set.Difference(actual.Set)) - } - - expectedComplex := NewThreadUnsafeSet(struct{ Val string }{Val: "a"}, struct{ Val string }{Val: "b"}) - actualComplex := NewThreadUnsafeSet[struct{ Val string }]() - - err = actualComplex.UnmarshalJSON([]byte(`[{"Val": "a"}, {"Val": "b"}]`)) - if err != nil { - t.Errorf("Error should be nil: %v", err) - } - if !expectedComplex.Equal(actualComplex) { - t.Errorf("Expected no difference, got: %v", expectedComplex.Difference(actualComplex)) - } - - actualComplex = NewThreadUnsafeSet[struct{ Val string }]() - err = json.Unmarshal([]byte(`[{"Val": "a"}, {"Val": "b"}]`), actualComplex) - if err != nil { - t.Errorf("Error should be nil: %v", err) - } - if !expectedComplex.Equal(actualComplex) { - t.Errorf("Expected no difference, got: %v", expectedComplex.Difference(actualComplex)) - } -} - -// this serves as an example of how to correctly unmarshal a struct with a Set property -type testStruct struct { - Other string - Set Set[string] -} - -func (t *testStruct) UnmarshalJSON(b []byte) error { - raw := struct { - Other string - Set []string - }{} - - err := json.Unmarshal(b, &raw) - if err != nil { - return err - } - - t.Other = raw.Other - t.Set = NewThreadUnsafeSet(raw.Set...) - - return nil -} diff --git a/makefile b/makefile index d99c5e0..0714b5d 100644 --- a/makefile +++ b/makefile @@ -15,10 +15,10 @@ EXT_DIR := ${PWD}/.ext EXT_BIN_DIR := ${EXT_DIR}/bin EXT_TMP_DIR := ${EXT_DIR}/tmp -GO_VER := 1.26 +GO_VER := 1.27 SVU_VER := 3.4.1 GOTESTSUM_VER := 1.13.0 -GOLANGCI-LINT_VER := 2.13.1 +GOLANGCI-LINT_VER := 2.14.0 RELEASE_TAG := $$(${EXT_BIN_DIR}/svu current) diff --git a/model/inverse.go b/model/inverse.go index a8c57d4..bd65836 100644 --- a/model/inverse.go +++ b/model/inverse.go @@ -4,7 +4,7 @@ import ( "fmt" "os" - set "github.com/aserto-dev/azm/internal/golang-set/v2" + set "github.com/deckarep/golang-set/v3" "github.com/samber/lo" ) diff --git a/model/model.go b/model/model.go index 9bba11e..17a1f38 100644 --- a/model/model.go +++ b/model/model.go @@ -8,8 +8,8 @@ import ( "sort" "time" - set "github.com/aserto-dev/azm/internal/golang-set/v2" "github.com/aserto-dev/go-directory/pkg/derr" + set "github.com/deckarep/golang-set/v3" "github.com/samber/lo" ) diff --git a/model/validate.go b/model/validate.go index 8177667..b4132e5 100644 --- a/model/validate.go +++ b/model/validate.go @@ -3,8 +3,8 @@ package model import ( "fmt" - set "github.com/aserto-dev/azm/internal/golang-set/v2" "github.com/aserto-dev/go-directory/pkg/derr" + set "github.com/deckarep/golang-set/v3" "github.com/hashicorp/go-multierror" "github.com/samber/lo" )