| /* |
| Open Source Initiative OSI - The MIT License (MIT):Licensing |
| |
| The MIT License (MIT) |
| Copyright (c) 2013 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 ( |
| "bytes" |
| "encoding/json" |
| "fmt" |
| "reflect" |
| "strings" |
| ) |
| |
| type threadUnsafeSet map[interface{}]struct{} |
| |
| // An OrderedPair represents a 2-tuple of values. |
| type OrderedPair struct { |
| First interface{} |
| Second interface{} |
| } |
| |
| func newThreadUnsafeSet() threadUnsafeSet { |
| return make(threadUnsafeSet) |
| } |
| |
| // Equal says whether two 2-tuples contain the same values in the same order. |
| func (pair *OrderedPair) Equal(other OrderedPair) bool { |
| if pair.First == other.First && |
| pair.Second == other.Second { |
| return true |
| } |
| |
| return false |
| } |
| |
| func (set *threadUnsafeSet) Add(i interface{}) bool { |
| _, found := (*set)[i] |
| (*set)[i] = struct{}{} |
| return !found //False if it existed already |
| } |
| |
| func (set *threadUnsafeSet) Contains(i ...interface{}) bool { |
| for _, val := range i { |
| if _, ok := (*set)[val]; !ok { |
| return false |
| } |
| } |
| return true |
| } |
| |
| func (set *threadUnsafeSet) IsSubset(other Set) bool { |
| _ = other.(*threadUnsafeSet) |
| for elem := range *set { |
| if !other.Contains(elem) { |
| return false |
| } |
| } |
| return true |
| } |
| |
| func (set *threadUnsafeSet) IsProperSubset(other Set) bool { |
| return set.IsSubset(other) && !set.Equal(other) |
| } |
| |
| func (set *threadUnsafeSet) IsSuperset(other Set) bool { |
| return other.IsSubset(set) |
| } |
| |
| func (set *threadUnsafeSet) IsProperSuperset(other Set) bool { |
| return set.IsSuperset(other) && !set.Equal(other) |
| } |
| |
| func (set *threadUnsafeSet) Union(other Set) Set { |
| o := other.(*threadUnsafeSet) |
| |
| unionedSet := newThreadUnsafeSet() |
| |
| for elem := range *set { |
| unionedSet.Add(elem) |
| } |
| for elem := range *o { |
| unionedSet.Add(elem) |
| } |
| return &unionedSet |
| } |
| |
| func (set *threadUnsafeSet) Intersect(other Set) Set { |
| o := other.(*threadUnsafeSet) |
| |
| intersection := newThreadUnsafeSet() |
| // loop over smaller set |
| if set.Cardinality() < other.Cardinality() { |
| for elem := range *set { |
| if other.Contains(elem) { |
| intersection.Add(elem) |
| } |
| } |
| } else { |
| for elem := range *o { |
| if set.Contains(elem) { |
| intersection.Add(elem) |
| } |
| } |
| } |
| return &intersection |
| } |
| |
| func (set *threadUnsafeSet) Difference(other Set) Set { |
| _ = other.(*threadUnsafeSet) |
| |
| difference := newThreadUnsafeSet() |
| for elem := range *set { |
| if !other.Contains(elem) { |
| difference.Add(elem) |
| } |
| } |
| return &difference |
| } |
| |
| func (set *threadUnsafeSet) SymmetricDifference(other Set) Set { |
| _ = other.(*threadUnsafeSet) |
| |
| aDiff := set.Difference(other) |
| bDiff := other.Difference(set) |
| return aDiff.Union(bDiff) |
| } |
| |
| func (set *threadUnsafeSet) Clear() { |
| *set = newThreadUnsafeSet() |
| } |
| |
| func (set *threadUnsafeSet) Remove(i interface{}) { |
| delete(*set, i) |
| } |
| |
| func (set *threadUnsafeSet) Cardinality() int { |
| return len(*set) |
| } |
| |
| func (set *threadUnsafeSet) Each(cb func(interface{}) bool) { |
| for elem := range *set { |
| if cb(elem) { |
| break |
| } |
| } |
| } |
| |
| func (set *threadUnsafeSet) Iter() <-chan interface{} { |
| ch := make(chan interface{}) |
| go func() { |
| for elem := range *set { |
| ch <- elem |
| } |
| close(ch) |
| }() |
| |
| return ch |
| } |
| |
| func (set *threadUnsafeSet) Iterator() *Iterator { |
| iterator, ch, stopCh := newIterator() |
| |
| go func() { |
| L: |
| for elem := range *set { |
| select { |
| case <-stopCh: |
| break L |
| case ch <- elem: |
| } |
| } |
| close(ch) |
| }() |
| |
| return iterator |
| } |
| |
| func (set *threadUnsafeSet) Equal(other Set) bool { |
| _ = other.(*threadUnsafeSet) |
| |
| if set.Cardinality() != other.Cardinality() { |
| return false |
| } |
| for elem := range *set { |
| if !other.Contains(elem) { |
| return false |
| } |
| } |
| return true |
| } |
| |
| func (set *threadUnsafeSet) Clone() Set { |
| clonedSet := newThreadUnsafeSet() |
| for elem := range *set { |
| clonedSet.Add(elem) |
| } |
| return &clonedSet |
| } |
| |
| func (set *threadUnsafeSet) String() string { |
| items := make([]string, 0, len(*set)) |
| |
| for elem := range *set { |
| items = append(items, fmt.Sprintf("%v", elem)) |
| } |
| return fmt.Sprintf("Set{%s}", strings.Join(items, ", ")) |
| } |
| |
| // String outputs a 2-tuple in the form "(A, B)". |
| func (pair OrderedPair) String() string { |
| return fmt.Sprintf("(%v, %v)", pair.First, pair.Second) |
| } |
| |
| func (set *threadUnsafeSet) PowerSet() Set { |
| powSet := NewThreadUnsafeSet() |
| nullset := newThreadUnsafeSet() |
| powSet.Add(&nullset) |
| |
| for es := range *set { |
| u := newThreadUnsafeSet() |
| j := powSet.Iter() |
| for er := range j { |
| p := newThreadUnsafeSet() |
| if reflect.TypeOf(er).Name() == "" { |
| k := er.(*threadUnsafeSet) |
| for ek := range *(k) { |
| p.Add(ek) |
| } |
| } else { |
| p.Add(er) |
| } |
| p.Add(es) |
| u.Add(&p) |
| } |
| |
| powSet = powSet.Union(&u) |
| } |
| |
| return powSet |
| } |
| |
| func (set *threadUnsafeSet) CartesianProduct(other Set) Set { |
| o := other.(*threadUnsafeSet) |
| cartProduct := NewThreadUnsafeSet() |
| |
| for i := range *set { |
| for j := range *o { |
| elem := OrderedPair{First: i, Second: j} |
| cartProduct.Add(elem) |
| } |
| } |
| |
| return cartProduct |
| } |
| |
| func (set *threadUnsafeSet) ToSlice() []interface{} { |
| keys := make([]interface{}, 0, set.Cardinality()) |
| for elem := range *set { |
| keys = append(keys, elem) |
| } |
| |
| return keys |
| } |
| |
| // MarshalJSON creates a JSON array from the set, it marshals all elements |
| func (set *threadUnsafeSet) MarshalJSON() ([]byte, error) { |
| items := make([]string, 0, set.Cardinality()) |
| |
| for elem := range *set { |
| b, err := json.Marshal(elem) |
| if err != nil { |
| return nil, err |
| } |
| |
| items = append(items, string(b)) |
| } |
| |
| return []byte(fmt.Sprintf("[%s]", strings.Join(items, ","))), nil |
| } |
| |
| // UnmarshalJSON recreates a set from a JSON array, it only decodes |
| // primitive types. Numbers are decoded as json.Number. |
| func (set *threadUnsafeSet) UnmarshalJSON(b []byte) error { |
| var i []interface{} |
| |
| d := json.NewDecoder(bytes.NewReader(b)) |
| d.UseNumber() |
| err := d.Decode(&i) |
| if err != nil { |
| return err |
| } |
| |
| for _, v := range i { |
| switch t := v.(type) { |
| case []interface{}, map[string]interface{}: |
| continue |
| default: |
| set.Add(t) |
| } |
| } |
| |
| return nil |
| } |