123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507 |
- // Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
- //
- // This Source Code Form is subject to the terms of the MIT License.
- // If a copy of the MIT was not distributed with this file,
- // You can obtain one at https://github.com/gogf/gf.
- // Package gset provides kinds of concurrent-safe/unsafe sets.
- package gset
- import (
- "bytes"
- "github.com/gogf/gf/internal/json"
- "github.com/gogf/gf/internal/rwmutex"
- "github.com/gogf/gf/text/gstr"
- "github.com/gogf/gf/util/gconv"
- )
- type Set struct {
- mu rwmutex.RWMutex
- data map[interface{}]struct{}
- }
- // New create and returns a new set, which contains un-repeated items.
- // The parameter <safe> is used to specify whether using set in concurrent-safety,
- // which is false in default.
- func New(safe ...bool) *Set {
- return NewSet(safe...)
- }
- // See New.
- func NewSet(safe ...bool) *Set {
- return &Set{
- data: make(map[interface{}]struct{}),
- mu: rwmutex.Create(safe...),
- }
- }
- // NewFrom returns a new set from <items>.
- // Parameter <items> can be either a variable of any type, or a slice.
- func NewFrom(items interface{}, safe ...bool) *Set {
- m := make(map[interface{}]struct{})
- for _, v := range gconv.Interfaces(items) {
- m[v] = struct{}{}
- }
- return &Set{
- data: m,
- mu: rwmutex.Create(safe...),
- }
- }
- // Iterator iterates the set readonly with given callback function <f>,
- // if <f> returns true then continue iterating; or false to stop.
- func (set *Set) Iterator(f func(v interface{}) bool) {
- set.mu.RLock()
- defer set.mu.RUnlock()
- for k, _ := range set.data {
- if !f(k) {
- break
- }
- }
- }
- // Add adds one or multiple items to the set.
- func (set *Set) Add(items ...interface{}) {
- set.mu.Lock()
- if set.data == nil {
- set.data = make(map[interface{}]struct{})
- }
- for _, v := range items {
- set.data[v] = struct{}{}
- }
- set.mu.Unlock()
- }
- // AddIfNotExist checks whether item exists in the set,
- // it adds the item to set and returns true if it does not exists in the set,
- // or else it does nothing and returns false.
- //
- // Note that, if <item> is nil, it does nothing and returns false.
- func (set *Set) AddIfNotExist(item interface{}) bool {
- if item == nil {
- return false
- }
- if !set.Contains(item) {
- set.mu.Lock()
- defer set.mu.Unlock()
- if set.data == nil {
- set.data = make(map[interface{}]struct{})
- }
- if _, ok := set.data[item]; !ok {
- set.data[item] = struct{}{}
- return true
- }
- }
- return false
- }
- // AddIfNotExistFunc checks whether item exists in the set,
- // it adds the item to set and returns true if it does not exists in the set and
- // function <f> returns true, or else it does nothing and returns false.
- //
- // Note that, if <item> is nil, it does nothing and returns false. The function <f>
- // is executed without writing lock.
- func (set *Set) AddIfNotExistFunc(item interface{}, f func() bool) bool {
- if item == nil {
- return false
- }
- if !set.Contains(item) {
- if f() {
- set.mu.Lock()
- defer set.mu.Unlock()
- if set.data == nil {
- set.data = make(map[interface{}]struct{})
- }
- if _, ok := set.data[item]; !ok {
- set.data[item] = struct{}{}
- return true
- }
- }
- }
- return false
- }
- // AddIfNotExistFunc checks whether item exists in the set,
- // it adds the item to set and returns true if it does not exists in the set and
- // function <f> returns true, or else it does nothing and returns false.
- //
- // Note that, if <item> is nil, it does nothing and returns false. The function <f>
- // is executed within writing lock.
- func (set *Set) AddIfNotExistFuncLock(item interface{}, f func() bool) bool {
- if item == nil {
- return false
- }
- if !set.Contains(item) {
- set.mu.Lock()
- defer set.mu.Unlock()
- if set.data == nil {
- set.data = make(map[interface{}]struct{})
- }
- if f() {
- if _, ok := set.data[item]; !ok {
- set.data[item] = struct{}{}
- return true
- }
- }
- }
- return false
- }
- // Contains checks whether the set contains <item>.
- func (set *Set) Contains(item interface{}) bool {
- var ok bool
- set.mu.RLock()
- if set.data != nil {
- _, ok = set.data[item]
- }
- set.mu.RUnlock()
- return ok
- }
- // Remove deletes <item> from set.
- func (set *Set) Remove(item interface{}) {
- set.mu.Lock()
- if set.data != nil {
- delete(set.data, item)
- }
- set.mu.Unlock()
- }
- // Size returns the size of the set.
- func (set *Set) Size() int {
- set.mu.RLock()
- l := len(set.data)
- set.mu.RUnlock()
- return l
- }
- // Clear deletes all items of the set.
- func (set *Set) Clear() {
- set.mu.Lock()
- set.data = make(map[interface{}]struct{})
- set.mu.Unlock()
- }
- // Slice returns the a of items of the set as slice.
- func (set *Set) Slice() []interface{} {
- set.mu.RLock()
- var (
- i = 0
- ret = make([]interface{}, len(set.data))
- )
- for item := range set.data {
- ret[i] = item
- i++
- }
- set.mu.RUnlock()
- return ret
- }
- // Join joins items with a string <glue>.
- func (set *Set) Join(glue string) string {
- set.mu.RLock()
- defer set.mu.RUnlock()
- if len(set.data) == 0 {
- return ""
- }
- var (
- l = len(set.data)
- i = 0
- buffer = bytes.NewBuffer(nil)
- )
- for k, _ := range set.data {
- buffer.WriteString(gconv.String(k))
- if i != l-1 {
- buffer.WriteString(glue)
- }
- i++
- }
- return buffer.String()
- }
- // String returns items as a string, which implements like json.Marshal does.
- func (set *Set) String() string {
- set.mu.RLock()
- defer set.mu.RUnlock()
- var (
- s = ""
- l = len(set.data)
- i = 0
- buffer = bytes.NewBuffer(nil)
- )
- buffer.WriteByte('[')
- for k, _ := range set.data {
- s = gconv.String(k)
- if gstr.IsNumeric(s) {
- buffer.WriteString(s)
- } else {
- buffer.WriteString(`"` + gstr.QuoteMeta(s, `"\`) + `"`)
- }
- if i != l-1 {
- buffer.WriteByte(',')
- }
- i++
- }
- buffer.WriteByte(']')
- return buffer.String()
- }
- // LockFunc locks writing with callback function <f>.
- func (set *Set) LockFunc(f func(m map[interface{}]struct{})) {
- set.mu.Lock()
- defer set.mu.Unlock()
- f(set.data)
- }
- // RLockFunc locks reading with callback function <f>.
- func (set *Set) RLockFunc(f func(m map[interface{}]struct{})) {
- set.mu.RLock()
- defer set.mu.RUnlock()
- f(set.data)
- }
- // Equal checks whether the two sets equal.
- func (set *Set) Equal(other *Set) bool {
- if set == other {
- return true
- }
- set.mu.RLock()
- defer set.mu.RUnlock()
- other.mu.RLock()
- defer other.mu.RUnlock()
- if len(set.data) != len(other.data) {
- return false
- }
- for key := range set.data {
- if _, ok := other.data[key]; !ok {
- return false
- }
- }
- return true
- }
- // IsSubsetOf checks whether the current set is a sub-set of <other>.
- func (set *Set) IsSubsetOf(other *Set) bool {
- if set == other {
- return true
- }
- set.mu.RLock()
- defer set.mu.RUnlock()
- other.mu.RLock()
- defer other.mu.RUnlock()
- for key := range set.data {
- if _, ok := other.data[key]; !ok {
- return false
- }
- }
- return true
- }
- // Union returns a new set which is the union of <set> and <others>.
- // Which means, all the items in <newSet> are in <set> or in <others>.
- func (set *Set) Union(others ...*Set) (newSet *Set) {
- newSet = NewSet()
- set.mu.RLock()
- defer set.mu.RUnlock()
- for _, other := range others {
- if set != other {
- other.mu.RLock()
- }
- for k, v := range set.data {
- newSet.data[k] = v
- }
- if set != other {
- for k, v := range other.data {
- newSet.data[k] = v
- }
- }
- if set != other {
- other.mu.RUnlock()
- }
- }
- return
- }
- // Diff returns a new set which is the difference set from <set> to <others>.
- // Which means, all the items in <newSet> are in <set> but not in <others>.
- func (set *Set) Diff(others ...*Set) (newSet *Set) {
- newSet = NewSet()
- set.mu.RLock()
- defer set.mu.RUnlock()
- for _, other := range others {
- if set == other {
- continue
- }
- other.mu.RLock()
- for k, v := range set.data {
- if _, ok := other.data[k]; !ok {
- newSet.data[k] = v
- }
- }
- other.mu.RUnlock()
- }
- return
- }
- // Intersect returns a new set which is the intersection from <set> to <others>.
- // Which means, all the items in <newSet> are in <set> and also in <others>.
- func (set *Set) Intersect(others ...*Set) (newSet *Set) {
- newSet = NewSet()
- set.mu.RLock()
- defer set.mu.RUnlock()
- for _, other := range others {
- if set != other {
- other.mu.RLock()
- }
- for k, v := range set.data {
- if _, ok := other.data[k]; ok {
- newSet.data[k] = v
- }
- }
- if set != other {
- other.mu.RUnlock()
- }
- }
- return
- }
- // Complement returns a new set which is the complement from <set> to <full>.
- // Which means, all the items in <newSet> are in <full> and not in <set>.
- //
- // It returns the difference between <full> and <set>
- // if the given set <full> is not the full set of <set>.
- func (set *Set) Complement(full *Set) (newSet *Set) {
- newSet = NewSet()
- set.mu.RLock()
- defer set.mu.RUnlock()
- if set != full {
- full.mu.RLock()
- defer full.mu.RUnlock()
- }
- for k, v := range full.data {
- if _, ok := set.data[k]; !ok {
- newSet.data[k] = v
- }
- }
- return
- }
- // Merge adds items from <others> sets into <set>.
- func (set *Set) Merge(others ...*Set) *Set {
- set.mu.Lock()
- defer set.mu.Unlock()
- for _, other := range others {
- if set != other {
- other.mu.RLock()
- }
- for k, v := range other.data {
- set.data[k] = v
- }
- if set != other {
- other.mu.RUnlock()
- }
- }
- return set
- }
- // Sum sums items.
- // Note: The items should be converted to int type,
- // or you'd get a result that you unexpected.
- func (set *Set) Sum() (sum int) {
- set.mu.RLock()
- defer set.mu.RUnlock()
- for k, _ := range set.data {
- sum += gconv.Int(k)
- }
- return
- }
- // Pops randomly pops an item from set.
- func (set *Set) Pop() interface{} {
- set.mu.Lock()
- defer set.mu.Unlock()
- for k, _ := range set.data {
- delete(set.data, k)
- return k
- }
- return nil
- }
- // Pops randomly pops <size> items from set.
- // It returns all items if size == -1.
- func (set *Set) Pops(size int) []interface{} {
- set.mu.Lock()
- defer set.mu.Unlock()
- if size > len(set.data) || size == -1 {
- size = len(set.data)
- }
- if size <= 0 {
- return nil
- }
- index := 0
- array := make([]interface{}, size)
- for k, _ := range set.data {
- delete(set.data, k)
- array[index] = k
- index++
- if index == size {
- break
- }
- }
- return array
- }
- // Walk applies a user supplied function <f> to every item of set.
- func (set *Set) Walk(f func(item interface{}) interface{}) *Set {
- set.mu.Lock()
- defer set.mu.Unlock()
- m := make(map[interface{}]struct{}, len(set.data))
- for k, v := range set.data {
- m[f(k)] = v
- }
- set.data = m
- return set
- }
- // MarshalJSON implements the interface MarshalJSON for json.Marshal.
- func (set *Set) MarshalJSON() ([]byte, error) {
- return json.Marshal(set.Slice())
- }
- // UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
- func (set *Set) UnmarshalJSON(b []byte) error {
- set.mu.Lock()
- defer set.mu.Unlock()
- if set.data == nil {
- set.data = make(map[interface{}]struct{})
- }
- var array []interface{}
- if err := json.Unmarshal(b, &array); err != nil {
- return err
- }
- for _, v := range array {
- set.data[v] = struct{}{}
- }
- return nil
- }
- // UnmarshalValue is an interface implement which sets any type of value for set.
- func (set *Set) UnmarshalValue(value interface{}) (err error) {
- set.mu.Lock()
- defer set.mu.Unlock()
- if set.data == nil {
- set.data = make(map[interface{}]struct{})
- }
- var array []interface{}
- switch value.(type) {
- case string, []byte:
- err = json.Unmarshal(gconv.Bytes(value), &array)
- default:
- array = gconv.SliceAny(value)
- }
- for _, v := range array {
- set.data[v] = struct{}{}
- }
- return
- }
|