| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package sets |
| |
| import ( |
| "fmt" |
| ) |
| |
| import ( |
| "golang.org/x/exp/constraints" |
| ) |
| |
| import ( |
| "github.com/apache/dubbo-kubernetes/pkg/util/slices" |
| ) |
| |
| type Set[T comparable] map[T]struct{} |
| |
| type String = Set[string] |
| |
| // NewWithLength returns an empty Set with the given capacity. |
| // It's only a hint, not a limitation. |
| func NewWithLength[T comparable](l int) Set[T] { |
| return make(Set[T], l) |
| } |
| |
| // New creates a new Set with the given items. |
| func New[T comparable](items ...T) Set[T] { |
| s := NewWithLength[T](len(items)) |
| return s.InsertAll(items...) |
| } |
| |
| // Insert a single item to this Set. |
| func (s Set[T]) Insert(item T) Set[T] { |
| s[item] = struct{}{} |
| return s |
| } |
| |
| // InsertAll adds the items to this Set. |
| func (s Set[T]) InsertAll(items ...T) Set[T] { |
| for _, item := range items { |
| s[item] = struct{}{} |
| } |
| return s |
| } |
| |
| // Delete removes an item from the set. |
| func (s Set[T]) Delete(item T) Set[T] { |
| delete(s, item) |
| return s |
| } |
| |
| // DeleteAll removes items from the set. |
| func (s Set[T]) DeleteAll(items ...T) Set[T] { |
| for _, item := range items { |
| delete(s, item) |
| } |
| return s |
| } |
| |
| // Merge a set of objects that are in s2 into s |
| // For example: |
| // s = {a1, a2, a3} |
| // s2 = {a3, a4, a5} |
| // s.Merge(s2) = {a1, a2, a3, a4, a5} |
| func (s Set[T]) Merge(s2 Set[T]) Set[T] { |
| for item := range s2 { |
| s[item] = struct{}{} |
| } |
| |
| return s |
| } |
| |
| // Copy this set. |
| func (s Set[T]) Copy() Set[T] { |
| result := NewWithLength[T](s.Len()) |
| for key := range s { |
| result.Insert(key) |
| } |
| return result |
| } |
| |
| // Union returns a set of objects that are in s or s2 |
| // For example: |
| // s = {a1, a2, a3} |
| // s2 = {a1, a2, a4, a5} |
| // s.Union(s2) = s2.Union(s) = {a1, a2, a3, a4, a5} |
| func (s Set[T]) Union(s2 Set[T]) Set[T] { |
| result := s.Copy() |
| for key := range s2 { |
| result.Insert(key) |
| } |
| return result |
| } |
| |
| // Difference returns a set of objects that are not in s2 |
| // For example: |
| // s = {a1, a2, a3} |
| // s2 = {a1, a2, a4, a5} |
| // s.Difference(s2) = {a3} |
| // s2.Difference(s) = {a4, a5} |
| func (s Set[T]) Difference(s2 Set[T]) Set[T] { |
| result := New[T]() |
| for key := range s { |
| if !s2.Contains(key) { |
| result.Insert(key) |
| } |
| } |
| return result |
| } |
| |
| // DifferenceInPlace similar to Difference, but has better performance. |
| // Note: This function modifies s in place. |
| func (s Set[T]) DifferenceInPlace(s2 Set[T]) Set[T] { |
| for key := range s { |
| if s2.Contains(key) { |
| delete(s, key) |
| } |
| } |
| return s |
| } |
| |
| // Diff takes a pair of Sets, and returns the elements that occur only on the left and right set. |
| func (s Set[T]) Diff(other Set[T]) (left []T, right []T) { |
| for k := range s { |
| if _, f := other[k]; !f { |
| left = append(left, k) |
| } |
| } |
| for k := range other { |
| if _, f := s[k]; !f { |
| right = append(right, k) |
| } |
| } |
| return |
| } |
| |
| // Intersection returns a set of objects that are common between s and s2 |
| // For example: |
| // s = {a1, a2, a3} |
| // s2 = {a1, a2, a4, a5} |
| // s.Intersection(s2) = {a1, a2} |
| func (s Set[T]) Intersection(s2 Set[T]) Set[T] { |
| result := New[T]() |
| for key := range s { |
| if s2.Contains(key) { |
| result.Insert(key) |
| } |
| } |
| return result |
| } |
| |
| // IntersectInPlace similar to Intersection, but has better performance. |
| // Note: This function modifies s in place. |
| func (s Set[T]) IntersectInPlace(s2 Set[T]) Set[T] { |
| for key := range s { |
| if !s2.Contains(key) { |
| delete(s, key) |
| } |
| } |
| return s |
| } |
| |
| // SupersetOf returns true if s contains all elements of s2 |
| // For example: |
| // s = {a1, a2, a3} |
| // s2 = {a1, a2, a3, a4, a5} |
| // s.SupersetOf(s2) = false |
| // s2.SupersetOf(s) = true |
| func (s Set[T]) SupersetOf(s2 Set[T]) bool { |
| if s2 == nil { |
| return true |
| } |
| if len(s2) > len(s) { |
| return false |
| } |
| for key := range s2 { |
| if !s.Contains(key) { |
| return false |
| } |
| } |
| return true |
| } |
| |
| // UnsortedList returns the slice with contents in random order. |
| func (s Set[T]) UnsortedList() []T { |
| res := make([]T, 0, s.Len()) |
| for key := range s { |
| res = append(res, key) |
| } |
| return res |
| } |
| |
| // SortedList returns the slice with contents sorted. |
| func SortedList[T constraints.Ordered](s Set[T]) []T { |
| res := s.UnsortedList() |
| slices.Sort(res) |
| return res |
| } |
| |
| // InsertContains inserts the item into the set and returns if it was already present. |
| // Example: |
| // |
| // if !set.InsertContains(item) { |
| // fmt.Println("Added item for the first time", item) |
| // } |
| func (s Set[T]) InsertContains(item T) bool { |
| if s.Contains(item) { |
| return true |
| } |
| s[item] = struct{}{} |
| return false |
| } |
| |
| // Contains returns whether the given item is in the set. |
| func (s Set[T]) Contains(item T) bool { |
| _, ok := s[item] |
| return ok |
| } |
| |
| // ContainsAll is alias of SupersetOf |
| // returns true if s contains all elements of s2 |
| func (s Set[T]) ContainsAll(s2 Set[T]) bool { |
| return s.SupersetOf(s2) |
| } |
| |
| // Equals checks whether the given set is equal to the current set. |
| func (s Set[T]) Equals(other Set[T]) bool { |
| if s.Len() != other.Len() { |
| return false |
| } |
| |
| for key := range s { |
| if !other.Contains(key) { |
| return false |
| } |
| } |
| |
| return true |
| } |
| |
| // Len returns the number of elements in this Set. |
| func (s Set[T]) Len() int { |
| return len(s) |
| } |
| |
| // IsEmpty indicates whether the set is the empty set. |
| func (s Set[T]) IsEmpty() bool { |
| return len(s) == 0 |
| } |
| |
| // String returns a string representation of the set. |
| // Be aware that the order of elements is random so the string representation may vary. |
| // Use it only for debugging and logging. |
| func (s Set[T]) String() string { |
| return fmt.Sprintf("%v", s.UnsortedList()) |
| } |
| |
| // InsertOrNew inserts t into the set if the set exists, or returns a new set with t if not. |
| // Works well with DeleteCleanupLast. |
| // Example: |
| // |
| // InsertOrNew(m, key, value) |
| func InsertOrNew[K comparable, T comparable](m map[K]Set[T], k K, v T) { |
| s, f := m[k] |
| if !f { |
| m[k] = New(v) |
| } else { |
| s.Insert(v) |
| } |
| } |
| |
| // DeleteCleanupLast removes an element from a set in a map of sets, deleting the key from the map if there are no keys left. |
| // Works well with InsertOrNew. |
| // Example: |
| // |
| // sets.DeleteCleanupLast(m, key, value) |
| func DeleteCleanupLast[K comparable, T comparable](m map[K]Set[T], k K, v T) { |
| if m[k].Delete(v).IsEmpty() { |
| delete(m, k) |
| } |
| } |