mirror of
https://github.com/dolthub/dolt.git
synced 2026-04-22 11:29:06 -05:00
212 lines
4.9 KiB
Go
212 lines
4.9 KiB
Go
// Copyright 2019 Dolthub, Inc.
|
|
//
|
|
// Licensed 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 set
|
|
|
|
import (
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/dolthub/dolt/go/libraries/utils/funcitr"
|
|
)
|
|
|
|
// StrSet is a simple set implementation providing standard set operations for strings.
|
|
type StrSet struct {
|
|
items map[string]bool
|
|
caseSensitive bool
|
|
}
|
|
|
|
// NewStrSet creates a set from a list of strings
|
|
func newStrSet(items []string, caseSensitive bool) *StrSet {
|
|
s := &StrSet{make(map[string]bool, len(items)), caseSensitive}
|
|
|
|
for _, item := range items {
|
|
s.items[item] = true
|
|
}
|
|
|
|
return s
|
|
}
|
|
|
|
func NewEmptyStrSet() *StrSet {
|
|
return newStrSet(nil, true)
|
|
}
|
|
|
|
func NewStrSet(items []string) *StrSet {
|
|
return newStrSet(items, true)
|
|
}
|
|
|
|
func NewCaseInsensitiveStrSet(items []string) *StrSet {
|
|
lwrStrs := funcitr.MapStrings(items, strings.ToLower)
|
|
return newStrSet(lwrStrs, false)
|
|
}
|
|
|
|
// Add adds new items to the set
|
|
func (s *StrSet) Add(items ...string) {
|
|
for _, item := range items {
|
|
if !s.caseSensitive {
|
|
item = strings.ToLower(item)
|
|
}
|
|
s.items[item] = true
|
|
}
|
|
}
|
|
|
|
// Remove removes existing items from the set
|
|
func (s *StrSet) Remove(items ...string) {
|
|
for _, item := range items {
|
|
if !s.caseSensitive {
|
|
item = strings.ToLower(item)
|
|
}
|
|
|
|
delete(s.items, item)
|
|
}
|
|
}
|
|
|
|
// Contains returns true if the item being checked is already in the set.
|
|
func (s *StrSet) Contains(item string) bool {
|
|
if s == nil {
|
|
return false
|
|
}
|
|
if !s.caseSensitive {
|
|
item = strings.ToLower(item)
|
|
}
|
|
|
|
_, present := s.items[item]
|
|
return present
|
|
}
|
|
|
|
// ContainsAll returns true if all the items being checked are already in the set.
|
|
func (s *StrSet) ContainsAll(items []string) bool {
|
|
if s == nil {
|
|
return false
|
|
}
|
|
if !s.caseSensitive {
|
|
items = funcitr.MapStrings(items, strings.ToLower)
|
|
}
|
|
|
|
for _, item := range items {
|
|
if _, present := s.items[item]; !present {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func (s *StrSet) Equals(other *StrSet) bool {
|
|
// two string sets can be equal even if one is sensitive and the other is insensitive as long al the items are a
|
|
// case sensitive match.
|
|
ss := s.AsSlice()
|
|
os := other.AsSlice()
|
|
sort.Strings(ss)
|
|
sort.Strings(os)
|
|
|
|
if len(ss) != len(os) {
|
|
return false
|
|
}
|
|
|
|
for i := range ss {
|
|
if ss[i] != os[i] {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// Size returns the number of unique elements in the set
|
|
func (s *StrSet) Size() int {
|
|
if s == nil {
|
|
return 0
|
|
}
|
|
return len(s.items)
|
|
}
|
|
|
|
// AsSlice converts the set to a slice of strings. If this is an insensitive set the resulting slice will be lowercase
|
|
// regardless of the case that was used when adding the string to the set.
|
|
func (s *StrSet) AsSlice() []string {
|
|
if s == nil {
|
|
return nil
|
|
}
|
|
size := len(s.items)
|
|
sl := make([]string, size)
|
|
|
|
i := 0
|
|
for k := range s.items {
|
|
sl[i] = k
|
|
i++
|
|
}
|
|
|
|
return sl
|
|
}
|
|
|
|
// AsSortedSlice converts the set to a slice of strings. If this is an insensitive set the resulting slice will be lowercase
|
|
// regardless of the case that was used when adding the string to the set. The slice is sorted in ascending order.
|
|
func (s *StrSet) AsSortedSlice() []string {
|
|
if s == nil {
|
|
return nil
|
|
}
|
|
slice := s.AsSlice()
|
|
sort.Slice(slice, func(i, j int) bool {
|
|
return slice[i] < slice[j]
|
|
})
|
|
return slice
|
|
}
|
|
|
|
// Iterate accepts a callback which will be called once for each element in the set until all items have been
|
|
// exhausted or callback returns false.
|
|
func (s *StrSet) Iterate(callBack func(string) (cont bool)) {
|
|
if s == nil {
|
|
return
|
|
}
|
|
for k := range s.items {
|
|
if !callBack(k) {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
// LeftIntersectionRight takes a slice of strings and returns a slice of strings containing the intersection with the
|
|
// set, and a slice of strings for the ones missing from the set.
|
|
func (s *StrSet) LeftIntersectionRight(other *StrSet) (left *StrSet, intersection *StrSet, right *StrSet) {
|
|
left = NewStrSet(nil)
|
|
intersection = NewStrSet(nil)
|
|
right = NewStrSet(nil)
|
|
|
|
for os := range other.items {
|
|
if s.Contains(os) {
|
|
intersection.Add(os)
|
|
} else {
|
|
right.Add(os)
|
|
}
|
|
}
|
|
for ss := range s.items {
|
|
if !intersection.Contains(ss) {
|
|
left.Add(ss)
|
|
}
|
|
}
|
|
|
|
return left, intersection, right
|
|
}
|
|
|
|
// JoinStrings returns the sorted values from the set concatenated with a given sep
|
|
func (s *StrSet) JoinStrings(sep string) string {
|
|
strSl := s.AsSlice()
|
|
sort.Strings(strSl)
|
|
return strings.Join(strSl, sep)
|
|
}
|
|
|
|
// Unique will return a slice of unique strings given an input slice
|
|
func Unique(strs []string) []string {
|
|
return NewStrSet(strs).AsSlice()
|
|
}
|