pkg/util/sets/set.go (179 lines of code) (raw):
/*
* 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)
}
}