mirror of
https://github.com/gonum/gonum.git
synced 2025-10-09 09:00:38 +08:00
168 lines
3.4 KiB
Go
168 lines
3.4 KiB
Go
package discrete
|
|
|
|
import (
|
|
"sync/atomic"
|
|
)
|
|
|
|
// On one hand, using an interface{} as a key works on some levels.
|
|
// On the other hand, from experience, I can say that working with interface{} is a pain
|
|
// so I don't like it in an API. An alternate idea is to make Set an interface with a method that allows you to GRAB a map[interface{}]struct{} from
|
|
// the implementation, but that adds a lot of calls and needless operations, making the library slower
|
|
//
|
|
// Another point, using an interface{} may be pointless because a map key MUST have == and != defined, limiting the possible keys anyway (for instance, if you had a set of [3]floats I don't think it will do a deep
|
|
// comparison, making it rather pointless). Also, keying with a float will mean it does a strict == with the floats, possibly causing bad behavior. It may be best to just make it a map[int]struct{}. Thoughts?
|
|
type Set struct {
|
|
data map[interface{}]struct{}
|
|
id uint64
|
|
}
|
|
|
|
// I highly doubt we have to worry about running out of IDs, but we could add a little reclaimID function if we're worried
|
|
var globalid uint64 = 0
|
|
|
|
// For cleanliness
|
|
var flag struct{} = struct{}{}
|
|
|
|
func NewSet() Set {
|
|
defer func() { atomic.AddUint64(&globalid, 1) }()
|
|
return Set{
|
|
data: make(map[interface{}]struct{}, 0),
|
|
id: atomic.LoadUint64(&globalid),
|
|
}
|
|
}
|
|
|
|
// Reverts the set to the empty set without reallocating
|
|
func (s1 Set) Clear() Set {
|
|
for el, _ := range s1.data {
|
|
delete(s1.data, el)
|
|
}
|
|
|
|
return s1
|
|
}
|
|
|
|
// Ensures a perfect copy from s1 to dest (meaning the sets will be equal)
|
|
func (s1 Set) CopyTo(dest Set) Set {
|
|
if s1.id == dest.id {
|
|
return dest
|
|
}
|
|
|
|
if len(dest.data) > 0 {
|
|
for el := range dest.data {
|
|
delete(dest.data, el)
|
|
}
|
|
}
|
|
|
|
for el := range s1.data {
|
|
dest.data[el] = flag
|
|
}
|
|
|
|
return dest
|
|
}
|
|
|
|
func (s1 Set) Equal(s2 Set) bool {
|
|
if s1.id == s2.id {
|
|
return true
|
|
} else if len(s1.data) != len(s2.data) {
|
|
return false
|
|
}
|
|
|
|
for el := range s1.data {
|
|
if _, ok := s2.data[el]; !ok {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func (dest Set) Union(s1, s2 Set) Set {
|
|
if s1.id == s2.id {
|
|
return s1.CopyTo(dest)
|
|
}
|
|
|
|
if s1.id != dest.id && s2.id != dest.id {
|
|
dest.Clear()
|
|
}
|
|
|
|
if dest.id != s1.id {
|
|
for el := range s1.data {
|
|
dest.data[el] = flag
|
|
}
|
|
}
|
|
|
|
if dest.id != s2.id {
|
|
for el := range s2.data {
|
|
dest.data[el] = flag
|
|
}
|
|
}
|
|
|
|
return dest
|
|
}
|
|
|
|
func (dest Set) Intersection(s1, s2 Set) Set {
|
|
var swap Set
|
|
|
|
if s1.id == s2.id {
|
|
return s1.CopyTo(dest)
|
|
} else if s1.id == dest.id {
|
|
swap = s2
|
|
} else if s2.id == dest.id {
|
|
swap = s1
|
|
} else {
|
|
dest.Clear()
|
|
|
|
if len(s1.data) > len(s2.data) {
|
|
s1, s2 = s2, s1
|
|
}
|
|
for el := range s1.data {
|
|
if _, ok := s2.data[el]; ok {
|
|
dest.data[el] = flag
|
|
}
|
|
}
|
|
|
|
return dest
|
|
}
|
|
|
|
for el := range dest.data {
|
|
if _, ok := swap.data[el]; !ok {
|
|
delete(dest.data, el)
|
|
}
|
|
}
|
|
|
|
return dest
|
|
}
|
|
|
|
func (dest Set) Diff(s1, s2 Set) Set {
|
|
if s1.id == s2.id {
|
|
return dest.Clear()
|
|
} else if s2.id == dest.id {
|
|
tmp := NewSet()
|
|
|
|
return s1.Diff(tmp, s2).CopyTo(dest)
|
|
} else if s1.id == dest.id {
|
|
for el := range dest.data {
|
|
if _, ok := s2.data[el]; ok {
|
|
delete(dest.data, el)
|
|
}
|
|
}
|
|
|
|
} else {
|
|
dest.Clear()
|
|
for el := range s1.data {
|
|
if _, ok := s2.data[el]; !ok {
|
|
dest.data[el] = flag
|
|
}
|
|
}
|
|
}
|
|
|
|
return dest
|
|
}
|
|
|
|
// Are Add/Remove necessary?
|
|
func (s1 Set) Add(element interface{}) {
|
|
s1.data[element] = flag
|
|
}
|
|
|
|
func (s1 Set) Remove(element interface{}) {
|
|
delete(s1.data, element)
|
|
}
|