improve Join/String functions for garray/gset/gmap; add AddIfNotExistFunc/AddIfNotExistFuncLock functions for gset

This commit is contained in:
John
2019-10-13 22:31:28 +08:00
parent 3ac0a66887
commit 69ee5375b9
12 changed files with 296 additions and 28 deletions

View File

@ -604,7 +604,7 @@ func (a *Array) CountValues() map[interface{}]int {
return m
}
// String returns current array as a string.
// String returns current array as a string, which implements like json.Marshal does.
func (a *Array) String() string {
a.mu.RLock()
defer a.mu.RUnlock()
@ -619,7 +619,7 @@ func (a *Array) String() string {
buffer.WriteString(`"` + gstr.QuoteMeta(s, `"\`) + `"`)
}
if k != len(a.array)-1 {
buffer.WriteString(",")
buffer.WriteByte(',')
}
}
buffer.WriteByte(']')

View File

@ -610,7 +610,7 @@ func (a *IntArray) CountValues() map[int]int {
return m
}
// String returns current array as a string.
// String returns current array as a string, which implements like json.Marshal does.
func (a *IntArray) String() string {
return "[" + a.Join(",") + "]"
}

View File

@ -611,7 +611,7 @@ func (a *StrArray) CountValues() map[string]int {
return m
}
// String returns current array as a string.
// String returns current array as a string, which implements like json.Marshal does.
func (a *StrArray) String() string {
a.mu.RLock()
defer a.mu.RUnlock()
@ -620,7 +620,7 @@ func (a *StrArray) String() string {
for k, v := range a.array {
buffer.WriteString(`"` + gstr.QuoteMeta(v, `"\`) + `"`)
if k != len(a.array)-1 {
buffer.WriteString(",")
buffer.WriteByte(',')
}
}
buffer.WriteByte(']')

View File

@ -549,7 +549,7 @@ func (a *SortedArray) CountValues() map[interface{}]int {
return m
}
// String returns current array as a string.
// String returns current array as a string, which implements like json.Marshal does.
func (a *SortedArray) String() string {
a.mu.RLock()
defer a.mu.RUnlock()
@ -564,7 +564,7 @@ func (a *SortedArray) String() string {
buffer.WriteString(`"` + gstr.QuoteMeta(s, `"\`) + `"`)
}
if k != len(a.array)-1 {
buffer.WriteString(",")
buffer.WriteByte(',')
}
}
buffer.WriteByte(']')

View File

@ -535,7 +535,7 @@ func (a *SortedIntArray) CountValues() map[int]int {
return m
}
// String returns current array as a string.
// String returns current array as a string, which implements like json.Marshal does.
func (a *SortedIntArray) String() string {
return "[" + a.Join(",") + "]"
}

View File

@ -536,7 +536,7 @@ func (a *SortedStrArray) CountValues() map[string]int {
return m
}
// String returns current array as a string.
// String returns current array as a string, which implements like json.Marshal does.
func (a *SortedStrArray) String() string {
a.mu.RLock()
defer a.mu.RUnlock()
@ -545,7 +545,7 @@ func (a *SortedStrArray) String() string {
for k, v := range a.array {
buffer.WriteString(`"` + gstr.QuoteMeta(v, `"\`) + `"`)
if k != len(a.array)-1 {
buffer.WriteString(",")
buffer.WriteByte(',')
}
}
buffer.WriteByte(']')

View File

@ -71,6 +71,48 @@ func (set *Set) Add(item ...interface{}) *Set {
return set
}
// AddIfNotExistFunc adds the returned value of callback function <f> to the set
// if <item> does not exit in the set.
func (set *Set) AddIfNotExistFunc(item interface{}, f func() interface{}) *Set {
if !set.Contains(item) {
set.doAddWithLockCheck(item, f())
}
return set
}
// AddIfNotExistFuncLock adds the returned value of callback function <f> to the set
// if <item> does not exit in the set.
//
// Note that the callback function <f> is executed in the mutex.Lock of the set.
func (set *Set) AddIfNotExistFuncLock(item interface{}, f func() interface{}) *Set {
if !set.Contains(item) {
set.doAddWithLockCheck(item, f)
}
return set
}
// doAddWithLockCheck checks whether item exists with mutex.Lock,
// if not exists, it adds item to the set or else just returns the existing value.
//
// If <value> is type of <func() interface {}>,
// it will be executed with mutex.Lock of the set,
// and its return value will be added to the set.
//
// It returns item successfully added..
func (set *Set) doAddWithLockCheck(item interface{}, value interface{}) interface{} {
set.mu.Lock()
defer set.mu.Unlock()
if _, ok := set.data[item]; !ok && value != nil {
if f, ok := value.(func() interface{}); ok {
item = f()
} else {
item = value
}
}
set.data[item] = struct{}{}
return item
}
// Contains checks whether the set contains <item>.
func (set *Set) Contains(item interface{}) bool {
set.mu.RLock()
@ -121,6 +163,24 @@ func (set *Set) Join(glue string) string {
set.mu.RLock()
defer set.mu.RUnlock()
buffer := bytes.NewBuffer(nil)
l := len(set.data)
i := 0
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()
buffer := bytes.NewBuffer(nil)
buffer.WriteByte('[')
s := ""
l := len(set.data)
i := 0
@ -132,18 +192,14 @@ func (set *Set) Join(glue string) string {
buffer.WriteString(`"` + gstr.QuoteMeta(s, `"\`) + `"`)
}
if i != l-1 {
buffer.WriteString(glue)
buffer.WriteByte(',')
}
i++
}
buffer.WriteByte(']')
return buffer.String()
}
// String returns items as a string, which are joined by char ','.
func (set *Set) String() string {
return "[" + set.Join(",") + "]"
}
// LockFunc locks writing with callback function <f>.
func (set *Set) LockFunc(f func(m map[interface{}]struct{})) {
set.mu.Lock()

View File

@ -64,6 +64,48 @@ func (set *IntSet) Add(item ...int) *IntSet {
return set
}
// AddIfNotExistFunc adds the returned value of callback function <f> to the set
// if <item> does not exit in the set.
func (set *IntSet) AddIfNotExistFunc(item int, f func() int) *IntSet {
if !set.Contains(item) {
set.doAddWithLockCheck(item, f())
}
return set
}
// AddIfNotExistFuncLock adds the returned value of callback function <f> to the set
// if <item> does not exit in the set.
//
// Note that the callback function <f> is executed in the mutex.Lock of the set.
func (set *IntSet) AddIfNotExistFuncLock(item int, f func() int) *IntSet {
if !set.Contains(item) {
set.doAddWithLockCheck(item, f)
}
return set
}
// doAddWithLockCheck checks whether item exists with mutex.Lock,
// if not exists, it adds item to the set or else just returns the existing value.
//
// If <value> is type of <func() interface {}>,
// it will be executed with mutex.Lock of the set,
// and its return value will be added to the set.
//
// It returns item successfully added..
func (set *IntSet) doAddWithLockCheck(item int, value interface{}) int {
set.mu.Lock()
defer set.mu.Unlock()
if _, ok := set.data[item]; !ok && value != nil {
if f, ok := value.(func() int); ok {
item = f()
} else {
item = value.(int)
}
}
set.data[item] = struct{}{}
return item
}
// Contains checks whether the set contains <item>.
func (set *IntSet) Contains(item int) bool {
set.mu.RLock()
@ -126,7 +168,7 @@ func (set *IntSet) Join(glue string) string {
return buffer.String()
}
// String returns items as a string, which are joined by char ','.
// String returns items as a string, which implements like json.Marshal does.
func (set *IntSet) String() string {
return "[" + set.Join(",") + "]"
}

View File

@ -65,6 +65,48 @@ func (set *StrSet) Add(item ...string) *StrSet {
return set
}
// AddIfNotExistFunc adds the returned value of callback function <f> to the set
// if <item> does not exit in the set.
func (set *StrSet) AddIfNotExistFunc(item string, f func() string) *StrSet {
if !set.Contains(item) {
set.doAddWithLockCheck(item, f())
}
return set
}
// AddIfNotExistFuncLock adds the returned value of callback function <f> to the set
// if <item> does not exit in the set.
//
// Note that the callback function <f> is executed in the mutex.Lock of the set.
func (set *StrSet) AddIfNotExistFuncLock(item string, f func() string) *StrSet {
if !set.Contains(item) {
set.doAddWithLockCheck(item, f)
}
return set
}
// doAddWithLockCheck checks whether item exists with mutex.Lock,
// if not exists, it adds item to the set or else just returns the existing value.
//
// If <value> is type of <func() interface {}>,
// it will be executed with mutex.Lock of the set,
// and its return value will be added to the set.
//
// It returns item successfully added..
func (set *StrSet) doAddWithLockCheck(item string, value interface{}) string {
set.mu.Lock()
defer set.mu.Unlock()
if _, ok := set.data[item]; !ok && value != nil {
if f, ok := value.(func() string); ok {
item = f()
} else {
item = value.(string)
}
}
set.data[item] = struct{}{}
return item
}
// Contains checks whether the set contains <item>.
func (set *StrSet) Contains(item string) bool {
set.mu.RLock()
@ -119,11 +161,7 @@ func (set *StrSet) Join(glue string) string {
l := len(set.data)
i := 0
for k, _ := range set.data {
if gstr.IsNumeric(k) {
buffer.WriteString(k)
} else {
buffer.WriteString(`"` + gstr.QuoteMeta(k, `"\`) + `"`)
}
buffer.WriteString(k)
if i != l-1 {
buffer.WriteString(glue)
}
@ -132,9 +170,21 @@ func (set *StrSet) Join(glue string) string {
return buffer.String()
}
// String returns items as a string, which are joined by char ','.
// String returns items as a string, which implements like json.Marshal does.
func (set *StrSet) String() string {
return "[" + set.Join(",") + "]"
set.mu.RLock()
defer set.mu.RUnlock()
buffer := bytes.NewBuffer(nil)
l := len(set.data)
i := 0
for k, _ := range set.data {
buffer.WriteString(`"` + gstr.QuoteMeta(k, `"\`) + `"`)
if i != l-1 {
buffer.WriteByte(',')
}
i++
}
return buffer.String()
}
// LockFunc locks writing with callback function <f>.

View File

@ -220,8 +220,8 @@ func TestSet_Join(t *testing.T) {
s1 := gset.New(true)
s1.Add("a").Add(`"b"`).Add(`\c`)
str1 := s1.Join(",")
gtest.Assert(strings.Contains(str1, `\"b\"`), true)
gtest.Assert(strings.Contains(str1, `\\c`), true)
gtest.Assert(strings.Contains(str1, `"b"`), true)
gtest.Assert(strings.Contains(str1, `\c`), true)
gtest.Assert(strings.Contains(str1, `a`), true)
})
}
@ -305,3 +305,43 @@ func TestSet_Json(t *testing.T) {
gtest.Assert(a3.Contains("e"), false)
})
}
func TestSet_AddIfNotExistFunc(t *testing.T) {
gtest.Case(t, func() {
s := gset.New(true)
s.Add(1)
gtest.Assert(s.Contains(1), true)
gtest.Assert(s.Contains(2), false)
s.AddIfNotExistFunc(2, func() interface{} {
return 3
})
gtest.Assert(s.Contains(2), false)
gtest.Assert(s.Contains(3), true)
s.AddIfNotExistFunc(3, func() interface{} {
return 4
})
gtest.Assert(s.Contains(3), true)
gtest.Assert(s.Contains(4), false)
})
gtest.Case(t, func() {
s := gset.New(true)
s.Add(1)
gtest.Assert(s.Contains(1), true)
gtest.Assert(s.Contains(2), false)
s.AddIfNotExistFuncLock(2, func() interface{} {
return 3
})
gtest.Assert(s.Contains(2), false)
gtest.Assert(s.Contains(3), true)
s.AddIfNotExistFuncLock(3, func() interface{} {
return 4
})
gtest.Assert(s.Contains(3), true)
gtest.Assert(s.Contains(4), false)
})
}

View File

@ -259,3 +259,43 @@ func TestIntSet_Json(t *testing.T) {
gtest.Assert(a2.Contains(5), false)
})
}
func TestIntSet_AddIfNotExistFunc(t *testing.T) {
gtest.Case(t, func() {
s := gset.NewIntSet(true)
s.Add(1)
gtest.Assert(s.Contains(1), true)
gtest.Assert(s.Contains(2), false)
s.AddIfNotExistFunc(2, func() int {
return 3
})
gtest.Assert(s.Contains(2), false)
gtest.Assert(s.Contains(3), true)
s.AddIfNotExistFunc(3, func() int {
return 4
})
gtest.Assert(s.Contains(3), true)
gtest.Assert(s.Contains(4), false)
})
gtest.Case(t, func() {
s := gset.NewIntSet(true)
s.Add(1)
gtest.Assert(s.Contains(1), true)
gtest.Assert(s.Contains(2), false)
s.AddIfNotExistFuncLock(2, func() int {
return 3
})
gtest.Assert(s.Contains(2), false)
gtest.Assert(s.Contains(3), true)
s.AddIfNotExistFuncLock(3, func() int {
return 4
})
gtest.Assert(s.Contains(3), true)
gtest.Assert(s.Contains(4), false)
})
}

View File

@ -207,8 +207,8 @@ func TestStrSet_Join(t *testing.T) {
s1 := gset.NewStrSet()
s1.Add("a").Add(`"b"`).Add(`\c`)
str1 := s1.Join(",")
gtest.Assert(strings.Contains(str1, `\"b\"`), true)
gtest.Assert(strings.Contains(str1, `\\c`), true)
gtest.Assert(strings.Contains(str1, `"b"`), true)
gtest.Assert(strings.Contains(str1, `\c`), true)
gtest.Assert(strings.Contains(str1, `a`), true)
})
}
@ -304,3 +304,43 @@ func TestStrSet_Json(t *testing.T) {
gtest.Assert(a3.Contains("e"), false)
})
}
func TestStrSet_AddIfNotExistFunc(t *testing.T) {
gtest.Case(t, func() {
s := gset.NewStrSet(true)
s.Add("1")
gtest.Assert(s.Contains("1"), true)
gtest.Assert(s.Contains("2"), false)
s.AddIfNotExistFunc("2", func() string {
return "3"
})
gtest.Assert(s.Contains("2"), false)
gtest.Assert(s.Contains("3"), true)
s.AddIfNotExistFunc("3", func() string {
return "4"
})
gtest.Assert(s.Contains("3"), true)
gtest.Assert(s.Contains("4"), false)
})
gtest.Case(t, func() {
s := gset.NewStrSet(true)
s.Add("1")
gtest.Assert(s.Contains("1"), true)
gtest.Assert(s.Contains("2"), false)
s.AddIfNotExistFuncLock("2", func() string {
return "3"
})
gtest.Assert(s.Contains("2"), false)
gtest.Assert(s.Contains("3"), true)
s.AddIfNotExistFuncLock("3", func() string {
return "4"
})
gtest.Assert(s.Contains("3"), true)
gtest.Assert(s.Contains("4"), false)
})
}