func (s *Set) Intersection(g *Set) *Set {
	both := NewEmptySet(len(s.values))
	for v := range s.values {
		if g.Contains(v) {
			both.Add(v)
		}
	}
	return both
}
Intersection returns the intersection a new set which represents the intersection of s and g.
package hare
import (
	"bytes"
	"fmt"
	"hash/fnv"
	"math"
	"sort"
	"github.com/spacemeshos/go-spacemesh/common/types"
)
type messageType byte
const (
	status   messageType = 0
	proposal messageType = 1
	commit   messageType = 2
	notify   messageType = 3
	pre      messageType = 10
)
const preRound uint32 = math.MaxUint32
const (
	statusRound uint32 = iota
	proposalRound
	commitRound
	notifyRound
)
const defaultSetSize = 200
func (mType messageType) String() string {
	switch mType {
	case status:
		return "Status"
	case proposal:
		return "Proposal"
	case commit:
		return "Commit"
	case notify:
		return "Notify"
	case pre:
		return "PreRound"
	default:
		return "Unknown message type"
	}
}
type Set struct {
	values    map[types.BlockID]struct{}
	id        uint32
	isIDValid bool
}
func NewDefaultEmptySet() *Set {
	return NewEmptySet(defaultSetSize)
}
func NewEmptySet(size int) *Set {
	s := &Set{}
	s.values = make(map[types.BlockID]struct{}, size)
	s.id = 0
	s.isIDValid = false
	return s
}
func NewSetFromValues(values ...types.BlockID) *Set {
	s := &Set{}
	s.values = make(map[types.BlockID]struct{}, len(values))
	for _, v := range values {
		s.Add(v)
	}
	s.id = 0
	s.isIDValid = false
	return s
}
func NewSet(data []types.BlockID) *Set {
	s := &Set{}
	s.isIDValid = false
	s.values = make(map[types.BlockID]struct{}, len(data))
	for _, bid := range data {
		s.values[bid] = struct{}{}
	}
	return s
}
func (s *Set) Clone() *Set {
	clone := NewEmptySet(len(s.values))
	for bid := range s.values {
		clone.Add(bid)
	}
	return clone
}
func (s *Set) Contains(id types.BlockID) bool {
	_, exist := s.values[id]
	return exist
}
func (s *Set) Add(id types.BlockID) {
	if _, exist := s.values[id]; exist {
		return
	}
	s.isIDValid = false
	s.values[id] = struct{}{}
}
func (s *Set) Remove(id types.BlockID) {
	if _, exist := s.values[id]; !exist {
		return
	}
	s.isIDValid = false
	delete(s.values, id)
}
func (s *Set) Equals(g *Set) bool {
	if len(s.values) != len(g.values) {
		return false
	}
	for bid := range s.values {
		if _, exist := g.values[bid]; !exist {
			return false
		}
	}
	return true
}
func (s *Set) ToSlice() []types.BlockID {
	keys := make([]types.BlockID, len(s.values))
	i := 0
	for k := range s.values {
		keys[i] = k
		i++
	}
	sort.Slice(keys, func(i, j int) bool { return bytes.Compare(keys[i].Bytes(), keys[j].Bytes()) == -1 })
	l := make([]types.BlockID, 0, len(s.values))
	for i := range keys {
		l = append(l, keys[i])
	}
	return l
}
func (s *Set) updateID() {
	keys := make([]types.BlockID, len(s.values))
	i := 0
	for k := range s.values {
		keys[i] = k
		i++
	}
	sort.Slice(keys, func(i, j int) bool { return bytes.Compare(keys[i].Bytes(), keys[j].Bytes()) == -1 })
	h := fnv.New32()
	for i := 0; i < len(keys); i++ {
		h.Write(keys[i].Bytes())
	}
	s.id = h.Sum32()
	s.isIDValid = true
}
func (s *Set) ID() uint32 {
	if !s.isIDValid {
		s.updateID()
	}
	return s.id
}
func (s *Set) String() string {
	b := new(bytes.Buffer)
	for v := range s.values {
		fmt.Fprintf(b, "%v,", v.String())
	}
	if b.Len() >= 1 {
		return b.String()[:b.Len()-1]
	}
	return b.String()
}
func (s *Set) IsSubSetOf(g *Set) bool {
	for v := range s.values {
		if !g.Contains(v) {
			return false
		}
	}
	return true
}