From 7c9ba67576d11c9bd580de34c496016c902bd4c2 Mon Sep 17 00:00:00 2001 From: Ralph Caraveo Date: Sat, 26 Mar 2022 20:14:21 -0700 Subject: [PATCH] Fixes to build with Go 1.18 official release thanks to @billinghamj input - Thank You --- .github/workflows/ci.yml | 4 +- set.go | 11 +--- set_test.go | 110 +++++++++------------------------------ threadsafe.go | 29 +---------- threadsafe_test.go | 29 ++++++----- threadunsafe.go | 79 ++-------------------------- 6 files changed, 47 insertions(+), 215 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f9dc00e..1bca3d1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,7 +4,7 @@ jobs: test: strategy: matrix: - go-version: [1.18.0-beta1] + go-version: [1.18.0] os: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.os }} steps: @@ -19,4 +19,4 @@ jobs: run: | go test -v -race ./... # go vet ./... - # go test -bench=. \ No newline at end of file + # go test -bench=. diff --git a/set.go b/set.go index ca0b1bf..1441467 100644 --- a/set.go +++ b/set.go @@ -162,14 +162,7 @@ type Set[T comparable] interface { Union(other Set[T]) Set[T] // Pop removes and returns an arbitrary item from the set. - Pop() any - - // Returns all subsets of a given set (Power Set). - // PowerSet({x, y, z}) -> {{}, {x}, {y}, {z}, {x, y}, {x, z}, {y, z}, {x, y, z}} - PowerSet() Set[any] - - // Returns the Cartesian Product of two sets. - CartesianProduct(other Set[T]) Set[any] + Pop() (T, bool) // Returns the members of the set as a slice. ToSlice() []T @@ -195,7 +188,7 @@ func NewSet[T comparable](vals ...T) Set[T] { // NewSetWith creates and returns a new set with the given elements. // Operations on the resulting set are thread-safe. func NewSetWith[T comparable](vals ...T) Set[T] { - return NewSetFromSlice[T](vals) + return NewSetFromSlice(vals) } // NewSetFromSlice creates and returns a reference to a set from an diff --git a/set_test.go b/set_test.go index 4fcb71f..44e3f1a 100644 --- a/set_test.go +++ b/set_test.go @@ -975,12 +975,17 @@ func Test_PopSafe(t *testing.T) { a.Add("c") a.Add("d") - captureSet := NewSet[any]() - captureSet.Add(a.Pop()) - captureSet.Add(a.Pop()) - captureSet.Add(a.Pop()) - captureSet.Add(a.Pop()) - finalNil := a.Pop() + 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") @@ -994,7 +999,7 @@ func Test_PopSafe(t *testing.T) { t.Error("unexpected result set; should be a,b,c,d (any order is fine") } - if finalNil != nil { + if finalNil != "" { t.Error("when original set is empty, further pops should result in nil") } } @@ -1007,12 +1012,17 @@ func Test_PopUnsafe(t *testing.T) { a.Add("c") a.Add("d") - captureSet := NewThreadUnsafeSet[any]() - captureSet.Add(a.Pop()) - captureSet.Add(a.Pop()) - captureSet.Add(a.Pop()) - captureSet.Add(a.Pop()) - finalNil := a.Pop() + 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") @@ -1026,39 +1036,11 @@ func Test_PopUnsafe(t *testing.T) { t.Error("unexpected result set; should be a,b,c,d (any order is fine") } - if finalNil != nil { + if finalNil != "" { t.Error("when original set is empty, further pops should result in nil") } } -func Test_PowerSet(t *testing.T) { - a := NewThreadUnsafeSet[string]() - - a.Add("1") - a.Add("delta") - a.Add("chi") - a.Add("4") - - b := a.PowerSet() - if b.Cardinality() != 16 { - t.Error("unexpected PowerSet cardinality") - } -} - -func Test_PowerSetThreadSafe(t *testing.T) { - // set := NewSet().PowerSet() - // _, setIsThreadSafe := set.(*threadSafeSet) - // if !setIsThreadSafe { - // t.Error("result of PowerSet should be thread safe") - // } - - // subset := set.Pop() - // _, subsetIsThreadSafe := subset.(*threadSafeSet) - // if !subsetIsThreadSafe { - // t.Error("subsets in PowerSet result should be thread safe") - // } -} - func Test_EmptySetProperties(t *testing.T) { empty := NewSet[string]() @@ -1095,53 +1077,9 @@ func Test_EmptySetProperties(t *testing.T) { t.Error("The intesection of any set with the empty set is supposed to be the empty set") } - d := a.CartesianProduct(empty) - if d.Cardinality() != 0 { - t.Error("Cartesian product of any set and the empty set must be the empty set") - } - if empty.Cardinality() != 0 { t.Error("Cardinality of the empty set is supposed to be zero") } - - // e := empty.PowerSet() - // if e.Cardinality() != 1 { - // t.Error("Cardinality of the power set of the empty set is supposed to be one { {} }") - // } -} - -func Test_CartesianProduct(t *testing.T) { - a := NewThreadUnsafeSet[any]() - b := NewThreadUnsafeSet[any]() - empty := NewThreadUnsafeSet[any]() - - a.Add(1) - a.Add(2) - a.Add(3) - - b.Add("one") - b.Add("two") - b.Add("three") - b.Add("alpha") - b.Add("gamma") - - c := a.CartesianProduct(b) - d := b.CartesianProduct(a) - - if c.Cardinality() != d.Cardinality() { - t.Error("Cardinality of AxB must be equal to BxA") - } - - if c.Cardinality() != (a.Cardinality() * b.Cardinality()) { - t.Error("Unexpected cardinality for cartesian product set") - } - - c = a.CartesianProduct(empty) - d = empty.CartesianProduct(b) - - if c.Cardinality() != 0 || d.Cardinality() != 0 { - t.Error("Cartesian product of any set and the empty set Ax0 || 0xA must be the empty set") - } } func Test_ToSliceUnthreadsafe(t *testing.T) { diff --git a/threadsafe.go b/threadsafe.go index b144ad4..1a137a9 100644 --- a/threadsafe.go +++ b/threadsafe.go @@ -227,39 +227,12 @@ func (s *threadSafeSet[T]) String() string { return ret } -func (s *threadSafeSet[T]) PowerSet() Set[any] { - s.RLock() - unsafePowerSet := s.uss.PowerSet().(*threadUnsafeSet[any]) - s.RUnlock() - - ret := &threadSafeSet[any]{uss: newThreadUnsafeSet[any]()} - for subset := range unsafePowerSet.Iter() { - unsafeSubset := subset.(*threadUnsafeSet[any]) - ret.Add(&threadSafeSet[any]{uss: *unsafeSubset}) - } - return ret -} - -func (s *threadSafeSet[T]) Pop() any { +func (s *threadSafeSet[T]) Pop() (T, bool) { s.Lock() defer s.Unlock() return s.uss.Pop() } -func (s *threadSafeSet[T]) CartesianProduct(other Set[T]) Set[any] { - o := other.(*threadSafeSet[T]) - - s.RLock() - o.RLock() - - unsafeCartProduct := s.uss.CartesianProduct(&o.uss).(*threadUnsafeSet[any]) - ret := &threadSafeSet[any]{uss: *unsafeCartProduct} - - s.RUnlock() - o.RUnlock() - return ret -} - func (s *threadSafeSet[T]) ToSlice() []T { keys := make([]T, 0, s.Cardinality()) s.RLock() diff --git a/threadsafe_test.go b/threadsafe_test.go index c257f52..9dcb050 100644 --- a/threadsafe_test.go +++ b/threadsafe_test.go @@ -472,16 +472,17 @@ func Test_ToSliceDeadlock(t *testing.T) { } func Test_UnmarshalJSON(t *testing.T) { - s := []byte(`["test", 1, 2, 3]`) //,["4,5,6"]]`) - expected := NewSetFromSlice[any]( - []any{ - json.Number("1"), - json.Number("2"), - json.Number("3"), + s := []byte(`["test", "1", "2", "3"]`) //,["4,5,6"]]`) + expected := NewSetFromSlice( + []string{ + string(json.Number("1")), + string(json.Number("2")), + string(json.Number("3")), "test", }, ) - actual := NewSet[any]() + + actual := NewSet[string]() err := json.Unmarshal(s, actual) if err != nil { t.Errorf("Error should be nil: %v", err) @@ -493,17 +494,17 @@ func Test_UnmarshalJSON(t *testing.T) { } func Test_MarshalJSON(t *testing.T) { - expected := NewSetFromSlice[any]( - []any{ - json.Number("1"), + expected := NewSetFromSlice( + []string{ + string(json.Number("1")), "test", }, ) b, err := json.Marshal( - NewSetFromSlice[any]( - []any{ - 1, + NewSetFromSlice( + []string{ + "1", "test", }, ), @@ -512,7 +513,7 @@ func Test_MarshalJSON(t *testing.T) { t.Errorf("Error should be nil: %v", err) } - actual := NewSet[any]() + actual := NewSet[string]() err = json.Unmarshal(b, actual) if err != nil { t.Errorf("Error should be nil: %v", err) diff --git a/threadunsafe.go b/threadunsafe.go index c98e6f0..afd15fa 100644 --- a/threadunsafe.go +++ b/threadunsafe.go @@ -29,31 +29,9 @@ import ( "bytes" "encoding/json" "fmt" - "reflect" "strings" ) -// An OrderedPair represents a 2-tuple of values. -type OrderedPair[T comparable] struct { - First T - Second T -} - -// Equal says whether two 2-tuples contain the same values in the same order. -func (pair *OrderedPair[T]) Equal(other OrderedPair[T]) bool { - if pair.First == other.First && - pair.Second == other.Second { - return true - } - - return false -} - -// String outputs a 2-tuple in the form "(A, B)". -func (pair OrderedPair[T]) String() string { - return fmt.Sprintf("(%v, %v)", pair.First, pair.Second) -} - type threadUnsafeSet[T comparable] map[T]struct{} // Assert concrete type:threadUnsafeSet adheres to Set interface. @@ -77,27 +55,6 @@ func (s *threadUnsafeSet[T]) Cardinality() int { return len(*s) } -func (s *threadUnsafeSet[T]) CartesianProduct(other Set[T]) Set[any] { - o := other.(*threadUnsafeSet[T]) - - // NOTE: limitation with Go s or of my knowledge of Go s? - - // I can't seem to declare this without an instantiation cycle. - //cartProduct := NewThreadUnsafeSet[OrderedPair[T]]() - - // So here is my crime against humanity. - cartProduct := NewThreadUnsafeSet[any]() - - for i := range *s { - for j := range *o { - elem := OrderedPair[T]{First: i, Second: j} - cartProduct.Add(elem) - } - } - - return cartProduct -} - func (s *threadUnsafeSet[T]) Clear() { *s = newThreadUnsafeSet[T]() } @@ -230,42 +187,12 @@ func (s *threadUnsafeSet[T]) Iterator() *Iterator[T] { } // TODO: how can we make this properly , return T but can't return nil. -func (s *threadUnsafeSet[T]) Pop() any { +func (s *threadUnsafeSet[T]) Pop() (v T, ok bool) { for item := range *s { delete(*s, item) - return item + return item, true } - return nil -} - -func (s *threadUnsafeSet[T]) PowerSet() Set[any] { - // The type must be any comparable so we have to dumb down to any. - powSet := NewThreadUnsafeSet[any]() - - nullset := newThreadUnsafeSet[T]() - powSet.Add(&nullset) - - for es := range *s { - u := newThreadUnsafeSet[any]() - j := powSet.Iter() - for er := range j { - p := newThreadUnsafeSet[T]() - if reflect.TypeOf(er).Name() == "" { - k := er.(*threadUnsafeSet[T]) - for ek := range *(k) { - p.Add(ek) - } - } else { - p.Add(er.(T)) - } - p.Add(es) - u.Add(&p) - } - - powSet = powSet.Union(&u) - } - - return powSet + return } func (s *threadUnsafeSet[T]) Remove(v T) {