diff --git a/.example/other/test.go b/.example/other/test.go
index 1ffd72098..3c5d6fd37 100644
--- a/.example/other/test.go
+++ b/.example/other/test.go
@@ -1,23 +1,12 @@
package main
import (
- "encoding/json"
+ "encoding/hex"
"fmt"
- "gopkg.in/yaml.v3"
)
func main() {
- data := []byte(`
-m:
- k: v
- `)
- var result map[string]interface{}
- if err := yaml.Unmarshal(data, &result); err != nil {
- panic(err)
- }
- b, err := json.Marshal(result)
- if err != nil {
- panic(err)
- }
+ b := []byte{3, 0, 0}
fmt.Println(string(b))
+ fmt.Println(hex.EncodeToString(b))
}
diff --git a/.travis.yml b/.travis.yml
index b9e38f278..5ef9c9afa 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,8 @@
language: go
go:
+ - "1.11.x"
+ - "1.12.x"
- "1.13.x"
- "1.14.x"
diff --git a/DONATOR.MD b/DONATOR.MD
index c7a954564..5bc75eea9 100644
--- a/DONATOR.MD
+++ b/DONATOR.MD
@@ -71,6 +71,8 @@ We currently accept donation by Alipay/WechatPay, please note your github/gitee
|[侯哥](http://www.macnie.com)|wechat|¥10.00|
|如果🍋|alipay|¥100.00| 错过的奶茶^_^
|蔡蔡|wechat|¥666.00| gf真强大,让项目省心
+|jack|wechat|¥100.00|
+|sbilly|wechat|¥100.00| 祝好!
diff --git a/README.MD b/README.MD
index 9d1336400..2c46baf2c 100644
--- a/README.MD
+++ b/README.MD
@@ -9,7 +9,7 @@
English | [简体中文](README_ZH.MD)
-`GF(GoFrame)` is a modular, full-featured and production-ready application development framework
+`GF(GoFrame)` is a modular, high-performance and production-ready application development framework
of golang. Providing a series of core components and dozens of practical modules, such as:
cache, logging, containers, timer, resource, validator, database orm, etc.
Supporting web server integrated with router, cookie, session, middleware, logger, configure,
@@ -27,9 +27,67 @@ require github.com/gogf/gf latest
# Limitation
```
-golang version >= 1.13
+golang version >= 1.11
```
+# Architecture
+
+

+
+
+# Performance
+
+Here's the most popular Golang frameworks and libraries performance testing result in `WEB Server`. Performance testing cases source codes are hosted at: https://github.com/gogf/gf-performance
+
+## Environment
+
+ OS : Ubuntu 18.04 amd64
+ CPU : AMD A8-6600K x 4
+ MEM : 32GB
+ GO : v1.13.4
+
+## Testing Tool
+
+`ab`: Apache HTTP server benchmarking tool.
+
+Command:
+```
+ab -t 10 -c 100 http://127.0.0.1:3000/hello
+ab -t 10 -c 100 http://127.0.0.1:3000/query?id=10000
+ab -t 10 -c 100 http://127.0.0.1:3000/json
+```
+The concurrency starts from `100` to `10000`.
+
+> Run `5` times for each case of each project and pick up the best testing result.
+
+## 1. Hello World
+
+
+| Throughputs |
+Mean Latency |
+P99 Latency |
+
+
+ |
+ |
+ |
+
+
+
+## 2. Json Response
+
+
+| Throughputs |
+Mean Latency |
+P99 Latency |
+
+
+ |
+ |
+ |
+
+
+
# Documentation
* 中文官网: https://goframe.org
@@ -43,12 +101,6 @@ golang version >= 1.13
> It's recommended learning `GoFrame` through its awesome source codes and API reference.
-# Architecture
-
-

-
-
-
# License
`GF` is licensed under the [MIT License](LICENSE), 100% free and open-source, forever.
diff --git a/README_ZH.MD b/README_ZH.MD
index 2ca02be7d..a9ae9c171 100644
--- a/README_ZH.MD
+++ b/README_ZH.MD
@@ -41,7 +41,7 @@ require github.com/gogf/gf latest
# 限制
```shell
-golang版本 >= 1.13
+golang版本 >= 1.11
```
# 架构
@@ -49,6 +49,59 @@ golang版本 >= 1.13
+# 性能
+
+以下是目前最流行的`WEB Server` Golang框架/类库性能测试结果。
+性能测试用例源代码仓库: https://github.com/gogf/gf-performance
+
+## 环境:
+
+ OS : Ubuntu 18.04 amd64
+ CPU : AMD A8-6600K x 4
+ MEM : 32GB
+ GO : v1.13.4
+
+## 工具
+
+`ab`: Apache HTTP server benchmarking tool.
+
+测试命令:
+```
+ab -t 10 -c 100 http://127.0.0.1:3000/hello
+ab -t 10 -c 100 http://127.0.0.1:3000/query?id=10000
+ab -t 10 -c 100 http://127.0.0.1:3000/json
+```
+并发客户端数量从 `100` 递增到 `10000`。
+
+> 每个项目的每个用例均运行`5`次,取最优的结果展示。
+
+## 1. Hello World
+
+
+| Throughputs |
+Mean Latency |
+P99 Latency |
+
+
+ |
+ |
+ |
+
+
+
+## 2. Json Response
+
+
+| Throughputs |
+Mean Latency |
+P99 Latency |
+
+
+ |
+ |
+ |
+
+
# 文档
diff --git a/container/garray/garray_func.go b/container/garray/garray_func.go
index 7ae0822b3..572cba444 100644
--- a/container/garray/garray_func.go
+++ b/container/garray/garray_func.go
@@ -8,6 +8,12 @@ package garray
import "strings"
+// apiInterfaces is used for type assert api for Interfaces.
+type apiInterfaces interface {
+ Interfaces() []interface{}
+}
+
+// defaultComparatorInt for int comparison.
func defaultComparatorInt(a, b int) int {
if a < b {
return -1
@@ -18,6 +24,7 @@ func defaultComparatorInt(a, b int) int {
return 0
}
+// defaultComparatorStr for string comparison.
func defaultComparatorStr(a, b string) int {
return strings.Compare(a, b)
}
diff --git a/container/garray/garray_normal_any.go b/container/garray/garray_normal_any.go
index 12d952585..6ffebe89e 100644
--- a/container/garray/garray_normal_any.go
+++ b/container/garray/garray_normal_any.go
@@ -23,7 +23,7 @@ import (
// Array is a golang array with rich features.
type Array struct {
- mu *rwmutex.RWMutex
+ mu rwmutex.RWMutex
array []interface{}
}
@@ -44,7 +44,7 @@ func NewArray(safe ...bool) *Array {
// which is false in default.
func NewArraySize(size int, cap int, safe ...bool) *Array {
return &Array{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
array: make([]interface{}, size, cap),
}
}
@@ -79,7 +79,7 @@ func NewFromCopy(array []interface{}, safe ...bool) *Array {
// which is false in default.
func NewArrayFrom(array []interface{}, safe ...bool) *Array {
return &Array{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
array: array,
}
}
@@ -91,7 +91,7 @@ func NewArrayFromCopy(array []interface{}, safe ...bool) *Array {
newArray := make([]interface{}, len(array))
copy(newArray, array)
return &Array{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
array: newArray,
}
}
@@ -533,23 +533,7 @@ func (a *Array) RLockFunc(f func(array []interface{})) *Array {
// The difference between Merge and Append is Append supports only specified slice type,
// but Merge supports more parameter types.
func (a *Array) Merge(array interface{}) *Array {
- switch v := array.(type) {
- case *Array:
- a.Append(gconv.Interfaces(v.Slice())...)
- case *IntArray:
- a.Append(gconv.Interfaces(v.Slice())...)
- case *StrArray:
- a.Append(gconv.Interfaces(v.Slice())...)
- case *SortedArray:
- a.Append(gconv.Interfaces(v.Slice())...)
- case *SortedIntArray:
- a.Append(gconv.Interfaces(v.Slice())...)
- case *SortedStrArray:
- a.Append(gconv.Interfaces(v.Slice())...)
- default:
- a.Append(gconv.Interfaces(array)...)
- }
- return a
+ return a.Append(gconv.Interfaces(array)...)
}
// Fill fills an array with num entries of the value ,
@@ -668,6 +652,9 @@ func (a *Array) Reverse() *Array {
func (a *Array) Join(glue string) string {
a.mu.RLock()
defer a.mu.RUnlock()
+ if len(a.array) == 0 {
+ return ""
+ }
buffer := bytes.NewBuffer(nil)
for k, v := range a.array {
buffer.WriteString(gconv.String(v))
@@ -694,7 +681,7 @@ func (a *Array) Iterator(f func(k int, v interface{}) bool) {
a.IteratorAsc(f)
}
-// IteratorAsc iterates the array in ascending order with given callback function .
+// IteratorAsc iterates the array readonly in ascending order with given callback function .
// If returns true, then it continues iterating; or false to stop.
func (a *Array) IteratorAsc(f func(k int, v interface{}) bool) {
a.mu.RLock()
@@ -706,7 +693,7 @@ func (a *Array) IteratorAsc(f func(k int, v interface{}) bool) {
}
}
-// IteratorDesc iterates the array in descending order with given callback function .
+// IteratorDesc iterates the array readonly in descending order with given callback function .
// If returns true, then it continues iterating; or false to stop.
func (a *Array) IteratorDesc(f func(k int, v interface{}) bool) {
a.mu.RLock()
@@ -749,8 +736,7 @@ func (a *Array) MarshalJSON() ([]byte, error) {
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
func (a *Array) UnmarshalJSON(b []byte) error {
- if a.mu == nil {
- a.mu = rwmutex.New()
+ if a.array == nil {
a.array = make([]interface{}, 0)
}
a.mu.Lock()
@@ -763,9 +749,6 @@ func (a *Array) UnmarshalJSON(b []byte) error {
// UnmarshalValue is an interface implement which sets any type of value for array.
func (a *Array) UnmarshalValue(value interface{}) error {
- if a.mu == nil {
- a.mu = rwmutex.New()
- }
a.mu.Lock()
defer a.mu.Unlock()
switch value.(type) {
@@ -806,6 +789,16 @@ func (a *Array) FilterEmpty() *Array {
return a
}
+// Walk applies a user supplied function to every item of array.
+func (a *Array) Walk(f func(value interface{}) interface{}) *Array {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ for i, v := range a.array {
+ a.array[i] = f(v)
+ }
+ return a
+}
+
// IsEmpty checks whether the array is empty.
func (a *Array) IsEmpty() bool {
return a.Len() == 0
diff --git a/container/garray/garray_normal_int.go b/container/garray/garray_normal_int.go
index ecaa20c3f..0cce6d71c 100644
--- a/container/garray/garray_normal_int.go
+++ b/container/garray/garray_normal_int.go
@@ -21,7 +21,7 @@ import (
// IntArray is a golang int array with rich features.
type IntArray struct {
- mu *rwmutex.RWMutex
+ mu rwmutex.RWMutex
array []int
}
@@ -37,7 +37,7 @@ func NewIntArray(safe ...bool) *IntArray {
// which is false in default.
func NewIntArraySize(size int, cap int, safe ...bool) *IntArray {
return &IntArray{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
array: make([]int, size, cap),
}
}
@@ -62,7 +62,7 @@ func NewIntArrayRange(start, end, step int, safe ...bool) *IntArray {
// which is false in default.
func NewIntArrayFrom(array []int, safe ...bool) *IntArray {
return &IntArray{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
array: array,
}
}
@@ -74,7 +74,7 @@ func NewIntArrayFromCopy(array []int, safe ...bool) *IntArray {
newArray := make([]int, len(array))
copy(newArray, array)
return &IntArray{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
array: newArray,
}
}
@@ -535,23 +535,7 @@ func (a *IntArray) RLockFunc(f func(array []int)) *IntArray {
// The difference between Merge and Append is Append supports only specified slice type,
// but Merge supports more parameter types.
func (a *IntArray) Merge(array interface{}) *IntArray {
- switch v := array.(type) {
- case *Array:
- a.Append(gconv.Ints(v.Slice())...)
- case *IntArray:
- a.Append(gconv.Ints(v.Slice())...)
- case *StrArray:
- a.Append(gconv.Ints(v.Slice())...)
- case *SortedArray:
- a.Append(gconv.Ints(v.Slice())...)
- case *SortedIntArray:
- a.Append(gconv.Ints(v.Slice())...)
- case *SortedStrArray:
- a.Append(gconv.Ints(v.Slice())...)
- default:
- a.Append(gconv.Ints(array)...)
- }
- return a
+ return a.Append(gconv.Ints(array)...)
}
// Fill fills an array with num entries of the value ,
@@ -670,6 +654,9 @@ func (a *IntArray) Reverse() *IntArray {
func (a *IntArray) Join(glue string) string {
a.mu.RLock()
defer a.mu.RUnlock()
+ if len(a.array) == 0 {
+ return ""
+ }
buffer := bytes.NewBuffer(nil)
for k, v := range a.array {
buffer.WriteString(gconv.String(v))
@@ -696,7 +683,7 @@ func (a *IntArray) Iterator(f func(k int, v int) bool) {
a.IteratorAsc(f)
}
-// IteratorAsc iterates the array in ascending order with given callback function .
+// IteratorAsc iterates the array readonly in ascending order with given callback function .
// If returns true, then it continues iterating; or false to stop.
func (a *IntArray) IteratorAsc(f func(k int, v int) bool) {
a.mu.RLock()
@@ -708,7 +695,7 @@ func (a *IntArray) IteratorAsc(f func(k int, v int) bool) {
}
}
-// IteratorDesc iterates the array in descending order with given callback function .
+// IteratorDesc iterates the array readonly in descending order with given callback function .
// If returns true, then it continues iterating; or false to stop.
func (a *IntArray) IteratorDesc(f func(k int, v int) bool) {
a.mu.RLock()
@@ -734,8 +721,7 @@ func (a *IntArray) MarshalJSON() ([]byte, error) {
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
func (a *IntArray) UnmarshalJSON(b []byte) error {
- if a.mu == nil {
- a.mu = rwmutex.New()
+ if a.array == nil {
a.array = make([]int, 0)
}
a.mu.Lock()
@@ -748,9 +734,6 @@ func (a *IntArray) UnmarshalJSON(b []byte) error {
// UnmarshalValue is an interface implement which sets any type of value for array.
func (a *IntArray) UnmarshalValue(value interface{}) error {
- if a.mu == nil {
- a.mu = rwmutex.New()
- }
a.mu.Lock()
defer a.mu.Unlock()
switch value.(type) {
@@ -776,6 +759,16 @@ func (a *IntArray) FilterEmpty() *IntArray {
return a
}
+// Walk applies a user supplied function to every item of array.
+func (a *IntArray) Walk(f func(value int) int) *IntArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ for i, v := range a.array {
+ a.array[i] = f(v)
+ }
+ return a
+}
+
// IsEmpty checks whether the array is empty.
func (a *IntArray) IsEmpty() bool {
return a.Len() == 0
diff --git a/container/garray/garray_normal_str.go b/container/garray/garray_normal_str.go
index 78fc98e0e..d24038a27 100644
--- a/container/garray/garray_normal_str.go
+++ b/container/garray/garray_normal_str.go
@@ -23,7 +23,7 @@ import (
// StrArray is a golang string array with rich features.
type StrArray struct {
- mu *rwmutex.RWMutex
+ mu rwmutex.RWMutex
array []string
}
@@ -39,7 +39,7 @@ func NewStrArray(safe ...bool) *StrArray {
// which is false in default.
func NewStrArraySize(size int, cap int, safe ...bool) *StrArray {
return &StrArray{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
array: make([]string, size, cap),
}
}
@@ -49,7 +49,7 @@ func NewStrArraySize(size int, cap int, safe ...bool) *StrArray {
// which is false in default.
func NewStrArrayFrom(array []string, safe ...bool) *StrArray {
return &StrArray{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
array: array,
}
}
@@ -61,7 +61,7 @@ func NewStrArrayFromCopy(array []string, safe ...bool) *StrArray {
newArray := make([]string, len(array))
copy(newArray, array)
return &StrArray{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
array: newArray,
}
}
@@ -526,23 +526,7 @@ func (a *StrArray) RLockFunc(f func(array []string)) *StrArray {
// The difference between Merge and Append is Append supports only specified slice type,
// but Merge supports more parameter types.
func (a *StrArray) Merge(array interface{}) *StrArray {
- switch v := array.(type) {
- case *Array:
- a.Append(gconv.Strings(v.Slice())...)
- case *IntArray:
- a.Append(gconv.Strings(v.Slice())...)
- case *StrArray:
- a.Append(gconv.Strings(v.Slice())...)
- case *SortedArray:
- a.Append(gconv.Strings(v.Slice())...)
- case *SortedIntArray:
- a.Append(gconv.Strings(v.Slice())...)
- case *SortedStrArray:
- a.Append(gconv.Strings(v.Slice())...)
- default:
- a.Append(gconv.Strings(array)...)
- }
- return a
+ return a.Append(gconv.Strings(array)...)
}
// Fill fills an array with num entries of the value ,
@@ -661,6 +645,9 @@ func (a *StrArray) Reverse() *StrArray {
func (a *StrArray) Join(glue string) string {
a.mu.RLock()
defer a.mu.RUnlock()
+ if len(a.array) == 0 {
+ return ""
+ }
buffer := bytes.NewBuffer(nil)
for k, v := range a.array {
buffer.WriteString(v)
@@ -687,7 +674,7 @@ func (a *StrArray) Iterator(f func(k int, v string) bool) {
a.IteratorAsc(f)
}
-// IteratorAsc iterates the array in ascending order with given callback function .
+// IteratorAsc iterates the array readonly in ascending order with given callback function .
// If returns true, then it continues iterating; or false to stop.
func (a *StrArray) IteratorAsc(f func(k int, v string) bool) {
a.mu.RLock()
@@ -699,7 +686,7 @@ func (a *StrArray) IteratorAsc(f func(k int, v string) bool) {
}
}
-// IteratorDesc iterates the array in descending order with given callback function .
+// IteratorDesc iterates the array readonly in descending order with given callback function .
// If returns true, then it continues iterating; or false to stop.
func (a *StrArray) IteratorDesc(f func(k int, v string) bool) {
a.mu.RLock()
@@ -736,8 +723,7 @@ func (a *StrArray) MarshalJSON() ([]byte, error) {
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
func (a *StrArray) UnmarshalJSON(b []byte) error {
- if a.mu == nil {
- a.mu = rwmutex.New()
+ if a.array == nil {
a.array = make([]string, 0)
}
a.mu.Lock()
@@ -750,9 +736,6 @@ func (a *StrArray) UnmarshalJSON(b []byte) error {
// UnmarshalValue is an interface implement which sets any type of value for array.
func (a *StrArray) UnmarshalValue(value interface{}) error {
- if a.mu == nil {
- a.mu = rwmutex.New()
- }
a.mu.Lock()
defer a.mu.Unlock()
switch value.(type) {
@@ -778,6 +761,16 @@ func (a *StrArray) FilterEmpty() *StrArray {
return a
}
+// Walk applies a user supplied function to every item of array.
+func (a *StrArray) Walk(f func(value string) string) *StrArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ for i, v := range a.array {
+ a.array[i] = f(v)
+ }
+ return a
+}
+
// IsEmpty checks whether the array is empty.
func (a *StrArray) IsEmpty() bool {
return a.Len() == 0
diff --git a/container/garray/garray_sorted_any.go b/container/garray/garray_sorted_any.go
index b4c3b4e63..31d222dac 100644
--- a/container/garray/garray_sorted_any.go
+++ b/container/garray/garray_sorted_any.go
@@ -16,7 +16,6 @@ import (
"math"
"sort"
- "github.com/gogf/gf/container/gtype"
"github.com/gogf/gf/internal/rwmutex"
"github.com/gogf/gf/util/gconv"
"github.com/gogf/gf/util/grand"
@@ -25,9 +24,9 @@ import (
// SortedArray is a golang sorted array with rich features.
// It's using increasing order in default.
type SortedArray struct {
- mu *rwmutex.RWMutex
+ mu rwmutex.RWMutex
array []interface{}
- unique *gtype.Bool // Whether enable unique feature(false)
+ unique bool // Whether enable unique feature(false)
comparator func(a, b interface{}) int // Comparison function(it returns -1: a < b; 0: a == b; 1: a > b)
}
@@ -46,8 +45,7 @@ func NewSortedArray(comparator func(a, b interface{}) int, safe ...bool) *Sorted
// which is false in default.
func NewSortedArraySize(cap int, comparator func(a, b interface{}) int, safe ...bool) *SortedArray {
return &SortedArray{
- mu: rwmutex.New(safe...),
- unique: gtype.NewBool(),
+ mu: rwmutex.Create(safe...),
array: make([]interface{}, 0, cap),
comparator: comparator,
}
@@ -75,7 +73,7 @@ func NewSortedArrayFrom(array []interface{}, comparator func(a, b interface{}) i
a := NewSortedArraySize(0, comparator, safe...)
a.array = array
sort.Slice(a.array, func(i, j int) bool {
- return a.comparator(a.array[i], a.array[j]) < 0
+ return a.getComparator()(a.array[i], a.array[j]) < 0
})
return a
}
@@ -95,19 +93,19 @@ func (a *SortedArray) SetArray(array []interface{}) *SortedArray {
defer a.mu.Unlock()
a.array = array
sort.Slice(a.array, func(i, j int) bool {
- return a.comparator(a.array[i], a.array[j]) < 0
+ return a.getComparator()(a.array[i], a.array[j]) < 0
})
return a
}
// SetComparator sets/changes the comparator for sorting.
+// It resorts the array as the comparator is changed.
func (a *SortedArray) SetComparator(comparator func(a, b interface{}) int) {
a.mu.Lock()
defer a.mu.Unlock()
a.comparator = comparator
- // Resort the array if comparator is changed.
sort.Slice(a.array, func(i, j int) bool {
- return a.comparator(a.array[i], a.array[j]) < 0
+ return a.getComparator()(a.array[i], a.array[j]) < 0
})
}
@@ -118,7 +116,7 @@ func (a *SortedArray) Sort() *SortedArray {
a.mu.Lock()
defer a.mu.Unlock()
sort.Slice(a.array, func(i, j int) bool {
- return a.comparator(a.array[i], a.array[j]) < 0
+ return a.getComparator()(a.array[i], a.array[j]) < 0
})
return a
}
@@ -132,7 +130,7 @@ func (a *SortedArray) Add(values ...interface{}) *SortedArray {
defer a.mu.Unlock()
for _, value := range values {
index, cmp := a.binSearch(value, false)
- if a.unique.Val() && cmp == 0 {
+ if a.unique && cmp == 0 {
continue
}
if index < 0 {
@@ -390,7 +388,7 @@ func (a *SortedArray) Len() int {
// Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,
// or else a pointer to the underlying data.
func (a *SortedArray) Slice() []interface{} {
- array := ([]interface{})(nil)
+ var array []interface{}
if a.mu.IsSafe() {
a.mu.RLock()
defer a.mu.RUnlock()
@@ -439,8 +437,8 @@ func (a *SortedArray) binSearch(value interface{}, lock bool) (index int, result
mid := 0
cmp := -2
for min <= max {
- mid = int((min + max) / 2)
- cmp = a.comparator(value, a.array[mid])
+ mid = (min + max) / 2
+ cmp = a.getComparator()(value, a.array[mid])
switch {
case cmp < 0:
max = mid - 1
@@ -457,8 +455,8 @@ func (a *SortedArray) binSearch(value interface{}, lock bool) (index int, result
// which means it does not contain any repeated items.
// It also do unique check, remove all repeated items.
func (a *SortedArray) SetUnique(unique bool) *SortedArray {
- oldUnique := a.unique.Val()
- a.unique.Set(unique)
+ oldUnique := a.unique
+ a.unique = unique
if unique && oldUnique != unique {
a.Unique()
}
@@ -477,7 +475,7 @@ func (a *SortedArray) Unique() *SortedArray {
if i == len(a.array)-1 {
break
}
- if a.comparator(a.array[i], a.array[i+1]) == 0 {
+ if a.getComparator()(a.array[i], a.array[i+1]) == 0 {
a.array = append(a.array[:i+1], a.array[i+1+1:]...)
} else {
i++
@@ -509,6 +507,12 @@ func (a *SortedArray) Clear() *SortedArray {
func (a *SortedArray) LockFunc(f func(array []interface{})) *SortedArray {
a.mu.Lock()
defer a.mu.Unlock()
+
+ // Keep the array always sorted.
+ defer sort.Slice(a.array, func(i, j int) bool {
+ return a.getComparator()(a.array[i], a.array[j]) < 0
+ })
+
f(a.array)
return a
}
@@ -526,23 +530,7 @@ func (a *SortedArray) RLockFunc(f func(array []interface{})) *SortedArray {
// The difference between Merge and Append is Append supports only specified slice type,
// but Merge supports more parameter types.
func (a *SortedArray) Merge(array interface{}) *SortedArray {
- switch v := array.(type) {
- case *Array:
- a.Add(gconv.Interfaces(v.Slice())...)
- case *IntArray:
- a.Add(gconv.Interfaces(v.Slice())...)
- case *StrArray:
- a.Add(gconv.Interfaces(v.Slice())...)
- case *SortedArray:
- a.Add(gconv.Interfaces(v.Slice())...)
- case *SortedIntArray:
- a.Add(gconv.Interfaces(v.Slice())...)
- case *SortedStrArray:
- a.Add(gconv.Interfaces(v.Slice())...)
- default:
- a.Add(gconv.Interfaces(array)...)
- }
- return a
+ return a.Add(gconv.Interfaces(array)...)
}
// Chunk splits an array into multiple arrays,
@@ -596,6 +584,9 @@ func (a *SortedArray) Rands(size int) []interface{} {
func (a *SortedArray) Join(glue string) string {
a.mu.RLock()
defer a.mu.RUnlock()
+ if len(a.array) == 0 {
+ return ""
+ }
buffer := bytes.NewBuffer(nil)
for k, v := range a.array {
buffer.WriteString(gconv.String(v))
@@ -622,7 +613,7 @@ func (a *SortedArray) Iterator(f func(k int, v interface{}) bool) {
a.IteratorAsc(f)
}
-// IteratorAsc iterates the array in ascending order with given callback function .
+// IteratorAsc iterates the array readonly in ascending order with given callback function .
// If returns true, then it continues iterating; or false to stop.
func (a *SortedArray) IteratorAsc(f func(k int, v interface{}) bool) {
a.mu.RLock()
@@ -634,7 +625,7 @@ func (a *SortedArray) IteratorAsc(f func(k int, v interface{}) bool) {
}
}
-// IteratorDesc iterates the array in descending order with given callback function .
+// IteratorDesc iterates the array readonly in descending order with given callback function .
// If returns true, then it continues iterating; or false to stop.
func (a *SortedArray) IteratorDesc(f func(k int, v interface{}) bool) {
a.mu.RLock()
@@ -676,12 +667,10 @@ func (a *SortedArray) MarshalJSON() ([]byte, error) {
}
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
+// Note that the comparator is set as string comparator in default.
func (a *SortedArray) UnmarshalJSON(b []byte) error {
- if a.mu == nil {
- a.mu = rwmutex.New()
+ if a.comparator == nil {
a.array = make([]interface{}, 0)
- a.unique = gtype.NewBool()
- // Note that the comparator is string comparator in default.
a.comparator = gutil.ComparatorString
}
a.mu.Lock()
@@ -698,11 +687,9 @@ func (a *SortedArray) UnmarshalJSON(b []byte) error {
}
// UnmarshalValue is an interface implement which sets any type of value for array.
+// Note that the comparator is set as string comparator in default.
func (a *SortedArray) UnmarshalValue(value interface{}) (err error) {
- if a.mu == nil {
- a.mu = rwmutex.New()
- a.unique = gtype.NewBool()
- // Note that the comparator is string comparator in default.
+ if a.comparator == nil {
a.comparator = gutil.ComparatorString
}
a.mu.Lock()
@@ -764,7 +751,30 @@ func (a *SortedArray) FilterEmpty() *SortedArray {
return a
}
+// Walk applies a user supplied function to every item of array.
+func (a *SortedArray) Walk(f func(value interface{}) interface{}) *SortedArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+ // Keep the array always sorted.
+ defer sort.Slice(a.array, func(i, j int) bool {
+ return a.getComparator()(a.array[i], a.array[j]) < 0
+ })
+ for i, v := range a.array {
+ a.array[i] = f(v)
+ }
+ return a
+}
+
// IsEmpty checks whether the array is empty.
func (a *SortedArray) IsEmpty() bool {
return a.Len() == 0
}
+
+// getComparator returns the comparator if it's previously set,
+// or else it panics.
+func (a *SortedArray) getComparator() func(a, b interface{}) int {
+ if a.comparator == nil {
+ panic("comparator is missing for sorted array")
+ }
+ return a.comparator
+}
diff --git a/container/garray/garray_sorted_int.go b/container/garray/garray_sorted_int.go
index 182f3f211..10a94fbaa 100644
--- a/container/garray/garray_sorted_int.go
+++ b/container/garray/garray_sorted_int.go
@@ -13,7 +13,6 @@ import (
"math"
"sort"
- "github.com/gogf/gf/container/gtype"
"github.com/gogf/gf/internal/rwmutex"
"github.com/gogf/gf/util/gconv"
"github.com/gogf/gf/util/grand"
@@ -22,9 +21,9 @@ import (
// SortedIntArray is a golang sorted int array with rich features.
// It's using increasing order in default.
type SortedIntArray struct {
- mu *rwmutex.RWMutex
+ mu rwmutex.RWMutex
array []int
- unique *gtype.Bool // Whether enable unique feature(false)
+ unique bool // Whether enable unique feature(false)
comparator func(a, b int) int // Comparison function(it returns -1: a < b; 0: a == b; 1: a > b)
}
@@ -48,9 +47,8 @@ func NewSortedIntArrayComparator(comparator func(a, b int) int, safe ...bool) *S
// which is false in default.
func NewSortedIntArraySize(cap int, safe ...bool) *SortedIntArray {
return &SortedIntArray{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
array: make([]int, 0, cap),
- unique: gtype.NewBool(),
comparator: defaultComparatorInt,
}
}
@@ -94,7 +92,7 @@ func (a *SortedIntArray) SetArray(array []int) *SortedIntArray {
a.mu.Lock()
defer a.mu.Unlock()
a.array = array
- sort.Ints(a.array)
+ quickSortInt(a.array, a.getComparator())
return a
}
@@ -104,7 +102,7 @@ func (a *SortedIntArray) SetArray(array []int) *SortedIntArray {
func (a *SortedIntArray) Sort() *SortedIntArray {
a.mu.Lock()
defer a.mu.Unlock()
- sort.Ints(a.array)
+ quickSortInt(a.array, a.getComparator())
return a
}
@@ -117,7 +115,7 @@ func (a *SortedIntArray) Add(values ...int) *SortedIntArray {
defer a.mu.Unlock()
for _, value := range values {
index, cmp := a.binSearch(value, false)
- if a.unique.Val() && cmp == 0 {
+ if a.unique && cmp == 0 {
continue
}
if index < 0 {
@@ -436,8 +434,8 @@ func (a *SortedIntArray) binSearch(value int, lock bool) (index int, result int)
mid := 0
cmp := -2
for min <= max {
- mid = int((min + max) / 2)
- cmp = a.comparator(value, a.array[mid])
+ mid = (min + max) / 2
+ cmp = a.getComparator()(value, a.array[mid])
switch {
case cmp < 0:
max = mid - 1
@@ -454,8 +452,8 @@ func (a *SortedIntArray) binSearch(value int, lock bool) (index int, result int)
// which means it does not contain any repeated items.
// It also do unique check, remove all repeated items.
func (a *SortedIntArray) SetUnique(unique bool) *SortedIntArray {
- oldUnique := a.unique.Val()
- a.unique.Set(unique)
+ oldUnique := a.unique
+ a.unique = unique
if unique && oldUnique != unique {
a.Unique()
}
@@ -474,7 +472,7 @@ func (a *SortedIntArray) Unique() *SortedIntArray {
if i == len(a.array)-1 {
break
}
- if a.comparator(a.array[i], a.array[i+1]) == 0 {
+ if a.getComparator()(a.array[i], a.array[i+1]) == 0 {
a.array = append(a.array[:i+1], a.array[i+1+1:]...)
} else {
i++
@@ -523,23 +521,7 @@ func (a *SortedIntArray) RLockFunc(f func(array []int)) *SortedIntArray {
// The difference between Merge and Append is Append supports only specified slice type,
// but Merge supports more parameter types.
func (a *SortedIntArray) Merge(array interface{}) *SortedIntArray {
- switch v := array.(type) {
- case *Array:
- a.Add(gconv.Ints(v.Slice())...)
- case *IntArray:
- a.Add(gconv.Ints(v.Slice())...)
- case *StrArray:
- a.Add(gconv.Ints(v.Slice())...)
- case *SortedArray:
- a.Add(gconv.Ints(v.Slice())...)
- case *SortedIntArray:
- a.Add(gconv.Ints(v.Slice())...)
- case *SortedStrArray:
- a.Add(gconv.Ints(v.Slice())...)
- default:
- a.Add(gconv.Ints(array)...)
- }
- return a
+ return a.Add(gconv.Ints(array)...)
}
// Chunk splits an array into multiple arrays,
@@ -593,6 +575,9 @@ func (a *SortedIntArray) Rands(size int) []int {
func (a *SortedIntArray) Join(glue string) string {
a.mu.RLock()
defer a.mu.RUnlock()
+ if len(a.array) == 0 {
+ return ""
+ }
buffer := bytes.NewBuffer(nil)
for k, v := range a.array {
buffer.WriteString(gconv.String(v))
@@ -619,7 +604,7 @@ func (a *SortedIntArray) Iterator(f func(k int, v int) bool) {
a.IteratorAsc(f)
}
-// IteratorAsc iterates the array in ascending order with given callback function .
+// IteratorAsc iterates the array readonly in ascending order with given callback function .
// If returns true, then it continues iterating; or false to stop.
func (a *SortedIntArray) IteratorAsc(f func(k int, v int) bool) {
a.mu.RLock()
@@ -631,7 +616,7 @@ func (a *SortedIntArray) IteratorAsc(f func(k int, v int) bool) {
}
}
-// IteratorDesc iterates the array in descending order with given callback function .
+// IteratorDesc iterates the array readonly in descending order with given callback function .
// If returns true, then it continues iterating; or false to stop.
func (a *SortedIntArray) IteratorDesc(f func(k int, v int) bool) {
a.mu.RLock()
@@ -657,10 +642,8 @@ func (a *SortedIntArray) MarshalJSON() ([]byte, error) {
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
func (a *SortedIntArray) UnmarshalJSON(b []byte) error {
- if a.mu == nil {
- a.mu = rwmutex.New()
+ if a.comparator == nil {
a.array = make([]int, 0)
- a.unique = gtype.NewBool()
a.comparator = defaultComparatorInt
}
a.mu.Lock()
@@ -676,10 +659,7 @@ func (a *SortedIntArray) UnmarshalJSON(b []byte) error {
// UnmarshalValue is an interface implement which sets any type of value for array.
func (a *SortedIntArray) UnmarshalValue(value interface{}) (err error) {
- if a.mu == nil {
- a.mu = rwmutex.New()
- a.unique = gtype.NewBool()
- // Note that the comparator is string comparator in default.
+ if a.comparator == nil {
a.comparator = defaultComparatorInt
}
a.mu.Lock()
@@ -717,7 +697,30 @@ func (a *SortedIntArray) FilterEmpty() *SortedIntArray {
return a
}
+// Walk applies a user supplied function to every item of array.
+func (a *SortedIntArray) Walk(f func(value int) int) *SortedIntArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+
+ // Keep the array always sorted.
+ defer quickSortInt(a.array, a.getComparator())
+
+ for i, v := range a.array {
+ a.array[i] = f(v)
+ }
+ return a
+}
+
// IsEmpty checks whether the array is empty.
func (a *SortedIntArray) IsEmpty() bool {
return a.Len() == 0
}
+
+// getComparator returns the comparator if it's previously set,
+// or else it returns a default comparator.
+func (a *SortedIntArray) getComparator() func(a, b int) int {
+ if a.comparator == nil {
+ return defaultComparatorInt
+ }
+ return a.comparator
+}
diff --git a/container/garray/garray_sorted_str.go b/container/garray/garray_sorted_str.go
index aed2ad100..61ad49b1d 100644
--- a/container/garray/garray_sorted_str.go
+++ b/container/garray/garray_sorted_str.go
@@ -13,7 +13,6 @@ import (
"math"
"sort"
- "github.com/gogf/gf/container/gtype"
"github.com/gogf/gf/internal/rwmutex"
"github.com/gogf/gf/util/gconv"
"github.com/gogf/gf/util/grand"
@@ -22,9 +21,9 @@ import (
// SortedStrArray is a golang sorted string array with rich features.
// It's using increasing order in default.
type SortedStrArray struct {
- mu *rwmutex.RWMutex
+ mu rwmutex.RWMutex
array []string
- unique *gtype.Bool // Whether enable unique feature(false)
+ unique bool // Whether enable unique feature(false)
comparator func(a, b string) int // Comparison function(it returns -1: a < b; 0: a == b; 1: a > b)
}
@@ -48,9 +47,8 @@ func NewSortedStrArrayComparator(comparator func(a, b string) int, safe ...bool)
// which is false in default.
func NewSortedStrArraySize(cap int, safe ...bool) *SortedStrArray {
return &SortedStrArray{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
array: make([]string, 0, cap),
- unique: gtype.NewBool(),
comparator: defaultComparatorStr,
}
}
@@ -61,7 +59,7 @@ func NewSortedStrArraySize(cap int, safe ...bool) *SortedStrArray {
func NewSortedStrArrayFrom(array []string, safe ...bool) *SortedStrArray {
a := NewSortedStrArraySize(0, safe...)
a.array = array
- quickSortStr(a.array, a.comparator)
+ quickSortStr(a.array, a.getComparator())
return a
}
@@ -79,7 +77,7 @@ func (a *SortedStrArray) SetArray(array []string) *SortedStrArray {
a.mu.Lock()
defer a.mu.Unlock()
a.array = array
- quickSortStr(a.array, a.comparator)
+ quickSortStr(a.array, a.getComparator())
return a
}
@@ -89,7 +87,7 @@ func (a *SortedStrArray) SetArray(array []string) *SortedStrArray {
func (a *SortedStrArray) Sort() *SortedStrArray {
a.mu.Lock()
defer a.mu.Unlock()
- quickSortStr(a.array, a.comparator)
+ quickSortStr(a.array, a.getComparator())
return a
}
@@ -102,7 +100,7 @@ func (a *SortedStrArray) Add(values ...string) *SortedStrArray {
defer a.mu.Unlock()
for _, value := range values {
index, cmp := a.binSearch(value, false)
- if a.unique.Val() && cmp == 0 {
+ if a.unique && cmp == 0 {
continue
}
if index < 0 {
@@ -421,8 +419,8 @@ func (a *SortedStrArray) binSearch(value string, lock bool) (index int, result i
mid := 0
cmp := -2
for min <= max {
- mid = int((min + max) / 2)
- cmp = a.comparator(value, a.array[mid])
+ mid = (min + max) / 2
+ cmp = a.getComparator()(value, a.array[mid])
switch {
case cmp < 0:
max = mid - 1
@@ -439,8 +437,8 @@ func (a *SortedStrArray) binSearch(value string, lock bool) (index int, result i
// which means it does not contain any repeated items.
// It also do unique check, remove all repeated items.
func (a *SortedStrArray) SetUnique(unique bool) *SortedStrArray {
- oldUnique := a.unique.Val()
- a.unique.Set(unique)
+ oldUnique := a.unique
+ a.unique = unique
if unique && oldUnique != unique {
a.Unique()
}
@@ -459,7 +457,7 @@ func (a *SortedStrArray) Unique() *SortedStrArray {
if i == len(a.array)-1 {
break
}
- if a.comparator(a.array[i], a.array[i+1]) == 0 {
+ if a.getComparator()(a.array[i], a.array[i+1]) == 0 {
a.array = append(a.array[:i+1], a.array[i+1+1:]...)
} else {
i++
@@ -508,23 +506,7 @@ func (a *SortedStrArray) RLockFunc(f func(array []string)) *SortedStrArray {
// The difference between Merge and Append is Append supports only specified slice type,
// but Merge supports more parameter types.
func (a *SortedStrArray) Merge(array interface{}) *SortedStrArray {
- switch v := array.(type) {
- case *Array:
- a.Add(gconv.Strings(v.Slice())...)
- case *IntArray:
- a.Add(gconv.Strings(v.Slice())...)
- case *StrArray:
- a.Add(gconv.Strings(v.Slice())...)
- case *SortedArray:
- a.Add(gconv.Strings(v.Slice())...)
- case *SortedIntArray:
- a.Add(gconv.Strings(v.Slice())...)
- case *SortedStrArray:
- a.Add(gconv.Strings(v.Slice())...)
- default:
- a.Add(gconv.Strings(array)...)
- }
- return a
+ return a.Add(gconv.Strings(array)...)
}
// Chunk splits an array into multiple arrays,
@@ -578,6 +560,9 @@ func (a *SortedStrArray) Rands(size int) []string {
func (a *SortedStrArray) Join(glue string) string {
a.mu.RLock()
defer a.mu.RUnlock()
+ if len(a.array) == 0 {
+ return ""
+ }
buffer := bytes.NewBuffer(nil)
for k, v := range a.array {
buffer.WriteString(v)
@@ -604,7 +589,7 @@ func (a *SortedStrArray) Iterator(f func(k int, v string) bool) {
a.IteratorAsc(f)
}
-// IteratorAsc iterates the array in ascending order with given callback function .
+// IteratorAsc iterates the array readonly in ascending order with given callback function .
// If returns true, then it continues iterating; or false to stop.
func (a *SortedStrArray) IteratorAsc(f func(k int, v string) bool) {
a.mu.RLock()
@@ -616,7 +601,7 @@ func (a *SortedStrArray) IteratorAsc(f func(k int, v string) bool) {
}
}
-// IteratorDesc iterates the array in descending order with given callback function .
+// IteratorDesc iterates the array readonly in descending order with given callback function .
// If returns true, then it continues iterating; or false to stop.
func (a *SortedStrArray) IteratorDesc(f func(k int, v string) bool) {
a.mu.RLock()
@@ -653,10 +638,8 @@ func (a *SortedStrArray) MarshalJSON() ([]byte, error) {
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
func (a *SortedStrArray) UnmarshalJSON(b []byte) error {
- if a.mu == nil {
- a.mu = rwmutex.New()
+ if a.comparator == nil {
a.array = make([]string, 0)
- a.unique = gtype.NewBool()
a.comparator = defaultComparatorStr
}
a.mu.Lock()
@@ -672,10 +655,7 @@ func (a *SortedStrArray) UnmarshalJSON(b []byte) error {
// UnmarshalValue is an interface implement which sets any type of value for array.
func (a *SortedStrArray) UnmarshalValue(value interface{}) (err error) {
- if a.mu == nil {
- a.mu = rwmutex.New()
- a.unique = gtype.NewBool()
- // Note that the comparator is string comparator in default.
+ if a.comparator == nil {
a.comparator = defaultComparatorStr
}
a.mu.Lock()
@@ -713,7 +693,30 @@ func (a *SortedStrArray) FilterEmpty() *SortedStrArray {
return a
}
+// Walk applies a user supplied function to every item of array.
+func (a *SortedStrArray) Walk(f func(value string) string) *SortedStrArray {
+ a.mu.Lock()
+ defer a.mu.Unlock()
+
+ // Keep the array always sorted.
+ defer quickSortStr(a.array, a.getComparator())
+
+ for i, v := range a.array {
+ a.array[i] = f(v)
+ }
+ return a
+}
+
// IsEmpty checks whether the array is empty.
func (a *SortedStrArray) IsEmpty() bool {
return a.Len() == 0
}
+
+// getComparator returns the comparator if it's previously set,
+// or else it returns a default comparator.
+func (a *SortedStrArray) getComparator() func(a, b string) int {
+ if a.comparator == nil {
+ return defaultComparatorStr
+ }
+ return a.comparator
+}
diff --git a/container/garray/garray_z_unit_all_basic_test.go b/container/garray/garray_z_unit_all_basic_test.go
index faeaa960d..b9da2fc95 100644
--- a/container/garray/garray_z_unit_all_basic_test.go
+++ b/container/garray/garray_z_unit_all_basic_test.go
@@ -9,6 +9,7 @@
package garray_test
import (
+ "github.com/gogf/gf/util/gutil"
"strings"
"testing"
@@ -17,6 +18,55 @@ import (
"github.com/gogf/gf/util/gconv"
)
+func Test_Array_Var(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ var array garray.Array
+ expect := []int{2, 3, 1}
+ array.Append(2, 3, 1)
+ t.Assert(array.Slice(), expect)
+ })
+ gtest.C(t, func(t *gtest.T) {
+ var array garray.IntArray
+ expect := []int{2, 3, 1}
+ array.Append(2, 3, 1)
+ t.Assert(array.Slice(), expect)
+ })
+ gtest.C(t, func(t *gtest.T) {
+ var array garray.StrArray
+ expect := []string{"b", "a"}
+ array.Append("b", "a")
+ t.Assert(array.Slice(), expect)
+ })
+ gtest.C(t, func(t *gtest.T) {
+ var array garray.SortedArray
+ array.SetComparator(gutil.ComparatorInt)
+ expect := []int{1, 2, 3}
+ array.Add(2, 3, 1)
+ t.Assert(array.Slice(), expect)
+ })
+ gtest.C(t, func(t *gtest.T) {
+ var array garray.SortedIntArray
+ expect := []int{1, 2, 3}
+ array.Add(2, 3, 1)
+ t.Assert(array.Slice(), expect)
+ })
+ gtest.C(t, func(t *gtest.T) {
+ var array garray.SortedStrArray
+ expect := []string{"a", "b", "c"}
+ array.Add("c", "a", "b")
+ t.Assert(array.Slice(), expect)
+ })
+}
+
+func Test_SortedIntArray_Var(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ var array garray.SortedIntArray
+ expect := []int{1, 2, 3}
+ array.Add(2, 3, 1)
+ t.Assert(array.Slice(), expect)
+ })
+}
+
func Test_IntArray_Unique(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
expect := []int{1, 2, 3, 4, 5, 6}
diff --git a/container/garray/garray_z_unit_normal_any_array_test.go b/container/garray/garray_z_unit_normal_any_array_test.go
index a1447c8ab..3cd7df5ff 100644
--- a/container/garray/garray_z_unit_normal_any_array_test.go
+++ b/container/garray/garray_z_unit_normal_any_array_test.go
@@ -650,3 +650,12 @@ func TestArray_FilterEmpty(t *testing.T) {
t.Assert(array.FilterEmpty(), g.Slice{1, 2, 3, 4})
})
}
+
+func TestArray_Walk(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ array := garray.NewArrayFrom(g.Slice{"1", "2"})
+ t.Assert(array.Walk(func(value interface{}) interface{} {
+ return "key-" + gconv.String(value)
+ }), g.Slice{"key-1", "key-2"})
+ })
+}
diff --git a/container/garray/garray_z_unit_normal_int_array_test.go b/container/garray/garray_z_unit_normal_int_array_test.go
index 112de3db7..9ee47c380 100644
--- a/container/garray/garray_z_unit_normal_int_array_test.go
+++ b/container/garray/garray_z_unit_normal_int_array_test.go
@@ -683,3 +683,12 @@ func TestIntArray_FilterEmpty(t *testing.T) {
t.Assert(array.FilterEmpty(), g.SliceInt{1, 2, 3, 4})
})
}
+
+func TestIntArray_Walk(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ array := garray.NewIntArrayFrom(g.SliceInt{1, 2})
+ t.Assert(array.Walk(func(value int) int {
+ return 10 + value
+ }), g.Slice{11, 12})
+ })
+}
diff --git a/container/garray/garray_z_unit_normal_str_array_test.go b/container/garray/garray_z_unit_normal_str_array_test.go
index 090705224..d0065f9df 100644
--- a/container/garray/garray_z_unit_normal_str_array_test.go
+++ b/container/garray/garray_z_unit_normal_str_array_test.go
@@ -671,3 +671,12 @@ func TestStrArray_FilterEmpty(t *testing.T) {
t.Assert(array.FilterEmpty(), g.SliceStr{"1", "2"})
})
}
+
+func TestStrArray_Walk(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ array := garray.NewStrArrayFrom(g.SliceStr{"1", "2"})
+ t.Assert(array.Walk(func(value string) string {
+ return "key-" + value
+ }), g.Slice{"key-1", "key-2"})
+ })
+}
diff --git a/container/garray/garray_z_unit_sorted_any_array_test.go b/container/garray/garray_z_unit_sorted_any_array_test.go
index bd639235b..7003dd458 100644
--- a/container/garray/garray_z_unit_sorted_any_array_test.go
+++ b/container/garray/garray_z_unit_sorted_any_array_test.go
@@ -779,3 +779,12 @@ func TestSortedArray_FilterEmpty(t *testing.T) {
t.Assert(array.FilterEmpty(), g.Slice{1, 2, 3, 4})
})
}
+
+func TestSortedArray_Walk(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ array := garray.NewSortedArrayFrom(g.Slice{"1", "2"}, gutil.ComparatorString)
+ t.Assert(array.Walk(func(value interface{}) interface{} {
+ return "key-" + gconv.String(value)
+ }), g.Slice{"key-1", "key-2"})
+ })
+}
diff --git a/container/garray/garray_z_unit_sorted_int_array_test.go b/container/garray/garray_z_unit_sorted_int_array_test.go
index 4265ddb08..f195fcd63 100644
--- a/container/garray/garray_z_unit_sorted_int_array_test.go
+++ b/container/garray/garray_z_unit_sorted_int_array_test.go
@@ -642,3 +642,12 @@ func TestSortedIntArray_FilterEmpty(t *testing.T) {
t.Assert(array.FilterEmpty(), g.SliceInt{1, 2, 3, 4})
})
}
+
+func TestSortedIntArray_Walk(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ array := garray.NewSortedIntArrayFrom(g.SliceInt{1, 2})
+ t.Assert(array.Walk(func(value int) int {
+ return 10 + value
+ }), g.Slice{11, 12})
+ })
+}
diff --git a/container/garray/garray_z_unit_sorted_str_array_test.go b/container/garray/garray_z_unit_sorted_str_array_test.go
index 0981add81..002c4e3b5 100644
--- a/container/garray/garray_z_unit_sorted_str_array_test.go
+++ b/container/garray/garray_z_unit_sorted_str_array_test.go
@@ -652,3 +652,12 @@ func TestSortedStrArray_FilterEmpty(t *testing.T) {
t.Assert(array.FilterEmpty(), g.SliceStr{"1", "2"})
})
}
+
+func TestSortedStrArray_Walk(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ array := garray.NewSortedStrArrayFrom(g.SliceStr{"1", "2"})
+ t.Assert(array.Walk(func(value string) string {
+ return "key-" + value
+ }), g.Slice{"key-1", "key-2"})
+ })
+}
diff --git a/container/glist/glist.go b/container/glist/glist.go
index 9e8dce8c1..6bdd3af9d 100644
--- a/container/glist/glist.go
+++ b/container/glist/glist.go
@@ -20,8 +20,8 @@ import (
type (
List struct {
- mu *rwmutex.RWMutex
- list *list.List
+ mu rwmutex.RWMutex
+ list list.List
}
Element = list.Element
@@ -30,8 +30,8 @@ type (
// New creates and returns a new empty doubly linked list.
func New(safe ...bool) *List {
return &List{
- mu: rwmutex.New(safe...),
- list: list.New(),
+ mu: rwmutex.Create(safe...),
+ list: list.List{},
}
}
@@ -39,12 +39,12 @@ func New(safe ...bool) *List {
// The parameter is used to specify whether using list in concurrent-safety,
// which is false in default.
func NewFrom(array []interface{}, safe ...bool) *List {
- l := list.New()
+ l := list.List{}
for _, v := range array {
l.PushBack(v)
}
return &List{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
list: l,
}
}
@@ -273,7 +273,7 @@ func (l *List) PushBackList(other *List) {
defer other.mu.RUnlock()
}
l.mu.Lock()
- l.list.PushBackList(other.list)
+ l.list.PushBackList(&other.list)
l.mu.Unlock()
}
@@ -285,7 +285,7 @@ func (l *List) PushFrontList(other *List) {
defer other.mu.RUnlock()
}
l.mu.Lock()
- l.list.PushFrontList(other.list)
+ l.list.PushFrontList(&other.list)
l.mu.Unlock()
}
@@ -332,7 +332,7 @@ func (l *List) Removes(es []*Element) {
// RemoveAll removes all elements from list .
func (l *List) RemoveAll() {
l.mu.Lock()
- l.list = list.New()
+ l.list = list.List{}
l.mu.Unlock()
}
@@ -345,14 +345,14 @@ func (l *List) Clear() {
func (l *List) RLockFunc(f func(list *list.List)) {
l.mu.RLock()
defer l.mu.RUnlock()
- f(l.list)
+ f(&l.list)
}
// LockFunc locks writing with given callback function within RWMutex.Lock.
func (l *List) LockFunc(f func(list *list.List)) {
l.mu.Lock()
defer l.mu.Unlock()
- f(l.list)
+ f(&l.list)
}
// Iterator is alias of IteratorAsc.
@@ -360,7 +360,7 @@ func (l *List) Iterator(f func(e *Element) bool) {
l.IteratorAsc(f)
}
-// IteratorAsc iterates the list in ascending order with given callback function .
+// IteratorAsc iterates the list readonly in ascending order with given callback function .
// If returns true, then it continues iterating; or false to stop.
func (l *List) IteratorAsc(f func(e *Element) bool) {
l.mu.RLock()
@@ -375,7 +375,7 @@ func (l *List) IteratorAsc(f func(e *Element) bool) {
}
}
-// IteratorDesc iterates the list in descending order with given callback function .
+// IteratorDesc iterates the list readonly in descending order with given callback function .
// If returns true, then it continues iterating; or false to stop.
func (l *List) IteratorDesc(f func(e *Element) bool) {
l.mu.RLock()
@@ -425,10 +425,6 @@ func (l *List) MarshalJSON() ([]byte, error) {
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
func (l *List) UnmarshalJSON(b []byte) error {
- if l.mu == nil {
- l.mu = rwmutex.New()
- l.list = list.New()
- }
l.mu.Lock()
defer l.mu.Unlock()
var array []interface{}
@@ -441,10 +437,6 @@ func (l *List) UnmarshalJSON(b []byte) error {
// UnmarshalValue is an interface implement which sets any type of value for list.
func (l *List) UnmarshalValue(value interface{}) (err error) {
- if l.mu == nil {
- l.mu = rwmutex.New()
- l.list = list.New()
- }
l.mu.Lock()
defer l.mu.Unlock()
var array []interface{}
diff --git a/container/glist/glist_z_unit_test.go b/container/glist/glist_z_unit_test.go
index 9d145d796..cd8b662cc 100644
--- a/container/glist/glist_z_unit_test.go
+++ b/container/glist/glist_z_unit_test.go
@@ -41,6 +41,44 @@ func checkListPointers(t *gtest.T, l *List, es []*Element) {
})
}
+func TestVar(t *testing.T) {
+ var l List
+ l.PushFront(1)
+ l.PushFront(2)
+ if v := l.PopBack(); v != 1 {
+ t.Errorf("EXPECT %v, GOT %v", 1, v)
+ } else {
+ //fmt.Println(v)
+ }
+ if v := l.PopBack(); v != 2 {
+ t.Errorf("EXPECT %v, GOT %v", 2, v)
+ } else {
+ //fmt.Println(v)
+ }
+ if v := l.PopBack(); v != nil {
+ t.Errorf("EXPECT %v, GOT %v", nil, v)
+ } else {
+ //fmt.Println(v)
+ }
+ l.PushBack(1)
+ l.PushBack(2)
+ if v := l.PopFront(); v != 1 {
+ t.Errorf("EXPECT %v, GOT %v", 1, v)
+ } else {
+ //fmt.Println(v)
+ }
+ if v := l.PopFront(); v != 2 {
+ t.Errorf("EXPECT %v, GOT %v", 2, v)
+ } else {
+ //fmt.Println(v)
+ }
+ if v := l.PopFront(); v != nil {
+ t.Errorf("EXPECT %v, GOT %v", nil, v)
+ } else {
+ //fmt.Println(v)
+ }
+}
+
func TestBasic(t *testing.T) {
l := New()
l.PushFront(1)
diff --git a/container/gmap/gmap.go b/container/gmap/gmap.go
index 1108262b1..4d0d28183 100644
--- a/container/gmap/gmap.go
+++ b/container/gmap/gmap.go
@@ -7,9 +7,10 @@
// Package gmap provides concurrent-safe/unsafe map containers.
package gmap
-// Map based on hash table, alias of AnyAnyMap.
-type Map = AnyAnyMap
-type HashMap = AnyAnyMap
+type (
+ Map = AnyAnyMap // Map is alias of AnyAnyMap.
+ HashMap = AnyAnyMap // HashMap is alias of AnyAnyMap.
+)
// New creates and returns an empty hash map.
// The parameter is used to specify whether using map in concurrent-safety,
diff --git a/container/gmap/gmap_hash_any_any_map.go b/container/gmap/gmap_hash_any_any_map.go
index 2a2b3c279..a26c486c7 100644
--- a/container/gmap/gmap_hash_any_any_map.go
+++ b/container/gmap/gmap_hash_any_any_map.go
@@ -18,7 +18,7 @@ import (
)
type AnyAnyMap struct {
- mu *rwmutex.RWMutex
+ mu rwmutex.RWMutex
data map[interface{}]interface{}
}
@@ -27,7 +27,7 @@ type AnyAnyMap struct {
// which is false in default.
func NewAnyAnyMap(safe ...bool) *AnyAnyMap {
return &AnyAnyMap{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
data: make(map[interface{}]interface{}),
}
}
@@ -37,12 +37,12 @@ func NewAnyAnyMap(safe ...bool) *AnyAnyMap {
// there might be some concurrent-safe issues when changing the map outside.
func NewAnyAnyMapFrom(data map[interface{}]interface{}, safe ...bool) *AnyAnyMap {
return &AnyAnyMap{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
data: data,
}
}
-// Iterator iterates the hash map with custom callback function .
+// Iterator iterates the hash map readonly with custom callback function .
// If returns true, then it continues iterating; or false to stop.
func (m *AnyAnyMap) Iterator(f func(k interface{}, v interface{}) bool) {
m.mu.RLock()
@@ -89,37 +89,44 @@ func (m *AnyAnyMap) MapCopy() map[interface{}]interface{} {
// MapStrAny returns a copy of the underlying data of the map as map[string]interface{}.
func (m *AnyAnyMap) MapStrAny() map[string]interface{} {
m.mu.RLock()
+ defer m.mu.RUnlock()
data := make(map[string]interface{}, len(m.data))
for k, v := range m.data {
data[gconv.String(k)] = v
}
- m.mu.RUnlock()
return data
}
// FilterEmpty deletes all key-value pair of which the value is empty.
func (m *AnyAnyMap) FilterEmpty() {
m.mu.Lock()
+ defer m.mu.Unlock()
for k, v := range m.data {
if empty.IsEmpty(v) {
delete(m.data, k)
}
}
- m.mu.Unlock()
}
// Set sets key-value to the hash map.
-func (m *AnyAnyMap) Set(key interface{}, val interface{}) {
+func (m *AnyAnyMap) Set(key interface{}, value interface{}) {
m.mu.Lock()
- m.data[key] = val
+ if m.data == nil {
+ m.data = make(map[interface{}]interface{})
+ }
+ m.data[key] = value
m.mu.Unlock()
}
// Sets batch sets key-values to the hash map.
func (m *AnyAnyMap) Sets(data map[interface{}]interface{}) {
m.mu.Lock()
- for k, v := range data {
- m.data[k] = v
+ if m.data == nil {
+ m.data = data
+ } else {
+ for k, v := range data {
+ m.data[k] = v
+ }
}
m.mu.Unlock()
}
@@ -128,17 +135,21 @@ func (m *AnyAnyMap) Sets(data map[interface{}]interface{}) {
// Second return parameter is true if key was found, otherwise false.
func (m *AnyAnyMap) Search(key interface{}) (value interface{}, found bool) {
m.mu.RLock()
- value, found = m.data[key]
+ if m.data != nil {
+ value, found = m.data[key]
+ }
m.mu.RUnlock()
return
}
// Get returns the value by given .
-func (m *AnyAnyMap) Get(key interface{}) interface{} {
+func (m *AnyAnyMap) Get(key interface{}) (value interface{}) {
m.mu.RLock()
- val, _ := m.data[key]
+ if m.data != nil {
+ value, _ = m.data[key]
+ }
m.mu.RUnlock()
- return val
+ return
}
// Pop retrieves and deletes an item from the map.
@@ -163,8 +174,10 @@ func (m *AnyAnyMap) Pops(size int) map[interface{}]interface{} {
if size == 0 {
return nil
}
- index := 0
- newMap := make(map[interface{}]interface{}, size)
+ var (
+ index = 0
+ newMap = make(map[interface{}]interface{}, size)
+ )
for k, v := range m.data {
delete(m.data, k)
newMap[k] = v
@@ -188,6 +201,9 @@ func (m *AnyAnyMap) Pops(size int) map[interface{}]interface{} {
func (m *AnyAnyMap) doSetWithLockCheck(key interface{}, value interface{}) interface{} {
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[interface{}]interface{})
+ }
if v, ok := m.data[key]; ok {
return v
}
@@ -235,26 +251,26 @@ func (m *AnyAnyMap) GetOrSetFuncLock(key interface{}, f func() interface{}) inte
}
}
-// GetVar returns a gvar.Var with the value by given .
-// The returned gvar.Var is un-concurrent safe.
+// GetVar returns a Var with the value by given .
+// The returned Var is un-concurrent safe.
func (m *AnyAnyMap) GetVar(key interface{}) *gvar.Var {
return gvar.New(m.Get(key))
}
-// GetVarOrSet returns a gvar.Var with result from GetVarOrSet.
-// The returned gvar.Var is un-concurrent safe.
+// GetVarOrSet returns a Var with result from GetVarOrSet.
+// The returned Var is un-concurrent safe.
func (m *AnyAnyMap) GetVarOrSet(key interface{}, value interface{}) *gvar.Var {
return gvar.New(m.GetOrSet(key, value))
}
-// GetVarOrSetFunc returns a gvar.Var with result from GetOrSetFunc.
-// The returned gvar.Var is un-concurrent safe.
+// GetVarOrSetFunc returns a Var with result from GetOrSetFunc.
+// The returned Var is un-concurrent safe.
func (m *AnyAnyMap) GetVarOrSetFunc(key interface{}, f func() interface{}) *gvar.Var {
return gvar.New(m.GetOrSetFunc(key, f))
}
-// GetVarOrSetFuncLock returns a gvar.Var with result from GetOrSetFuncLock.
-// The returned gvar.Var is un-concurrent safe.
+// GetVarOrSetFuncLock returns a Var with result from GetOrSetFuncLock.
+// The returned Var is un-concurrent safe.
func (m *AnyAnyMap) GetVarOrSetFuncLock(key interface{}, f func() interface{}) *gvar.Var {
return gvar.New(m.GetOrSetFuncLock(key, f))
}
@@ -293,21 +309,25 @@ func (m *AnyAnyMap) SetIfNotExistFuncLock(key interface{}, f func() interface{})
}
// Remove deletes value from map by given , and return this deleted value.
-func (m *AnyAnyMap) Remove(key interface{}) interface{} {
+func (m *AnyAnyMap) Remove(key interface{}) (value interface{}) {
m.mu.Lock()
- val, exists := m.data[key]
- if exists {
- delete(m.data, key)
+ if m.data != nil {
+ var ok bool
+ if value, ok = m.data[key]; ok {
+ delete(m.data, key)
+ }
}
m.mu.Unlock()
- return val
+ return
}
// Removes batch deletes values of the map by keys.
func (m *AnyAnyMap) Removes(keys []interface{}) {
m.mu.Lock()
- for _, key := range keys {
- delete(m.data, key)
+ if m.data != nil {
+ for _, key := range keys {
+ delete(m.data, key)
+ }
}
m.mu.Unlock()
}
@@ -315,36 +335,43 @@ func (m *AnyAnyMap) Removes(keys []interface{}) {
// Keys returns all keys of the map as a slice.
func (m *AnyAnyMap) Keys() []interface{} {
m.mu.RLock()
- keys := make([]interface{}, len(m.data))
- index := 0
+ defer m.mu.RUnlock()
+ var (
+ keys = make([]interface{}, len(m.data))
+ index = 0
+ )
for key := range m.data {
keys[index] = key
index++
}
- m.mu.RUnlock()
return keys
}
// Values returns all values of the map as a slice.
func (m *AnyAnyMap) Values() []interface{} {
m.mu.RLock()
- values := make([]interface{}, len(m.data))
- index := 0
+ defer m.mu.RUnlock()
+ var (
+ values = make([]interface{}, len(m.data))
+ index = 0
+ )
for _, value := range m.data {
values[index] = value
index++
}
- m.mu.RUnlock()
return values
}
// Contains checks whether a key exists.
// It returns true if the exists, or else false.
func (m *AnyAnyMap) Contains(key interface{}) bool {
+ var ok bool
m.mu.RLock()
- _, exists := m.data[key]
+ if m.data != nil {
+ _, ok = m.data[key]
+ }
m.mu.RUnlock()
- return exists
+ return ok
}
// Size returns the size of the map.
@@ -405,6 +432,10 @@ func (m *AnyAnyMap) Flip() {
func (m *AnyAnyMap) Merge(other *AnyAnyMap) {
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = other.MapCopy()
+ return
+ }
if other != m {
other.mu.RLock()
defer other.mu.RUnlock()
@@ -421,12 +452,11 @@ func (m *AnyAnyMap) MarshalJSON() ([]byte, error) {
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
func (m *AnyAnyMap) UnmarshalJSON(b []byte) error {
- if m.mu == nil {
- m.mu = rwmutex.New()
- m.data = make(map[interface{}]interface{})
- }
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[interface{}]interface{})
+ }
var data map[string]interface{}
if err := json.Unmarshal(b, &data); err != nil {
return err
@@ -439,12 +469,11 @@ func (m *AnyAnyMap) UnmarshalJSON(b []byte) error {
// UnmarshalValue is an interface implement which sets any type of value for map.
func (m *AnyAnyMap) UnmarshalValue(value interface{}) (err error) {
- if m.mu == nil {
- m.mu = rwmutex.New()
- m.data = make(map[interface{}]interface{})
- }
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[interface{}]interface{})
+ }
for k, v := range gconv.Map(value) {
m.data[k] = v
}
diff --git a/container/gmap/gmap_hash_int_any_map.go b/container/gmap/gmap_hash_int_any_map.go
index 8c3479add..cb72e812c 100644
--- a/container/gmap/gmap_hash_int_any_map.go
+++ b/container/gmap/gmap_hash_int_any_map.go
@@ -18,7 +18,7 @@ import (
)
type IntAnyMap struct {
- mu *rwmutex.RWMutex
+ mu rwmutex.RWMutex
data map[int]interface{}
}
@@ -27,7 +27,7 @@ type IntAnyMap struct {
// which is false in default.
func NewIntAnyMap(safe ...bool) *IntAnyMap {
return &IntAnyMap{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
data: make(map[int]interface{}),
}
}
@@ -37,12 +37,12 @@ func NewIntAnyMap(safe ...bool) *IntAnyMap {
// there might be some concurrent-safe issues when changing the map outside.
func NewIntAnyMapFrom(data map[int]interface{}, safe ...bool) *IntAnyMap {
return &IntAnyMap{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
data: data,
}
}
-// Iterator iterates the hash map with custom callback function .
+// Iterator iterates the hash map readonly with custom callback function .
// If returns true, then it continues iterating; or false to stop.
func (m *IntAnyMap) Iterator(f func(k int, v interface{}) bool) {
m.mu.RLock()
@@ -111,6 +111,9 @@ func (m *IntAnyMap) FilterEmpty() {
// Set sets key-value to the hash map.
func (m *IntAnyMap) Set(key int, val interface{}) {
m.mu.Lock()
+ if m.data == nil {
+ m.data = make(map[int]interface{})
+ }
m.data[key] = val
m.mu.Unlock()
}
@@ -118,8 +121,12 @@ func (m *IntAnyMap) Set(key int, val interface{}) {
// Sets batch sets key-values to the hash map.
func (m *IntAnyMap) Sets(data map[int]interface{}) {
m.mu.Lock()
- for k, v := range data {
- m.data[k] = v
+ if m.data == nil {
+ m.data = data
+ } else {
+ for k, v := range data {
+ m.data[k] = v
+ }
}
m.mu.Unlock()
}
@@ -128,17 +135,21 @@ func (m *IntAnyMap) Sets(data map[int]interface{}) {
// Second return parameter is true if key was found, otherwise false.
func (m *IntAnyMap) Search(key int) (value interface{}, found bool) {
m.mu.RLock()
- value, found = m.data[key]
+ if m.data != nil {
+ value, found = m.data[key]
+ }
m.mu.RUnlock()
return
}
// Get returns the value by given .
-func (m *IntAnyMap) Get(key int) interface{} {
+func (m *IntAnyMap) Get(key int) (value interface{}) {
m.mu.RLock()
- val, _ := m.data[key]
+ if m.data != nil {
+ value, _ = m.data[key]
+ }
m.mu.RUnlock()
- return val
+ return
}
// Pop retrieves and deletes an item from the map.
@@ -163,8 +174,10 @@ func (m *IntAnyMap) Pops(size int) map[int]interface{} {
if size == 0 {
return nil
}
- index := 0
- newMap := make(map[int]interface{}, size)
+ var (
+ index = 0
+ newMap = make(map[int]interface{}, size)
+ )
for k, v := range m.data {
delete(m.data, k)
newMap[k] = v
@@ -188,6 +201,9 @@ func (m *IntAnyMap) Pops(size int) map[int]interface{} {
func (m *IntAnyMap) doSetWithLockCheck(key int, value interface{}) interface{} {
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[int]interface{})
+ }
if v, ok := m.data[key]; ok {
return v
}
@@ -233,26 +249,26 @@ func (m *IntAnyMap) GetOrSetFuncLock(key int, f func() interface{}) interface{}
}
}
-// GetVar returns a gvar.Var with the value by given .
-// The returned gvar.Var is un-concurrent safe.
+// GetVar returns a Var with the value by given .
+// The returned Var is un-concurrent safe.
func (m *IntAnyMap) GetVar(key int) *gvar.Var {
return gvar.New(m.Get(key))
}
-// GetVarOrSet returns a gvar.Var with result from GetVarOrSet.
-// The returned gvar.Var is un-concurrent safe.
+// GetVarOrSet returns a Var with result from GetVarOrSet.
+// The returned Var is un-concurrent safe.
func (m *IntAnyMap) GetVarOrSet(key int, value interface{}) *gvar.Var {
return gvar.New(m.GetOrSet(key, value))
}
-// GetVarOrSetFunc returns a gvar.Var with result from GetOrSetFunc.
-// The returned gvar.Var is un-concurrent safe.
+// GetVarOrSetFunc returns a Var with result from GetOrSetFunc.
+// The returned Var is un-concurrent safe.
func (m *IntAnyMap) GetVarOrSetFunc(key int, f func() interface{}) *gvar.Var {
return gvar.New(m.GetOrSetFunc(key, f))
}
-// GetVarOrSetFuncLock returns a gvar.Var with result from GetOrSetFuncLock.
-// The returned gvar.Var is un-concurrent safe.
+// GetVarOrSetFuncLock returns a Var with result from GetOrSetFuncLock.
+// The returned Var is un-concurrent safe.
func (m *IntAnyMap) GetVarOrSetFuncLock(key int, f func() interface{}) *gvar.Var {
return gvar.New(m.GetOrSetFuncLock(key, f))
}
@@ -293,28 +309,34 @@ func (m *IntAnyMap) SetIfNotExistFuncLock(key int, f func() interface{}) bool {
// Removes batch deletes values of the map by keys.
func (m *IntAnyMap) Removes(keys []int) {
m.mu.Lock()
- for _, key := range keys {
- delete(m.data, key)
+ if m.data != nil {
+ for _, key := range keys {
+ delete(m.data, key)
+ }
}
m.mu.Unlock()
}
// Remove deletes value from map by given , and return this deleted value.
-func (m *IntAnyMap) Remove(key int) interface{} {
+func (m *IntAnyMap) Remove(key int) (value interface{}) {
m.mu.Lock()
- val, exists := m.data[key]
- if exists {
- delete(m.data, key)
+ if m.data != nil {
+ var ok bool
+ if value, ok = m.data[key]; ok {
+ delete(m.data, key)
+ }
}
m.mu.Unlock()
- return val
+ return
}
// Keys returns all keys of the map as a slice.
func (m *IntAnyMap) Keys() []int {
m.mu.RLock()
- keys := make([]int, len(m.data))
- index := 0
+ var (
+ keys = make([]int, len(m.data))
+ index = 0
+ )
for key := range m.data {
keys[index] = key
index++
@@ -326,8 +348,10 @@ func (m *IntAnyMap) Keys() []int {
// Values returns all values of the map as a slice.
func (m *IntAnyMap) Values() []interface{} {
m.mu.RLock()
- values := make([]interface{}, len(m.data))
- index := 0
+ var (
+ values = make([]interface{}, len(m.data))
+ index = 0
+ )
for _, value := range m.data {
values[index] = value
index++
@@ -339,10 +363,13 @@ func (m *IntAnyMap) Values() []interface{} {
// Contains checks whether a key exists.
// It returns true if the exists, or else false.
func (m *IntAnyMap) Contains(key int) bool {
+ var ok bool
m.mu.RLock()
- _, exists := m.data[key]
+ if m.data != nil {
+ _, ok = m.data[key]
+ }
m.mu.RUnlock()
- return exists
+ return ok
}
// Size returns the size of the map.
@@ -403,6 +430,10 @@ func (m *IntAnyMap) Flip() {
func (m *IntAnyMap) Merge(other *IntAnyMap) {
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = other.MapCopy()
+ return
+ }
if other != m {
other.mu.RLock()
defer other.mu.RUnlock()
@@ -421,12 +452,11 @@ func (m *IntAnyMap) MarshalJSON() ([]byte, error) {
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
func (m *IntAnyMap) UnmarshalJSON(b []byte) error {
- if m.mu == nil {
- m.mu = rwmutex.New()
- m.data = make(map[int]interface{})
- }
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[int]interface{})
+ }
if err := json.Unmarshal(b, &m.data); err != nil {
return err
}
@@ -435,12 +465,11 @@ func (m *IntAnyMap) UnmarshalJSON(b []byte) error {
// UnmarshalValue is an interface implement which sets any type of value for map.
func (m *IntAnyMap) UnmarshalValue(value interface{}) (err error) {
- if m.mu == nil {
- m.mu = rwmutex.New()
- m.data = make(map[int]interface{})
- }
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[int]interface{})
+ }
switch value.(type) {
case string, []byte:
return json.Unmarshal(gconv.Bytes(value), &m.data)
diff --git a/container/gmap/gmap_hash_int_int_map.go b/container/gmap/gmap_hash_int_int_map.go
index 826ac3d59..eb6449831 100644
--- a/container/gmap/gmap_hash_int_int_map.go
+++ b/container/gmap/gmap_hash_int_int_map.go
@@ -16,7 +16,7 @@ import (
)
type IntIntMap struct {
- mu *rwmutex.RWMutex
+ mu rwmutex.RWMutex
data map[int]int
}
@@ -25,7 +25,7 @@ type IntIntMap struct {
// which is false in default.
func NewIntIntMap(safe ...bool) *IntIntMap {
return &IntIntMap{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
data: make(map[int]int),
}
}
@@ -35,12 +35,12 @@ func NewIntIntMap(safe ...bool) *IntIntMap {
// there might be some concurrent-safe issues when changing the map outside.
func NewIntIntMapFrom(data map[int]int, safe ...bool) *IntIntMap {
return &IntIntMap{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
data: data,
}
}
-// Iterator iterates the hash map with custom callback function .
+// Iterator iterates the hash map readonly with custom callback function .
// If returns true, then it continues iterating; or false to stop.
func (m *IntIntMap) Iterator(f func(k int, v int) bool) {
m.mu.RLock()
@@ -109,6 +109,9 @@ func (m *IntIntMap) FilterEmpty() {
// Set sets key-value to the hash map.
func (m *IntIntMap) Set(key int, val int) {
m.mu.Lock()
+ if m.data == nil {
+ m.data = make(map[int]int)
+ }
m.data[key] = val
m.mu.Unlock()
}
@@ -116,8 +119,12 @@ func (m *IntIntMap) Set(key int, val int) {
// Sets batch sets key-values to the hash map.
func (m *IntIntMap) Sets(data map[int]int) {
m.mu.Lock()
- for k, v := range data {
- m.data[k] = v
+ if m.data == nil {
+ m.data = data
+ } else {
+ for k, v := range data {
+ m.data[k] = v
+ }
}
m.mu.Unlock()
}
@@ -126,17 +133,21 @@ func (m *IntIntMap) Sets(data map[int]int) {
// Second return parameter is true if key was found, otherwise false.
func (m *IntIntMap) Search(key int) (value int, found bool) {
m.mu.RLock()
- value, found = m.data[key]
+ if m.data != nil {
+ value, found = m.data[key]
+ }
m.mu.RUnlock()
return
}
// Get returns the value by given .
-func (m *IntIntMap) Get(key int) int {
+func (m *IntIntMap) Get(key int) (value int) {
m.mu.RLock()
- val, _ := m.data[key]
+ if m.data != nil {
+ value, _ = m.data[key]
+ }
m.mu.RUnlock()
- return val
+ return
}
// Pop retrieves and deletes an item from the map.
@@ -161,8 +172,10 @@ func (m *IntIntMap) Pops(size int) map[int]int {
if size == 0 {
return nil
}
- index := 0
- newMap := make(map[int]int, size)
+ var (
+ index = 0
+ newMap = make(map[int]int, size)
+ )
for k, v := range m.data {
delete(m.data, k)
newMap[k] = v
@@ -181,12 +194,14 @@ func (m *IntIntMap) Pops(size int) map[int]int {
// It returns value with given .
func (m *IntIntMap) doSetWithLockCheck(key int, value int) int {
m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[int]int)
+ }
if v, ok := m.data[key]; ok {
- m.mu.Unlock()
return v
}
m.data[key] = value
- m.mu.Unlock()
return value
}
@@ -219,6 +234,9 @@ func (m *IntIntMap) GetOrSetFuncLock(key int, f func() int) int {
if v, ok := m.Search(key); !ok {
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[int]int)
+ }
if v, ok = m.data[key]; ok {
return v
}
@@ -259,6 +277,9 @@ func (m *IntIntMap) SetIfNotExistFuncLock(key int, f func() int) bool {
if !m.Contains(key) {
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[int]int)
+ }
if _, ok := m.data[key]; !ok {
m.data[key] = f()
}
@@ -270,28 +291,34 @@ func (m *IntIntMap) SetIfNotExistFuncLock(key int, f func() int) bool {
// Removes batch deletes values of the map by keys.
func (m *IntIntMap) Removes(keys []int) {
m.mu.Lock()
- for _, key := range keys {
- delete(m.data, key)
+ if m.data != nil {
+ for _, key := range keys {
+ delete(m.data, key)
+ }
}
m.mu.Unlock()
}
// Remove deletes value from map by given , and return this deleted value.
-func (m *IntIntMap) Remove(key int) int {
+func (m *IntIntMap) Remove(key int) (value int) {
m.mu.Lock()
- val, exists := m.data[key]
- if exists {
- delete(m.data, key)
+ if m.data != nil {
+ var ok bool
+ if value, ok = m.data[key]; ok {
+ delete(m.data, key)
+ }
}
m.mu.Unlock()
- return val
+ return
}
// Keys returns all keys of the map as a slice.
func (m *IntIntMap) Keys() []int {
m.mu.RLock()
- keys := make([]int, len(m.data))
- index := 0
+ var (
+ keys = make([]int, len(m.data))
+ index = 0
+ )
for key := range m.data {
keys[index] = key
index++
@@ -303,8 +330,10 @@ func (m *IntIntMap) Keys() []int {
// Values returns all values of the map as a slice.
func (m *IntIntMap) Values() []int {
m.mu.RLock()
- values := make([]int, len(m.data))
- index := 0
+ var (
+ values = make([]int, len(m.data))
+ index = 0
+ )
for _, value := range m.data {
values[index] = value
index++
@@ -316,10 +345,13 @@ func (m *IntIntMap) Values() []int {
// Contains checks whether a key exists.
// It returns true if the exists, or else false.
func (m *IntIntMap) Contains(key int) bool {
+ var ok bool
m.mu.RLock()
- _, exists := m.data[key]
+ if m.data != nil {
+ _, ok = m.data[key]
+ }
m.mu.RUnlock()
- return exists
+ return ok
}
// Size returns the size of the map.
@@ -380,6 +412,10 @@ func (m *IntIntMap) Flip() {
func (m *IntIntMap) Merge(other *IntIntMap) {
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = other.MapCopy()
+ return
+ }
if other != m {
other.mu.RLock()
defer other.mu.RUnlock()
@@ -398,12 +434,11 @@ func (m *IntIntMap) MarshalJSON() ([]byte, error) {
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
func (m *IntIntMap) UnmarshalJSON(b []byte) error {
- if m.mu == nil {
- m.mu = rwmutex.New()
- m.data = make(map[int]int)
- }
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[int]int)
+ }
if err := json.Unmarshal(b, &m.data); err != nil {
return err
}
@@ -412,12 +447,11 @@ func (m *IntIntMap) UnmarshalJSON(b []byte) error {
// UnmarshalValue is an interface implement which sets any type of value for map.
func (m *IntIntMap) UnmarshalValue(value interface{}) (err error) {
- if m.mu == nil {
- m.mu = rwmutex.New()
- m.data = make(map[int]int)
- }
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[int]int)
+ }
switch value.(type) {
case string, []byte:
return json.Unmarshal(gconv.Bytes(value), &m.data)
diff --git a/container/gmap/gmap_hash_int_str_map.go b/container/gmap/gmap_hash_int_str_map.go
index 5db6b23f8..842d288e8 100644
--- a/container/gmap/gmap_hash_int_str_map.go
+++ b/container/gmap/gmap_hash_int_str_map.go
@@ -16,7 +16,7 @@ import (
)
type IntStrMap struct {
- mu *rwmutex.RWMutex
+ mu rwmutex.RWMutex
data map[int]string
}
@@ -25,7 +25,7 @@ type IntStrMap struct {
// which is false in default.
func NewIntStrMap(safe ...bool) *IntStrMap {
return &IntStrMap{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
data: make(map[int]string),
}
}
@@ -35,12 +35,12 @@ func NewIntStrMap(safe ...bool) *IntStrMap {
// there might be some concurrent-safe issues when changing the map outside.
func NewIntStrMapFrom(data map[int]string, safe ...bool) *IntStrMap {
return &IntStrMap{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
data: data,
}
}
-// Iterator iterates the hash map with custom callback function .
+// Iterator iterates the hash map readonly with custom callback function .
// If returns true, then it continues iterating; or false to stop.
func (m *IntStrMap) Iterator(f func(k int, v string) bool) {
m.mu.RLock()
@@ -109,6 +109,9 @@ func (m *IntStrMap) FilterEmpty() {
// Set sets key-value to the hash map.
func (m *IntStrMap) Set(key int, val string) {
m.mu.Lock()
+ if m.data == nil {
+ m.data = make(map[int]string)
+ }
m.data[key] = val
m.mu.Unlock()
}
@@ -116,8 +119,12 @@ func (m *IntStrMap) Set(key int, val string) {
// Sets batch sets key-values to the hash map.
func (m *IntStrMap) Sets(data map[int]string) {
m.mu.Lock()
- for k, v := range data {
- m.data[k] = v
+ if m.data == nil {
+ m.data = data
+ } else {
+ for k, v := range data {
+ m.data[k] = v
+ }
}
m.mu.Unlock()
}
@@ -126,17 +133,21 @@ func (m *IntStrMap) Sets(data map[int]string) {
// Second return parameter is true if key was found, otherwise false.
func (m *IntStrMap) Search(key int) (value string, found bool) {
m.mu.RLock()
- value, found = m.data[key]
+ if m.data != nil {
+ value, found = m.data[key]
+ }
m.mu.RUnlock()
return
}
// Get returns the value by given .
-func (m *IntStrMap) Get(key int) string {
+func (m *IntStrMap) Get(key int) (value string) {
m.mu.RLock()
- val, _ := m.data[key]
+ if m.data != nil {
+ value, _ = m.data[key]
+ }
m.mu.RUnlock()
- return val
+ return
}
// Pop retrieves and deletes an item from the map.
@@ -161,8 +172,10 @@ func (m *IntStrMap) Pops(size int) map[int]string {
if size == 0 {
return nil
}
- index := 0
- newMap := make(map[int]string, size)
+ var (
+ index = 0
+ newMap = make(map[int]string, size)
+ )
for k, v := range m.data {
delete(m.data, k)
newMap[k] = v
@@ -182,6 +195,9 @@ func (m *IntStrMap) Pops(size int) map[int]string {
func (m *IntStrMap) doSetWithLockCheck(key int, value string) string {
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[int]string)
+ }
if v, ok := m.data[key]; ok {
return v
}
@@ -218,13 +234,14 @@ func (m *IntStrMap) GetOrSetFuncLock(key int, f func() string) string {
if v, ok := m.Search(key); !ok {
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[int]string)
+ }
if v, ok = m.data[key]; ok {
return v
}
v = f()
- if v != "" {
- m.data[key] = v
- }
+ m.data[key] = v
return v
} else {
return v
@@ -260,6 +277,9 @@ func (m *IntStrMap) SetIfNotExistFuncLock(key int, f func() string) bool {
if !m.Contains(key) {
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[int]string)
+ }
if _, ok := m.data[key]; !ok {
m.data[key] = f()
}
@@ -271,28 +291,34 @@ func (m *IntStrMap) SetIfNotExistFuncLock(key int, f func() string) bool {
// Removes batch deletes values of the map by keys.
func (m *IntStrMap) Removes(keys []int) {
m.mu.Lock()
- for _, key := range keys {
- delete(m.data, key)
+ if m.data != nil {
+ for _, key := range keys {
+ delete(m.data, key)
+ }
}
m.mu.Unlock()
}
// Remove deletes value from map by given , and return this deleted value.
-func (m *IntStrMap) Remove(key int) string {
+func (m *IntStrMap) Remove(key int) (value string) {
m.mu.Lock()
- val, exists := m.data[key]
- if exists {
- delete(m.data, key)
+ if m.data != nil {
+ var ok bool
+ if value, ok = m.data[key]; ok {
+ delete(m.data, key)
+ }
}
m.mu.Unlock()
- return val
+ return
}
// Keys returns all keys of the map as a slice.
func (m *IntStrMap) Keys() []int {
m.mu.RLock()
- keys := make([]int, len(m.data))
- index := 0
+ var (
+ keys = make([]int, len(m.data))
+ index = 0
+ )
for key := range m.data {
keys[index] = key
index++
@@ -304,8 +330,10 @@ func (m *IntStrMap) Keys() []int {
// Values returns all values of the map as a slice.
func (m *IntStrMap) Values() []string {
m.mu.RLock()
- values := make([]string, len(m.data))
- index := 0
+ var (
+ values = make([]string, len(m.data))
+ index = 0
+ )
for _, value := range m.data {
values[index] = value
index++
@@ -317,10 +345,13 @@ func (m *IntStrMap) Values() []string {
// Contains checks whether a key exists.
// It returns true if the exists, or else false.
func (m *IntStrMap) Contains(key int) bool {
+ var ok bool
m.mu.RLock()
- _, exists := m.data[key]
+ if m.data != nil {
+ _, ok = m.data[key]
+ }
m.mu.RUnlock()
- return exists
+ return ok
}
// Size returns the size of the map.
@@ -381,6 +412,10 @@ func (m *IntStrMap) Flip() {
func (m *IntStrMap) Merge(other *IntStrMap) {
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = other.MapCopy()
+ return
+ }
if other != m {
other.mu.RLock()
defer other.mu.RUnlock()
@@ -399,12 +434,11 @@ func (m *IntStrMap) MarshalJSON() ([]byte, error) {
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
func (m *IntStrMap) UnmarshalJSON(b []byte) error {
- if m.mu == nil {
- m.mu = rwmutex.New()
- m.data = make(map[int]string)
- }
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[int]string)
+ }
if err := json.Unmarshal(b, &m.data); err != nil {
return err
}
@@ -413,12 +447,11 @@ func (m *IntStrMap) UnmarshalJSON(b []byte) error {
// UnmarshalValue is an interface implement which sets any type of value for map.
func (m *IntStrMap) UnmarshalValue(value interface{}) (err error) {
- if m.mu == nil {
- m.mu = rwmutex.New()
- m.data = make(map[int]string)
- }
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[int]string)
+ }
switch value.(type) {
case string, []byte:
return json.Unmarshal(gconv.Bytes(value), &m.data)
diff --git a/container/gmap/gmap_hash_str_any_map.go b/container/gmap/gmap_hash_str_any_map.go
index cd7925c08..08b466018 100644
--- a/container/gmap/gmap_hash_str_any_map.go
+++ b/container/gmap/gmap_hash_str_any_map.go
@@ -18,7 +18,7 @@ import (
)
type StrAnyMap struct {
- mu *rwmutex.RWMutex
+ mu rwmutex.RWMutex
data map[string]interface{}
}
@@ -27,7 +27,7 @@ type StrAnyMap struct {
// which is false in default.
func NewStrAnyMap(safe ...bool) *StrAnyMap {
return &StrAnyMap{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
data: make(map[string]interface{}),
}
}
@@ -37,12 +37,12 @@ func NewStrAnyMap(safe ...bool) *StrAnyMap {
// there might be some concurrent-safe issues when changing the map outside.
func NewStrAnyMapFrom(data map[string]interface{}, safe ...bool) *StrAnyMap {
return &StrAnyMap{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
data: data,
}
}
-// Iterator iterates the hash map with custom callback function .
+// Iterator iterates the hash map readonly with custom callback function .
// If returns true, then it continues iterating; or false to stop.
func (m *StrAnyMap) Iterator(f func(k string, v interface{}) bool) {
m.mu.RLock()
@@ -105,6 +105,9 @@ func (m *StrAnyMap) FilterEmpty() {
// Set sets key-value to the hash map.
func (m *StrAnyMap) Set(key string, val interface{}) {
m.mu.Lock()
+ if m.data == nil {
+ m.data = make(map[string]interface{})
+ }
m.data[key] = val
m.mu.Unlock()
}
@@ -112,8 +115,12 @@ func (m *StrAnyMap) Set(key string, val interface{}) {
// Sets batch sets key-values to the hash map.
func (m *StrAnyMap) Sets(data map[string]interface{}) {
m.mu.Lock()
- for k, v := range data {
- m.data[k] = v
+ if m.data == nil {
+ m.data = data
+ } else {
+ for k, v := range data {
+ m.data[k] = v
+ }
}
m.mu.Unlock()
}
@@ -122,17 +129,21 @@ func (m *StrAnyMap) Sets(data map[string]interface{}) {
// Second return parameter is true if key was found, otherwise false.
func (m *StrAnyMap) Search(key string) (value interface{}, found bool) {
m.mu.RLock()
- value, found = m.data[key]
+ if m.data != nil {
+ value, found = m.data[key]
+ }
m.mu.RUnlock()
return
}
// Get returns the value by given .
-func (m *StrAnyMap) Get(key string) interface{} {
+func (m *StrAnyMap) Get(key string) (value interface{}) {
m.mu.RLock()
- val, _ := m.data[key]
+ if m.data != nil {
+ value, _ = m.data[key]
+ }
m.mu.RUnlock()
- return val
+ return
}
// Pop retrieves and deletes an item from the map.
@@ -157,8 +168,10 @@ func (m *StrAnyMap) Pops(size int) map[string]interface{} {
if size == 0 {
return nil
}
- index := 0
- newMap := make(map[string]interface{}, size)
+ var (
+ index = 0
+ newMap = make(map[string]interface{}, size)
+ )
for k, v := range m.data {
delete(m.data, k)
newMap[k] = v
@@ -182,6 +195,9 @@ func (m *StrAnyMap) Pops(size int) map[string]interface{} {
func (m *StrAnyMap) doSetWithLockCheck(key string, value interface{}) interface{} {
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[string]interface{})
+ }
if v, ok := m.data[key]; ok {
return v
}
@@ -229,26 +245,26 @@ func (m *StrAnyMap) GetOrSetFuncLock(key string, f func() interface{}) interface
}
}
-// GetVar returns a gvar.Var with the value by given .
-// The returned gvar.Var is un-concurrent safe.
+// GetVar returns a Var with the value by given .
+// The returned Var is un-concurrent safe.
func (m *StrAnyMap) GetVar(key string) *gvar.Var {
return gvar.New(m.Get(key))
}
-// GetVarOrSet returns a gvar.Var with result from GetVarOrSet.
-// The returned gvar.Var is un-concurrent safe.
+// GetVarOrSet returns a Var with result from GetVarOrSet.
+// The returned Var is un-concurrent safe.
func (m *StrAnyMap) GetVarOrSet(key string, value interface{}) *gvar.Var {
return gvar.New(m.GetOrSet(key, value))
}
-// GetVarOrSetFunc returns a gvar.Var with result from GetOrSetFunc.
-// The returned gvar.Var is un-concurrent safe.
+// GetVarOrSetFunc returns a Var with result from GetOrSetFunc.
+// The returned Var is un-concurrent safe.
func (m *StrAnyMap) GetVarOrSetFunc(key string, f func() interface{}) *gvar.Var {
return gvar.New(m.GetOrSetFunc(key, f))
}
-// GetVarOrSetFuncLock returns a gvar.Var with result from GetOrSetFuncLock.
-// The returned gvar.Var is un-concurrent safe.
+// GetVarOrSetFuncLock returns a Var with result from GetOrSetFuncLock.
+// The returned Var is un-concurrent safe.
func (m *StrAnyMap) GetVarOrSetFuncLock(key string, f func() interface{}) *gvar.Var {
return gvar.New(m.GetOrSetFuncLock(key, f))
}
@@ -289,28 +305,34 @@ func (m *StrAnyMap) SetIfNotExistFuncLock(key string, f func() interface{}) bool
// Removes batch deletes values of the map by keys.
func (m *StrAnyMap) Removes(keys []string) {
m.mu.Lock()
- for _, key := range keys {
- delete(m.data, key)
+ if m.data != nil {
+ for _, key := range keys {
+ delete(m.data, key)
+ }
}
m.mu.Unlock()
}
// Remove deletes value from map by given , and return this deleted value.
-func (m *StrAnyMap) Remove(key string) interface{} {
+func (m *StrAnyMap) Remove(key string) (value interface{}) {
m.mu.Lock()
- val, exists := m.data[key]
- if exists {
- delete(m.data, key)
+ if m.data != nil {
+ var ok bool
+ if value, ok = m.data[key]; ok {
+ delete(m.data, key)
+ }
}
m.mu.Unlock()
- return val
+ return
}
// Keys returns all keys of the map as a slice.
func (m *StrAnyMap) Keys() []string {
m.mu.RLock()
- keys := make([]string, len(m.data))
- index := 0
+ var (
+ keys = make([]string, len(m.data))
+ index = 0
+ )
for key := range m.data {
keys[index] = key
index++
@@ -322,8 +344,10 @@ func (m *StrAnyMap) Keys() []string {
// Values returns all values of the map as a slice.
func (m *StrAnyMap) Values() []interface{} {
m.mu.RLock()
- values := make([]interface{}, len(m.data))
- index := 0
+ var (
+ values = make([]interface{}, len(m.data))
+ index = 0
+ )
for _, value := range m.data {
values[index] = value
index++
@@ -335,10 +359,13 @@ func (m *StrAnyMap) Values() []interface{} {
// Contains checks whether a key exists.
// It returns true if the exists, or else false.
func (m *StrAnyMap) Contains(key string) bool {
+ var ok bool
m.mu.RLock()
- _, exists := m.data[key]
+ if m.data != nil {
+ _, ok = m.data[key]
+ }
m.mu.RUnlock()
- return exists
+ return ok
}
// Size returns the size of the map.
@@ -399,6 +426,10 @@ func (m *StrAnyMap) Flip() {
func (m *StrAnyMap) Merge(other *StrAnyMap) {
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = other.MapCopy()
+ return
+ }
if other != m {
other.mu.RLock()
defer other.mu.RUnlock()
@@ -417,12 +448,11 @@ func (m *StrAnyMap) MarshalJSON() ([]byte, error) {
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
func (m *StrAnyMap) UnmarshalJSON(b []byte) error {
- if m.mu == nil {
- m.mu = rwmutex.New()
- m.data = make(map[string]interface{})
- }
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[string]interface{})
+ }
if err := json.Unmarshal(b, &m.data); err != nil {
return err
}
@@ -431,10 +461,6 @@ func (m *StrAnyMap) UnmarshalJSON(b []byte) error {
// UnmarshalValue is an interface implement which sets any type of value for map.
func (m *StrAnyMap) UnmarshalValue(value interface{}) (err error) {
- if m.mu == nil {
- m.mu = rwmutex.New()
- m.data = make(map[string]interface{})
- }
m.mu.Lock()
defer m.mu.Unlock()
m.data = gconv.Map(value)
diff --git a/container/gmap/gmap_hash_str_int_map.go b/container/gmap/gmap_hash_str_int_map.go
index 2f98237c3..df19a1296 100644
--- a/container/gmap/gmap_hash_str_int_map.go
+++ b/container/gmap/gmap_hash_str_int_map.go
@@ -16,7 +16,7 @@ import (
)
type StrIntMap struct {
- mu *rwmutex.RWMutex
+ mu rwmutex.RWMutex
data map[string]int
}
@@ -25,7 +25,7 @@ type StrIntMap struct {
// which is false in default.
func NewStrIntMap(safe ...bool) *StrIntMap {
return &StrIntMap{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
data: make(map[string]int),
}
}
@@ -35,12 +35,12 @@ func NewStrIntMap(safe ...bool) *StrIntMap {
// there might be some concurrent-safe issues when changing the map outside.
func NewStrIntMapFrom(data map[string]int, safe ...bool) *StrIntMap {
return &StrIntMap{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
data: data,
}
}
-// Iterator iterates the hash map with custom callback function .
+// Iterator iterates the hash map readonly with custom callback function .
// If returns true, then it continues iterating; or false to stop.
func (m *StrIntMap) Iterator(f func(k string, v int) bool) {
m.mu.RLock()
@@ -76,11 +76,11 @@ func (m *StrIntMap) Map() map[string]int {
// MapStrAny returns a copy of the underlying data of the map as map[string]interface{}.
func (m *StrIntMap) MapStrAny() map[string]interface{} {
m.mu.RLock()
+ defer m.mu.RUnlock()
data := make(map[string]interface{}, len(m.data))
for k, v := range m.data {
data[k] = v
}
- m.mu.RUnlock()
return data
}
@@ -109,6 +109,9 @@ func (m *StrIntMap) FilterEmpty() {
// Set sets key-value to the hash map.
func (m *StrIntMap) Set(key string, val int) {
m.mu.Lock()
+ if m.data == nil {
+ m.data = make(map[string]int)
+ }
m.data[key] = val
m.mu.Unlock()
}
@@ -116,8 +119,12 @@ func (m *StrIntMap) Set(key string, val int) {
// Sets batch sets key-values to the hash map.
func (m *StrIntMap) Sets(data map[string]int) {
m.mu.Lock()
- for k, v := range data {
- m.data[k] = v
+ if m.data == nil {
+ m.data = data
+ } else {
+ for k, v := range data {
+ m.data[k] = v
+ }
}
m.mu.Unlock()
}
@@ -126,17 +133,21 @@ func (m *StrIntMap) Sets(data map[string]int) {
// Second return parameter is true if key was found, otherwise false.
func (m *StrIntMap) Search(key string) (value int, found bool) {
m.mu.RLock()
- value, found = m.data[key]
+ if m.data != nil {
+ value, found = m.data[key]
+ }
m.mu.RUnlock()
return
}
// Get returns the value by given .
-func (m *StrIntMap) Get(key string) int {
+func (m *StrIntMap) Get(key string) (value int) {
m.mu.RLock()
- val, _ := m.data[key]
+ if m.data != nil {
+ value, _ = m.data[key]
+ }
m.mu.RUnlock()
- return val
+ return
}
// Pop retrieves and deletes an item from the map.
@@ -161,8 +172,10 @@ func (m *StrIntMap) Pops(size int) map[string]int {
if size == 0 {
return nil
}
- index := 0
- newMap := make(map[string]int, size)
+ var (
+ index = 0
+ newMap = make(map[string]int, size)
+ )
for k, v := range m.data {
delete(m.data, k)
newMap[k] = v
@@ -181,6 +194,9 @@ func (m *StrIntMap) Pops(size int) map[string]int {
// It returns value with given .
func (m *StrIntMap) doSetWithLockCheck(key string, value int) int {
m.mu.Lock()
+ if m.data == nil {
+ m.data = make(map[string]int)
+ }
if v, ok := m.data[key]; ok {
m.mu.Unlock()
return v
@@ -221,6 +237,9 @@ func (m *StrIntMap) GetOrSetFuncLock(key string, f func() int) int {
if v, ok := m.Search(key); !ok {
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[string]int)
+ }
if v, ok = m.data[key]; ok {
return v
}
@@ -261,6 +280,9 @@ func (m *StrIntMap) SetIfNotExistFuncLock(key string, f func() int) bool {
if !m.Contains(key) {
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[string]int)
+ }
if _, ok := m.data[key]; !ok {
m.data[key] = f()
}
@@ -272,28 +294,34 @@ func (m *StrIntMap) SetIfNotExistFuncLock(key string, f func() int) bool {
// Removes batch deletes values of the map by keys.
func (m *StrIntMap) Removes(keys []string) {
m.mu.Lock()
- for _, key := range keys {
- delete(m.data, key)
+ if m.data != nil {
+ for _, key := range keys {
+ delete(m.data, key)
+ }
}
m.mu.Unlock()
}
// Remove deletes value from map by given , and return this deleted value.
-func (m *StrIntMap) Remove(key string) int {
+func (m *StrIntMap) Remove(key string) (value int) {
m.mu.Lock()
- val, exists := m.data[key]
- if exists {
- delete(m.data, key)
+ if m.data != nil {
+ var ok bool
+ if value, ok = m.data[key]; ok {
+ delete(m.data, key)
+ }
}
m.mu.Unlock()
- return val
+ return
}
// Keys returns all keys of the map as a slice.
func (m *StrIntMap) Keys() []string {
m.mu.RLock()
- keys := make([]string, len(m.data))
- index := 0
+ var (
+ keys = make([]string, len(m.data))
+ index = 0
+ )
for key := range m.data {
keys[index] = key
index++
@@ -305,8 +333,10 @@ func (m *StrIntMap) Keys() []string {
// Values returns all values of the map as a slice.
func (m *StrIntMap) Values() []int {
m.mu.RLock()
- values := make([]int, len(m.data))
- index := 0
+ var (
+ values = make([]int, len(m.data))
+ index = 0
+ )
for _, value := range m.data {
values[index] = value
index++
@@ -318,10 +348,13 @@ func (m *StrIntMap) Values() []int {
// Contains checks whether a key exists.
// It returns true if the exists, or else false.
func (m *StrIntMap) Contains(key string) bool {
+ var ok bool
m.mu.RLock()
- _, exists := m.data[key]
+ if m.data != nil {
+ _, ok = m.data[key]
+ }
m.mu.RUnlock()
- return exists
+ return ok
}
// Size returns the size of the map.
@@ -382,6 +415,10 @@ func (m *StrIntMap) Flip() {
func (m *StrIntMap) Merge(other *StrIntMap) {
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = other.MapCopy()
+ return
+ }
if other != m {
other.mu.RLock()
defer other.mu.RUnlock()
@@ -400,12 +437,11 @@ func (m *StrIntMap) MarshalJSON() ([]byte, error) {
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
func (m *StrIntMap) UnmarshalJSON(b []byte) error {
- if m.mu == nil {
- m.mu = rwmutex.New()
- m.data = make(map[string]int)
- }
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[string]int)
+ }
if err := json.Unmarshal(b, &m.data); err != nil {
return err
}
@@ -414,12 +450,11 @@ func (m *StrIntMap) UnmarshalJSON(b []byte) error {
// UnmarshalValue is an interface implement which sets any type of value for map.
func (m *StrIntMap) UnmarshalValue(value interface{}) (err error) {
- if m.mu == nil {
- m.mu = rwmutex.New()
- m.data = make(map[string]int)
- }
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[string]int)
+ }
switch value.(type) {
case string, []byte:
return json.Unmarshal(gconv.Bytes(value), &m.data)
diff --git a/container/gmap/gmap_hash_str_str_map.go b/container/gmap/gmap_hash_str_str_map.go
index 669b48033..c1ed1de01 100644
--- a/container/gmap/gmap_hash_str_str_map.go
+++ b/container/gmap/gmap_hash_str_str_map.go
@@ -17,7 +17,7 @@ import (
)
type StrStrMap struct {
- mu *rwmutex.RWMutex
+ mu rwmutex.RWMutex
data map[string]string
}
@@ -27,7 +27,7 @@ type StrStrMap struct {
func NewStrStrMap(safe ...bool) *StrStrMap {
return &StrStrMap{
data: make(map[string]string),
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
}
}
@@ -36,12 +36,12 @@ func NewStrStrMap(safe ...bool) *StrStrMap {
// there might be some concurrent-safe issues when changing the map outside.
func NewStrStrMapFrom(data map[string]string, safe ...bool) *StrStrMap {
return &StrStrMap{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
data: data,
}
}
-// Iterator iterates the hash map with custom callback function .
+// Iterator iterates the hash map readonly with custom callback function .
// If returns true, then it continues iterating; or false to stop.
func (m *StrStrMap) Iterator(f func(k string, v string) bool) {
m.mu.RLock()
@@ -110,6 +110,9 @@ func (m *StrStrMap) FilterEmpty() {
// Set sets key-value to the hash map.
func (m *StrStrMap) Set(key string, val string) {
m.mu.Lock()
+ if m.data == nil {
+ m.data = make(map[string]string)
+ }
m.data[key] = val
m.mu.Unlock()
}
@@ -117,8 +120,12 @@ func (m *StrStrMap) Set(key string, val string) {
// Sets batch sets key-values to the hash map.
func (m *StrStrMap) Sets(data map[string]string) {
m.mu.Lock()
- for k, v := range data {
- m.data[k] = v
+ if m.data == nil {
+ m.data = data
+ } else {
+ for k, v := range data {
+ m.data[k] = v
+ }
}
m.mu.Unlock()
}
@@ -127,17 +134,21 @@ func (m *StrStrMap) Sets(data map[string]string) {
// Second return parameter is true if key was found, otherwise false.
func (m *StrStrMap) Search(key string) (value string, found bool) {
m.mu.RLock()
- value, found = m.data[key]
+ if m.data != nil {
+ value, found = m.data[key]
+ }
m.mu.RUnlock()
return
}
// Get returns the value by given .
-func (m *StrStrMap) Get(key string) string {
+func (m *StrStrMap) Get(key string) (value string) {
m.mu.RLock()
- val, _ := m.data[key]
+ if m.data != nil {
+ value, _ = m.data[key]
+ }
m.mu.RUnlock()
- return val
+ return
}
// Pop retrieves and deletes an item from the map.
@@ -162,8 +173,10 @@ func (m *StrStrMap) Pops(size int) map[string]string {
if size == 0 {
return nil
}
- index := 0
- newMap := make(map[string]string, size)
+ var (
+ index = 0
+ newMap = make(map[string]string, size)
+ )
for k, v := range m.data {
delete(m.data, k)
newMap[k] = v
@@ -183,6 +196,9 @@ func (m *StrStrMap) Pops(size int) map[string]string {
func (m *StrStrMap) doSetWithLockCheck(key string, value string) string {
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[string]string)
+ }
if v, ok := m.data[key]; ok {
return v
}
@@ -221,13 +237,14 @@ func (m *StrStrMap) GetOrSetFuncLock(key string, f func() string) string {
if v, ok := m.Search(key); !ok {
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[string]string)
+ }
if v, ok = m.data[key]; ok {
return v
}
v = f()
- if v != "" {
- m.data[key] = v
- }
+ m.data[key] = v
return v
} else {
return v
@@ -263,6 +280,9 @@ func (m *StrStrMap) SetIfNotExistFuncLock(key string, f func() string) bool {
if !m.Contains(key) {
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[string]string)
+ }
if _, ok := m.data[key]; !ok {
m.data[key] = f()
}
@@ -274,28 +294,34 @@ func (m *StrStrMap) SetIfNotExistFuncLock(key string, f func() string) bool {
// Removes batch deletes values of the map by keys.
func (m *StrStrMap) Removes(keys []string) {
m.mu.Lock()
- for _, key := range keys {
- delete(m.data, key)
+ if m.data != nil {
+ for _, key := range keys {
+ delete(m.data, key)
+ }
}
m.mu.Unlock()
}
// Remove deletes value from map by given , and return this deleted value.
-func (m *StrStrMap) Remove(key string) string {
+func (m *StrStrMap) Remove(key string) (value string) {
m.mu.Lock()
- val, exists := m.data[key]
- if exists {
- delete(m.data, key)
+ if m.data != nil {
+ var ok bool
+ if value, ok = m.data[key]; ok {
+ delete(m.data, key)
+ }
}
m.mu.Unlock()
- return val
+ return
}
// Keys returns all keys of the map as a slice.
func (m *StrStrMap) Keys() []string {
m.mu.RLock()
- keys := make([]string, len(m.data))
- index := 0
+ var (
+ keys = make([]string, len(m.data))
+ index = 0
+ )
for key := range m.data {
keys[index] = key
index++
@@ -307,8 +333,10 @@ func (m *StrStrMap) Keys() []string {
// Values returns all values of the map as a slice.
func (m *StrStrMap) Values() []string {
m.mu.RLock()
- values := make([]string, len(m.data))
- index := 0
+ var (
+ values = make([]string, len(m.data))
+ index = 0
+ )
for _, value := range m.data {
values[index] = value
index++
@@ -320,10 +348,13 @@ func (m *StrStrMap) Values() []string {
// Contains checks whether a key exists.
// It returns true if the exists, or else false.
func (m *StrStrMap) Contains(key string) bool {
+ var ok bool
m.mu.RLock()
- _, exists := m.data[key]
+ if m.data != nil {
+ _, ok = m.data[key]
+ }
m.mu.RUnlock()
- return exists
+ return ok
}
// Size returns the size of the map.
@@ -384,6 +415,10 @@ func (m *StrStrMap) Flip() {
func (m *StrStrMap) Merge(other *StrStrMap) {
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = other.MapCopy()
+ return
+ }
if other != m {
other.mu.RLock()
defer other.mu.RUnlock()
@@ -402,12 +437,11 @@ func (m *StrStrMap) MarshalJSON() ([]byte, error) {
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
func (m *StrStrMap) UnmarshalJSON(b []byte) error {
- if m.mu == nil {
- m.mu = rwmutex.New()
- m.data = make(map[string]string)
- }
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[string]string)
+ }
if err := json.Unmarshal(b, &m.data); err != nil {
return err
}
@@ -416,9 +450,6 @@ func (m *StrStrMap) UnmarshalJSON(b []byte) error {
// UnmarshalValue is an interface implement which sets any type of value for map.
func (m *StrStrMap) UnmarshalValue(value interface{}) (err error) {
- if m.mu == nil {
- m.mu = rwmutex.New()
- }
m.mu.Lock()
defer m.mu.Unlock()
m.data = gconv.MapStrStr(value)
diff --git a/container/gmap/gmap_list_map.go b/container/gmap/gmap_list_map.go
index 349a50f56..9a6e97ae2 100644
--- a/container/gmap/gmap_list_map.go
+++ b/container/gmap/gmap_list_map.go
@@ -19,7 +19,7 @@ import (
)
type ListMap struct {
- mu *rwmutex.RWMutex
+ mu rwmutex.RWMutex
data map[interface{}]*glist.Element
list *glist.List
}
@@ -35,7 +35,7 @@ type gListMapNode struct {
// which is false in default.
func NewListMap(safe ...bool) *ListMap {
return &ListMap{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
data: make(map[interface{}]*glist.Element),
list: glist.New(),
}
@@ -55,28 +55,32 @@ func (m *ListMap) Iterator(f func(key, value interface{}) bool) {
m.IteratorAsc(f)
}
-// IteratorAsc iterates the map in ascending order with given callback function .
+// IteratorAsc iterates the map readonly in ascending order with given callback function .
// If returns true, then it continues iterating; or false to stop.
func (m *ListMap) IteratorAsc(f func(key interface{}, value interface{}) bool) {
m.mu.RLock()
defer m.mu.RUnlock()
- node := (*gListMapNode)(nil)
- m.list.IteratorAsc(func(e *glist.Element) bool {
- node = e.Value.(*gListMapNode)
- return f(node.key, node.value)
- })
+ if m.list != nil {
+ node := (*gListMapNode)(nil)
+ m.list.IteratorAsc(func(e *glist.Element) bool {
+ node = e.Value.(*gListMapNode)
+ return f(node.key, node.value)
+ })
+ }
}
-// IteratorDesc iterates the map in descending order with given callback function .
+// IteratorDesc iterates the map readonly in descending order with given callback function .
// If returns true, then it continues iterating; or false to stop.
func (m *ListMap) IteratorDesc(f func(key interface{}, value interface{}) bool) {
m.mu.RLock()
defer m.mu.RUnlock()
- node := (*gListMapNode)(nil)
- m.list.IteratorDesc(func(e *glist.Element) bool {
- node = e.Value.(*gListMapNode)
- return f(node.key, node.value)
- })
+ if m.list != nil {
+ node := (*gListMapNode)(nil)
+ m.list.IteratorDesc(func(e *glist.Element) bool {
+ node = e.Value.(*gListMapNode)
+ return f(node.key, node.value)
+ })
+ }
}
// Clone returns a new link map with copy of current map data.
@@ -110,13 +114,16 @@ func (m *ListMap) Replace(data map[interface{}]interface{}) {
// Map returns a copy of the underlying data of the map.
func (m *ListMap) Map() map[interface{}]interface{} {
m.mu.RLock()
- node := (*gListMapNode)(nil)
- data := make(map[interface{}]interface{}, len(m.data))
- m.list.IteratorAsc(func(e *glist.Element) bool {
- node = e.Value.(*gListMapNode)
- data[node.key] = node.value
- return true
- })
+ var node *gListMapNode
+ var data map[interface{}]interface{}
+ if m.list != nil {
+ data = make(map[interface{}]interface{}, len(m.data))
+ m.list.IteratorAsc(func(e *glist.Element) bool {
+ node = e.Value.(*gListMapNode)
+ data[node.key] = node.value
+ return true
+ })
+ }
m.mu.RUnlock()
return data
}
@@ -124,13 +131,16 @@ func (m *ListMap) Map() map[interface{}]interface{} {
// MapStrAny returns a copy of the underlying data of the map as map[string]interface{}.
func (m *ListMap) MapStrAny() map[string]interface{} {
m.mu.RLock()
- node := (*gListMapNode)(nil)
- data := make(map[string]interface{}, len(m.data))
- m.list.IteratorAsc(func(e *glist.Element) bool {
- node = e.Value.(*gListMapNode)
- data[gconv.String(node.key)] = node.value
- return true
- })
+ var node *gListMapNode
+ var data map[string]interface{}
+ if m.list != nil {
+ data = make(map[string]interface{}, len(m.data))
+ m.list.IteratorAsc(func(e *glist.Element) bool {
+ node = e.Value.(*gListMapNode)
+ data[gconv.String(node.key)] = node.value
+ return true
+ })
+ }
m.mu.RUnlock()
return data
}
@@ -138,20 +148,22 @@ func (m *ListMap) MapStrAny() map[string]interface{} {
// FilterEmpty deletes all key-value pair of which the value is empty.
func (m *ListMap) FilterEmpty() {
m.mu.Lock()
- keys := make([]interface{}, 0)
- node := (*gListMapNode)(nil)
- m.list.IteratorAsc(func(e *glist.Element) bool {
- node = e.Value.(*gListMapNode)
- if empty.IsEmpty(node.value) {
- keys = append(keys, node.key)
- }
- return true
- })
- if len(keys) > 0 {
- for _, key := range keys {
- if e, ok := m.data[key]; ok {
- delete(m.data, key)
- m.list.Remove(e)
+ if m.list != nil {
+ keys := make([]interface{}, 0)
+ node := (*gListMapNode)(nil)
+ m.list.IteratorAsc(func(e *glist.Element) bool {
+ node = e.Value.(*gListMapNode)
+ if empty.IsEmpty(node.value) {
+ keys = append(keys, node.key)
+ }
+ return true
+ })
+ if len(keys) > 0 {
+ for _, key := range keys {
+ if e, ok := m.data[key]; ok {
+ delete(m.data, key)
+ m.list.Remove(e)
+ }
}
}
}
@@ -161,6 +173,10 @@ func (m *ListMap) FilterEmpty() {
// Set sets key-value to the map.
func (m *ListMap) Set(key interface{}, value interface{}) {
m.mu.Lock()
+ if m.data == nil {
+ m.data = make(map[interface{}]*glist.Element)
+ m.list = glist.New()
+ }
if e, ok := m.data[key]; !ok {
m.data[key] = m.list.PushBack(&gListMapNode{key, value})
} else {
@@ -172,6 +188,10 @@ func (m *ListMap) Set(key interface{}, value interface{}) {
// Sets batch sets key-values to the map.
func (m *ListMap) Sets(data map[interface{}]interface{}) {
m.mu.Lock()
+ if m.data == nil {
+ m.data = make(map[interface{}]*glist.Element)
+ m.list = glist.New()
+ }
for key, value := range data {
if e, ok := m.data[key]; !ok {
m.data[key] = m.list.PushBack(&gListMapNode{key, value})
@@ -186,9 +206,11 @@ func (m *ListMap) Sets(data map[interface{}]interface{}) {
// Second return parameter is true if key was found, otherwise false.
func (m *ListMap) Search(key interface{}) (value interface{}, found bool) {
m.mu.RLock()
- if e, ok := m.data[key]; ok {
- value = e.Value.(*gListMapNode).value
- found = ok
+ if m.data != nil {
+ if e, ok := m.data[key]; ok {
+ value = e.Value.(*gListMapNode).value
+ found = ok
+ }
}
m.mu.RUnlock()
return
@@ -197,8 +219,10 @@ func (m *ListMap) Search(key interface{}) (value interface{}, found bool) {
// Get returns the value by given .
func (m *ListMap) Get(key interface{}) (value interface{}) {
m.mu.RLock()
- if e, ok := m.data[key]; ok {
- value = e.Value.(*gListMapNode).value
+ if m.data != nil {
+ if e, ok := m.data[key]; ok {
+ value = e.Value.(*gListMapNode).value
+ }
}
m.mu.RUnlock()
return
@@ -255,6 +279,10 @@ func (m *ListMap) Pops(size int) map[interface{}]interface{} {
func (m *ListMap) doSetWithLockCheck(key interface{}, value interface{}) interface{} {
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[interface{}]*glist.Element)
+ m.list = glist.New()
+ }
if e, ok := m.data[key]; ok {
return e.Value.(*gListMapNode).value
}
@@ -302,26 +330,26 @@ func (m *ListMap) GetOrSetFuncLock(key interface{}, f func() interface{}) interf
}
}
-// GetVar returns a gvar.Var with the value by given .
-// The returned gvar.Var is un-concurrent safe.
+// GetVar returns a Var with the value by given .
+// The returned Var is un-concurrent safe.
func (m *ListMap) GetVar(key interface{}) *gvar.Var {
return gvar.New(m.Get(key))
}
-// GetVarOrSet returns a gvar.Var with result from GetVarOrSet.
-// The returned gvar.Var is un-concurrent safe.
+// GetVarOrSet returns a Var with result from GetVarOrSet.
+// The returned Var is un-concurrent safe.
func (m *ListMap) GetVarOrSet(key interface{}, value interface{}) *gvar.Var {
return gvar.New(m.GetOrSet(key, value))
}
-// GetVarOrSetFunc returns a gvar.Var with result from GetOrSetFunc.
-// The returned gvar.Var is un-concurrent safe.
+// GetVarOrSetFunc returns a Var with result from GetOrSetFunc.
+// The returned Var is un-concurrent safe.
func (m *ListMap) GetVarOrSetFunc(key interface{}, f func() interface{}) *gvar.Var {
return gvar.New(m.GetOrSetFunc(key, f))
}
-// GetVarOrSetFuncLock returns a gvar.Var with result from GetOrSetFuncLock.
-// The returned gvar.Var is un-concurrent safe.
+// GetVarOrSetFuncLock returns a Var with result from GetOrSetFuncLock.
+// The returned Var is un-concurrent safe.
func (m *ListMap) GetVarOrSetFuncLock(key interface{}, f func() interface{}) *gvar.Var {
return gvar.New(m.GetOrSetFuncLock(key, f))
}
@@ -362,10 +390,12 @@ func (m *ListMap) SetIfNotExistFuncLock(key interface{}, f func() interface{}) b
// Remove deletes value from map by given , and return this deleted value.
func (m *ListMap) Remove(key interface{}) (value interface{}) {
m.mu.Lock()
- if e, ok := m.data[key]; ok {
- value = e.Value.(*gListMapNode).value
- delete(m.data, key)
- m.list.Remove(e)
+ if m.data != nil {
+ if e, ok := m.data[key]; ok {
+ value = e.Value.(*gListMapNode).value
+ delete(m.data, key)
+ m.list.Remove(e)
+ }
}
m.mu.Unlock()
return
@@ -374,10 +404,12 @@ func (m *ListMap) Remove(key interface{}) (value interface{}) {
// Removes batch deletes values of the map by keys.
func (m *ListMap) Removes(keys []interface{}) {
m.mu.Lock()
- for _, key := range keys {
- if e, ok := m.data[key]; ok {
- delete(m.data, key)
- m.list.Remove(e)
+ if m.data != nil {
+ for _, key := range keys {
+ if e, ok := m.data[key]; ok {
+ delete(m.data, key)
+ m.list.Remove(e)
+ }
}
}
m.mu.Unlock()
@@ -386,13 +418,17 @@ func (m *ListMap) Removes(keys []interface{}) {
// Keys returns all keys of the map as a slice in ascending order.
func (m *ListMap) Keys() []interface{} {
m.mu.RLock()
- keys := make([]interface{}, m.list.Len())
- index := 0
- m.list.IteratorAsc(func(e *glist.Element) bool {
- keys[index] = e.Value.(*gListMapNode).key
- index++
- return true
- })
+ var (
+ keys = make([]interface{}, m.list.Len())
+ index = 0
+ )
+ if m.list != nil {
+ m.list.IteratorAsc(func(e *glist.Element) bool {
+ keys[index] = e.Value.(*gListMapNode).key
+ index++
+ return true
+ })
+ }
m.mu.RUnlock()
return keys
}
@@ -400,13 +436,17 @@ func (m *ListMap) Keys() []interface{} {
// Values returns all values of the map as a slice.
func (m *ListMap) Values() []interface{} {
m.mu.RLock()
- values := make([]interface{}, m.list.Len())
- index := 0
- m.list.IteratorAsc(func(e *glist.Element) bool {
- values[index] = e.Value.(*gListMapNode).value
- index++
- return true
- })
+ var (
+ values = make([]interface{}, m.list.Len())
+ index = 0
+ )
+ if m.list != nil {
+ m.list.IteratorAsc(func(e *glist.Element) bool {
+ values[index] = e.Value.(*gListMapNode).value
+ index++
+ return true
+ })
+ }
m.mu.RUnlock()
return values
}
@@ -415,7 +455,9 @@ func (m *ListMap) Values() []interface{} {
// It returns true if the exists, or else false.
func (m *ListMap) Contains(key interface{}) (ok bool) {
m.mu.RLock()
- _, ok = m.data[key]
+ if m.data != nil {
+ _, ok = m.data[key]
+ }
m.mu.RUnlock()
return
}
@@ -448,6 +490,10 @@ func (m *ListMap) Flip() {
func (m *ListMap) Merge(other *ListMap) {
m.mu.Lock()
defer m.mu.Unlock()
+ if m.data == nil {
+ m.data = make(map[interface{}]*glist.Element)
+ m.list = glist.New()
+ }
if other != m {
other.mu.RLock()
defer other.mu.RUnlock()
@@ -471,13 +517,12 @@ func (m *ListMap) MarshalJSON() ([]byte, error) {
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
func (m *ListMap) UnmarshalJSON(b []byte) error {
- if m.mu == nil {
- m.mu = rwmutex.New()
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
m.data = make(map[interface{}]*glist.Element)
m.list = glist.New()
}
- m.mu.Lock()
- defer m.mu.Unlock()
var data map[string]interface{}
if err := json.Unmarshal(b, &data); err != nil {
return err
@@ -494,13 +539,12 @@ func (m *ListMap) UnmarshalJSON(b []byte) error {
// UnmarshalValue is an interface implement which sets any type of value for map.
func (m *ListMap) UnmarshalValue(value interface{}) (err error) {
- if m.mu == nil {
- m.mu = rwmutex.New()
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if m.data == nil {
m.data = make(map[interface{}]*glist.Element)
m.list = glist.New()
}
- m.mu.Lock()
- defer m.mu.Unlock()
for k, v := range gconv.Map(value) {
if e, ok := m.data[k]; !ok {
m.data[k] = m.list.PushBack(&gListMapNode{k, v})
diff --git a/container/gmap/gmap_z_basic_test.go b/container/gmap/gmap_z_basic_test.go
index 383a3f4f5..534ccc610 100644
--- a/container/gmap/gmap_z_basic_test.go
+++ b/container/gmap/gmap_z_basic_test.go
@@ -7,6 +7,7 @@
package gmap_test
import (
+ "github.com/gogf/gf/util/gutil"
"testing"
"github.com/gogf/gf/container/gmap"
@@ -17,6 +18,55 @@ func getValue() interface{} {
return 3
}
+func Test_Map_Var(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ var m gmap.Map
+ m.Set(1, 11)
+ t.Assert(m.Get(1), 11)
+ })
+ gtest.C(t, func(t *gtest.T) {
+ var m gmap.IntAnyMap
+ m.Set(1, 11)
+ t.Assert(m.Get(1), 11)
+ })
+ gtest.C(t, func(t *gtest.T) {
+ var m gmap.IntIntMap
+ m.Set(1, 11)
+ t.Assert(m.Get(1), 11)
+ })
+ gtest.C(t, func(t *gtest.T) {
+ var m gmap.IntStrMap
+ m.Set(1, "11")
+ t.Assert(m.Get(1), "11")
+ })
+ gtest.C(t, func(t *gtest.T) {
+ var m gmap.StrAnyMap
+ m.Set("1", "11")
+ t.Assert(m.Get("1"), "11")
+ })
+ gtest.C(t, func(t *gtest.T) {
+ var m gmap.StrStrMap
+ m.Set("1", "11")
+ t.Assert(m.Get("1"), "11")
+ })
+ gtest.C(t, func(t *gtest.T) {
+ var m gmap.StrIntMap
+ m.Set("1", 11)
+ t.Assert(m.Get("1"), 11)
+ })
+ gtest.C(t, func(t *gtest.T) {
+ var m gmap.ListMap
+ m.Set("1", 11)
+ t.Assert(m.Get("1"), 11)
+ })
+ gtest.C(t, func(t *gtest.T) {
+ var m gmap.TreeMap
+ m.SetComparator(gutil.ComparatorString)
+ m.Set("1", 11)
+ t.Assert(m.Get("1"), 11)
+ })
+}
+
func Test_Map_Basic(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.New()
diff --git a/container/gmap/gmap_z_unit_any_any_test.go b/container/gmap/gmap_z_unit_any_any_test.go
index 37520c728..88fd41daa 100644
--- a/container/gmap/gmap_z_unit_any_any_test.go
+++ b/container/gmap/gmap_z_unit_any_any_test.go
@@ -17,8 +17,34 @@ import (
"github.com/gogf/gf/test/gtest"
)
-func anyAnyCallBack(int, interface{}) bool {
- return true
+func Test_AnyAnyMap_Var(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ var m gmap.AnyAnyMap
+ m.Set(1, 1)
+
+ t.Assert(m.Get(1), 1)
+ t.Assert(m.Size(), 1)
+ t.Assert(m.IsEmpty(), false)
+
+ t.Assert(m.GetOrSet(2, "2"), "2")
+ t.Assert(m.SetIfNotExist(2, "2"), false)
+
+ t.Assert(m.SetIfNotExist(3, 3), true)
+
+ t.Assert(m.Remove(2), "2")
+ t.Assert(m.Contains(2), false)
+
+ t.AssertIN(3, m.Keys())
+ t.AssertIN(1, m.Keys())
+ t.AssertIN(3, m.Values())
+ t.AssertIN(1, m.Values())
+ m.Flip()
+ t.Assert(m.Map(), map[interface{}]int{1: 1, 3: 3})
+
+ m.Clear()
+ t.Assert(m.Size(), 0)
+ t.Assert(m.IsEmpty(), true)
+ })
}
func Test_AnyAnyMap_Basic(t *testing.T) {
diff --git a/container/gmap/gmap_z_unit_int_any_test.go b/container/gmap/gmap_z_unit_int_any_test.go
index 9bf922ed7..125596992 100644
--- a/container/gmap/gmap_z_unit_int_any_test.go
+++ b/container/gmap/gmap_z_unit_int_any_test.go
@@ -20,9 +20,37 @@ import (
func getAny() interface{} {
return 123
}
-func intAnyCallBack(int, interface{}) bool {
- return true
+
+func Test_IntAnyMap_Var(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ var m gmap.IntAnyMap
+ m.Set(1, 1)
+
+ t.Assert(m.Get(1), 1)
+ t.Assert(m.Size(), 1)
+ t.Assert(m.IsEmpty(), false)
+
+ t.Assert(m.GetOrSet(2, "2"), "2")
+ t.Assert(m.SetIfNotExist(2, "2"), false)
+
+ t.Assert(m.SetIfNotExist(3, 3), true)
+
+ t.Assert(m.Remove(2), "2")
+ t.Assert(m.Contains(2), false)
+
+ t.AssertIN(3, m.Keys())
+ t.AssertIN(1, m.Keys())
+ t.AssertIN(3, m.Values())
+ t.AssertIN(1, m.Values())
+ m.Flip()
+ t.Assert(m.Map(), map[interface{}]int{1: 1, 3: 3})
+
+ m.Clear()
+ t.Assert(m.Size(), 0)
+ t.Assert(m.IsEmpty(), true)
+ })
}
+
func Test_IntAnyMap_Basic(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewIntAnyMap()
@@ -55,6 +83,7 @@ func Test_IntAnyMap_Basic(t *testing.T) {
t.Assert(m2.Map(), map[int]interface{}{1: 1, 2: "2"})
})
}
+
func Test_IntAnyMap_Set_Fun(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewIntAnyMap()
diff --git a/container/gmap/gmap_z_unit_int_int_test.go b/container/gmap/gmap_z_unit_int_int_test.go
index 5a37ddcc2..ae7092c14 100644
--- a/container/gmap/gmap_z_unit_int_int_test.go
+++ b/container/gmap/gmap_z_unit_int_int_test.go
@@ -20,9 +20,41 @@ import (
func getInt() int {
return 123
}
+
func intIntCallBack(int, int) bool {
return true
}
+
+func Test_IntIntMap_Var(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ var m gmap.IntIntMap
+ m.Set(1, 1)
+
+ t.Assert(m.Get(1), 1)
+ t.Assert(m.Size(), 1)
+ t.Assert(m.IsEmpty(), false)
+
+ t.Assert(m.GetOrSet(2, 2), 2)
+ t.Assert(m.SetIfNotExist(2, 2), false)
+
+ t.Assert(m.SetIfNotExist(3, 3), true)
+
+ t.Assert(m.Remove(2), 2)
+ t.Assert(m.Contains(2), false)
+
+ t.AssertIN(3, m.Keys())
+ t.AssertIN(1, m.Keys())
+ t.AssertIN(3, m.Values())
+ t.AssertIN(1, m.Values())
+ m.Flip()
+ t.Assert(m.Map(), map[int]int{1: 1, 3: 3})
+
+ m.Clear()
+ t.Assert(m.Size(), 0)
+ t.Assert(m.IsEmpty(), true)
+ })
+}
+
func Test_IntIntMap_Basic(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewIntIntMap()
@@ -55,6 +87,7 @@ func Test_IntIntMap_Basic(t *testing.T) {
t.Assert(m2.Map(), map[int]int{1: 1, 2: 2})
})
}
+
func Test_IntIntMap_Set_Fun(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewIntIntMap()
diff --git a/container/gmap/gmap_z_unit_int_str_test.go b/container/gmap/gmap_z_unit_int_str_test.go
index 47622c24b..1312684ea 100644
--- a/container/gmap/gmap_z_unit_int_str_test.go
+++ b/container/gmap/gmap_z_unit_int_str_test.go
@@ -20,9 +20,40 @@ import (
func getStr() string {
return "z"
}
-func intStrCallBack(int, string) bool {
- return true
+
+func Test_IntStrMap_Var(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ var m gmap.IntStrMap
+ m.Set(1, "a")
+
+ t.Assert(m.Get(1), "a")
+ t.Assert(m.Size(), 1)
+ t.Assert(m.IsEmpty(), false)
+
+ t.Assert(m.GetOrSet(2, "b"), "b")
+ t.Assert(m.SetIfNotExist(2, "b"), false)
+
+ t.Assert(m.SetIfNotExist(3, "c"), true)
+
+ t.Assert(m.Remove(2), "b")
+ t.Assert(m.Contains(2), false)
+
+ t.AssertIN(3, m.Keys())
+ t.AssertIN(1, m.Keys())
+ t.AssertIN("a", m.Values())
+ t.AssertIN("c", m.Values())
+
+ m_f := gmap.NewIntStrMap()
+ m_f.Set(1, "2")
+ m_f.Flip()
+ t.Assert(m_f.Map(), map[int]string{2: "1"})
+
+ m.Clear()
+ t.Assert(m.Size(), 0)
+ t.Assert(m.IsEmpty(), true)
+ })
}
+
func Test_IntStrMap_Basic(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewIntStrMap()
@@ -60,6 +91,7 @@ func Test_IntStrMap_Basic(t *testing.T) {
t.Assert(m2.Map(), map[int]string{1: "a", 2: "b"})
})
}
+
func Test_IntStrMap_Set_Fun(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewIntStrMap()
diff --git a/container/gmap/gmap_z_unit_list_map_test.go b/container/gmap/gmap_z_unit_list_map_test.go
index ec8feb4c2..564321c1c 100644
--- a/container/gmap/gmap_z_unit_list_map_test.go
+++ b/container/gmap/gmap_z_unit_list_map_test.go
@@ -17,6 +17,38 @@ import (
"github.com/gogf/gf/test/gtest"
)
+func Test_ListMap_Var(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ var m gmap.ListMap
+ m.Set("key1", "val1")
+ t.Assert(m.Keys(), []interface{}{"key1"})
+
+ t.Assert(m.Get("key1"), "val1")
+ t.Assert(m.Size(), 1)
+ t.Assert(m.IsEmpty(), false)
+
+ t.Assert(m.GetOrSet("key2", "val2"), "val2")
+ t.Assert(m.SetIfNotExist("key2", "val2"), false)
+
+ t.Assert(m.SetIfNotExist("key3", "val3"), true)
+ t.Assert(m.Remove("key2"), "val2")
+ t.Assert(m.Contains("key2"), false)
+
+ t.AssertIN("key3", m.Keys())
+ t.AssertIN("key1", m.Keys())
+ t.AssertIN("val3", m.Values())
+ t.AssertIN("val1", m.Values())
+
+ m.Flip()
+
+ t.Assert(m.Map(), map[interface{}]interface{}{"val3": "key3", "val1": "key1"})
+
+ m.Clear()
+ t.Assert(m.Size(), 0)
+ t.Assert(m.IsEmpty(), true)
+ })
+}
+
func Test_ListMap_Basic(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewListMap()
@@ -51,6 +83,7 @@ func Test_ListMap_Basic(t *testing.T) {
t.Assert(m2.Map(), map[interface{}]interface{}{1: 1, "key1": "val1"})
})
}
+
func Test_ListMap_Set_Fun(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewListMap()
diff --git a/container/gmap/gmap_z_unit_str_any_test.go b/container/gmap/gmap_z_unit_str_any_test.go
index 04965342f..a2159a38c 100644
--- a/container/gmap/gmap_z_unit_str_any_test.go
+++ b/container/gmap/gmap_z_unit_str_any_test.go
@@ -17,9 +17,37 @@ import (
"github.com/gogf/gf/test/gtest"
)
-func stringAnyCallBack(string, interface{}) bool {
- return true
+func Test_StrAnyMap_Var(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ var m gmap.StrAnyMap
+ m.Set("a", 1)
+
+ t.Assert(m.Get("a"), 1)
+ t.Assert(m.Size(), 1)
+ t.Assert(m.IsEmpty(), false)
+
+ t.Assert(m.GetOrSet("b", "2"), "2")
+ t.Assert(m.SetIfNotExist("b", "2"), false)
+
+ t.Assert(m.SetIfNotExist("c", 3), true)
+
+ t.Assert(m.Remove("b"), "2")
+ t.Assert(m.Contains("b"), false)
+
+ t.AssertIN("c", m.Keys())
+ t.AssertIN("a", m.Keys())
+ t.AssertIN(3, m.Values())
+ t.AssertIN(1, m.Values())
+
+ m.Flip()
+ t.Assert(m.Map(), map[string]interface{}{"1": "a", "3": "c"})
+
+ m.Clear()
+ t.Assert(m.Size(), 0)
+ t.Assert(m.IsEmpty(), true)
+ })
}
+
func Test_StrAnyMap_Basic(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewStrAnyMap()
@@ -53,6 +81,7 @@ func Test_StrAnyMap_Basic(t *testing.T) {
t.Assert(m2.Map(), map[string]interface{}{"a": 1, "b": "2"})
})
}
+
func Test_StrAnyMap_Set_Fun(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewStrAnyMap()
diff --git a/container/gmap/gmap_z_unit_str_int_test.go b/container/gmap/gmap_z_unit_str_int_test.go
index b20f23040..22a87e94f 100644
--- a/container/gmap/gmap_z_unit_str_int_test.go
+++ b/container/gmap/gmap_z_unit_str_int_test.go
@@ -17,9 +17,39 @@ import (
"github.com/gogf/gf/test/gtest"
)
-func stringIntCallBack(string, int) bool {
- return true
+func Test_StrIntMap_Var(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ var m gmap.StrIntMap
+ m.Set("a", 1)
+
+ t.Assert(m.Get("a"), 1)
+ t.Assert(m.Size(), 1)
+ t.Assert(m.IsEmpty(), false)
+
+ t.Assert(m.GetOrSet("b", 2), 2)
+ t.Assert(m.SetIfNotExist("b", 2), false)
+
+ t.Assert(m.SetIfNotExist("c", 3), true)
+
+ t.Assert(m.Remove("b"), 2)
+ t.Assert(m.Contains("b"), false)
+
+ t.AssertIN("c", m.Keys())
+ t.AssertIN("a", m.Keys())
+ t.AssertIN(3, m.Values())
+ t.AssertIN(1, m.Values())
+
+ m_f := gmap.NewStrIntMap()
+ m_f.Set("1", 2)
+ m_f.Flip()
+ t.Assert(m_f.Map(), map[string]int{"2": 1})
+
+ m.Clear()
+ t.Assert(m.Size(), 0)
+ t.Assert(m.IsEmpty(), true)
+ })
}
+
func Test_StrIntMap_Basic(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewStrIntMap()
@@ -55,6 +85,7 @@ func Test_StrIntMap_Basic(t *testing.T) {
t.Assert(m2.Map(), map[string]int{"a": 1, "b": 2})
})
}
+
func Test_StrIntMap_Set_Fun(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewStrIntMap()
diff --git a/container/gmap/gmap_z_unit_str_str_test.go b/container/gmap/gmap_z_unit_str_str_test.go
index f18ecc98e..d452b1648 100644
--- a/container/gmap/gmap_z_unit_str_str_test.go
+++ b/container/gmap/gmap_z_unit_str_str_test.go
@@ -17,9 +17,38 @@ import (
"github.com/gogf/gf/test/gtest"
)
-func stringStrCallBack(string, string) bool {
- return true
+func Test_StrStrMap_Var(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ var m gmap.StrStrMap
+ m.Set("a", "a")
+
+ t.Assert(m.Get("a"), "a")
+ t.Assert(m.Size(), 1)
+ t.Assert(m.IsEmpty(), false)
+
+ t.Assert(m.GetOrSet("b", "b"), "b")
+ t.Assert(m.SetIfNotExist("b", "b"), false)
+
+ t.Assert(m.SetIfNotExist("c", "c"), true)
+
+ t.Assert(m.Remove("b"), "b")
+ t.Assert(m.Contains("b"), false)
+
+ t.AssertIN("c", m.Keys())
+ t.AssertIN("a", m.Keys())
+ t.AssertIN("a", m.Values())
+ t.AssertIN("c", m.Values())
+
+ m.Flip()
+
+ t.Assert(m.Map(), map[string]string{"a": "a", "c": "c"})
+
+ m.Clear()
+ t.Assert(m.Size(), 0)
+ t.Assert(m.IsEmpty(), true)
+ })
}
+
func Test_StrStrMap_Basic(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewStrStrMap()
@@ -54,6 +83,7 @@ func Test_StrStrMap_Basic(t *testing.T) {
t.Assert(m2.Map(), map[string]string{"a": "a", "b": "b"})
})
}
+
func Test_StrStrMap_Set_Fun(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewStrStrMap()
diff --git a/container/gmap/gmap_z_unit_tree_map_test.go b/container/gmap/gmap_z_unit_tree_map_test.go
index 6e623722f..611482d31 100644
--- a/container/gmap/gmap_z_unit_tree_map_test.go
+++ b/container/gmap/gmap_z_unit_tree_map_test.go
@@ -17,6 +17,39 @@ import (
"github.com/gogf/gf/util/gutil"
)
+func Test_TreeMap_Var(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ var m gmap.TreeMap
+ m.SetComparator(gutil.ComparatorString)
+ m.Set("key1", "val1")
+ t.Assert(m.Keys(), []interface{}{"key1"})
+
+ t.Assert(m.Get("key1"), "val1")
+ t.Assert(m.Size(), 1)
+ t.Assert(m.IsEmpty(), false)
+
+ t.Assert(m.GetOrSet("key2", "val2"), "val2")
+ t.Assert(m.SetIfNotExist("key2", "val2"), false)
+
+ t.Assert(m.SetIfNotExist("key3", "val3"), true)
+
+ t.Assert(m.Remove("key2"), "val2")
+ t.Assert(m.Contains("key2"), false)
+
+ t.AssertIN("key3", m.Keys())
+ t.AssertIN("key1", m.Keys())
+ t.AssertIN("val3", m.Values())
+ t.AssertIN("val1", m.Values())
+
+ m.Flip()
+ t.Assert(m.Map(), map[interface{}]interface{}{"val3": "key3", "val1": "key1"})
+
+ m.Clear()
+ t.Assert(m.Size(), 0)
+ t.Assert(m.IsEmpty(), true)
+ })
+}
+
func Test_TreeMap_Basic(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewTreeMap(gutil.ComparatorString)
@@ -51,6 +84,7 @@ func Test_TreeMap_Basic(t *testing.T) {
t.Assert(m2.Map(), map[interface{}]interface{}{1: 1, "key1": "val1"})
})
}
+
func Test_TreeMap_Set_Fun(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewTreeMap(gutil.ComparatorString)
diff --git a/container/gring/gring.go b/container/gring/gring.go
index 884be1159..fc75335a5 100644
--- a/container/gring/gring.go
+++ b/container/gring/gring.go
@@ -14,6 +14,7 @@ import (
"github.com/gogf/gf/internal/rwmutex"
)
+// Ring is a struct of ring structure.
type Ring struct {
mu *rwmutex.RWMutex
ring *ring.Ring // Underlying ring.
@@ -22,6 +23,9 @@ type Ring struct {
dirty *gtype.Bool // Dirty, which means the len and cap should be recalculated. It's marked dirty when the size of ring changes.
}
+// New creates and returns a Ring structure of elements.
+// The optional parameter specifies whether using this structure in concurrent safety,
+// which is false in default.
func New(cap int, safe ...bool) *Ring {
return &Ring{
mu: rwmutex.New(safe...),
diff --git a/container/gring/gring_unit_test.go b/container/gring/gring_unit_test.go
index 9032d9222..144a0d565 100644
--- a/container/gring/gring_unit_test.go
+++ b/container/gring/gring_unit_test.go
@@ -1,3 +1,9 @@
+// Copyright 2018 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 gring_test
import (
diff --git a/container/gset/gset_any_set.go b/container/gset/gset_any_set.go
index 175329546..d1826bcb3 100644
--- a/container/gset/gset_any_set.go
+++ b/container/gset/gset_any_set.go
@@ -16,7 +16,7 @@ import (
)
type Set struct {
- mu *rwmutex.RWMutex
+ mu rwmutex.RWMutex
data map[interface{}]struct{}
}
@@ -31,7 +31,7 @@ func New(safe ...bool) *Set {
func NewSet(safe ...bool) *Set {
return &Set{
data: make(map[interface{}]struct{}),
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
}
}
@@ -44,13 +44,13 @@ func NewFrom(items interface{}, safe ...bool) *Set {
}
return &Set{
data: m,
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
}
}
-// Iterator iterates the set with given callback function ,
+// Iterator iterates the set readonly with given callback function ,
// if returns true then continue iterating; or false to stop.
-func (set *Set) Iterator(f func(v interface{}) bool) *Set {
+func (set *Set) Iterator(f func(v interface{}) bool) {
set.mu.RLock()
defer set.mu.RUnlock()
for k, _ := range set.data {
@@ -58,77 +58,113 @@ func (set *Set) Iterator(f func(v interface{}) bool) *Set {
break
}
}
- return set
}
// Add adds one or multiple items to the set.
-func (set *Set) Add(item ...interface{}) *Set {
+func (set *Set) Add(item ...interface{}) {
set.mu.Lock()
+ if set.data == nil {
+ set.data = make(map[interface{}]struct{})
+ }
for _, v := range item {
set.data[v] = struct{}{}
}
set.mu.Unlock()
- return set
}
-// AddIfNotExistFunc adds the returned value of callback function to the set
-// if - does not exit in the set.
-func (set *Set) AddIfNotExistFunc(item interface{}, f func() interface{}) *Set {
- if !set.Contains(item) {
- set.doAddWithLockCheck(item, f())
+// 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
- is nil, it does nothing and returns false.
+func (set *Set) AddIfNotExist(item interface{}) bool {
+ if item == nil {
+ return false
}
- return set
-}
-
-// AddIfNotExistFuncLock adds the returned value of callback function to the set
-// if
- does not exit in the set.
-//
-// Note that the callback function 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 is type of ,
-// 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.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
}
}
- if item != nil {
- set.data[item] = struct{}{}
+ 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 returns true, or else it does nothing and returns false.
+//
+// Note that, if
- is nil, it does nothing and returns false. The function
+// is executed without writing lock.
+func (set *Set) AddIfNotExistFunc(item interface{}, f func() bool) bool {
+ if item == nil {
+ return false
}
- return item
+ 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 returns true, or else it does nothing and returns false.
+//
+// Note that, if
- is nil, it does nothing and returns false. The function
+// 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
- .
func (set *Set) Contains(item interface{}) bool {
+ var ok bool
set.mu.RLock()
- _, exists := set.data[item]
+ if set.data != nil {
+ _, ok = set.data[item]
+ }
set.mu.RUnlock()
- return exists
+ return ok
}
// Remove deletes
- from set.
-func (set *Set) Remove(item interface{}) *Set {
+func (set *Set) Remove(item interface{}) {
set.mu.Lock()
- delete(set.data, item)
+ if set.data != nil {
+ delete(set.data, item)
+ }
set.mu.Unlock()
- return set
}
// Size returns the size of the set.
@@ -140,18 +176,19 @@ func (set *Set) Size() int {
}
// Clear deletes all items of the set.
-func (set *Set) Clear() *Set {
+func (set *Set) Clear() {
set.mu.Lock()
set.data = make(map[interface{}]struct{})
set.mu.Unlock()
- return set
}
// Slice returns the a of items of the set as slice.
func (set *Set) Slice() []interface{} {
set.mu.RLock()
- i := 0
- ret := make([]interface{}, len(set.data))
+ var (
+ i = 0
+ ret = make([]interface{}, len(set.data))
+ )
for item := range set.data {
ret[i] = item
i++
@@ -164,9 +201,14 @@ func (set *Set) Slice() []interface{} {
func (set *Set) Join(glue string) string {
set.mu.RLock()
defer set.mu.RUnlock()
- buffer := bytes.NewBuffer(nil)
- l := len(set.data)
- i := 0
+ 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 {
@@ -181,11 +223,13 @@ func (set *Set) Join(glue string) string {
func (set *Set) String() string {
set.mu.RLock()
defer set.mu.RUnlock()
- buffer := bytes.NewBuffer(nil)
+ var (
+ s = ""
+ l = len(set.data)
+ i = 0
+ buffer = bytes.NewBuffer(nil)
+ )
buffer.WriteByte('[')
- s := ""
- l := len(set.data)
- i := 0
for k, _ := range set.data {
s = gconv.String(k)
if gstr.IsNumeric(s) {
@@ -256,7 +300,7 @@ func (set *Set) IsSubsetOf(other *Set) bool {
// Union returns a new set which is the union of and .
// Which means, all the items in are in or in .
func (set *Set) Union(others ...*Set) (newSet *Set) {
- newSet = NewSet(true)
+ newSet = NewSet()
set.mu.RLock()
defer set.mu.RUnlock()
for _, other := range others {
@@ -282,7 +326,7 @@ func (set *Set) Union(others ...*Set) (newSet *Set) {
// Diff returns a new set which is the difference set from to .
// Which means, all the items in are in but not in .
func (set *Set) Diff(others ...*Set) (newSet *Set) {
- newSet = NewSet(true)
+ newSet = NewSet()
set.mu.RLock()
defer set.mu.RUnlock()
for _, other := range others {
@@ -303,7 +347,7 @@ func (set *Set) Diff(others ...*Set) (newSet *Set) {
// Intersect returns a new set which is the intersection from to .
// Which means, all the items in are in and also in .
func (set *Set) Intersect(others ...*Set) (newSet *Set) {
- newSet = NewSet(true)
+ newSet = NewSet()
set.mu.RLock()
defer set.mu.RUnlock()
for _, other := range others {
@@ -328,7 +372,7 @@ func (set *Set) Intersect(others ...*Set) (newSet *Set) {
// It returns the difference between and
// if the given set is not the full set of .
func (set *Set) Complement(full *Set) (newSet *Set) {
- newSet = NewSet(true)
+ newSet = NewSet()
set.mu.RLock()
defer set.mu.RUnlock()
if set != full {
@@ -415,12 +459,11 @@ func (set *Set) MarshalJSON() ([]byte, error) {
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
func (set *Set) UnmarshalJSON(b []byte) error {
- if set.mu == nil {
- set.mu = rwmutex.New()
- set.data = make(map[interface{}]struct{})
- }
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
@@ -433,12 +476,11 @@ func (set *Set) UnmarshalJSON(b []byte) error {
// UnmarshalValue is an interface implement which sets any type of value for set.
func (set *Set) UnmarshalValue(value interface{}) (err error) {
- if set.mu == nil {
- set.mu = rwmutex.New()
- set.data = make(map[interface{}]struct{})
- }
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:
diff --git a/container/gset/gset_int_set.go b/container/gset/gset_int_set.go
index f853700a3..70d810edc 100644
--- a/container/gset/gset_int_set.go
+++ b/container/gset/gset_int_set.go
@@ -15,7 +15,7 @@ import (
)
type IntSet struct {
- mu *rwmutex.RWMutex
+ mu rwmutex.RWMutex
data map[int]struct{}
}
@@ -24,7 +24,7 @@ type IntSet struct {
// which is false in default.
func NewIntSet(safe ...bool) *IntSet {
return &IntSet{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
data: make(map[int]struct{}),
}
}
@@ -36,14 +36,14 @@ func NewIntSetFrom(items []int, safe ...bool) *IntSet {
m[v] = struct{}{}
}
return &IntSet{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
data: m,
}
}
-// Iterator iterates the set with given callback function ,
+// Iterator iterates the set readonly with given callback function ,
// if returns true then continue iterating; or false to stop.
-func (set *IntSet) Iterator(f func(v int) bool) *IntSet {
+func (set *IntSet) Iterator(f func(v int) bool) {
set.mu.RLock()
defer set.mu.RUnlock()
for k, _ := range set.data {
@@ -51,75 +51,102 @@ func (set *IntSet) Iterator(f func(v int) bool) *IntSet {
break
}
}
- return set
}
// Add adds one or multiple items to the set.
-func (set *IntSet) Add(item ...int) *IntSet {
+func (set *IntSet) Add(item ...int) {
set.mu.Lock()
+ if set.data == nil {
+ set.data = make(map[int]struct{})
+ }
for _, v := range item {
set.data[v] = struct{}{}
}
set.mu.Unlock()
- return set
}
-// AddIfNotExistFunc adds the returned value of callback function to the set
-// if
- does not exit in the set.
-func (set *IntSet) AddIfNotExistFunc(item int, f func() int) *IntSet {
+// 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
- is nil, it does nothing and returns false.
+func (set *IntSet) AddIfNotExist(item int) bool {
if !set.Contains(item) {
- set.doAddWithLockCheck(item, f())
- }
- return set
-}
-
-// AddIfNotExistFuncLock adds the returned value of callback function to the set
-// if
- does not exit in the set.
-//
-// Note that the callback function 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 is type of ,
-// 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.mu.Lock()
+ defer set.mu.Unlock()
+ if set.data == nil {
+ set.data = make(map[int]struct{})
+ }
+ if _, ok := set.data[item]; !ok {
+ set.data[item] = struct{}{}
+ return true
}
}
- set.data[item] = struct{}{}
- return item
+ 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 returns true, or else it does nothing and returns false.
+//
+// Note that, the function is executed without writing lock.
+func (set *IntSet) AddIfNotExistFunc(item int, f func() bool) bool {
+ if !set.Contains(item) {
+ if f() {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ if set.data == nil {
+ set.data = make(map[int]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 returns true, or else it does nothing and returns false.
+//
+// Note that, the function is executed without writing lock.
+func (set *IntSet) AddIfNotExistFuncLock(item int, f func() bool) bool {
+ if !set.Contains(item) {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ if set.data == nil {
+ set.data = make(map[int]struct{})
+ }
+ if f() {
+ if _, ok := set.data[item]; !ok {
+ set.data[item] = struct{}{}
+ return true
+ }
+ }
+ }
+ return false
}
// Contains checks whether the set contains
- .
func (set *IntSet) Contains(item int) bool {
+ var ok bool
set.mu.RLock()
- _, exists := set.data[item]
+ if set.data != nil {
+ _, ok = set.data[item]
+ }
set.mu.RUnlock()
- return exists
+ return ok
}
// Remove deletes
- from set.
-func (set *IntSet) Remove(item int) *IntSet {
+func (set *IntSet) Remove(item int) {
set.mu.Lock()
- delete(set.data, item)
+ if set.data != nil {
+ delete(set.data, item)
+ }
set.mu.Unlock()
- return set
}
// Size returns the size of the set.
@@ -131,18 +158,19 @@ func (set *IntSet) Size() int {
}
// Clear deletes all items of the set.
-func (set *IntSet) Clear() *IntSet {
+func (set *IntSet) Clear() {
set.mu.Lock()
set.data = make(map[int]struct{})
set.mu.Unlock()
- return set
}
// Slice returns the a of items of the set as slice.
func (set *IntSet) Slice() []int {
set.mu.RLock()
- ret := make([]int, len(set.data))
- i := 0
+ var (
+ i = 0
+ ret = make([]int, len(set.data))
+ )
for k, _ := range set.data {
ret[i] = k
i++
@@ -155,9 +183,14 @@ func (set *IntSet) Slice() []int {
func (set *IntSet) Join(glue string) string {
set.mu.RLock()
defer set.mu.RUnlock()
- buffer := bytes.NewBuffer(nil)
- l := len(set.data)
- i := 0
+ 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 {
@@ -227,7 +260,7 @@ func (set *IntSet) IsSubsetOf(other *IntSet) bool {
// Union returns a new set which is the union of and .
// Which means, all the items in are in or in .
func (set *IntSet) Union(others ...*IntSet) (newSet *IntSet) {
- newSet = NewIntSet(true)
+ newSet = NewIntSet()
set.mu.RLock()
defer set.mu.RUnlock()
for _, other := range others {
@@ -253,7 +286,7 @@ func (set *IntSet) Union(others ...*IntSet) (newSet *IntSet) {
// Diff returns a new set which is the difference set from to .
// Which means, all the items in are in but not in .
func (set *IntSet) Diff(others ...*IntSet) (newSet *IntSet) {
- newSet = NewIntSet(true)
+ newSet = NewIntSet()
set.mu.RLock()
defer set.mu.RUnlock()
for _, other := range others {
@@ -274,7 +307,7 @@ func (set *IntSet) Diff(others ...*IntSet) (newSet *IntSet) {
// Intersect returns a new set which is the intersection from to .
// Which means, all the items in are in and also in .
func (set *IntSet) Intersect(others ...*IntSet) (newSet *IntSet) {
- newSet = NewIntSet(true)
+ newSet = NewIntSet()
set.mu.RLock()
defer set.mu.RUnlock()
for _, other := range others {
@@ -299,7 +332,7 @@ func (set *IntSet) Intersect(others ...*IntSet) (newSet *IntSet) {
// It returns the difference between and
// if the given set is not the full set of .
func (set *IntSet) Complement(full *IntSet) (newSet *IntSet) {
- newSet = NewIntSet(true)
+ newSet = NewIntSet()
set.mu.RLock()
defer set.mu.RUnlock()
if set != full {
@@ -386,12 +419,11 @@ func (set *IntSet) MarshalJSON() ([]byte, error) {
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
func (set *IntSet) UnmarshalJSON(b []byte) error {
- if set.mu == nil {
- set.mu = rwmutex.New()
- set.data = make(map[int]struct{})
- }
set.mu.Lock()
defer set.mu.Unlock()
+ if set.data == nil {
+ set.data = make(map[int]struct{})
+ }
var array []int
if err := json.Unmarshal(b, &array); err != nil {
return err
@@ -404,12 +436,11 @@ func (set *IntSet) UnmarshalJSON(b []byte) error {
// UnmarshalValue is an interface implement which sets any type of value for set.
func (set *IntSet) UnmarshalValue(value interface{}) (err error) {
- if set.mu == nil {
- set.mu = rwmutex.New()
- set.data = make(map[int]struct{})
- }
set.mu.Lock()
defer set.mu.Unlock()
+ if set.data == nil {
+ set.data = make(map[int]struct{})
+ }
var array []int
switch value.(type) {
case string, []byte:
diff --git a/container/gset/gset_str_set.go b/container/gset/gset_str_set.go
index cd4ce4723..fe02c817f 100644
--- a/container/gset/gset_str_set.go
+++ b/container/gset/gset_str_set.go
@@ -16,7 +16,7 @@ import (
)
type StrSet struct {
- mu *rwmutex.RWMutex
+ mu rwmutex.RWMutex
data map[string]struct{}
}
@@ -25,7 +25,7 @@ type StrSet struct {
// which is false in default.
func NewStrSet(safe ...bool) *StrSet {
return &StrSet{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
data: make(map[string]struct{}),
}
}
@@ -37,14 +37,14 @@ func NewStrSetFrom(items []string, safe ...bool) *StrSet {
m[v] = struct{}{}
}
return &StrSet{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
data: m,
}
}
-// Iterator iterates the set with given callback function ,
+// Iterator iterates the set readonly with given callback function ,
// if returns true then continue iterating; or false to stop.
-func (set *StrSet) Iterator(f func(v string) bool) *StrSet {
+func (set *StrSet) Iterator(f func(v string) bool) {
set.mu.RLock()
defer set.mu.RUnlock()
for k, _ := range set.data {
@@ -52,77 +52,100 @@ func (set *StrSet) Iterator(f func(v string) bool) *StrSet {
break
}
}
- return set
}
// Add adds one or multiple items to the set.
-func (set *StrSet) Add(item ...string) *StrSet {
+func (set *StrSet) Add(item ...string) {
set.mu.Lock()
+ if set.data == nil {
+ set.data = make(map[string]struct{})
+ }
for _, v := range item {
set.data[v] = struct{}{}
}
set.mu.Unlock()
- return set
}
-// AddIfNotExistFunc adds the returned value of callback function to the set
-// if
- does not exit in the set.
-func (set *StrSet) AddIfNotExistFunc(item string, f func() string) *StrSet {
+// 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.
+func (set *StrSet) AddIfNotExist(item string) bool {
if !set.Contains(item) {
- set.doAddWithLockCheck(item, f())
- }
- return set
-}
-
-// AddIfNotExistFuncLock adds the returned value of callback function to the set
-// if
- does not exit in the set.
-//
-// Note that the callback function 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 is type of ,
-// 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.mu.Lock()
+ defer set.mu.Unlock()
+ if set.data == nil {
+ set.data = make(map[string]struct{})
+ }
+ if _, ok := set.data[item]; !ok {
+ set.data[item] = struct{}{}
+ return true
}
}
- if item != "" {
- set.data[item] = struct{}{}
+ 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 returns true, or else it does nothing and returns false.
+//
+// Note that, the function is executed without writing lock.
+func (set *StrSet) AddIfNotExistFunc(item string, f func() bool) bool {
+ if !set.Contains(item) {
+ if f() {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ if set.data == nil {
+ set.data = make(map[string]struct{})
+ }
+ if _, ok := set.data[item]; !ok {
+ set.data[item] = struct{}{}
+ return true
+ }
+ }
}
- return item
+ 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 returns true, or else it does nothing and returns false.
+//
+// Note that, the function is executed without writing lock.
+func (set *StrSet) AddIfNotExistFuncLock(item string, f func() bool) bool {
+ if !set.Contains(item) {
+ set.mu.Lock()
+ defer set.mu.Unlock()
+ if set.data == nil {
+ set.data = make(map[string]struct{})
+ }
+ if f() {
+ if _, ok := set.data[item]; !ok {
+ set.data[item] = struct{}{}
+ return true
+ }
+ }
+ }
+ return false
}
// Contains checks whether the set contains
- .
func (set *StrSet) Contains(item string) bool {
+ var ok bool
set.mu.RLock()
- _, exists := set.data[item]
+ if set.data != nil {
+ _, ok = set.data[item]
+ }
set.mu.RUnlock()
- return exists
+ return ok
}
// Remove deletes
- from set.
-func (set *StrSet) Remove(item string) *StrSet {
+func (set *StrSet) Remove(item string) {
set.mu.Lock()
- delete(set.data, item)
+ if set.data != nil {
+ delete(set.data, item)
+ }
set.mu.Unlock()
- return set
}
// Size returns the size of the set.
@@ -134,18 +157,19 @@ func (set *StrSet) Size() int {
}
// Clear deletes all items of the set.
-func (set *StrSet) Clear() *StrSet {
+func (set *StrSet) Clear() {
set.mu.Lock()
set.data = make(map[string]struct{})
set.mu.Unlock()
- return set
}
// Slice returns the a of items of the set as slice.
func (set *StrSet) Slice() []string {
set.mu.RLock()
- ret := make([]string, len(set.data))
- i := 0
+ var (
+ i = 0
+ ret = make([]string, len(set.data))
+ )
for item := range set.data {
ret[i] = item
i++
@@ -159,9 +183,14 @@ func (set *StrSet) Slice() []string {
func (set *StrSet) Join(glue string) string {
set.mu.RLock()
defer set.mu.RUnlock()
- buffer := bytes.NewBuffer(nil)
- l := len(set.data)
- i := 0
+ if len(set.data) == 0 {
+ return ""
+ }
+ var (
+ l = len(set.data)
+ i = 0
+ buffer = bytes.NewBuffer(nil)
+ )
for k, _ := range set.data {
buffer.WriteString(k)
if i != l-1 {
@@ -176,9 +205,11 @@ func (set *StrSet) Join(glue string) string {
func (set *StrSet) String() string {
set.mu.RLock()
defer set.mu.RUnlock()
- buffer := bytes.NewBuffer(nil)
- l := len(set.data)
- i := 0
+ var (
+ l = len(set.data)
+ i = 0
+ buffer = bytes.NewBuffer(nil)
+ )
for k, _ := range set.data {
buffer.WriteString(`"` + gstr.QuoteMeta(k, `"\`) + `"`)
if i != l-1 {
@@ -243,7 +274,7 @@ func (set *StrSet) IsSubsetOf(other *StrSet) bool {
// Union returns a new set which is the union of and .
// Which means, all the items in are in or in .
func (set *StrSet) Union(others ...*StrSet) (newSet *StrSet) {
- newSet = NewStrSet(true)
+ newSet = NewStrSet()
set.mu.RLock()
defer set.mu.RUnlock()
for _, other := range others {
@@ -269,7 +300,7 @@ func (set *StrSet) Union(others ...*StrSet) (newSet *StrSet) {
// Diff returns a new set which is the difference set from to .
// Which means, all the items in are in but not in .
func (set *StrSet) Diff(others ...*StrSet) (newSet *StrSet) {
- newSet = NewStrSet(true)
+ newSet = NewStrSet()
set.mu.RLock()
defer set.mu.RUnlock()
for _, other := range others {
@@ -290,7 +321,7 @@ func (set *StrSet) Diff(others ...*StrSet) (newSet *StrSet) {
// Intersect returns a new set which is the intersection from to .
// Which means, all the items in are in and also in .
func (set *StrSet) Intersect(others ...*StrSet) (newSet *StrSet) {
- newSet = NewStrSet(true)
+ newSet = NewStrSet()
set.mu.RLock()
defer set.mu.RUnlock()
for _, other := range others {
@@ -315,7 +346,7 @@ func (set *StrSet) Intersect(others ...*StrSet) (newSet *StrSet) {
// It returns the difference between and
// if the given set is not the full set of .
func (set *StrSet) Complement(full *StrSet) (newSet *StrSet) {
- newSet = NewStrSet(true)
+ newSet = NewStrSet()
set.mu.RLock()
defer set.mu.RUnlock()
if set != full {
@@ -402,12 +433,11 @@ func (set *StrSet) MarshalJSON() ([]byte, error) {
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
func (set *StrSet) UnmarshalJSON(b []byte) error {
- if set.mu == nil {
- set.mu = rwmutex.New()
- set.data = make(map[string]struct{})
- }
set.mu.Lock()
defer set.mu.Unlock()
+ if set.data == nil {
+ set.data = make(map[string]struct{})
+ }
var array []string
if err := json.Unmarshal(b, &array); err != nil {
return err
@@ -420,12 +450,11 @@ func (set *StrSet) UnmarshalJSON(b []byte) error {
// UnmarshalValue is an interface implement which sets any type of value for set.
func (set *StrSet) UnmarshalValue(value interface{}) (err error) {
- if set.mu == nil {
- set.mu = rwmutex.New()
- set.data = make(map[string]struct{})
- }
set.mu.Lock()
defer set.mu.Unlock()
+ if set.data == nil {
+ set.data = make(map[string]struct{})
+ }
var array []string
switch value.(type) {
case string, []byte:
diff --git a/container/gset/gset_z_unit_any_test.go b/container/gset/gset_z_unit_any_test.go
index 583d17332..64db0e4ad 100644
--- a/container/gset/gset_z_unit_any_test.go
+++ b/container/gset/gset_z_unit_any_test.go
@@ -13,6 +13,8 @@ import (
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/util/gconv"
"strings"
+ "sync"
+ "time"
"github.com/gogf/gf/container/garray"
"github.com/gogf/gf/container/gset"
@@ -21,10 +23,30 @@ import (
"testing"
)
+func TestSet_Var(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ var s gset.Set
+ s.Add(1, 1, 2)
+ s.Add([]interface{}{3, 4}...)
+ t.Assert(s.Size(), 4)
+ t.AssertIN(1, s.Slice())
+ t.AssertIN(2, s.Slice())
+ t.AssertIN(3, s.Slice())
+ t.AssertIN(4, s.Slice())
+ t.AssertNI(0, s.Slice())
+ t.Assert(s.Contains(4), true)
+ t.Assert(s.Contains(5), false)
+ s.Remove(1)
+ t.Assert(s.Size(), 3)
+ s.Clear()
+ t.Assert(s.Size(), 0)
+ })
+}
+
func TestSet_New(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s := gset.New()
- s.Add(1).Add(1).Add(2)
+ s.Add(1, 1, 2)
s.Add([]interface{}{3, 4}...)
t.Assert(s.Size(), 4)
t.AssertIN(1, s.Slice())
@@ -44,7 +66,7 @@ func TestSet_New(t *testing.T) {
func TestSet_Basic(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s := gset.NewSet()
- s.Add(1).Add(1).Add(2)
+ s.Add(1, 1, 2)
s.Add([]interface{}{3, 4}...)
t.Assert(s.Size(), 4)
t.AssertIN(1, s.Slice())
@@ -64,7 +86,7 @@ func TestSet_Basic(t *testing.T) {
func TestSet_Iterator(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s := gset.NewSet()
- s.Add(1).Add(2).Add(3)
+ s.Add(1, 2, 3)
t.Assert(s.Size(), 3)
a1 := garray.New(true)
@@ -85,7 +107,7 @@ func TestSet_Iterator(t *testing.T) {
func TestSet_LockFunc(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s := gset.NewSet()
- s.Add(1).Add(2).Add(3)
+ s.Add(1, 2, 3)
t.Assert(s.Size(), 3)
s.LockFunc(func(m map[interface{}]struct{}) {
delete(m, 1)
@@ -105,9 +127,9 @@ func TestSet_Equal(t *testing.T) {
s1 := gset.NewSet()
s2 := gset.NewSet()
s3 := gset.NewSet()
- s1.Add(1).Add(2).Add(3)
- s2.Add(1).Add(2).Add(3)
- s3.Add(1).Add(2).Add(3).Add(4)
+ s1.Add(1, 2, 3)
+ s2.Add(1, 2, 3)
+ s3.Add(1, 2, 3, 4)
t.Assert(s1.Equal(s2), true)
t.Assert(s1.Equal(s3), false)
})
@@ -118,9 +140,9 @@ func TestSet_IsSubsetOf(t *testing.T) {
s1 := gset.NewSet()
s2 := gset.NewSet()
s3 := gset.NewSet()
- s1.Add(1).Add(2)
- s2.Add(1).Add(2).Add(3)
- s3.Add(1).Add(2).Add(3).Add(4)
+ s1.Add(1, 2)
+ s2.Add(1, 2, 3)
+ s3.Add(1, 2, 3, 4)
t.Assert(s1.IsSubsetOf(s2), true)
t.Assert(s2.IsSubsetOf(s3), true)
t.Assert(s1.IsSubsetOf(s3), true)
@@ -133,8 +155,8 @@ func TestSet_Union(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := gset.NewSet()
s2 := gset.NewSet()
- s1.Add(1).Add(2)
- s2.Add(3).Add(4)
+ s1.Add(1, 2)
+ s2.Add(3, 4)
s3 := s1.Union(s2)
t.Assert(s3.Contains(1), true)
t.Assert(s3.Contains(2), true)
@@ -147,8 +169,8 @@ func TestSet_Diff(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := gset.NewSet()
s2 := gset.NewSet()
- s1.Add(1).Add(2).Add(3)
- s2.Add(3).Add(4).Add(5)
+ s1.Add(1, 2, 3)
+ s2.Add(3, 4, 5)
s3 := s1.Diff(s2)
t.Assert(s3.Contains(1), true)
t.Assert(s3.Contains(2), true)
@@ -161,8 +183,8 @@ func TestSet_Intersect(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := gset.NewSet()
s2 := gset.NewSet()
- s1.Add(1).Add(2).Add(3)
- s2.Add(3).Add(4).Add(5)
+ s1.Add(1, 2, 3)
+ s2.Add(3, 4, 5)
s3 := s1.Intersect(s2)
t.Assert(s3.Contains(1), false)
t.Assert(s3.Contains(2), false)
@@ -175,8 +197,8 @@ func TestSet_Complement(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := gset.NewSet()
s2 := gset.NewSet()
- s1.Add(1).Add(2).Add(3)
- s2.Add(3).Add(4).Add(5)
+ s1.Add(1, 2, 3)
+ s2.Add(3, 4, 5)
s3 := s1.Complement(s2)
t.Assert(s3.Contains(1), false)
t.Assert(s3.Contains(2), false)
@@ -203,9 +225,9 @@ func TestNewFrom(t *testing.T) {
func TestNew(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := gset.New()
- s1.Add("a").Add(2)
+ s1.Add("a", 2)
s2 := gset.New(true)
- s2.Add("b").Add(3)
+ s2.Add("b", 3)
t.Assert(s1.Contains("a"), true)
})
@@ -214,13 +236,13 @@ func TestNew(t *testing.T) {
func TestSet_Join(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := gset.New(true)
- s1.Add("a").Add("a1").Add("b").Add("c")
+ s1.Add("a", "a1", "b", "c")
str1 := s1.Join(",")
t.Assert(strings.Contains(str1, "a1"), true)
})
gtest.C(t, func(t *gtest.T) {
s1 := gset.New(true)
- s1.Add("a").Add(`"b"`).Add(`\c`)
+ s1.Add("a", `"b"`, `\c`)
str1 := s1.Join(",")
t.Assert(strings.Contains(str1, `"b"`), true)
t.Assert(strings.Contains(str1, `\c`), true)
@@ -231,7 +253,7 @@ func TestSet_Join(t *testing.T) {
func TestSet_String(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := gset.New(true)
- s1.Add("a").Add("a2").Add("b").Add("c")
+ s1.Add("a", "a2", "b", "c")
str1 := s1.String()
t.Assert(strings.Contains(str1, "["), true)
t.Assert(strings.Contains(str1, "]"), true)
@@ -243,8 +265,8 @@ func TestSet_Merge(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := gset.New(true)
s2 := gset.New(true)
- s1.Add("a").Add("a2").Add("b").Add("c")
- s2.Add("b").Add("b1").Add("e").Add("f")
+ s1.Add("a", "a2", "b", "c")
+ s2.Add("b", "b1", "e", "f")
ss := s1.Merge(s2)
t.Assert(ss.Contains("a2"), true)
t.Assert(ss.Contains("b1"), true)
@@ -255,7 +277,7 @@ func TestSet_Merge(t *testing.T) {
func TestSet_Sum(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := gset.New(true)
- s1.Add(1).Add(2).Add(3).Add(4)
+ s1.Add(1, 2, 3, 4)
t.Assert(s1.Sum(), int(10))
})
@@ -264,7 +286,7 @@ func TestSet_Sum(t *testing.T) {
func TestSet_Pop(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s := gset.New(true)
- s.Add(1).Add(2).Add(3).Add(4)
+ s.Add(1, 2, 3, 4)
t.Assert(s.Size(), 4)
t.AssertIN(s.Pop(), []int{1, 2, 3, 4})
t.Assert(s.Size(), 3)
@@ -274,7 +296,7 @@ func TestSet_Pop(t *testing.T) {
func TestSet_Pops(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s := gset.New(true)
- s.Add(1).Add(2).Add(3).Add(4)
+ s.Add(1, 2, 3, 4)
t.Assert(s.Size(), 4)
t.Assert(s.Pops(0), nil)
t.AssertIN(s.Pops(1), []int{1, 2, 3, 4})
@@ -324,43 +346,71 @@ func TestSet_Json(t *testing.T) {
})
}
+func TestSet_AddIfNotExist(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ s := gset.New(true)
+ s.Add(1)
+ t.Assert(s.Contains(1), true)
+ t.Assert(s.AddIfNotExist(1), false)
+ t.Assert(s.AddIfNotExist(2), true)
+ t.Assert(s.Contains(2), true)
+ t.Assert(s.AddIfNotExist(2), false)
+ t.Assert(s.Contains(2), true)
+ })
+}
+
func TestSet_AddIfNotExistFunc(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s := gset.New(true)
s.Add(1)
t.Assert(s.Contains(1), true)
t.Assert(s.Contains(2), false)
-
- s.AddIfNotExistFunc(2, func() interface{} {
- return 3
- })
+ t.Assert(s.AddIfNotExistFunc(2, func() bool { return false }), false)
t.Assert(s.Contains(2), false)
- t.Assert(s.Contains(3), true)
-
- s.AddIfNotExistFunc(3, func() interface{} {
- return 4
- })
- t.Assert(s.Contains(3), true)
- t.Assert(s.Contains(4), false)
+ t.Assert(s.AddIfNotExistFunc(2, func() bool { return true }), true)
+ t.Assert(s.Contains(2), true)
+ t.Assert(s.AddIfNotExistFunc(2, func() bool { return true }), false)
+ t.Assert(s.Contains(2), true)
})
-
gtest.C(t, func(t *gtest.T) {
s := gset.New(true)
+ wg := sync.WaitGroup{}
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ r := s.AddIfNotExistFunc(1, func() bool {
+ time.Sleep(100 * time.Millisecond)
+ return true
+ })
+ t.Assert(r, false)
+ }()
s.Add(1)
- t.Assert(s.Contains(1), true)
- t.Assert(s.Contains(2), false)
+ wg.Wait()
+ })
+}
- s.AddIfNotExistFuncLock(2, func() interface{} {
- return 3
- })
- t.Assert(s.Contains(2), false)
- t.Assert(s.Contains(3), true)
-
- s.AddIfNotExistFuncLock(3, func() interface{} {
- return 4
- })
- t.Assert(s.Contains(3), true)
- t.Assert(s.Contains(4), false)
+func TestSet_AddIfNotExistFuncLock(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ s := gset.New(true)
+ wg := sync.WaitGroup{}
+ wg.Add(2)
+ go func() {
+ defer wg.Done()
+ r := s.AddIfNotExistFuncLock(1, func() bool {
+ time.Sleep(500 * time.Millisecond)
+ return true
+ })
+ t.Assert(r, true)
+ }()
+ time.Sleep(100 * time.Millisecond)
+ go func() {
+ defer wg.Done()
+ r := s.AddIfNotExistFuncLock(1, func() bool {
+ return true
+ })
+ t.Assert(r, false)
+ }()
+ wg.Wait()
})
}
diff --git a/container/gset/gset_z_unit_int_test.go b/container/gset/gset_z_unit_int_test.go
index ee36c7805..a749fa27d 100644
--- a/container/gset/gset_z_unit_int_test.go
+++ b/container/gset/gset_z_unit_int_test.go
@@ -13,17 +13,39 @@ import (
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/util/gconv"
"strings"
+ "sync"
"testing"
+ "time"
"github.com/gogf/gf/container/garray"
"github.com/gogf/gf/container/gset"
"github.com/gogf/gf/test/gtest"
)
+func TestIntSet_Var(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ var s gset.IntSet
+ s.Add(1, 1, 2)
+ s.Add([]int{3, 4}...)
+ t.Assert(s.Size(), 4)
+ t.AssertIN(1, s.Slice())
+ t.AssertIN(2, s.Slice())
+ t.AssertIN(3, s.Slice())
+ t.AssertIN(4, s.Slice())
+ t.AssertNI(0, s.Slice())
+ t.Assert(s.Contains(4), true)
+ t.Assert(s.Contains(5), false)
+ s.Remove(1)
+ t.Assert(s.Size(), 3)
+ s.Clear()
+ t.Assert(s.Size(), 0)
+ })
+}
+
func TestIntSet_Basic(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s := gset.NewIntSet()
- s.Add(1).Add(1).Add(2)
+ s.Add(1, 1, 2)
s.Add([]int{3, 4}...)
t.Assert(s.Size(), 4)
t.AssertIN(1, s.Slice())
@@ -43,7 +65,7 @@ func TestIntSet_Basic(t *testing.T) {
func TestIntSet_Iterator(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s := gset.NewIntSet()
- s.Add(1).Add(2).Add(3)
+ s.Add(1, 2, 3)
t.Assert(s.Size(), 3)
a1 := garray.New(true)
@@ -64,7 +86,7 @@ func TestIntSet_Iterator(t *testing.T) {
func TestIntSet_LockFunc(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s := gset.NewIntSet()
- s.Add(1).Add(2).Add(3)
+ s.Add(1, 2, 3)
t.Assert(s.Size(), 3)
s.LockFunc(func(m map[int]struct{}) {
delete(m, 1)
@@ -84,9 +106,9 @@ func TestIntSet_Equal(t *testing.T) {
s1 := gset.NewIntSet()
s2 := gset.NewIntSet()
s3 := gset.NewIntSet()
- s1.Add(1).Add(2).Add(3)
- s2.Add(1).Add(2).Add(3)
- s3.Add(1).Add(2).Add(3).Add(4)
+ s1.Add(1, 2, 3)
+ s2.Add(1, 2, 3)
+ s3.Add(1, 2, 3, 4)
t.Assert(s1.Equal(s2), true)
t.Assert(s1.Equal(s3), false)
})
@@ -97,9 +119,9 @@ func TestIntSet_IsSubsetOf(t *testing.T) {
s1 := gset.NewIntSet()
s2 := gset.NewIntSet()
s3 := gset.NewIntSet()
- s1.Add(1).Add(2)
- s2.Add(1).Add(2).Add(3)
- s3.Add(1).Add(2).Add(3).Add(4)
+ s1.Add(1, 2)
+ s2.Add(1, 2, 3)
+ s3.Add(1, 2, 3, 4)
t.Assert(s1.IsSubsetOf(s2), true)
t.Assert(s2.IsSubsetOf(s3), true)
t.Assert(s1.IsSubsetOf(s3), true)
@@ -112,8 +134,8 @@ func TestIntSet_Union(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := gset.NewIntSet()
s2 := gset.NewIntSet()
- s1.Add(1).Add(2)
- s2.Add(3).Add(4)
+ s1.Add(1, 2)
+ s2.Add(3, 4)
s3 := s1.Union(s2)
t.Assert(s3.Contains(1), true)
t.Assert(s3.Contains(2), true)
@@ -126,8 +148,8 @@ func TestIntSet_Diff(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := gset.NewIntSet()
s2 := gset.NewIntSet()
- s1.Add(1).Add(2).Add(3)
- s2.Add(3).Add(4).Add(5)
+ s1.Add(1, 2, 3)
+ s2.Add(3, 4, 5)
s3 := s1.Diff(s2)
t.Assert(s3.Contains(1), true)
t.Assert(s3.Contains(2), true)
@@ -140,8 +162,8 @@ func TestIntSet_Intersect(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := gset.NewIntSet()
s2 := gset.NewIntSet()
- s1.Add(1).Add(2).Add(3)
- s2.Add(3).Add(4).Add(5)
+ s1.Add(1, 2, 3)
+ s2.Add(3, 4, 5)
s3 := s1.Intersect(s2)
t.Assert(s3.Contains(1), false)
t.Assert(s3.Contains(2), false)
@@ -154,8 +176,8 @@ func TestIntSet_Complement(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := gset.NewIntSet()
s2 := gset.NewIntSet()
- s1.Add(1).Add(2).Add(3)
- s2.Add(3).Add(4).Add(5)
+ s1.Add(1, 2, 3)
+ s2.Add(3, 4, 5)
s3 := s1.Complement(s2)
t.Assert(s3.Contains(1), false)
t.Assert(s3.Contains(2), false)
@@ -167,7 +189,7 @@ func TestIntSet_Complement(t *testing.T) {
func TestIntSet_Size(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := gset.NewIntSet(true)
- s1.Add(1).Add(2).Add(3)
+ s1.Add(1, 2, 3)
t.Assert(s1.Size(), 3)
})
@@ -178,8 +200,8 @@ func TestIntSet_Merge(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := gset.NewIntSet()
s2 := gset.NewIntSet()
- s1.Add(1).Add(2).Add(3)
- s2.Add(3).Add(4).Add(5)
+ s1.Add(1, 2, 3)
+ s2.Add(3, 4, 5)
s3 := s1.Merge(s2)
t.Assert(s3.Contains(1), true)
t.Assert(s3.Contains(5), true)
@@ -190,7 +212,7 @@ func TestIntSet_Merge(t *testing.T) {
func TestIntSet_Join(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := gset.NewIntSet()
- s1.Add(1).Add(2).Add(3)
+ s1.Add(1, 2, 3)
s3 := s1.Join(",")
t.Assert(strings.Contains(s3, "1"), true)
t.Assert(strings.Contains(s3, "2"), true)
@@ -201,7 +223,7 @@ func TestIntSet_Join(t *testing.T) {
func TestIntSet_String(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := gset.NewIntSet()
- s1.Add(1).Add(2).Add(3)
+ s1.Add(1, 2, 3)
s3 := s1.String()
t.Assert(strings.Contains(s3, "["), true)
t.Assert(strings.Contains(s3, "]"), true)
@@ -214,9 +236,9 @@ func TestIntSet_String(t *testing.T) {
func TestIntSet_Sum(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := gset.NewIntSet()
- s1.Add(1).Add(2).Add(3)
+ s1.Add(1, 2, 3)
s2 := gset.NewIntSet()
- s2.Add(5).Add(6).Add(7)
+ s2.Add(5, 6, 7)
t.Assert(s2.Sum(), 18)
})
@@ -226,7 +248,7 @@ func TestIntSet_Sum(t *testing.T) {
func TestIntSet_Pop(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s := gset.NewIntSet()
- s.Add(4).Add(2).Add(3)
+ s.Add(4, 2, 3)
t.Assert(s.Size(), 3)
t.AssertIN(s.Pop(), []int{4, 2, 3})
t.AssertIN(s.Pop(), []int{4, 2, 3})
@@ -237,7 +259,7 @@ func TestIntSet_Pop(t *testing.T) {
func TestIntSet_Pops(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s := gset.NewIntSet()
- s.Add(1).Add(4).Add(2).Add(3)
+ s.Add(1, 4, 2, 3)
t.Assert(s.Size(), 4)
t.Assert(s.Pops(0), nil)
t.AssertIN(s.Pops(1), []int{1, 4, 2, 3})
@@ -258,6 +280,74 @@ func TestIntSet_Pops(t *testing.T) {
})
}
+func TestIntSet_AddIfNotExist(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ s := gset.NewIntSet(true)
+ s.Add(1)
+ t.Assert(s.Contains(1), true)
+ t.Assert(s.AddIfNotExist(1), false)
+ t.Assert(s.AddIfNotExist(2), true)
+ t.Assert(s.Contains(2), true)
+ t.Assert(s.AddIfNotExist(2), false)
+ t.Assert(s.Contains(2), true)
+ })
+}
+
+func TestIntSet_AddIfNotExistFunc(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ s := gset.NewIntSet(true)
+ s.Add(1)
+ t.Assert(s.Contains(1), true)
+ t.Assert(s.Contains(2), false)
+ t.Assert(s.AddIfNotExistFunc(2, func() bool { return false }), false)
+ t.Assert(s.Contains(2), false)
+ t.Assert(s.AddIfNotExistFunc(2, func() bool { return true }), true)
+ t.Assert(s.Contains(2), true)
+ t.Assert(s.AddIfNotExistFunc(2, func() bool { return true }), false)
+ t.Assert(s.Contains(2), true)
+ })
+ gtest.C(t, func(t *gtest.T) {
+ s := gset.NewIntSet(true)
+ wg := sync.WaitGroup{}
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ r := s.AddIfNotExistFunc(1, func() bool {
+ time.Sleep(100 * time.Millisecond)
+ return true
+ })
+ t.Assert(r, false)
+ }()
+ s.Add(1)
+ wg.Wait()
+ })
+}
+
+func TestIntSet_AddIfNotExistFuncLock(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ s := gset.NewIntSet(true)
+ wg := sync.WaitGroup{}
+ wg.Add(2)
+ go func() {
+ defer wg.Done()
+ r := s.AddIfNotExistFuncLock(1, func() bool {
+ time.Sleep(500 * time.Millisecond)
+ return true
+ })
+ t.Assert(r, true)
+ }()
+ time.Sleep(100 * time.Millisecond)
+ go func() {
+ defer wg.Done()
+ r := s.AddIfNotExistFuncLock(1, func() bool {
+ return true
+ })
+ t.Assert(r, false)
+ }()
+ wg.Wait()
+ })
+}
+
func TestIntSet_Json(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := []int{1, 3, 2, 4}
@@ -287,46 +377,6 @@ func TestIntSet_Json(t *testing.T) {
})
}
-func TestIntSet_AddIfNotExistFunc(t *testing.T) {
- gtest.C(t, func(t *gtest.T) {
- s := gset.NewIntSet(true)
- s.Add(1)
- t.Assert(s.Contains(1), true)
- t.Assert(s.Contains(2), false)
-
- s.AddIfNotExistFunc(2, func() int {
- return 3
- })
- t.Assert(s.Contains(2), false)
- t.Assert(s.Contains(3), true)
-
- s.AddIfNotExistFunc(3, func() int {
- return 4
- })
- t.Assert(s.Contains(3), true)
- t.Assert(s.Contains(4), false)
- })
-
- gtest.C(t, func(t *gtest.T) {
- s := gset.NewIntSet(true)
- s.Add(1)
- t.Assert(s.Contains(1), true)
- t.Assert(s.Contains(2), false)
-
- s.AddIfNotExistFuncLock(2, func() int {
- return 3
- })
- t.Assert(s.Contains(2), false)
- t.Assert(s.Contains(3), true)
-
- s.AddIfNotExistFuncLock(3, func() int {
- return 4
- })
- t.Assert(s.Contains(3), true)
- t.Assert(s.Contains(4), false)
- })
-}
-
func TestIntSet_UnmarshalValue(t *testing.T) {
type V struct {
Name string
diff --git a/container/gset/gset_z_unit_str_test.go b/container/gset/gset_z_unit_str_test.go
index 7f0fbb3a6..ce654c3fa 100644
--- a/container/gset/gset_z_unit_str_test.go
+++ b/container/gset/gset_z_unit_str_test.go
@@ -13,17 +13,39 @@ import (
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/util/gconv"
"strings"
+ "sync"
"testing"
+ "time"
"github.com/gogf/gf/container/garray"
"github.com/gogf/gf/container/gset"
"github.com/gogf/gf/test/gtest"
)
+func TestStrSet_Var(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ var s gset.StrSet
+ s.Add("1", "1", "2")
+ s.Add([]string{"3", "4"}...)
+ t.Assert(s.Size(), 4)
+ t.AssertIN("1", s.Slice())
+ t.AssertIN("2", s.Slice())
+ t.AssertIN("3", s.Slice())
+ t.AssertIN("4", s.Slice())
+ t.AssertNI("0", s.Slice())
+ t.Assert(s.Contains("4"), true)
+ t.Assert(s.Contains("5"), false)
+ s.Remove("1")
+ t.Assert(s.Size(), 3)
+ s.Clear()
+ t.Assert(s.Size(), 0)
+ })
+}
+
func TestStrSet_Basic(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s := gset.NewStrSet()
- s.Add("1").Add("1").Add("2")
+ s.Add("1", "1", "2")
s.Add([]string{"3", "4"}...)
t.Assert(s.Size(), 4)
t.AssertIN("1", s.Slice())
@@ -43,7 +65,7 @@ func TestStrSet_Basic(t *testing.T) {
func TestStrSet_Iterator(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s := gset.NewStrSet()
- s.Add("1").Add("2").Add("3")
+ s.Add("1", "2", "3")
t.Assert(s.Size(), 3)
a1 := garray.New(true)
@@ -64,7 +86,7 @@ func TestStrSet_Iterator(t *testing.T) {
func TestStrSet_LockFunc(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s := gset.NewStrSet()
- s.Add("1").Add("2").Add("3")
+ s.Add("1", "2", "3")
t.Assert(s.Size(), 3)
s.LockFunc(func(m map[string]struct{}) {
delete(m, "1")
@@ -84,9 +106,9 @@ func TestStrSet_Equal(t *testing.T) {
s1 := gset.NewStrSet()
s2 := gset.NewStrSet()
s3 := gset.NewStrSet()
- s1.Add("1").Add("2").Add("3")
- s2.Add("1").Add("2").Add("3")
- s3.Add("1").Add("2").Add("3").Add("4")
+ s1.Add("1", "2", "3")
+ s2.Add("1", "2", "3")
+ s3.Add("1", "2", "3", "4")
t.Assert(s1.Equal(s2), true)
t.Assert(s1.Equal(s3), false)
})
@@ -97,9 +119,9 @@ func TestStrSet_IsSubsetOf(t *testing.T) {
s1 := gset.NewStrSet()
s2 := gset.NewStrSet()
s3 := gset.NewStrSet()
- s1.Add("1").Add("2")
- s2.Add("1").Add("2").Add("3")
- s3.Add("1").Add("2").Add("3").Add("4")
+ s1.Add("1", "2")
+ s2.Add("1", "2", "3")
+ s3.Add("1", "2", "3", "4")
t.Assert(s1.IsSubsetOf(s2), true)
t.Assert(s2.IsSubsetOf(s3), true)
t.Assert(s1.IsSubsetOf(s3), true)
@@ -112,8 +134,8 @@ func TestStrSet_Union(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := gset.NewStrSet()
s2 := gset.NewStrSet()
- s1.Add("1").Add("2")
- s2.Add("3").Add("4")
+ s1.Add("1", "2")
+ s2.Add("3", "4")
s3 := s1.Union(s2)
t.Assert(s3.Contains("1"), true)
t.Assert(s3.Contains("2"), true)
@@ -126,8 +148,8 @@ func TestStrSet_Diff(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := gset.NewStrSet()
s2 := gset.NewStrSet()
- s1.Add("1").Add("2").Add("3")
- s2.Add("3").Add("4").Add("5")
+ s1.Add("1", "2", "3")
+ s2.Add("3", "4", "5")
s3 := s1.Diff(s2)
t.Assert(s3.Contains("1"), true)
t.Assert(s3.Contains("2"), true)
@@ -140,8 +162,8 @@ func TestStrSet_Intersect(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := gset.NewStrSet()
s2 := gset.NewStrSet()
- s1.Add("1").Add("2").Add("3")
- s2.Add("3").Add("4").Add("5")
+ s1.Add("1", "2", "3")
+ s2.Add("3", "4", "5")
s3 := s1.Intersect(s2)
t.Assert(s3.Contains("1"), false)
t.Assert(s3.Contains("2"), false)
@@ -154,8 +176,8 @@ func TestStrSet_Complement(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := gset.NewStrSet()
s2 := gset.NewStrSet()
- s1.Add("1").Add("2").Add("3")
- s2.Add("3").Add("4").Add("5")
+ s1.Add("1", "2", "3")
+ s2.Add("3", "4", "5")
s3 := s1.Complement(s2)
t.Assert(s3.Contains("1"), false)
t.Assert(s3.Contains("2"), false)
@@ -179,8 +201,8 @@ func TestStrSet_Merge(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := gset.NewStrSet()
s2 := gset.NewStrSet()
- s1.Add("1").Add("2").Add("3")
- s2.Add("3").Add("4").Add("5")
+ s1.Add("1", "2", "3")
+ s2.Add("3", "4", "5")
s3 := s1.Merge(s2)
t.Assert(s3.Contains("1"), true)
t.Assert(s3.Contains("6"), false)
@@ -207,7 +229,7 @@ func TestStrSet_Join(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := gset.NewStrSet()
- s1.Add("a").Add(`"b"`).Add(`\c`)
+ s1.Add("a", `"b"`, `\c`)
str1 := s1.Join(",")
t.Assert(strings.Contains(str1, `"b"`), true)
t.Assert(strings.Contains(str1, `\c`), true)
@@ -225,7 +247,7 @@ func TestStrSet_String(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := gset.New(true)
- s1.Add("a").Add("a2").Add("b").Add("c")
+ s1.Add("a", "a2", "b", "c")
str1 := s1.String()
t.Assert(strings.Contains(str1, "["), true)
t.Assert(strings.Contains(str1, "]"), true)
@@ -253,7 +275,7 @@ func TestStrSet_Size(t *testing.T) {
func TestStrSet_Remove(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := gset.NewStrSetFrom([]string{"a", "b", "c"}, true)
- s1 = s1.Remove("b")
+ s1.Remove("b")
t.Assert(s1.Contains("b"), false)
t.Assert(s1.Contains("c"), true)
})
@@ -294,6 +316,74 @@ func TestStrSet_Pops(t *testing.T) {
})
}
+func TestStrSet_AddIfNotExist(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ s := gset.NewStrSet(true)
+ s.Add("1")
+ t.Assert(s.Contains("1"), true)
+ t.Assert(s.AddIfNotExist("1"), false)
+ t.Assert(s.AddIfNotExist("2"), true)
+ t.Assert(s.Contains("2"), true)
+ t.Assert(s.AddIfNotExist("2"), false)
+ t.Assert(s.Contains("2"), true)
+ })
+}
+
+func TestStrSet_AddIfNotExistFunc(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ s := gset.NewStrSet(true)
+ s.Add("1")
+ t.Assert(s.Contains("1"), true)
+ t.Assert(s.Contains("2"), false)
+ t.Assert(s.AddIfNotExistFunc("2", func() bool { return false }), false)
+ t.Assert(s.Contains("2"), false)
+ t.Assert(s.AddIfNotExistFunc("2", func() bool { return true }), true)
+ t.Assert(s.Contains("2"), true)
+ t.Assert(s.AddIfNotExistFunc("2", func() bool { return true }), false)
+ t.Assert(s.Contains("2"), true)
+ })
+ gtest.C(t, func(t *gtest.T) {
+ s := gset.NewStrSet(true)
+ wg := sync.WaitGroup{}
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ r := s.AddIfNotExistFunc("1", func() bool {
+ time.Sleep(100 * time.Millisecond)
+ return true
+ })
+ t.Assert(r, false)
+ }()
+ s.Add("1")
+ wg.Wait()
+ })
+}
+
+func TestStrSet_AddIfNotExistFuncLock(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ s := gset.NewStrSet(true)
+ wg := sync.WaitGroup{}
+ wg.Add(2)
+ go func() {
+ defer wg.Done()
+ r := s.AddIfNotExistFuncLock("1", func() bool {
+ time.Sleep(500 * time.Millisecond)
+ return true
+ })
+ t.Assert(r, true)
+ }()
+ time.Sleep(100 * time.Millisecond)
+ go func() {
+ defer wg.Done()
+ r := s.AddIfNotExistFuncLock("1", func() bool {
+ return true
+ })
+ t.Assert(r, false)
+ }()
+ wg.Wait()
+ })
+}
+
func TestStrSet_Json(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := []string{"a", "b", "d", "c"}
@@ -323,46 +413,6 @@ func TestStrSet_Json(t *testing.T) {
})
}
-func TestStrSet_AddIfNotExistFunc(t *testing.T) {
- gtest.C(t, func(t *gtest.T) {
- s := gset.NewStrSet(true)
- s.Add("1")
- t.Assert(s.Contains("1"), true)
- t.Assert(s.Contains("2"), false)
-
- s.AddIfNotExistFunc("2", func() string {
- return "3"
- })
- t.Assert(s.Contains("2"), false)
- t.Assert(s.Contains("3"), true)
-
- s.AddIfNotExistFunc("3", func() string {
- return "4"
- })
- t.Assert(s.Contains("3"), true)
- t.Assert(s.Contains("4"), false)
- })
-
- gtest.C(t, func(t *gtest.T) {
- s := gset.NewStrSet(true)
- s.Add("1")
- t.Assert(s.Contains("1"), true)
- t.Assert(s.Contains("2"), false)
-
- s.AddIfNotExistFuncLock("2", func() string {
- return "3"
- })
- t.Assert(s.Contains("2"), false)
- t.Assert(s.Contains("3"), true)
-
- s.AddIfNotExistFuncLock("3", func() string {
- return "4"
- })
- t.Assert(s.Contains("3"), true)
- t.Assert(s.Contains("4"), false)
- })
-}
-
func TestStrSet_UnmarshalValue(t *testing.T) {
type V struct {
Name string
diff --git a/container/gtree/gtree_avltree.go b/container/gtree/gtree_avltree.go
index ba41adce4..aa195aa1c 100644
--- a/container/gtree/gtree_avltree.go
+++ b/container/gtree/gtree_avltree.go
@@ -18,7 +18,7 @@ import (
// AVLTree holds elements of the AVL tree.
type AVLTree struct {
- mu *rwmutex.RWMutex
+ mu rwmutex.RWMutex
root *AVLTreeNode
comparator func(v1, v2 interface{}) int
size int
@@ -38,7 +38,7 @@ type AVLTreeNode struct {
// which is false in default.
func NewAVLTree(comparator func(v1, v2 interface{}) int, safe ...bool) *AVLTree {
return &AVLTree{
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
comparator: comparator,
}
}
@@ -55,7 +55,7 @@ func NewAVLTreeFrom(comparator func(v1, v2 interface{}) int, data map[interface{
}
// Clone returns a new tree with a copy of current tree.
-func (tree *AVLTree) Clone(safe ...bool) *AVLTree {
+func (tree *AVLTree) Clone() *AVLTree {
newTree := NewAVLTree(tree.comparator, !tree.mu.IsSafe())
newTree.Sets(tree.Map())
return newTree
@@ -93,7 +93,7 @@ func (tree *AVLTree) Search(key interface{}) (value interface{}, found bool) {
func (tree *AVLTree) doSearch(key interface{}) (node *AVLTreeNode, found bool) {
node = tree.root
for node != nil {
- cmp := tree.comparator(key, node.Key)
+ cmp := tree.getComparator()(key, node.Key)
switch {
case cmp == 0:
return node, true
@@ -331,7 +331,7 @@ func (tree *AVLTree) Floor(key interface{}) (floor *AVLTreeNode, found bool) {
defer tree.mu.RUnlock()
n := tree.root
for n != nil {
- c := tree.comparator(key, n.Key)
+ c := tree.getComparator()(key, n.Key)
switch {
case c == 0:
return n, true
@@ -361,7 +361,7 @@ func (tree *AVLTree) Ceiling(key interface{}) (ceiling *AVLTreeNode, found bool)
defer tree.mu.RUnlock()
n := tree.root
for n != nil {
- c := tree.comparator(key, n.Key)
+ c := tree.getComparator()(key, n.Key)
switch {
case c == 0:
return n, true
@@ -465,7 +465,7 @@ func (tree *AVLTree) IteratorFrom(key interface{}, match bool, f func(key, value
tree.IteratorAscFrom(key, match, f)
}
-// IteratorAsc iterates the tree in ascending order with given callback function .
+// IteratorAsc iterates the tree readonly in ascending order with given callback function .
// If returns true, then it continues iterating; or false to stop.
func (tree *AVLTree) IteratorAsc(f func(key, value interface{}) bool) {
tree.mu.RLock()
@@ -473,7 +473,7 @@ func (tree *AVLTree) IteratorAsc(f func(key, value interface{}) bool) {
tree.doIteratorAsc(tree.bottom(0), f)
}
-// IteratorAscFrom iterates the tree in ascending order with given callback function .
+// IteratorAscFrom iterates the tree readonly in ascending order with given callback function .
// The parameter specifies the start entry for iterating. The specifies whether
// starting iterating if the is fully matched, or else using index searching iterating.
// If returns true, then it continues iterating; or false to stop.
@@ -499,7 +499,7 @@ func (tree *AVLTree) doIteratorAsc(node *AVLTreeNode, f func(key, value interfac
}
}
-// IteratorDesc iterates the tree in descending order with given callback function .
+// IteratorDesc iterates the tree readonly in descending order with given callback function .
// If returns true, then it continues iterating; or false to stop.
func (tree *AVLTree) IteratorDesc(f func(key, value interface{}) bool) {
tree.mu.RLock()
@@ -507,7 +507,7 @@ func (tree *AVLTree) IteratorDesc(f func(key, value interface{}) bool) {
tree.doIteratorDesc(tree.bottom(1), f)
}
-// IteratorDescFrom iterates the tree in descending order with given callback function .
+// IteratorDescFrom iterates the tree readonly in descending order with given callback function .
// The parameter specifies the start entry for iterating. The specifies whether
// starting iterating if the is fully matched, or else using index searching iterating.
// If returns true, then it continues iterating; or false to stop.
@@ -541,7 +541,7 @@ func (tree *AVLTree) put(key interface{}, value interface{}, p *AVLTreeNode, qp
return true
}
- c := tree.comparator(key, q.Key)
+ c := tree.getComparator()(key, q.Key)
if c == 0 {
q.Key = key
q.Value = value
@@ -566,7 +566,7 @@ func (tree *AVLTree) remove(key interface{}, qp **AVLTreeNode) (value interface{
return nil, false
}
- c := tree.comparator(key, q.Key)
+ c := tree.getComparator()(key, q.Key)
if c == 0 {
tree.size--
value = q.Value
@@ -784,3 +784,12 @@ func output(node *AVLTreeNode, prefix string, isTail bool, str *string) {
func (tree *AVLTree) MarshalJSON() ([]byte, error) {
return json.Marshal(tree.Map())
}
+
+// getComparator returns the comparator if it's previously set,
+// or else it panics.
+func (tree *AVLTree) getComparator() func(a, b interface{}) int {
+ if tree.comparator == nil {
+ panic("comparator is missing for tree")
+ }
+ return tree.comparator
+}
diff --git a/container/gtree/gtree_btree.go b/container/gtree/gtree_btree.go
index b174cdd28..05c567591 100644
--- a/container/gtree/gtree_btree.go
+++ b/container/gtree/gtree_btree.go
@@ -20,7 +20,7 @@ import (
// BTree holds elements of the B-tree.
type BTree struct {
- mu *rwmutex.RWMutex
+ mu rwmutex.RWMutex
root *BTreeNode
comparator func(v1, v2 interface{}) int
size int // Total number of keys in the tree
@@ -50,7 +50,7 @@ func NewBTree(m int, comparator func(v1, v2 interface{}) int, safe ...bool) *BTr
}
return &BTree{
comparator: comparator,
- mu: rwmutex.New(safe...),
+ mu: rwmutex.Create(safe...),
m: m,
}
}
@@ -67,7 +67,7 @@ func NewBTreeFrom(m int, comparator func(v1, v2 interface{}) int, data map[inter
}
// Clone returns a new tree with a copy of current tree.
-func (tree *BTree) Clone(safe ...bool) *BTree {
+func (tree *BTree) Clone() *BTree {
newTree := NewBTree(tree.m, tree.comparator, !tree.mu.IsSafe())
newTree.Sets(tree.Map())
return newTree
@@ -406,7 +406,7 @@ func (tree *BTree) IteratorFrom(key interface{}, match bool, f func(key, value i
tree.IteratorAscFrom(key, match, f)
}
-// IteratorAsc iterates the tree in ascending order with given callback function