go-pkg/set/set.go
2024-02-15 11:58:37 -07:00

142 lines
2.4 KiB
Go

package set
import (
"fmt"
"sort"
"strings"
"go.sour.is/pkg/math"
"golang.org/x/exp/maps"
)
type Set[T comparable] map[T]struct{}
func New[T comparable](items ...T) Set[T] {
s := make(map[T]struct{}, len(items))
for i := range items {
s[items[i]] = struct{}{}
}
return s
}
func (s Set[T]) Has(v T) bool {
_, ok := (s)[v]
return ok
}
func (s Set[T]) Add(items ...T) Set[T] {
for _, i := range items {
s[i] = struct{}{}
}
return s
}
func (s Set[T]) Delete(items ...T) Set[T] {
for _, i := range items {
delete(s, i)
}
return s
}
func (s Set[T]) Values() []T {
return maps.Keys(s)
}
func (s Set[T]) Equal(e Set[T]) bool {
for k := range s {
if _, ok := e[k]; !ok {
return false
}
}
for k := range e {
if _, ok := s[k]; !ok {
return false
}
}
return true
}
func (s Set[T]) String() string {
if s == nil {
return "set(<nil>)"
}
lis := make([]string, 0, len(s))
for k := range s {
lis = append(lis, fmt.Sprint(k))
}
var b strings.Builder
b.WriteString("set(")
b.WriteString(strings.Join(lis, ","))
b.WriteString(")")
return b.String()
}
type ordered interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 |
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
~float32 | ~float64
}
type BoundSet[T ordered] struct {
min, max T
s Set[T]
}
func NewBoundSet[T ordered](min, max T, items ...T) *BoundSet[T] {
b := &BoundSet[T]{
min: min,
max: max,
s: New[T](),
}
b.Add(items...)
return b
}
func (l *BoundSet[T]) Add(items ...T) *BoundSet[T] {
n := 0
for i := range items {
if items[i] >= l.min && items[i] <= l.max {
items[n] = items[i]
n++
}
}
l.s.Add(items[:n]...)
return l
}
func (l *BoundSet[T]) AddRange(min, max T) {
min = math.Max(min, l.min)
max = math.Min(max, l.max)
var lis []T
for ; min <= max; min++ {
lis = append(lis, min)
}
l.s.Add(lis...)
}
func (l *BoundSet[T]) Delete(items ...T) *BoundSet[T] {
n := 0
for i := range items {
if items[i] >= l.min && items[i] <= l.max {
items[n] = items[i]
n++
}
}
l.s.Delete(items[:n]...)
return l
}
func (l *BoundSet[T]) Has(v T) bool {
return l.s.Has(v)
}
func (l *BoundSet[T]) String() string {
lis := make([]string, len(l.s))
n := 0
for k := range l.s {
lis[n] = fmt.Sprint(k)
n++
}
sort.Strings(lis)
var b strings.Builder
b.WriteString("set(")
b.WriteString(strings.Join(lis, ","))
b.WriteString(")")
return b.String()
}