parent
							
								
									1b0baed761
								
							
						
					
					
						commit
						ea97eca24d
					
				@ -0,0 +1,3 @@
 | 
			
		||||
module git.blauwelle.com/go/crate/mapset
 | 
			
		||||
 | 
			
		||||
go 1.20
 | 
			
		||||
@ -0,0 +1,294 @@
 | 
			
		||||
package mapset
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// New 返回 [MapSet]
 | 
			
		||||
func New[T comparable](keys ...T) MapSet[T] {
 | 
			
		||||
	s := make(MapSet[T], len(keys))
 | 
			
		||||
	s.AddMany(keys...)
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MapSet 是集合的范型实现
 | 
			
		||||
type MapSet[T comparable] map[T]struct{}
 | 
			
		||||
 | 
			
		||||
// Cardinality 返回集合的元素个数
 | 
			
		||||
func (s MapSet[T]) Cardinality() int {
 | 
			
		||||
	return len(s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddOne 添加元素到集合
 | 
			
		||||
func (s MapSet[T]) AddOne(key T) {
 | 
			
		||||
	s[key] = struct{}{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddOneOk 添加元素到集合并返回是否添加成功
 | 
			
		||||
func (s MapSet[T]) AddOneOk(key T) bool {
 | 
			
		||||
	size := len(s)
 | 
			
		||||
	s[key] = struct{}{}
 | 
			
		||||
	return len(s) > size
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddMany 添加多个元素到集合
 | 
			
		||||
func (s MapSet[T]) AddMany(keys ...T) {
 | 
			
		||||
	for _, key := range keys {
 | 
			
		||||
		s[key] = struct{}{}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddManyOk 添加多个元素到集合并返回添加成功的个数
 | 
			
		||||
func (s MapSet[T]) AddManyOk(keys ...T) int {
 | 
			
		||||
	size := len(s)
 | 
			
		||||
	for _, key := range keys {
 | 
			
		||||
		s[key] = struct{}{}
 | 
			
		||||
	}
 | 
			
		||||
	return len(s) - size
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeleteOne 从集合中删除元素
 | 
			
		||||
func (s MapSet[T]) DeleteOne(key T) {
 | 
			
		||||
	delete(s, key)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeleteOneOk 从集合中删除元素并返回是否删除成功
 | 
			
		||||
func (s MapSet[T]) DeleteOneOk(key T) bool {
 | 
			
		||||
	size := len(s)
 | 
			
		||||
	delete(s, key)
 | 
			
		||||
	return size > len(s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeleteMany 从集合删除多个元素
 | 
			
		||||
func (s MapSet[T]) DeleteMany(keys ...T) {
 | 
			
		||||
	for _, key := range keys {
 | 
			
		||||
		delete(s, key)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeleteManyOk 从集合删除多个元素并返回成功删除的个数
 | 
			
		||||
func (s MapSet[T]) DeleteManyOk(keys ...T) int {
 | 
			
		||||
	size := len(s)
 | 
			
		||||
	for _, key := range keys {
 | 
			
		||||
		delete(s, key)
 | 
			
		||||
	}
 | 
			
		||||
	return size - len(s)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// PopOne 从集合中删除1个元素, 并把被删除的元素返回
 | 
			
		||||
func (s MapSet[T]) PopOne() (key T, ok bool) {
 | 
			
		||||
	for k := range s {
 | 
			
		||||
		key, ok = k, true
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Clear 清空集合
 | 
			
		||||
func (s MapSet[T]) Clear() {
 | 
			
		||||
	for key := range s {
 | 
			
		||||
		delete(s, key)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Clone 返回集合的浅拷贝
 | 
			
		||||
func (s MapSet[T]) Clone() MapSet[T] {
 | 
			
		||||
	n := make(MapSet[T], len(s))
 | 
			
		||||
	for key := range s {
 | 
			
		||||
		n[key] = struct{}{}
 | 
			
		||||
	}
 | 
			
		||||
	return n
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsEmpty 判断集合是否为空
 | 
			
		||||
func (s MapSet[T]) IsEmpty() bool {
 | 
			
		||||
	return len(s) == 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Equal 判断集合是否和另1个集合相等
 | 
			
		||||
func (s MapSet[T]) Equal(o MapSet[T]) bool {
 | 
			
		||||
	if len(s) != len(o) {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	for key := range s {
 | 
			
		||||
		if _, exists := o[key]; !exists {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ContainsOne 判断集合是否包含1个元素
 | 
			
		||||
func (s MapSet[T]) ContainsOne(key T) bool {
 | 
			
		||||
	_, exists := s[key]
 | 
			
		||||
	return exists
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ContainsAll 判断集合是否包含全部元素
 | 
			
		||||
// 参数为空时返回 true
 | 
			
		||||
func (s MapSet[T]) ContainsAll(keys ...T) bool {
 | 
			
		||||
	for _, key := range keys {
 | 
			
		||||
		if _, exists := s[key]; !exists {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ContainsAny 判断集合是否包含任意元素
 | 
			
		||||
// 参数为空时返回 false
 | 
			
		||||
func (s MapSet[T]) ContainsAny(keys ...T) bool {
 | 
			
		||||
	for _, key := range keys {
 | 
			
		||||
		if _, exists := s[key]; exists {
 | 
			
		||||
			return true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsSubsetOf 判断集合是否是另1个集合的子集
 | 
			
		||||
func (s MapSet[T]) IsSubsetOf(o MapSet[T]) bool {
 | 
			
		||||
	if len(s) > len(o) {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	for key := range s {
 | 
			
		||||
		if _, exists := o[key]; !exists {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsProperSubsetOf 判断集合是否是另1个集合的真子集
 | 
			
		||||
func (s MapSet[T]) IsProperSubsetOf(o MapSet[T]) bool {
 | 
			
		||||
	if len(s) >= len(o) {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	for key := range s {
 | 
			
		||||
		if _, exists := o[key]; !exists {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Union 返回集合和另1个集合的并集
 | 
			
		||||
func (s MapSet[T]) Union(o MapSet[T]) MapSet[T] {
 | 
			
		||||
	r := make(MapSet[T], maxInt(len(s), len(o)))
 | 
			
		||||
	for key := range s {
 | 
			
		||||
		r[key] = struct{}{}
 | 
			
		||||
	}
 | 
			
		||||
	for key := range o {
 | 
			
		||||
		r[key] = struct{}{}
 | 
			
		||||
	}
 | 
			
		||||
	return r
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Intersection 返回集合和另1个集合的交集
 | 
			
		||||
func (s MapSet[T]) Intersection(o MapSet[T]) MapSet[T] {
 | 
			
		||||
	a, b := s, o
 | 
			
		||||
	if len(a) > len(b) {
 | 
			
		||||
		a, b = b, a
 | 
			
		||||
	}
 | 
			
		||||
	r := make(MapSet[T], len(a))
 | 
			
		||||
	for key := range a {
 | 
			
		||||
		if _, exists := b[key]; exists {
 | 
			
		||||
			r[key] = struct{}{}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return r
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Difference 返回集合和另1个集合的差集
 | 
			
		||||
func (s MapSet[T]) Difference(o MapSet[T]) MapSet[T] {
 | 
			
		||||
	r := make(MapSet[T])
 | 
			
		||||
	for key := range s {
 | 
			
		||||
		if _, exists := o[key]; !exists {
 | 
			
		||||
			r[key] = struct{}{}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return r
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SymmetricDifference 返回集合和另1个集合相互差集的并集
 | 
			
		||||
func (s MapSet[T]) SymmetricDifference(o MapSet[T]) MapSet[T] {
 | 
			
		||||
	r := make(MapSet[T])
 | 
			
		||||
	for key := range s {
 | 
			
		||||
		if _, exists := o[key]; !exists {
 | 
			
		||||
			r[key] = struct{}{}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	for key := range o {
 | 
			
		||||
		if _, exists := s[key]; !exists {
 | 
			
		||||
			r[key] = struct{}{}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return r
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ToSlice 把集合转换成切片
 | 
			
		||||
func (s MapSet[T]) ToSlice() []T {
 | 
			
		||||
	keys := make([]T, 0, len(s))
 | 
			
		||||
	for key := range s {
 | 
			
		||||
		keys = append(keys, key)
 | 
			
		||||
	}
 | 
			
		||||
	return keys
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ToAnySlice 把集合转换成 []any
 | 
			
		||||
func (s MapSet[T]) ToAnySlice() []any {
 | 
			
		||||
	keys := make([]any, 0, len(s))
 | 
			
		||||
	for key := range s {
 | 
			
		||||
		keys = append(keys, key)
 | 
			
		||||
	}
 | 
			
		||||
	return keys
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MarshalJSON 实现 [encoding/json.Marshaler]
 | 
			
		||||
func (s MapSet[T]) MarshalJSON() ([]byte, error) {
 | 
			
		||||
	return json.Marshal(s.ToSlice())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// UnmarshalJSON 实现 [encoding/json.Unmarshaler]
 | 
			
		||||
func (s *MapSet[T]) UnmarshalJSON(b []byte) error {
 | 
			
		||||
	var keys []T
 | 
			
		||||
	if *s == nil {
 | 
			
		||||
		*s = New[T]()
 | 
			
		||||
	}
 | 
			
		||||
	if err := json.Unmarshal(b, &keys); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	s.AddMany(keys...)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s MapSet[T]) String() string {
 | 
			
		||||
	size := s.Cardinality()
 | 
			
		||||
	if size > 64 {
 | 
			
		||||
		size = 64
 | 
			
		||||
	}
 | 
			
		||||
	keys := make([]string, 0, size)
 | 
			
		||||
	for key := range s {
 | 
			
		||||
		switch any(key).(type) {
 | 
			
		||||
		case string:
 | 
			
		||||
			keys = append(keys, fmt.Sprintf("%q", any(key)))
 | 
			
		||||
		default:
 | 
			
		||||
			keys = append(keys, fmt.Sprintf("%v", any(key)))
 | 
			
		||||
		}
 | 
			
		||||
		size--
 | 
			
		||||
		if size == 0 {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return "MapSet(" + strconv.Itoa(s.Cardinality()) + "){" + strings.Join(keys, ",") + "}"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func maxInt(a, b int) int {
 | 
			
		||||
	if a > b {
 | 
			
		||||
		return a
 | 
			
		||||
	}
 | 
			
		||||
	return b
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,523 @@
 | 
			
		||||
package mapset_test
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"git.blauwelle.com/go/crate/mapset"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func TestNewEmpty(t *testing.T) {
 | 
			
		||||
	s := mapset.New[int]()
 | 
			
		||||
	if size := s.Cardinality(); size != 0 {
 | 
			
		||||
		t.Fatalf("got %d, want cardinality 0", size)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestNew(t *testing.T) {
 | 
			
		||||
	s := mapset.New(1, 2, 3, 4, 5)
 | 
			
		||||
	if size := s.Cardinality(); size != 5 {
 | 
			
		||||
		t.Fatalf("got %d, want cardinality 5", size)
 | 
			
		||||
	}
 | 
			
		||||
	keys := make([]int, 0, 10)
 | 
			
		||||
	for i := 1; i < 6; i++ {
 | 
			
		||||
		keys = append(keys, i)
 | 
			
		||||
		if ok := s.ContainsOne(i); !ok {
 | 
			
		||||
			t.Fatalf("got false, want contains %d", i)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if ok := s.ContainsAll(keys...); !ok {
 | 
			
		||||
		t.Fatalf("want contains all of %v", keys)
 | 
			
		||||
	}
 | 
			
		||||
	for i := 6; i < 11; i++ {
 | 
			
		||||
		keys = append(keys, i)
 | 
			
		||||
		if ok := s.ContainsOne(i); ok {
 | 
			
		||||
			t.Fatalf("want do not contain %d", i)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if ok := s.ContainsAll(keys...); ok {
 | 
			
		||||
		t.Fatalf("want do not contain all of %v", keys)
 | 
			
		||||
	}
 | 
			
		||||
	if ok := s.ContainsAny(keys...); !ok {
 | 
			
		||||
		t.Fatalf("want contains any of %v", keys)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAddOne(t *testing.T) {
 | 
			
		||||
	s := mapset.New[int]()
 | 
			
		||||
	s.AddOne(1)
 | 
			
		||||
	if size := s.Cardinality(); size != 1 {
 | 
			
		||||
		t.Fatalf("got %d, want cardinality 1", size)
 | 
			
		||||
	}
 | 
			
		||||
	if ok := s.ContainsOne(1); !ok {
 | 
			
		||||
		t.Fatalf("want contains 1")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAddOneOk(t *testing.T) {
 | 
			
		||||
	t.Run("ok", func(t *testing.T) {
 | 
			
		||||
		s := mapset.New[int]()
 | 
			
		||||
		ok := s.AddOneOk(1)
 | 
			
		||||
		if size := s.Cardinality(); size != 1 {
 | 
			
		||||
			t.Fatalf("got %d, want cardinality 1", size)
 | 
			
		||||
		}
 | 
			
		||||
		if !ok {
 | 
			
		||||
			t.Fatalf("fail")
 | 
			
		||||
		}
 | 
			
		||||
		if ok := s.ContainsOne(1); !ok {
 | 
			
		||||
			t.Fatalf("want contains 1")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	t.Run("exists", func(t *testing.T) {
 | 
			
		||||
		s := mapset.New[int](1)
 | 
			
		||||
		ok := s.AddOneOk(1)
 | 
			
		||||
		if size := s.Cardinality(); size != 1 {
 | 
			
		||||
			t.Fatalf("got %d, want cardinality 1", size)
 | 
			
		||||
		}
 | 
			
		||||
		if ok {
 | 
			
		||||
			t.Fatalf("fail")
 | 
			
		||||
		}
 | 
			
		||||
		if ok := s.ContainsOne(1); !ok {
 | 
			
		||||
			t.Fatalf("want contains 1")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestAddManyOk(t *testing.T) {
 | 
			
		||||
	t.Run("ok", func(t *testing.T) {
 | 
			
		||||
		s := mapset.New[int]()
 | 
			
		||||
		n := s.AddManyOk(1, 2, 3)
 | 
			
		||||
		if n != 3 {
 | 
			
		||||
			t.Fatalf("fail")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	t.Run("exists", func(t *testing.T) {
 | 
			
		||||
		s := mapset.New(1, 2)
 | 
			
		||||
		n := s.AddManyOk(1, 2, 3, 4)
 | 
			
		||||
		if n != 2 {
 | 
			
		||||
			t.Fatalf("fail")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDeleteOneOk(t *testing.T) {
 | 
			
		||||
	t.Run("ok", func(t *testing.T) {
 | 
			
		||||
		s := mapset.New(1, 2, 3)
 | 
			
		||||
		ok := s.DeleteOneOk(1)
 | 
			
		||||
		if !ok {
 | 
			
		||||
			t.Fatalf("fail")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	t.Run("not_exists", func(t *testing.T) {
 | 
			
		||||
		s := mapset.New(1, 2, 3)
 | 
			
		||||
		ok := s.DeleteOneOk(4)
 | 
			
		||||
		if ok {
 | 
			
		||||
			t.Fatalf("faila")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDeleteManyOk(t *testing.T) {
 | 
			
		||||
	t.Run("ok", func(t *testing.T) {
 | 
			
		||||
		s := mapset.New(1, 2, 3)
 | 
			
		||||
		n := s.DeleteManyOk(1, 2, 3)
 | 
			
		||||
		if n != 3 {
 | 
			
		||||
			t.Fatalf("fail")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	t.Run("delete_more", func(t *testing.T) {
 | 
			
		||||
		s := mapset.New(1, 2, 3)
 | 
			
		||||
		n := s.DeleteManyOk(1, 2, 3, 4)
 | 
			
		||||
		if n != 3 {
 | 
			
		||||
			t.Fatalf("fail")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	t.Run("delete_partial", func(t *testing.T) {
 | 
			
		||||
		s := mapset.New(1, 2, 3)
 | 
			
		||||
		n := s.DeleteManyOk(1, 2, 4)
 | 
			
		||||
		if n != 2 {
 | 
			
		||||
			t.Fatalf("fail")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDelete(t *testing.T) {
 | 
			
		||||
	s := mapset.New(1)
 | 
			
		||||
	s.DeleteOne(1)
 | 
			
		||||
	if size := s.Cardinality(); size != 0 {
 | 
			
		||||
		t.Fatalf("got %d, want cardinality 0", size)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDeleteMany(t *testing.T) {
 | 
			
		||||
	s := mapset.New(1, 2, 3)
 | 
			
		||||
	s.DeleteMany(1, 3)
 | 
			
		||||
	if size := s.Cardinality(); size != 1 {
 | 
			
		||||
		t.Fatalf("got %d, want cardinality 1", size)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestContainsAny(t *testing.T) {
 | 
			
		||||
	s := mapset.New(1, 2, 3)
 | 
			
		||||
	if ok := s.ContainsAny(); ok {
 | 
			
		||||
		t.Fatalf("got true, should not contains empty")
 | 
			
		||||
	}
 | 
			
		||||
	if ok := s.ContainsAny(-1, -2); ok {
 | 
			
		||||
		t.Fatalf("got true, should not contains any of -1, -2")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestPopOne(t *testing.T) {
 | 
			
		||||
	s := mapset.New[int]()
 | 
			
		||||
	if _, ok := s.PopOne(); ok {
 | 
			
		||||
		t.Fatalf("should not pop any key")
 | 
			
		||||
	}
 | 
			
		||||
	s.AddMany(1, 2, 3)
 | 
			
		||||
	if key, ok := s.PopOne(); !ok {
 | 
			
		||||
		t.Fatalf("should pop 1 key")
 | 
			
		||||
	} else if key < 1 || key > 3 {
 | 
			
		||||
		t.Fatalf("wrong key")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestClear(t *testing.T) {
 | 
			
		||||
	s := mapset.New(1, 2, 3)
 | 
			
		||||
	s.Clear()
 | 
			
		||||
	if size := s.Cardinality(); size != 0 {
 | 
			
		||||
		t.Fatalf("got %d, want 0 cardinality after clean", size)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestClone(t *testing.T) {
 | 
			
		||||
	s := mapset.New(1, 2)
 | 
			
		||||
	c := s.Clone()
 | 
			
		||||
	if ok := s.Equal(c); !ok {
 | 
			
		||||
		t.Fatalf("got false, want equal")
 | 
			
		||||
	}
 | 
			
		||||
	s.AddOne(3)
 | 
			
		||||
	if size := c.Cardinality(); size != 2 {
 | 
			
		||||
		t.Fatalf("got %d, want 2", size)
 | 
			
		||||
	}
 | 
			
		||||
	if ok := s.Equal(c); ok {
 | 
			
		||||
		t.Fatalf("got true, want not equal")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestIsEmpty(t *testing.T) {
 | 
			
		||||
	t.Run("empty", func(t *testing.T) {
 | 
			
		||||
		s := mapset.New[int]()
 | 
			
		||||
		if ok := s.IsEmpty(); !ok {
 | 
			
		||||
			t.Fatalf("got false, want empty")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	t.Run("not_empty", func(t *testing.T) {
 | 
			
		||||
		s := mapset.New(1)
 | 
			
		||||
		if ok := s.IsEmpty(); ok {
 | 
			
		||||
			t.Fatalf("got true, want not empty")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestEqual(t *testing.T) {
 | 
			
		||||
	s := mapset.New(1, 2)
 | 
			
		||||
	c := mapset.New(1, 2)
 | 
			
		||||
	v := mapset.New(1, 2, 3)
 | 
			
		||||
	p := mapset.New(2, 3)
 | 
			
		||||
	t.Run("equal", func(t *testing.T) {
 | 
			
		||||
		if ok := s.Equal(c); !ok {
 | 
			
		||||
			t.Fatalf("got false, want equal")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	t.Run("not_equal_1", func(t *testing.T) {
 | 
			
		||||
		if ok := s.Equal(v); ok {
 | 
			
		||||
			t.Fatalf("got true, want not equal")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	t.Run("not_equal_2", func(t *testing.T) {
 | 
			
		||||
		if ok := s.Equal(p); ok {
 | 
			
		||||
			t.Fatalf("got true, want not equal")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestIsSubsetOf(t *testing.T) {
 | 
			
		||||
	s := mapset.New(1, 2)
 | 
			
		||||
	c := mapset.New(1, 2, 3)
 | 
			
		||||
	v := mapset.New(2, 3)
 | 
			
		||||
	e := mapset.New[int]()
 | 
			
		||||
	t.Run("is_subset_of_self", func(t *testing.T) {
 | 
			
		||||
		if ok := s.IsSubsetOf(s); !ok {
 | 
			
		||||
			t.Fatalf("fail")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	t.Run("is_subset", func(t *testing.T) {
 | 
			
		||||
		if ok := s.IsSubsetOf(c); !ok {
 | 
			
		||||
			t.Fatalf("fail")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	t.Run("not_subset_1", func(t *testing.T) {
 | 
			
		||||
		if ok := s.IsSubsetOf(v); ok {
 | 
			
		||||
			t.Fatalf("fail")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	t.Run("not_subset_2", func(t *testing.T) {
 | 
			
		||||
		if ok := c.IsSubsetOf(s); ok {
 | 
			
		||||
			t.Fatalf("fail")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	t.Run("empty_is_subset_of_empty", func(t *testing.T) {
 | 
			
		||||
		if ok := e.IsSubsetOf(e); !ok {
 | 
			
		||||
			t.Fatalf("fail")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	t.Run("empty_is_subset_of_other", func(t *testing.T) {
 | 
			
		||||
		if ok := e.IsSubsetOf(s); !ok {
 | 
			
		||||
			t.Fatalf("fail")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestIsProperSubsetOf(t *testing.T) {
 | 
			
		||||
	s := mapset.New(1, 2)
 | 
			
		||||
	c := mapset.New(1, 2, 3)
 | 
			
		||||
	v := mapset.New(2, 3)
 | 
			
		||||
	p := mapset.New(1, 3, 5, 7)
 | 
			
		||||
	t.Run("not_proper_subset_of_self", func(t *testing.T) {
 | 
			
		||||
		if ok := s.IsProperSubsetOf(s); ok {
 | 
			
		||||
			t.Fatalf("fail")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	t.Run("is_proper_subset", func(t *testing.T) {
 | 
			
		||||
		if ok := s.IsProperSubsetOf(c); !ok {
 | 
			
		||||
			t.Fatalf("fail")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	t.Run("not_proper_subset_1", func(t *testing.T) {
 | 
			
		||||
		if ok := s.IsProperSubsetOf(v); ok {
 | 
			
		||||
			t.Fatalf("fail")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	t.Run("not_proper_subset_2", func(t *testing.T) {
 | 
			
		||||
		if ok := c.IsProperSubsetOf(s); ok {
 | 
			
		||||
			t.Fatalf("fail")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	t.Run("not_proper_subset_3", func(t *testing.T) {
 | 
			
		||||
		if ok := s.IsProperSubsetOf(p); ok {
 | 
			
		||||
			t.Fatalf("fail")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestUnion(t *testing.T) {
 | 
			
		||||
	t.Run("union_1", func(t *testing.T) {
 | 
			
		||||
		s := mapset.New(1, 2)
 | 
			
		||||
		c := mapset.New(2, 3)
 | 
			
		||||
		u := mapset.New(1, 2, 3)
 | 
			
		||||
		if g := s.Union(c); !g.Equal(u) {
 | 
			
		||||
			t.Fatalf("fail")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	t.Run("union_2", func(t *testing.T) {
 | 
			
		||||
		s := mapset.New(1, 2, 5, 7)
 | 
			
		||||
		c := mapset.New(2, 3)
 | 
			
		||||
		u := mapset.New(1, 2, 3, 5, 7)
 | 
			
		||||
		if g := s.Union(c); !g.Equal(u) {
 | 
			
		||||
			t.Fatalf("fail")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestIntersection(t *testing.T) {
 | 
			
		||||
	t.Run("intersection_1", func(t *testing.T) {
 | 
			
		||||
		s := mapset.New(1, 2)
 | 
			
		||||
		c := mapset.New(2, 3)
 | 
			
		||||
		u := mapset.New(2)
 | 
			
		||||
		if g := s.Intersection(c); !g.Equal(u) {
 | 
			
		||||
			t.Fatalf("fail")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	t.Run("intersection_2", func(t *testing.T) {
 | 
			
		||||
		s := mapset.New(1, 2, 4)
 | 
			
		||||
		c := mapset.New(2, 3)
 | 
			
		||||
		u := mapset.New(2)
 | 
			
		||||
		if g := s.Intersection(c); !g.Equal(u) {
 | 
			
		||||
			t.Fatalf("fail")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDifference(t *testing.T) {
 | 
			
		||||
	s := mapset.New(1, 2, 3)
 | 
			
		||||
	c := mapset.New(1, 2)
 | 
			
		||||
	t.Run("diff_1", func(t *testing.T) {
 | 
			
		||||
		o := s.Difference(c)
 | 
			
		||||
		if !o.Equal(mapset.New(3)) {
 | 
			
		||||
			t.Fatalf("fail")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestSymmetricDifference(t *testing.T) {
 | 
			
		||||
	s := mapset.New(1, 2, 3)
 | 
			
		||||
	c := mapset.New(1, 2, 4)
 | 
			
		||||
	t.Run("diff_1", func(t *testing.T) {
 | 
			
		||||
		o := s.SymmetricDifference(c)
 | 
			
		||||
		if !o.Equal(mapset.New(3, 4)) {
 | 
			
		||||
			t.Fatalf("fail")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestToSlice(t *testing.T) {
 | 
			
		||||
	s := mapset.New(1, 2, 3)
 | 
			
		||||
	r := s.ToSlice()
 | 
			
		||||
	sort.Ints(r)
 | 
			
		||||
	if size := len(r); size != 3 {
 | 
			
		||||
		t.Fatalf("got %d, want 3", size)
 | 
			
		||||
	}
 | 
			
		||||
	if !([3]int(r) == [3]int{1, 2, 3}) {
 | 
			
		||||
		t.Fatalf("fail")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestToAnySlice(t *testing.T) {
 | 
			
		||||
	s := mapset.New(1, 2, 3)
 | 
			
		||||
	r := s.ToAnySlice()
 | 
			
		||||
	if size := len(r); size != 3 {
 | 
			
		||||
		t.Fatalf("got %d, want 3", size)
 | 
			
		||||
	}
 | 
			
		||||
	sort.Slice(r, func(i, j int) bool {
 | 
			
		||||
		return r[i].(int) < r[j].(int)
 | 
			
		||||
	})
 | 
			
		||||
	if !([3]any(r) == [3]any{1, 2, 3}) {
 | 
			
		||||
		t.Fatalf("fail")
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestString(t *testing.T) {
 | 
			
		||||
	t.Run("int", func(t *testing.T) {
 | 
			
		||||
		s := mapset.New(1, 2, 3)
 | 
			
		||||
		str := s.String()
 | 
			
		||||
		t.Log(str)
 | 
			
		||||
	})
 | 
			
		||||
	t.Run("int_large", func(t *testing.T) {
 | 
			
		||||
		s := mapset.New[int]()
 | 
			
		||||
		for i := 0; i < 80; i++ {
 | 
			
		||||
			s.AddOne(i)
 | 
			
		||||
		}
 | 
			
		||||
		str := s.String()
 | 
			
		||||
		t.Log(str)
 | 
			
		||||
	})
 | 
			
		||||
	t.Run("string", func(t *testing.T) {
 | 
			
		||||
		s := mapset.New("a", "aa,bb", `"cc"`)
 | 
			
		||||
		t.Log(s.String())
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestMarshalUnmarshal(t *testing.T) {
 | 
			
		||||
	t.Run("marshal", func(t *testing.T) {
 | 
			
		||||
		s := mapset.New(1)
 | 
			
		||||
		b, err := json.Marshal(s)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			t.Fatalf("err: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
		if string(b) != "[1]" {
 | 
			
		||||
			t.Fatalf("fail")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	t.Run("unmarshal", func(t *testing.T) {
 | 
			
		||||
		b := []byte(`[1, 2]`)
 | 
			
		||||
		var s mapset.MapSet[int]
 | 
			
		||||
		if err := json.Unmarshal(b, &s); err != nil {
 | 
			
		||||
			t.Fatalf("err: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
		if !s.Equal(mapset.New(1, 2)) {
 | 
			
		||||
			t.Fatalf("failed")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	t.Run("unmarshal_error", func(t *testing.T) {
 | 
			
		||||
		b := []byte(`1`)
 | 
			
		||||
		var s mapset.MapSet[int]
 | 
			
		||||
		if err := json.Unmarshal(b, &s); err == nil {
 | 
			
		||||
			t.Fatalf("fail")
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func BenchmarkAdd(b *testing.B) {
 | 
			
		||||
	size := 1024 * 1
 | 
			
		||||
	s := mapset.New[int]()
 | 
			
		||||
	keys := make([]int, size)
 | 
			
		||||
	for i := 0; i < size; i++ {
 | 
			
		||||
		s.AddOne(i)
 | 
			
		||||
		keys[i] = i
 | 
			
		||||
	}
 | 
			
		||||
	b.Run("addOne", func(b *testing.B) {
 | 
			
		||||
		for i := 0; i < b.N; i++ {
 | 
			
		||||
			for i := 0; i < size; i++ {
 | 
			
		||||
				s.AddOne(i)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	b.Run("addMany", func(b *testing.B) {
 | 
			
		||||
		for i := 0; i < b.N; i++ {
 | 
			
		||||
			for i := 0; i < size; i++ {
 | 
			
		||||
				keys[i] = i
 | 
			
		||||
			}
 | 
			
		||||
			s.AddMany(keys...)
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	b.Run("addManyPrepared", func(b *testing.B) {
 | 
			
		||||
		for i := 0; i < b.N; i++ {
 | 
			
		||||
			s.AddMany(keys...)
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func BenchmarkContains(b *testing.B) {
 | 
			
		||||
	s := mapset.New[int]()
 | 
			
		||||
	for i := 0; i < 1024; i++ {
 | 
			
		||||
		s.AddOne(i)
 | 
			
		||||
	}
 | 
			
		||||
	b.Run("containsAll_keyExists", func(b *testing.B) {
 | 
			
		||||
		for i := 0; i < b.N; i++ {
 | 
			
		||||
			s.ContainsAll(1)
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	b.Run("containsAll_keyNotExists", func(b *testing.B) {
 | 
			
		||||
		for i := 0; i < b.N; i++ {
 | 
			
		||||
			s.ContainsAll(-1)
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	b.Run("containsOne_keyExists", func(b *testing.B) {
 | 
			
		||||
		for i := 0; i < b.N; i++ {
 | 
			
		||||
			s.ContainsOne(1)
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	b.Run("containsOne_keyNotExists", func(b *testing.B) {
 | 
			
		||||
		for i := 0; i < b.N; i++ {
 | 
			
		||||
			s.ContainsOne(-1)
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func BenchmarkRaw(b *testing.B) {
 | 
			
		||||
	b.Run("raw-64", func(b *testing.B) {
 | 
			
		||||
		for i := 0; i < b.N; i++ {
 | 
			
		||||
			m := map[int]struct{}{}
 | 
			
		||||
			for j := 0; j < 64; j++ {
 | 
			
		||||
				m[j] = struct{}{}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	b.Run("mapset-64", func(b *testing.B) {
 | 
			
		||||
		for i := 0; i < b.N; i++ {
 | 
			
		||||
			s := mapset.New[int]()
 | 
			
		||||
			for j := 0; j < 64; j++ {
 | 
			
		||||
				s.AddOne(j)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
					Loading…
					
					
				
		Reference in New Issue