Skip to content

Commit

Permalink
Fixes to build with Go 1.18 official release thanks to @billinghamj i…
Browse files Browse the repository at this point in the history
…nput - Thank You
  • Loading branch information
deckarep committed Mar 27, 2022
1 parent 1035f5f commit 7c9ba67
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 215 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -19,4 +19,4 @@ jobs:
run: |
go test -v -race ./...
# go vet ./...
# go test -bench=.
# go test -bench=.
11 changes: 2 additions & 9 deletions set.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
110 changes: 24 additions & 86 deletions set_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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")
}
}
Expand All @@ -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")
Expand All @@ -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]()

Expand Down Expand Up @@ -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) {
Expand Down
29 changes: 1 addition & 28 deletions threadsafe.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
29 changes: 15 additions & 14 deletions threadsafe_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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",
},
),
Expand All @@ -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)
Expand Down
79 changes: 3 additions & 76 deletions threadunsafe.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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]()
}
Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit 7c9ba67

Please sign in to comment.