Files

138 lines
3.1 KiB
Go

// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package setmap
import (
"github.com/luxfi/math/set"
)
type Entry[K any, V comparable] struct {
Key K
Set set.Set[V]
}
// SetMap is a map to a set where all sets are non-overlapping.
type SetMap[K, V comparable] struct {
keyToSet map[K]set.Set[V]
valueToKey map[V]K
}
// New creates a new empty setmap.
func New[K, V comparable]() *SetMap[K, V] {
return &SetMap[K, V]{
keyToSet: make(map[K]set.Set[V]),
valueToKey: make(map[V]K),
}
}
// Put the new entry into the map. Removes and returns:
// * The existing entry for [key].
// * Existing entries where the set overlaps with the [set].
func (m *SetMap[K, V]) Put(key K, set set.Set[V]) []Entry[K, V] {
removed := m.DeleteOverlapping(set)
if removedSet, ok := m.DeleteKey(key); ok {
removed = append(removed, Entry[K, V]{
Key: key,
Set: removedSet,
})
}
m.keyToSet[key] = set
for val := range set {
m.valueToKey[val] = key
}
return removed
}
// GetKey that maps to the provided value.
func (m *SetMap[K, V]) GetKey(val V) (K, bool) {
key, ok := m.valueToKey[val]
return key, ok
}
// GetSet that is mapped to by the provided key.
func (m *SetMap[K, V]) GetSet(key K) (set.Set[V], bool) {
val, ok := m.keyToSet[key]
return val, ok
}
// HasKey returns true if [key] is in the map.
func (m *SetMap[K, _]) HasKey(key K) bool {
_, ok := m.keyToSet[key]
return ok
}
// HasValue returns true if [val] is in a set in the map.
func (m *SetMap[_, V]) HasValue(val V) bool {
_, ok := m.valueToKey[val]
return ok
}
// HasOverlap returns true if [set] overlaps with any of the sets in the map.
func (m *SetMap[_, V]) HasOverlap(set set.Set[V]) bool {
if set.Len() < len(m.valueToKey) {
for val := range set {
if _, ok := m.valueToKey[val]; ok {
return true
}
}
} else {
for val := range m.valueToKey {
if set.Contains(val) {
return true
}
}
}
return false
}
// DeleteKey removes [key] from the map and returns the set it mapped to.
func (m *SetMap[K, V]) DeleteKey(key K) (set.Set[V], bool) {
set, ok := m.keyToSet[key]
if !ok {
return nil, false
}
delete(m.keyToSet, key)
for val := range set {
delete(m.valueToKey, val)
}
return set, true
}
// DeleteValue removes and returns the entry that contained [val].
func (m *SetMap[K, V]) DeleteValue(val V) (K, set.Set[V], bool) {
key, ok := m.valueToKey[val]
if !ok {
return zero[K](), nil, false
}
set, _ := m.DeleteKey(key)
return key, set, true
}
// DeleteOverlapping removes and returns all the entries where the set overlaps
// with [set].
func (m *SetMap[K, V]) DeleteOverlapping(set set.Set[V]) []Entry[K, V] {
var removed []Entry[K, V]
for val := range set {
if k, removedSet, ok := m.DeleteValue(val); ok {
removed = append(removed, Entry[K, V]{
Key: k,
Set: removedSet,
})
}
}
return removed
}
// Len return the number of sets in the map.
func (m *SetMap[K, V]) Len() int {
return len(m.keyToSet)
}
// LenValues return the total number of values across all sets in the map.
func (m *SetMap[K, V]) LenValues() int {
return len(m.valueToKey)
}