mirror of
https://gitee.com/johng/gf
synced 2026-06-09 02:57:43 +08:00
Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 977c8b7ee3 | |||
| 939e6244ee | |||
| e764b2393d | |||
| 6384e75ed9 | |||
| 195cae6577 | |||
| c8cf46a5a7 | |||
| eba97277b2 | |||
| 4e19fbc5fb | |||
| 494b5bbae2 | |||
| 987ce709e5 | |||
| 35ad4d869f | |||
| 39d654e3f2 | |||
| 7fe9c641f4 | |||
| ee1414c010 | |||
| 8eb1b685a5 | |||
| 46768d6f91 | |||
| bb6fed3dc2 | |||
| 47e74d27bf | |||
| b830f9b96d | |||
| c85162a8a0 | |||
| ef4e128af7 | |||
| cb7c3a9fa4 | |||
| b0f859cc91 | |||
| 6d4da529ee | |||
| 6c7e536eeb | |||
| 36c2648be8 | |||
| a876b6133d | |||
| 03ff358da8 | |||
| 037f74c549 | |||
| a8caf4ad21 | |||
| 51d9fe5253 | |||
| 3218c89f17 |
@ -1,16 +0,0 @@
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
array := []uint{1, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6}
|
||||
for i := 0; i < len(array)-1; i++ {
|
||||
for j := i + 1; j < len(array); j++ {
|
||||
if array[i] == array[j] {
|
||||
array = append(array[:j], array[j+1:]...)
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Println(array)
|
||||
|
||||
}
|
||||
46
.example/container/garray/basic_array.go
Normal file
46
.example/container/garray/basic_array.go
Normal file
@ -0,0 +1,46 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/container/garray"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Create a int array, which is concurrent-unsafe in default.
|
||||
a := garray.NewIntArray()
|
||||
|
||||
// Appending items.
|
||||
for i := 0; i < 10; i++ {
|
||||
a.Append(i)
|
||||
}
|
||||
|
||||
// Get the length of the array.
|
||||
fmt.Println(a.Len())
|
||||
|
||||
// Get the slice of the array.
|
||||
fmt.Println(a.Slice())
|
||||
|
||||
// Get the item of specified index.
|
||||
fmt.Println(a.Get(6))
|
||||
|
||||
// Insert after/before specified index.
|
||||
a.InsertAfter(9, 11)
|
||||
a.InsertBefore(10, 10)
|
||||
fmt.Println(a.Slice())
|
||||
|
||||
a.Set(0, 100)
|
||||
fmt.Println(a.Slice())
|
||||
|
||||
// Searching the item and returning the index.
|
||||
fmt.Println(a.Search(5))
|
||||
|
||||
// Remove item of specified index.
|
||||
a.Remove(0)
|
||||
fmt.Println(a.Slice())
|
||||
|
||||
// Clearing the array.
|
||||
fmt.Println(a.Slice())
|
||||
a.Clear()
|
||||
fmt.Println(a.Slice())
|
||||
}
|
||||
@ -1,59 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/container/garray"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// 创建普通的int类型数组,并关闭默认的并发安全特性
|
||||
a := garray.NewIntArray(true)
|
||||
|
||||
// 添加数据项
|
||||
for i := 0; i < 10; i++ {
|
||||
a.Append(i)
|
||||
}
|
||||
|
||||
// 获取当前数组长度
|
||||
fmt.Println(a.Len())
|
||||
|
||||
// 获取当前数据项列表
|
||||
fmt.Println(a.Slice())
|
||||
|
||||
// 获取指定索引项
|
||||
fmt.Println(a.Get(6))
|
||||
|
||||
// 在指定索引前插入数据项
|
||||
a.InsertAfter(9, 11)
|
||||
// 在指定索引后插入数据项
|
||||
a.InsertBefore(10, 10)
|
||||
fmt.Println(a.Slice())
|
||||
|
||||
// 修改指定索引的数据项
|
||||
a.Set(0, 100)
|
||||
fmt.Println(a.Slice())
|
||||
|
||||
// 搜索数据项,返回搜索到的索引位置
|
||||
fmt.Println(a.Search(5))
|
||||
|
||||
// 删除指定索引的数据项
|
||||
a.Remove(0)
|
||||
fmt.Println(a.Slice())
|
||||
|
||||
// 并发安全,写锁操作
|
||||
a.LockFunc(func(array []int) {
|
||||
// 将末尾项改为100
|
||||
array[len(array)-1] = 100
|
||||
})
|
||||
|
||||
// 并发安全,读锁操作
|
||||
a.RLockFunc(func(array []int) {
|
||||
fmt.Println(array[len(array)-1])
|
||||
})
|
||||
|
||||
// 清空数组
|
||||
fmt.Println(a.Slice())
|
||||
a.Clear()
|
||||
fmt.Println(a.Slice())
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/container/garray"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
a := garray.NewIntArray()
|
||||
a.Append(1, 2, 3)
|
||||
|
||||
v := a.Slice()
|
||||
v[0] = 4
|
||||
|
||||
g.Dump(a.Slice())
|
||||
g.Dump(v)
|
||||
}
|
||||
22
.example/container/garray/json_marshal.go
Normal file
22
.example/container/garray/json_marshal.go
Normal file
@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/container/garray"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Student struct {
|
||||
Id int
|
||||
Name string
|
||||
Scores *garray.IntArray
|
||||
}
|
||||
s := Student{
|
||||
Id: 1,
|
||||
Name: "john",
|
||||
Scores: garray.NewIntArrayFrom([]int{100, 99, 98}),
|
||||
}
|
||||
b, _ := json.Marshal(s)
|
||||
fmt.Println(string(b))
|
||||
}
|
||||
19
.example/container/garray/json_unmarshal.go
Normal file
19
.example/container/garray/json_unmarshal.go
Normal file
@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/container/garray"
|
||||
)
|
||||
|
||||
func main() {
|
||||
b := []byte(`{"Id":1,"Name":"john","Scores":[100,99,98]}`)
|
||||
type Student struct {
|
||||
Id int
|
||||
Name string
|
||||
Scores *garray.IntArray
|
||||
}
|
||||
s := Student{}
|
||||
json.Unmarshal(b, &s)
|
||||
fmt.Println(s)
|
||||
}
|
||||
@ -1,20 +1,23 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/container/garray"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
array := garray.NewSortedStringArray()
|
||||
array.Add("1")
|
||||
array.Add("2")
|
||||
array.Add("3")
|
||||
array.Add("4")
|
||||
array.Add("5")
|
||||
array.Add("6")
|
||||
array.Add("7")
|
||||
array.Add("8")
|
||||
array := garray.NewSortedStrArray()
|
||||
array.Add("9")
|
||||
g.Dump(array.Slice())
|
||||
array.Add("8")
|
||||
array.Add("7")
|
||||
array.Add("6")
|
||||
array.Add("5")
|
||||
array.Add("4")
|
||||
array.Add("3")
|
||||
array.Add("2")
|
||||
array.Add("1")
|
||||
fmt.Println(array.Slice())
|
||||
// output:
|
||||
// [1 2 3 4 5 6 7 8 9]
|
||||
}
|
||||
@ -1,27 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/container/garray"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
array := garray.NewSortedStringArray()
|
||||
array.Add("/api/ctl/show")
|
||||
array.Add("/api/ctl/post")
|
||||
array.Add("/api/obj/rest")
|
||||
array.Add("/api/handler")
|
||||
array.Add("/api/obj/delete")
|
||||
array.Add("/api/obj/show")
|
||||
array.Add("/api/obj/my-show")
|
||||
array.Add("/api/*")
|
||||
array.Add("/api/ctl/rest")
|
||||
array.Add("/api/ctl/my-show")
|
||||
g.Dump(array.Slice())
|
||||
|
||||
fmt.Println(strings.Compare("/api/ctl/post", "/api/*"))
|
||||
fmt.Println(strings.Compare("/api/*", "/api/ctl/my-show"))
|
||||
}
|
||||
22
.example/container/glist/basic.go
Normal file
22
.example/container/glist/basic.go
Normal file
@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/container/glist"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l := glist.New()
|
||||
// Push
|
||||
l.PushBack(1)
|
||||
l.PushBack(2)
|
||||
e0 := l.PushFront(0)
|
||||
// Insert
|
||||
l.InsertBefore(e0, -1)
|
||||
l.InsertAfter(e0, "a")
|
||||
fmt.Println(l)
|
||||
// Pop
|
||||
fmt.Println(l.PopFront())
|
||||
fmt.Println(l.PopBack())
|
||||
fmt.Println(l)
|
||||
}
|
||||
23
.example/container/glist/json_marshal.go
Normal file
23
.example/container/glist/json_marshal.go
Normal file
@ -0,0 +1,23 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/container/glist"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Student struct {
|
||||
Id int
|
||||
Name string
|
||||
Scores *glist.List
|
||||
}
|
||||
s := Student{
|
||||
Id: 1,
|
||||
Name: "john",
|
||||
Scores: glist.NewFrom(g.Slice{100, 99, 98}),
|
||||
}
|
||||
b, _ := json.Marshal(s)
|
||||
fmt.Println(string(b))
|
||||
}
|
||||
19
.example/container/glist/json_unmarshal.go
Normal file
19
.example/container/glist/json_unmarshal.go
Normal file
@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/container/glist"
|
||||
)
|
||||
|
||||
func main() {
|
||||
b := []byte(`{"Id":1,"Name":"john","Scores":[100,99,98]}`)
|
||||
type Student struct {
|
||||
Id int
|
||||
Name string
|
||||
Scores *glist.List
|
||||
}
|
||||
s := Student{}
|
||||
json.Unmarshal(b, &s)
|
||||
fmt.Println(s)
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/container/gmap"
|
||||
)
|
||||
|
||||
func main() {
|
||||
//m := gmap.New()
|
||||
//m.Set("k", "v")
|
||||
//m.Set("1", "2")
|
||||
//b, err := json.Marshal(m)
|
||||
//fmt.Println(err)
|
||||
//fmt.Println(string(b))
|
||||
|
||||
m := gmap.NewIntIntMap()
|
||||
m.Set(1, 2)
|
||||
m.Set(3, 4)
|
||||
b, err := json.Marshal(m)
|
||||
fmt.Println(err)
|
||||
fmt.Println(string(b))
|
||||
}
|
||||
19
.example/container/gmap/gmap_json_marshal.go
Normal file
19
.example/container/gmap/gmap_json_marshal.go
Normal file
@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
|
||||
"github.com/gogf/gf/container/gmap"
|
||||
)
|
||||
|
||||
func main() {
|
||||
m := gmap.New()
|
||||
m.Sets(g.MapAnyAny{
|
||||
"name": "john",
|
||||
"score": 100,
|
||||
})
|
||||
b, _ := json.Marshal(m)
|
||||
fmt.Println(string(b))
|
||||
}
|
||||
14
.example/container/gmap/gmap_json_unmarshal.go
Normal file
14
.example/container/gmap/gmap_json_unmarshal.go
Normal file
@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/container/gmap"
|
||||
)
|
||||
|
||||
func main() {
|
||||
m := gmap.Map{}
|
||||
s := []byte(`{"name":"john","score":100}`)
|
||||
json.Unmarshal(s, &m)
|
||||
fmt.Println(m.Map())
|
||||
}
|
||||
26
.example/container/gmap/gmap_map_clone_safe.go
Normal file
26
.example/container/gmap/gmap_map_clone_safe.go
Normal file
@ -0,0 +1,26 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/container/gmap"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
m1 := gmap.New()
|
||||
m1.Set("1", "1")
|
||||
|
||||
m2 := m1.Map()
|
||||
m2["2"] = "2"
|
||||
|
||||
g.Dump(m1.Clone())
|
||||
g.Dump(m2)
|
||||
//output:
|
||||
//{
|
||||
// "1": "1"
|
||||
//}
|
||||
//
|
||||
//{
|
||||
// "1": "1",
|
||||
// "2": "2"
|
||||
//}
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/container/gmap"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
m := gmap.New()
|
||||
m.Set("1", "1")
|
||||
|
||||
m1 := m.Map()
|
||||
m1["2"] = "2"
|
||||
|
||||
g.Dump(m.Clone())
|
||||
g.Dump(m1)
|
||||
}
|
||||
@ -10,9 +10,9 @@ import (
|
||||
|
||||
func main() {
|
||||
array := g.Slice{2, 3, 1, 5, 4, 6, 8, 7, 9}
|
||||
hashMap := gmap.New(true)
|
||||
linkMap := gmap.NewLinkMap(true)
|
||||
treeMap := gmap.NewTreeMap(gutil.ComparatorInt, true)
|
||||
hashMap := gmap.New()
|
||||
linkMap := gmap.NewListMap()
|
||||
treeMap := gmap.NewTreeMap(gutil.ComparatorInt)
|
||||
for _, v := range array {
|
||||
hashMap.Set(v, v)
|
||||
}
|
||||
@ -1,39 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 验证 map 的delete方法是否并发安全
|
||||
func main() {
|
||||
// 创建一个初始化的map
|
||||
m := make(map[int]int)
|
||||
for i := 0; i < 10000; i++ {
|
||||
m[i] = i
|
||||
}
|
||||
|
||||
fmt.Println("map size:", len(m))
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
ev := make(chan struct{}, 0)
|
||||
|
||||
// 创建10个并发的goroutine,使用ev控制并发开始事件,更容易模拟data race
|
||||
for i := 0; i < 10; i++ {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
<-ev
|
||||
fmt.Println("start")
|
||||
for i := 0; i < 10000; i++ {
|
||||
delete(m, i)
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
close(ev)
|
||||
wg.Wait()
|
||||
}
|
||||
22
.example/container/gset/json_marshal.go
Normal file
22
.example/container/gset/json_marshal.go
Normal file
@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/container/gset"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Student struct {
|
||||
Id int
|
||||
Name string
|
||||
Scores *gset.IntSet
|
||||
}
|
||||
s := Student{
|
||||
Id: 1,
|
||||
Name: "john",
|
||||
Scores: gset.NewIntSetFrom([]int{100, 99, 98}),
|
||||
}
|
||||
b, _ := json.Marshal(s)
|
||||
fmt.Println(string(b))
|
||||
}
|
||||
19
.example/container/gset/json_unmarshal.go
Normal file
19
.example/container/gset/json_unmarshal.go
Normal file
@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/container/gset"
|
||||
)
|
||||
|
||||
func main() {
|
||||
b := []byte(`{"Id":1,"Name":"john","Scores":[100,99,98]}`)
|
||||
type Student struct {
|
||||
Id int
|
||||
Name string
|
||||
Scores *gset.IntSet
|
||||
}
|
||||
s := Student{}
|
||||
json.Unmarshal(b, &s)
|
||||
fmt.Println(s)
|
||||
}
|
||||
22
.example/container/gtype/json_marshal.go
Normal file
22
.example/container/gtype/json_marshal.go
Normal file
@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/container/gtype"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Student struct {
|
||||
Id *gtype.Int
|
||||
Name *gtype.String
|
||||
Scores *gtype.Interface
|
||||
}
|
||||
s := Student{
|
||||
Id: gtype.NewInt(1),
|
||||
Name: gtype.NewString("john"),
|
||||
Scores: gtype.NewInterface([]int{100, 99, 98}),
|
||||
}
|
||||
b, _ := json.Marshal(s)
|
||||
fmt.Println(string(b))
|
||||
}
|
||||
19
.example/container/gtype/json_unmarshal.go
Normal file
19
.example/container/gtype/json_unmarshal.go
Normal file
@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/container/gtype"
|
||||
)
|
||||
|
||||
func main() {
|
||||
b := []byte(`{"Id":1,"Name":"john","Scores":[100,99,98]}`)
|
||||
type Student struct {
|
||||
Id *gtype.Int
|
||||
Name *gtype.String
|
||||
Scores *gtype.Interface
|
||||
}
|
||||
s := Student{}
|
||||
json.Unmarshal(b, &s)
|
||||
fmt.Println(s)
|
||||
}
|
||||
22
.example/container/gvar/json_marshal.go
Normal file
22
.example/container/gvar/json_marshal.go
Normal file
@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Student struct {
|
||||
Id *g.Var
|
||||
Name *g.Var
|
||||
Scores *g.Var
|
||||
}
|
||||
s := Student{
|
||||
Id: g.NewVar(1),
|
||||
Name: g.NewVar("john"),
|
||||
Scores: g.NewVar([]int{100, 99, 98}),
|
||||
}
|
||||
b, _ := json.Marshal(s)
|
||||
fmt.Println(string(b))
|
||||
}
|
||||
19
.example/container/gvar/json_unmarshal.go
Normal file
19
.example/container/gvar/json_unmarshal.go
Normal file
@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
b := []byte(`{"Id":1,"Name":"john","Scores":[100,99,98]}`)
|
||||
type Student struct {
|
||||
Id *g.Var
|
||||
Name *g.Var
|
||||
Scores *g.Var
|
||||
}
|
||||
s := Student{}
|
||||
json.Unmarshal(b, &s)
|
||||
fmt.Println(s)
|
||||
}
|
||||
@ -30,8 +30,4 @@ func main() {
|
||||
s := new(Score)
|
||||
v.Struct(s)
|
||||
fmt.Println(s)
|
||||
|
||||
// 只读接口
|
||||
r := v.ReadOnly()
|
||||
fmt.Println(r.String())
|
||||
}
|
||||
@ -519,7 +519,6 @@ func getQueriedSqls() {
|
||||
fmt.Println("Sql :", v.Sql)
|
||||
fmt.Println("Args :", v.Args)
|
||||
fmt.Println("Error:", v.Error)
|
||||
fmt.Println("Func :", v.Func)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -8,9 +8,9 @@ import (
|
||||
|
||||
func main() {
|
||||
db := g.DB()
|
||||
db.SetMaxIdleConns(10)
|
||||
db.SetMaxOpenConns(10)
|
||||
db.SetConnMaxLifetime(10)
|
||||
db.SetMaxIdleConnCount(10)
|
||||
db.SetMaxOpenConnCount(10)
|
||||
db.SetMaxConnLifetime(time.Minute)
|
||||
|
||||
// 开启调试模式,以便于记录所有执行的SQL
|
||||
db.SetDebug(true)
|
||||
|
||||
@ -1,20 +1,24 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
db := g.DB()
|
||||
db.SetDebug(true)
|
||||
|
||||
r, e := db.Table("test").Where("id IN (?)", []interface{}{1, 2}).All()
|
||||
type User struct {
|
||||
Id int
|
||||
Name *gtime.Time
|
||||
}
|
||||
|
||||
user := new(User)
|
||||
e := db.Table("test").Where("id", 10000).Struct(user)
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
if r != nil {
|
||||
fmt.Println(r.ToList())
|
||||
}
|
||||
g.Dump(user)
|
||||
|
||||
}
|
||||
|
||||
@ -520,7 +520,6 @@ func getQueriedSqls() {
|
||||
fmt.Println("Sql :", v.Sql)
|
||||
fmt.Println("Args :", v.Args)
|
||||
fmt.Println("Error:", v.Error)
|
||||
fmt.Println("Func :", v.Func)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,47 +1,47 @@
|
||||
package main
|
||||
|
||||
//import (
|
||||
// _ "github.com/mattn/go-sqlite3"
|
||||
// "github.com/gogf/gf/database/gdb"
|
||||
// "github.com/gogf/gf/frame/g"
|
||||
// "fmt"
|
||||
//)
|
||||
//
|
||||
//func main() {
|
||||
// gdb.SetConfig(gdb.Config{
|
||||
// "default": gdb.ConfigGroup{
|
||||
// gdb.ConfigNode{
|
||||
// Name: "/tmp/my.db",
|
||||
// Type: "sqlite",
|
||||
// },
|
||||
// },
|
||||
// })
|
||||
// db := g.Database()
|
||||
// if db == nil {
|
||||
// panic("db create failed")
|
||||
// }
|
||||
// defer db.Close()
|
||||
//
|
||||
// // 创建表
|
||||
// sql := `CREATE TABLE user (
|
||||
// uid INT PRIMARY KEY NOT NULL,
|
||||
// name VARCHAR(30) NOT NULL
|
||||
// );`
|
||||
// if _, err := db.Exec(sql); err != nil {
|
||||
// fmt.Println(err)
|
||||
// }
|
||||
//
|
||||
// // 写入数据
|
||||
// result, err := db.Table("user").Data(g.Map{"uid" : 1, "name" : "john"}).Save()
|
||||
// if err == nil {
|
||||
// fmt.Println(result.RowsAffected())
|
||||
// } else {
|
||||
// fmt.Println(err)
|
||||
// }
|
||||
//
|
||||
// // 删除表
|
||||
// sql = `DROP TABLE user;`
|
||||
// if _, err := db.Exec(sql); err != nil {
|
||||
// fmt.Println(err)
|
||||
// }
|
||||
//}
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/database/gdb"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
func main() {
|
||||
gdb.SetConfig(gdb.Config{
|
||||
"default": gdb.ConfigGroup{
|
||||
gdb.ConfigNode{
|
||||
Name: "/tmp/my.db",
|
||||
Type: "sqlite",
|
||||
},
|
||||
},
|
||||
})
|
||||
db := g.DB()
|
||||
if db == nil {
|
||||
panic("db create failed")
|
||||
}
|
||||
|
||||
// 创建表
|
||||
sql := `CREATE TABLE user (
|
||||
uid INT PRIMARY KEY NOT NULL,
|
||||
name VARCHAR(30) NOT NULL
|
||||
);`
|
||||
if _, err := db.Exec(sql); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
// 写入数据
|
||||
result, err := db.Table("user").Data(g.Map{"uid": 1, "name": "john"}).Save()
|
||||
if err == nil {
|
||||
fmt.Println(result.RowsAffected())
|
||||
} else {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
||||
// 删除表
|
||||
sql = `DROP TABLE user;`
|
||||
if _, err := db.Exec(sql); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,60 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
|
||||
"github.com/gogf/gf/os/gcmd"
|
||||
|
||||
"github.com/gogf/gf/container/garray"
|
||||
"github.com/gogf/gf/database/gredis"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
batchNumber := 1000
|
||||
redis1Config, err := gredis.ConfigFromStr("im-redis-slave:6379,9")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
redis2Config, err := gredis.ConfigFromStr("r-bp1f0a5d4efd8744.redis.rds.aliyuncs.com:6379,9")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
gredis.SetConfig(redis1Config)
|
||||
|
||||
v, err := g.Redis().DoVar("keys", "*")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
array := garray.NewStrArrayFrom(v.Strings())
|
||||
for {
|
||||
slice := array.PopLefts(batchNumber)
|
||||
if len(slice) > 0 {
|
||||
// `migrate %s %d "" 0 2000 copy replace auth %s keys %s`,
|
||||
params := g.Slice{
|
||||
redis2Config.Host,
|
||||
redis2Config.Port,
|
||||
"",
|
||||
redis2Config.Db,
|
||||
2000,
|
||||
"copy",
|
||||
"replace",
|
||||
"keys",
|
||||
}
|
||||
params = append(params, gconv.Interfaces(slice)...)
|
||||
fmt.Println(params)
|
||||
if gcmd.GetOpt("dryrun") == "0" {
|
||||
if v, err := g.Redis().DoVar("migrate", params...); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
fmt.Println(v.String())
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
fmt.Println("done")
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package main
|
||||
package gbase64
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@ -9,26 +9,19 @@ import (
|
||||
|
||||
func main() {
|
||||
// 使用gbinary.Encoded对基本数据类型进行二进制打包
|
||||
if buffer, err := gbinary.Encode(18, 300, 1.01); err != nil {
|
||||
glog.Error(err)
|
||||
} else {
|
||||
fmt.Println(buffer)
|
||||
}
|
||||
fmt.Println(gbinary.Encode(18, 300, 1.01))
|
||||
|
||||
// 使用gbinary.Decode对整形二进制解包,注意第二个及其后参数为字长确定的整形变量的指针地址,字长确定的类型,
|
||||
// 例如:int8/16/32/64、uint8/16/32/64、float32/64
|
||||
// 这里的1.01默认为float64类型(64位系统下)
|
||||
if buffer, err := gbinary.Encode(18, 300, 1.01); err != nil {
|
||||
buffer := gbinary.Encode(18, 300, 1.01)
|
||||
var i1 int8
|
||||
var i2 int16
|
||||
var f3 float64
|
||||
if err := gbinary.Decode(buffer, &i1, &i2, &f3); err != nil {
|
||||
glog.Error(err)
|
||||
} else {
|
||||
var i1 int8
|
||||
var i2 int16
|
||||
var f3 float64
|
||||
if err := gbinary.Decode(buffer, &i1, &i2, &f3); err != nil {
|
||||
glog.Error(err)
|
||||
} else {
|
||||
fmt.Println(i1, i2, f3)
|
||||
}
|
||||
fmt.Println(i1, i2, f3)
|
||||
}
|
||||
|
||||
// 编码/解析 int,自动识别变量长度
|
||||
|
||||
@ -15,6 +15,6 @@ func main() {
|
||||
}
|
||||
|
||||
redisCfg := new(RedisConfig)
|
||||
fmt.Println(g.Config().GetToStruct("redis", redisCfg))
|
||||
fmt.Println(g.Config().GetStruct("redis", redisCfg))
|
||||
fmt.Println(redisCfg)
|
||||
}
|
||||
|
||||
@ -15,4 +15,6 @@ func main() {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(str)
|
||||
// output:
|
||||
// 花间一壶酒,独酌无相亲。
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@ func getWithPattern1() {
|
||||
}
|
||||
}`
|
||||
|
||||
if p, e := gparser.LoadContent([]byte(data), "json"); e != nil {
|
||||
if p, e := gparser.LoadContent([]byte(data)); e != nil {
|
||||
glog.Error(e)
|
||||
} else {
|
||||
fmt.Println("John Score:", p.GetFloat32("users.list.1.score"))
|
||||
@ -36,7 +36,7 @@ func getWithPattern2() {
|
||||
<body>Don't forget me this weekend!</body>
|
||||
</note>`
|
||||
|
||||
if p, e := gparser.LoadContent([]byte(data), "xml"); e != nil {
|
||||
if p, e := gparser.LoadContent([]byte(data)); e != nil {
|
||||
glog.Error(e)
|
||||
} else {
|
||||
fmt.Println("Heading:", p.GetString("note.heading"))
|
||||
@ -52,7 +52,7 @@ func multiDots1() {
|
||||
},
|
||||
"users.count" : 101
|
||||
}`
|
||||
if p, e := gparser.LoadContent([]byte(data), "json"); e != nil {
|
||||
if p, e := gparser.LoadContent([]byte(data)); e != nil {
|
||||
glog.Error(e)
|
||||
} else {
|
||||
fmt.Println("Users Count:", p.Get("users.count"))
|
||||
@ -70,7 +70,7 @@ func multiDots2() {
|
||||
"count.type1" : 100
|
||||
}
|
||||
}`
|
||||
if p, e := gparser.LoadContent([]byte(data), "json"); e != nil {
|
||||
if p, e := gparser.LoadContent([]byte(data)); e != nil {
|
||||
glog.Error(e)
|
||||
} else {
|
||||
fmt.Println("Users Count:", p.Get("users.count.type1"))
|
||||
@ -88,7 +88,7 @@ func set1() {
|
||||
<list><title>gf article2</title><content>gf content2</content></list>
|
||||
<list><title>gf article3</title><content>gf content3</content></list>
|
||||
</article>`
|
||||
if p, e := gparser.LoadContent([]byte(data), "xml"); e != nil {
|
||||
if p, e := gparser.LoadContent([]byte(data)); e != nil {
|
||||
glog.Error(e)
|
||||
} else {
|
||||
p.Set("article.list.0", nil)
|
||||
@ -105,7 +105,7 @@ func set2() {
|
||||
"count" : 100
|
||||
}
|
||||
}`
|
||||
if p, e := gparser.LoadContent([]byte(data), "json"); e != nil {
|
||||
if p, e := gparser.LoadContent([]byte(data)); e != nil {
|
||||
glog.Error(e)
|
||||
} else {
|
||||
p.Set("users.count", 1)
|
||||
@ -116,7 +116,7 @@ func set2() {
|
||||
}
|
||||
|
||||
func makeXml1() {
|
||||
p := gparser.New()
|
||||
p := gparser.New(nil)
|
||||
p.Set("name", "john")
|
||||
p.Set("age", 18)
|
||||
p.Set("scores", map[string]int{
|
||||
@ -133,7 +133,7 @@ func makeJson1() {
|
||||
Id int `json:"id"`
|
||||
Price float32 `json:"price"`
|
||||
}
|
||||
p := gparser.New()
|
||||
p := gparser.New(nil)
|
||||
p.Set("orders.list.0", Order{1, 100})
|
||||
p.Set("orders.list.1", Order{2, 666})
|
||||
p.Set("orders.list.2", Order{3, 999.99})
|
||||
|
||||
@ -1,4 +0,0 @@
|
||||
|
||||
# MySQL数据库配置
|
||||
[database]
|
||||
link = "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
@ -1,13 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/.example/frame/mvc/model/test"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
g.DB().SetDebug(true)
|
||||
user, err := test.ModelUser().One()
|
||||
g.Dump(err)
|
||||
g.Dump(user)
|
||||
}
|
||||
@ -7,7 +7,7 @@ import (
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.SetNameToUriType(ghttp.NAME_TO_URI_TYPE_FULLNAME)
|
||||
s.SetNameToUriType(ghttp.URI_TYPE_FULLNAME)
|
||||
s.EnableAdmin()
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Response.Write("hello world")
|
||||
|
||||
25
.example/net/ghttp/server/cors/cors1.go
Normal file
25
.example/net/ghttp/server/cors/cors1.go
Normal file
@ -0,0 +1,25 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func MiddlewareCORS(r *ghttp.Request) {
|
||||
r.Response.CORSDefault()
|
||||
r.Middleware.Next()
|
||||
}
|
||||
|
||||
func Order(r *ghttp.Request) {
|
||||
r.Response.Write("GET")
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.Group("/api.v1", func(g *ghttp.RouterGroup) {
|
||||
g.Middleware(MiddlewareCORS)
|
||||
g.GET("/order", Order)
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
27
.example/net/ghttp/server/cors/cors2.go
Normal file
27
.example/net/ghttp/server/cors/cors2.go
Normal file
@ -0,0 +1,27 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func MiddlewareCORS(r *ghttp.Request) {
|
||||
corsOptions := r.Response.DefaultCORSOptions()
|
||||
corsOptions.AllowDomain = []string{"goframe.org", "baidu.com"}
|
||||
r.Response.CORS(corsOptions)
|
||||
r.Middleware.Next()
|
||||
}
|
||||
|
||||
func Order(r *ghttp.Request) {
|
||||
r.Response.Write("GET")
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.Group("/api.v1", func(g *ghttp.RouterGroup) {
|
||||
g.Middleware(MiddlewareCORS)
|
||||
g.GET("/order", Order)
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
33
.example/net/ghttp/server/cors/cors3.go
Normal file
33
.example/net/ghttp/server/cors/cors3.go
Normal file
@ -0,0 +1,33 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func MiddlewareCORS(r *ghttp.Request) {
|
||||
corsOptions := r.Response.DefaultCORSOptions()
|
||||
corsOptions.AllowDomain = []string{"goframe.org"}
|
||||
if !r.Response.CORSAllowedOrigin(corsOptions) {
|
||||
r.Response.WriteStatus(http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
r.Response.CORS(corsOptions)
|
||||
r.Middleware.Next()
|
||||
}
|
||||
|
||||
func Order(r *ghttp.Request) {
|
||||
r.Response.Write("GET")
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.Group("/api.v1", func(g *ghttp.RouterGroup) {
|
||||
g.Middleware(MiddlewareCORS)
|
||||
g.GET("/order", Order)
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
@ -2,26 +2,18 @@ package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/frame/gmvc"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
type Order struct {
|
||||
gmvc.Controller
|
||||
}
|
||||
|
||||
func (o *Order) Get() {
|
||||
o.Response.Write("GET")
|
||||
func Order(r *ghttp.Request) {
|
||||
r.Response.Write("GET")
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHookHandlerByMap("/api.v1/*any", map[string]ghttp.HandlerFunc{
|
||||
"BeforeServe": func(r *ghttp.Request) {
|
||||
r.Response.SetAllowCrossDomainRequest("*", "PUT,GET,POST,DELETE,OPTIONS")
|
||||
},
|
||||
s.Group("/api.v1", func(g *ghttp.RouterGroup) {
|
||||
g.GET("/order", Order)
|
||||
})
|
||||
s.BindControllerRest("/api.v1/{.struct}", new(Order))
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
|
||||
@ -2,26 +2,21 @@ package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/frame/gmvc"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
type Order2 struct {
|
||||
gmvc.Controller
|
||||
}
|
||||
|
||||
func (o *Order2) Get() {
|
||||
o.Response.Write("GET")
|
||||
func Order(r *ghttp.Request) {
|
||||
r.Response.Write("GET")
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHookHandlerByMap("/api.v2/*any", map[string]ghttp.HandlerFunc{
|
||||
"BeforeServe": func(r *ghttp.Request) {
|
||||
s.Group("/api.v1", func(g *ghttp.RouterGroup) {
|
||||
g.Hook("/*any", ghttp.HOOK_BEFORE_SERVE, func(r *ghttp.Request) {
|
||||
r.Response.CORSDefault()
|
||||
},
|
||||
})
|
||||
g.GET("/order", Order)
|
||||
})
|
||||
s.BindControllerRest("/api.v2/{.struct}", new(Order2))
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
|
||||
@ -11,12 +11,10 @@ func main() {
|
||||
p := "/:name/info/{uid}"
|
||||
s := g.Server()
|
||||
s.BindHookHandlerByMap(p, map[string]ghttp.HandlerFunc{
|
||||
"BeforeServe": func(r *ghttp.Request) { glog.Println("BeforeServe") },
|
||||
"AfterServe": func(r *ghttp.Request) { glog.Println("AfterServe") },
|
||||
"BeforeOutput": func(r *ghttp.Request) { glog.Println("BeforeOutput") },
|
||||
"AfterOutput": func(r *ghttp.Request) { glog.Println("AfterOutput") },
|
||||
"BeforeClose": func(r *ghttp.Request) { glog.Println("BeforeClose") },
|
||||
"AfterClose": func(r *ghttp.Request) { glog.Println("AfterClose") },
|
||||
ghttp.HOOK_BEFORE_SERVE: func(r *ghttp.Request) { glog.Println(ghttp.HOOK_BEFORE_SERVE) },
|
||||
ghttp.HOOK_AFTER_SERVE: func(r *ghttp.Request) { glog.Println(ghttp.HOOK_AFTER_SERVE) },
|
||||
ghttp.HOOK_BEFORE_OUTPUT: func(r *ghttp.Request) { glog.Println(ghttp.HOOK_BEFORE_OUTPUT) },
|
||||
ghttp.HOOK_AFTER_OUTPUT: func(r *ghttp.Request) { glog.Println(ghttp.HOOK_AFTER_OUTPUT) },
|
||||
})
|
||||
s.BindHandler(p, func(r *ghttp.Request) {
|
||||
r.Response.Write("用户:", r.Get("name"), ", uid:", r.Get("uid"))
|
||||
|
||||
@ -1,38 +1,32 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
// 优先调用的HOOK
|
||||
func beforeServeHook1(r *ghttp.Request) {
|
||||
r.SetParam("name", "GoFrame")
|
||||
r.Response.Writeln("set name")
|
||||
}
|
||||
|
||||
// 随后调用的HOOK
|
||||
func beforeServeHook2(r *ghttp.Request) {
|
||||
r.SetParam("site", "https://goframe.org")
|
||||
r.Response.Writeln("set site")
|
||||
}
|
||||
|
||||
// 允许对同一个路由同一个事件注册多个回调函数,按照注册顺序进行优先级调用。
|
||||
// 为便于在路由表中对比查看优先级,这里讲HOOK回调函数单独定义为了两个函数。
|
||||
func main() {
|
||||
s := g.Server()
|
||||
|
||||
// 多事件回调示例,事件1
|
||||
pattern1 := "/:name/info"
|
||||
s.BindHookHandlerByMap(pattern1, map[string]ghttp.HandlerFunc{
|
||||
"BeforeServe": func(r *ghttp.Request) {
|
||||
r.SetQuery("uid", "1000")
|
||||
},
|
||||
})
|
||||
s.BindHandler(pattern1, func(r *ghttp.Request) {
|
||||
r.Response.Write("用户:", r.Get("name"), ", uid:", r.GetQueryString("uid"))
|
||||
})
|
||||
|
||||
// 多事件回调示例,事件2
|
||||
pattern2 := "/{object}/list/{page}.java"
|
||||
s.BindHookHandlerByMap(pattern2, map[string]ghttp.HandlerFunc{
|
||||
"BeforeOutput": func(r *ghttp.Request) {
|
||||
r.Response.SetBuffer([]byte(
|
||||
fmt.Sprintf("通过事件修改输出内容, object:%s, page:%s", r.Get("object"), r.GetRouterString("page"))),
|
||||
)
|
||||
},
|
||||
})
|
||||
s.BindHandler(pattern2, func(r *ghttp.Request) {
|
||||
r.Response.Write(r.Router.Uri)
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Response.Writeln(r.Get("name"))
|
||||
r.Response.Writeln(r.Get("site"))
|
||||
})
|
||||
s.BindHookHandler("/", ghttp.HOOK_BEFORE_SERVE, beforeServeHook1)
|
||||
s.BindHookHandler("/", ghttp.HOOK_BEFORE_SERVE, beforeServeHook2)
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
|
||||
@ -1,31 +1,35 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"github.com/gogf/gf/os/glog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/priority/show", func(r *ghttp.Request) {
|
||||
r.Response.Write("priority test")
|
||||
// 多事件回调示例,事件1
|
||||
pattern1 := "/:name/info"
|
||||
s.BindHookHandlerByMap(pattern1, map[string]ghttp.HandlerFunc{
|
||||
ghttp.HOOK_BEFORE_SERVE: func(r *ghttp.Request) {
|
||||
r.SetParam("uid", 1000)
|
||||
},
|
||||
})
|
||||
s.BindHandler(pattern1, func(r *ghttp.Request) {
|
||||
r.Response.Write("用户:", r.Get("name"), ", uid:", r.Get("uid"))
|
||||
})
|
||||
|
||||
s.BindHookHandlerByMap("/priority/:name", map[string]ghttp.HandlerFunc{
|
||||
"BeforeServe": func(r *ghttp.Request) {
|
||||
glog.Println(r.Router.Uri)
|
||||
// 多事件回调示例,事件2
|
||||
pattern2 := "/{object}/list/{page}.java"
|
||||
s.BindHookHandlerByMap(pattern2, map[string]ghttp.HandlerFunc{
|
||||
ghttp.HOOK_BEFORE_OUTPUT: func(r *ghttp.Request) {
|
||||
r.Response.SetBuffer([]byte(
|
||||
fmt.Sprintf("通过事件修改输出内容, object:%s, page:%s", r.Get("object"), r.GetRouterString("page"))),
|
||||
)
|
||||
},
|
||||
})
|
||||
s.BindHookHandlerByMap("/priority/*any", map[string]ghttp.HandlerFunc{
|
||||
"BeforeServe": func(r *ghttp.Request) {
|
||||
glog.Println(r.Router.Uri)
|
||||
},
|
||||
})
|
||||
s.BindHookHandlerByMap("/priority/show", map[string]ghttp.HandlerFunc{
|
||||
"BeforeServe": func(r *ghttp.Request) {
|
||||
glog.Println(r.Router.Uri)
|
||||
},
|
||||
s.BindHandler(pattern2, func(r *ghttp.Request) {
|
||||
r.Response.Write(r.Router.Uri)
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
|
||||
@ -8,7 +8,7 @@ import (
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Response.Writeln(r.GetParam("name").String())
|
||||
r.Response.Writeln(r.Get("name"))
|
||||
})
|
||||
s.BindHookHandlerByMap("/", map[string]ghttp.HandlerFunc{
|
||||
ghttp.HOOK_BEFORE_SERVE: func(r *ghttp.Request) {
|
||||
|
||||
@ -5,28 +5,27 @@ import (
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
// 优先调用的HOOK
|
||||
func beforeServeHook1(r *ghttp.Request) {
|
||||
r.SetParam("name", "GoFrame")
|
||||
r.Response.Writeln("set name")
|
||||
}
|
||||
|
||||
// 随后调用的HOOK
|
||||
func beforeServeHook2(r *ghttp.Request) {
|
||||
r.SetParam("site", "https://goframe.org")
|
||||
r.Response.Writeln("set site")
|
||||
}
|
||||
|
||||
// 允许对同一个路由同一个事件注册多个回调函数,按照注册顺序进行优先级调用。
|
||||
// 为便于在路由表中对比查看优先级,这里讲HOOK回调函数单独定义为了两个函数。
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Response.Writeln(r.GetParam("name").String())
|
||||
r.Response.Writeln(r.GetParam("site").String())
|
||||
s.BindHandler("/priority/show", func(r *ghttp.Request) {
|
||||
r.Response.Writeln("priority service")
|
||||
})
|
||||
|
||||
s.BindHookHandlerByMap("/priority/:name", map[string]ghttp.HandlerFunc{
|
||||
ghttp.HOOK_BEFORE_SERVE: func(r *ghttp.Request) {
|
||||
r.Response.Writeln("/priority/:name")
|
||||
},
|
||||
})
|
||||
s.BindHookHandlerByMap("/priority/*any", map[string]ghttp.HandlerFunc{
|
||||
ghttp.HOOK_BEFORE_SERVE: func(r *ghttp.Request) {
|
||||
r.Response.Writeln("/priority/*any")
|
||||
},
|
||||
})
|
||||
s.BindHookHandlerByMap("/priority/show", map[string]ghttp.HandlerFunc{
|
||||
ghttp.HOOK_BEFORE_SERVE: func(r *ghttp.Request) {
|
||||
r.Response.Writeln("/priority/show")
|
||||
},
|
||||
})
|
||||
s.BindHookHandler("/", ghttp.HOOK_BEFORE_SERVE, beforeServeHook1)
|
||||
s.BindHookHandler("/", ghttp.HOOK_BEFORE_SERVE, beforeServeHook2)
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
|
||||
@ -17,10 +17,10 @@ func main() {
|
||||
s3 := g.Server(3)
|
||||
s4 := g.Server(4)
|
||||
|
||||
s1.SetNameToUriType(ghttp.NAME_TO_URI_TYPE_DEFAULT)
|
||||
s2.SetNameToUriType(ghttp.NAME_TO_URI_TYPE_FULLNAME)
|
||||
s3.SetNameToUriType(ghttp.NAME_TO_URI_TYPE_ALLLOWER)
|
||||
s4.SetNameToUriType(ghttp.NAME_TO_URI_TYPE_CAMEL)
|
||||
s1.SetNameToUriType(ghttp.URI_TYPE_DEFAULT)
|
||||
s2.SetNameToUriType(ghttp.URI_TYPE_FULLNAME)
|
||||
s3.SetNameToUriType(ghttp.URI_TYPE_ALLLOWER)
|
||||
s4.SetNameToUriType(ghttp.URI_TYPE_CAMEL)
|
||||
|
||||
s1.BindObject("/{.struct}/{.method}", new(User))
|
||||
s2.BindObject("/{.struct}/{.method}", new(User))
|
||||
|
||||
@ -6,7 +6,7 @@ import "github.com/gogf/gf/frame/g"
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.SetIndexFolder(true)
|
||||
s.SetServerRoot("/Users/john/Temp")
|
||||
s.SetServerRoot("/Users/john/Downloads")
|
||||
s.AddSearchPath("/Users/john/Documents")
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
|
||||
@ -9,7 +9,7 @@ import (
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.SetServerRoot("public")
|
||||
s.SetNameToUriType(ghttp.NAME_TO_URI_TYPE_ALLLOWER)
|
||||
s.SetNameToUriType(ghttp.URI_TYPE_ALLLOWER)
|
||||
s.SetErrorLogEnabled(true)
|
||||
s.SetAccessLogEnabled(true)
|
||||
s.SetPort(2333)
|
||||
|
||||
@ -1,16 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l := flock.NewFlock("/tmp/go-lock.lock")
|
||||
l.Lock()
|
||||
fmt.Printf("lock 1")
|
||||
l.Lock()
|
||||
fmt.Printf("lock 1")
|
||||
|
||||
time.Sleep(time.Hour)
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/os/gflock"
|
||||
"github.com/gogf/gf/os/glog"
|
||||
"github.com/gogf/gf/os/gproc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
l := gflock.New("demo.lock")
|
||||
l.Lock()
|
||||
glog.Printf("locked by pid: %d", gproc.Pid())
|
||||
time.Sleep(10 * time.Second)
|
||||
l.UnLock()
|
||||
glog.Printf("unlocked by pid: %d", gproc.Pid())
|
||||
}
|
||||
@ -1,12 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/os/gcmd"
|
||||
"github.com/gogf/gf/os/glog"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
)
|
||||
|
||||
func main() {
|
||||
glog.SetFlags(glog.F_TIME_DATE | glog.F_TIME_TIME | glog.F_FILE_SHORT)
|
||||
glog.Debug("dd")
|
||||
glog.Println("timeout", gcmd.GetOpt("timeout"))
|
||||
b, _ := json.Marshal([]interface{}{1, 2, 3, 4, 5, 123.456, "a"})
|
||||
fmt.Println(gconv.String(b))
|
||||
}
|
||||
|
||||
12
.github/FUNDING.yml
vendored
Normal file
12
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
otechie: # Replace with a single Otechie username
|
||||
custom: https://github.com/gogf/gf#donators
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -14,3 +14,4 @@ bin/
|
||||
cbuild
|
||||
**/.DS_Store
|
||||
.vscode/
|
||||
go.sum
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
|[zfan_codes](https://gitee.com/zfan_codes)|gitee|¥10.00
|
||||
|[arden](https://github.com/arden)|alipay|¥10.00
|
||||
|[macnie](https://www.macnie.com)|wechat|¥100.00
|
||||
|lah|wechat|¥100.00
|
||||
|x*z|wechat|¥20.00
|
||||
|潘兄|wechat|¥100.00
|
||||
|Fly的狐狸|wechat|¥100.00
|
||||
|
||||
191
README.MD
191
README.MD
@ -38,7 +38,6 @@ golang version >= 1.10
|
||||
|
||||
# Quick Start
|
||||
|
||||
## Hello World
|
||||
```go
|
||||
package main
|
||||
|
||||
@ -55,196 +54,6 @@ func main() {
|
||||
s.Run()
|
||||
}
|
||||
```
|
||||
## Router & Middleware
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.Group("/api.v2", func(g *ghttp.RouterGroup) {
|
||||
g.Middleware(func(r *ghttp.Request) {
|
||||
r.Response.Write("start")
|
||||
r.Middleware.Next()
|
||||
r.Response.Write("end")
|
||||
})
|
||||
g.Group("/order", func(g *ghttp.RouterGroup) {
|
||||
g.GET("/list", func(r *ghttp.Request) {
|
||||
r.Response.Write("list")
|
||||
})
|
||||
})
|
||||
g.Group("/user", func(g *ghttp.RouterGroup) {
|
||||
g.GET("/info", func(r *ghttp.Request) {
|
||||
r.Response.Write("info")
|
||||
})
|
||||
g.POST("/edit", func(r *ghttp.Request) {
|
||||
r.Response.Write("edit")
|
||||
})
|
||||
})
|
||||
g.Group("/hook", func(g *ghttp.RouterGroup) {
|
||||
g.Hook("/*", ghttp.HOOK_BEFORE_SERVE, func(r *ghttp.Request) {
|
||||
r.Response.Write("hook any")
|
||||
})
|
||||
g.Hook("/:name", ghttp.HOOK_BEFORE_SERVE, func(r *ghttp.Request) {
|
||||
r.Response.Write("hook name")
|
||||
})
|
||||
})
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
```
|
||||
|
||||
## Multi ports & domains
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func Hello1(r *ghttp.Request) {
|
||||
r.Response.Write("127.0.0.1: Hello1!")
|
||||
}
|
||||
|
||||
func Hello2(r *ghttp.Request) {
|
||||
r.Response.Write("localhost: Hello2!")
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.Domain("127.0.0.1").BindHandler("/", Hello1)
|
||||
s.Domain("localhost").BindHandler("/", Hello2)
|
||||
s.SetPort(8100, 8200, 8300)
|
||||
s.Run()
|
||||
}
|
||||
```
|
||||
## Template Engine
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/template", func(r *ghttp.Request) {
|
||||
r.Response.WriteTpl("index.tpl", g.Map{
|
||||
"id": 123,
|
||||
"name": "john",
|
||||
})
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
```
|
||||
## File Uploading
|
||||
```go
|
||||
func Upload(r *ghttp.Request) {
|
||||
if f, h, e := r.FormFile("upload-file"); e == nil {
|
||||
defer f.Close()
|
||||
name := gfile.Basename(h.Filename)
|
||||
buffer := make([]byte, h.Size)
|
||||
f.Read(buffer)
|
||||
gfile.PutBytes("/tmp/" + name, buffer)
|
||||
r.Response.Write(name + " uploaded successly")
|
||||
} else {
|
||||
r.Response.Write(e.Error())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## ORM Operations
|
||||
|
||||
### 1. Retrieving instance
|
||||
```go
|
||||
db := g.DB()
|
||||
db := g.DB("user-center")
|
||||
```
|
||||
### 2. Chaining Operations
|
||||
|
||||
`Where + string`
|
||||
```go
|
||||
// SELECT * FROM user WHERE uid>1 LIMIT 0,10
|
||||
r, err := db.Table("user").Where("uid > ?", 1).Limit(0, 10).Select()
|
||||
|
||||
// SELECT uid,name FROM user WHERE uid>1 LIMIT 0,10
|
||||
r, err := db.Table("user").Fileds("uid,name").Where("uid > ?", 1).Limit(0, 10).Select()
|
||||
|
||||
// SELECT * FROM user WHERE uid=1
|
||||
r, err := db.Table("user").Where("u.uid=1",).One()
|
||||
r, err := db.Table("user").Where("u.uid", 1).One()
|
||||
r, err := db.Table("user").Where("u.uid=?", 1).One()
|
||||
// SELECT * FROM user WHERE (uid=1) AND (name='john')
|
||||
r, err := db.Table("user").Where("uid", 1).Where("name", "john").One()
|
||||
r, err := db.Table("user").Where("uid=?", 1).And("name=?", "john").One()
|
||||
// SELECT * FROM user WHERE (uid=1) OR (name='john')
|
||||
r, err := db.Table("user").Where("uid=?", 1).Or("name=?", "john").One()
|
||||
```
|
||||
`Where + map`
|
||||
```go
|
||||
// SELECT * FROM user WHERE uid=1 AND name='john'
|
||||
r, err := db.Table("user").Where(g.Map{"uid" : 1, "name" : "john"}).One()
|
||||
// SELECT * FROM user WHERE uid=1 AND age>18
|
||||
r, err := db.Table("user").Where(g.Map{"uid" : 1, "age>" : 18}).One()
|
||||
```
|
||||
`Where + struct/*struct`
|
||||
```go
|
||||
type User struct {
|
||||
Id int `json:"uid"`
|
||||
UserName string `gconv:"name"`
|
||||
}
|
||||
// SELECT * FROM user WHERE uid =1 AND name='john'
|
||||
r, err := db.Table("user").Where(User{ Id : 1, UserName : "john"}).One()
|
||||
// SELECT * FROM user WHERE uid =1
|
||||
r, err := db.Table("user").Where(&User{ Id : 1}).One()
|
||||
```
|
||||
### 3. Update & Delete
|
||||
```go
|
||||
// UPDATE user SET name='john guo' WHERE name='john'
|
||||
r, err := db.Table("user").Data(gdb.Map{"name" : "john guo"}).Where("name=?", "john").Update()
|
||||
r, err := db.Table("user").Data("name='john guo'").Where("name=?", "john").Update()
|
||||
// UPDATE user SET status=1 ORDER BY login_time asc LIMIT 10
|
||||
r, err := db.Table("user").Data("status", 1).OrderBy("login_time asc").Limit(10).Update
|
||||
|
||||
// DELETE FROM user WHERE uid=10
|
||||
r, err := db.Table("user").Where("uid=?", 10).Delete()
|
||||
// DELETE FROM user ORDER BY login_time asc LIMIT 10
|
||||
r, err := db.Table("user").OrderBy("login_time asc").Limit(10).Delete()
|
||||
```
|
||||
### 4. Insert & Replace & Save
|
||||
```go
|
||||
r, err := db.Table("user").Data(g.Map{"name": "john"}).Insert()
|
||||
r, err := db.Table("user").Data(g.Map{"uid": 10000, "name": "john"}).Replace()
|
||||
r, err := db.Table("user").Data(g.Map{"uid": 10001, "name": "john"}).Save()
|
||||
```
|
||||
### 5. Transaction
|
||||
```go
|
||||
if tx, err := db.Begin(); err == nil {
|
||||
r, err := tx.Save("user", g.Map{
|
||||
"uid" : 1,
|
||||
"name" : "john",
|
||||
})
|
||||
tx.Commit()
|
||||
}
|
||||
```
|
||||
### 6. Error Handling
|
||||
```go
|
||||
func GetOrderInfo(id int) (order *Order, err error) {
|
||||
err = g.DB().Table("order").Where("id", id).Struct(&order)
|
||||
if err != nil && err == sql.ErrNoRows {
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
[More Features...](https://goframe.org/start/index)
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# `v1.9.0`
|
||||
# `v1.9.3`
|
||||
|
||||
该版本实际为`v2.0.0`的大版本发布,为避免`go module`机制严格要求`v2`版本以上需要修改`import`并加上`v2`后缀,因此使用了`v1.9.0`进行发布。
|
||||
该版本实际为`v2.0`的大版本发布,为避免`go module`机制严格要求`v2`版本以上需要修改`import`并加上`v2`后缀,因此使用了`v1.9`版本进行发布。
|
||||
|
||||
## 新特性
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
|
||||
1. `ghttp`
|
||||
- 改进`Request`参数解析方式:https://goframe.org/net/ghttp/request
|
||||
- 改进跨域请求功能,新增`Origin`设置及校验功能:https://goframe.org/net/ghttp/cors
|
||||
- `Cookie`及`Session`的`TTL`配置数据类型修改为`time.Duration`;
|
||||
- 新增允许同时通过`Header/Cookie`传递`SessionId`;
|
||||
- 新增`ConfigFromMap/SetConfigWithMap`方法,支持通过`map`参数设置WebServer;
|
||||
|
||||
@ -9,6 +9,7 @@ package garray
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"math"
|
||||
"sort"
|
||||
|
||||
@ -355,19 +356,18 @@ func (a *Array) Len() int {
|
||||
}
|
||||
|
||||
// Slice returns the underlying data of array.
|
||||
// Notice, if in concurrent-safe usage, it returns a copy of slice;
|
||||
// else a pointer to the underlying data.
|
||||
// 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 *Array) Slice() []interface{} {
|
||||
array := ([]interface{})(nil)
|
||||
if a.mu.IsSafe() {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
array = make([]interface{}, len(a.array))
|
||||
array := make([]interface{}, len(a.array))
|
||||
copy(array, a.array)
|
||||
return array
|
||||
} else {
|
||||
array = a.array
|
||||
return a.array
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
// Clone returns a new array, which is a copy of current array.
|
||||
@ -584,8 +584,14 @@ func (a *Array) Join(glue string) string {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
s := ""
|
||||
for k, v := range a.array {
|
||||
buffer.WriteString(gconv.String(v))
|
||||
s = gconv.String(v)
|
||||
if gstr.IsNumeric(s) {
|
||||
buffer.WriteString(s)
|
||||
} else {
|
||||
buffer.WriteString(`"` + gstr.QuoteMeta(s, `"\`) + `"`)
|
||||
}
|
||||
if k != len(a.array)-1 {
|
||||
buffer.WriteString(glue)
|
||||
}
|
||||
@ -606,10 +612,7 @@ func (a *Array) CountValues() map[interface{}]int {
|
||||
|
||||
// String returns current array as a string.
|
||||
func (a *Array) String() string {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
jsonContent, _ := json.Marshal(a.array)
|
||||
return string(jsonContent)
|
||||
return "[" + a.Join(",") + "]"
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
@ -618,3 +621,17 @@ func (a *Array) MarshalJSON() ([]byte, error) {
|
||||
defer a.mu.RUnlock()
|
||||
return json.Marshal(a.array)
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
|
||||
func (a *Array) UnmarshalJSON(b []byte) error {
|
||||
if a.mu == nil {
|
||||
a.mu = rwmutex.New()
|
||||
a.array = make([]interface{}, 0)
|
||||
}
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if err := json.Unmarshal(b, &a.array); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -361,8 +361,8 @@ func (a *IntArray) Len() int {
|
||||
}
|
||||
|
||||
// Slice returns the underlying data of array.
|
||||
// Notice, if in concurrent-safe usage, it returns a copy of slice;
|
||||
// else a pointer to the underlying data.
|
||||
// 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 *IntArray) Slice() []int {
|
||||
array := ([]int)(nil)
|
||||
if a.mu.IsSafe() {
|
||||
@ -612,10 +612,7 @@ func (a *IntArray) CountValues() map[int]int {
|
||||
|
||||
// String returns current array as a string.
|
||||
func (a *IntArray) String() string {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
jsonContent, _ := json.Marshal(a.array)
|
||||
return string(jsonContent)
|
||||
return "[" + a.Join(",") + "]"
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
@ -624,3 +621,17 @@ func (a *IntArray) MarshalJSON() ([]byte, error) {
|
||||
defer a.mu.RUnlock()
|
||||
return json.Marshal(a.array)
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
|
||||
func (a *IntArray) UnmarshalJSON(b []byte) error {
|
||||
if a.mu == nil {
|
||||
a.mu = rwmutex.New()
|
||||
a.array = make([]int, 0)
|
||||
}
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if err := json.Unmarshal(b, &a.array); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ package garray
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"math"
|
||||
"sort"
|
||||
"strings"
|
||||
@ -362,8 +363,8 @@ func (a *StrArray) Len() int {
|
||||
}
|
||||
|
||||
// Slice returns the underlying data of array.
|
||||
// Notice, if in concurrent-safe usage, it returns a copy of slice;
|
||||
// else a pointer to the underlying data.
|
||||
// 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 *StrArray) Slice() []string {
|
||||
array := ([]string)(nil)
|
||||
if a.mu.IsSafe() {
|
||||
@ -591,7 +592,7 @@ func (a *StrArray) Join(glue string) string {
|
||||
defer a.mu.RUnlock()
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
for k, v := range a.array {
|
||||
buffer.WriteString(gconv.String(v))
|
||||
buffer.WriteString(`"` + gstr.QuoteMeta(v, `"\`) + `"`)
|
||||
if k != len(a.array)-1 {
|
||||
buffer.WriteString(glue)
|
||||
}
|
||||
@ -612,10 +613,7 @@ func (a *StrArray) CountValues() map[string]int {
|
||||
|
||||
// String returns current array as a string.
|
||||
func (a *StrArray) String() string {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
jsonContent, _ := json.Marshal(a.array)
|
||||
return string(jsonContent)
|
||||
return "[" + a.Join(",") + "]"
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
@ -624,3 +622,17 @@ func (a *StrArray) MarshalJSON() ([]byte, error) {
|
||||
defer a.mu.RUnlock()
|
||||
return json.Marshal(a.array)
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
|
||||
func (a *StrArray) UnmarshalJSON(b []byte) error {
|
||||
if a.mu == nil {
|
||||
a.mu = rwmutex.New()
|
||||
a.array = make([]string, 0)
|
||||
}
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if err := json.Unmarshal(b, &a.array); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -9,6 +9,8 @@ package garray
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"github.com/gogf/gf/util/gutil"
|
||||
"math"
|
||||
"sort"
|
||||
|
||||
@ -80,6 +82,17 @@ func (a *SortedArray) SetArray(array []interface{}) *SortedArray {
|
||||
return a
|
||||
}
|
||||
|
||||
// SetComparator sets/changes the comparator for sorting.
|
||||
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
|
||||
})
|
||||
}
|
||||
|
||||
// Sort sorts the array in increasing order.
|
||||
// The parameter <reverse> controls whether sort
|
||||
// in increasing order(default) or decreasing order
|
||||
@ -314,8 +327,8 @@ func (a *SortedArray) Len() int {
|
||||
}
|
||||
|
||||
// Slice returns the underlying data of array.
|
||||
// Notice, if in concurrent-safe usage, it returns a copy of slice;
|
||||
// else a pointer to the underlying data.
|
||||
// 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)
|
||||
if a.mu.IsSafe() {
|
||||
@ -516,8 +529,14 @@ func (a *SortedArray) Join(glue string) string {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
s := ""
|
||||
for k, v := range a.array {
|
||||
buffer.WriteString(gconv.String(v))
|
||||
s = gconv.String(v)
|
||||
if gstr.IsNumeric(s) {
|
||||
buffer.WriteString(s)
|
||||
} else {
|
||||
buffer.WriteString(`"` + gstr.QuoteMeta(s, `"\`) + `"`)
|
||||
}
|
||||
if k != len(a.array)-1 {
|
||||
buffer.WriteString(glue)
|
||||
}
|
||||
@ -538,10 +557,7 @@ func (a *SortedArray) CountValues() map[interface{}]int {
|
||||
|
||||
// String returns current array as a string.
|
||||
func (a *SortedArray) String() string {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
jsonContent, _ := json.Marshal(a.array)
|
||||
return string(jsonContent)
|
||||
return "[" + a.Join(",") + "]"
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
@ -550,3 +566,25 @@ func (a *SortedArray) MarshalJSON() ([]byte, error) {
|
||||
defer a.mu.RUnlock()
|
||||
return json.Marshal(a.array)
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
|
||||
func (a *SortedArray) UnmarshalJSON(b []byte) error {
|
||||
if a.mu == nil {
|
||||
a.mu = rwmutex.New()
|
||||
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()
|
||||
defer a.mu.Unlock()
|
||||
if err := json.Unmarshal(b, &a.array); err != nil {
|
||||
return err
|
||||
}
|
||||
if a.comparator != nil {
|
||||
sort.Slice(a.array, func(i, j int) bool {
|
||||
return a.comparator(a.array[i], a.array[j]) < 0
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -313,8 +313,8 @@ func (a *SortedIntArray) Sum() (sum int) {
|
||||
}
|
||||
|
||||
// Slice returns the underlying data of array.
|
||||
// Notice, if in concurrent-safe usage, it returns a copy of slice;
|
||||
// else a pointer to the underlying data.
|
||||
// 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 *SortedIntArray) Slice() []int {
|
||||
array := ([]int)(nil)
|
||||
if a.mu.IsSafe() {
|
||||
@ -537,10 +537,7 @@ func (a *SortedIntArray) CountValues() map[int]int {
|
||||
|
||||
// String returns current array as a string.
|
||||
func (a *SortedIntArray) String() string {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
jsonContent, _ := json.Marshal(a.array)
|
||||
return string(jsonContent)
|
||||
return "[" + a.Join(",") + "]"
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
@ -549,3 +546,20 @@ func (a *SortedIntArray) MarshalJSON() ([]byte, error) {
|
||||
defer a.mu.RUnlock()
|
||||
return json.Marshal(a.array)
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
|
||||
func (a *SortedIntArray) UnmarshalJSON(b []byte) error {
|
||||
if a.mu == nil {
|
||||
a.mu = rwmutex.New()
|
||||
a.array = make([]int, 0)
|
||||
a.unique = gtype.NewBool()
|
||||
a.comparator = defaultComparatorInt
|
||||
}
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if err := json.Unmarshal(b, &a.array); err != nil {
|
||||
return err
|
||||
}
|
||||
sort.Ints(a.array)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -9,7 +9,9 @@ package garray
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"math"
|
||||
"sort"
|
||||
|
||||
"github.com/gogf/gf/container/gtype"
|
||||
"github.com/gogf/gf/internal/rwmutex"
|
||||
@ -312,8 +314,8 @@ func (a *SortedStrArray) Len() int {
|
||||
}
|
||||
|
||||
// Slice returns the underlying data of array.
|
||||
// Notice, if in concurrent-safe usage, it returns a copy of slice;
|
||||
// else a pointer to the underlying data.
|
||||
// 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 *SortedStrArray) Slice() []string {
|
||||
array := ([]string)(nil)
|
||||
if a.mu.IsSafe() {
|
||||
@ -515,7 +517,7 @@ func (a *SortedStrArray) Join(glue string) string {
|
||||
defer a.mu.RUnlock()
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
for k, v := range a.array {
|
||||
buffer.WriteString(gconv.String(v))
|
||||
buffer.WriteString(`"` + gstr.QuoteMeta(v, `"\`) + `"`)
|
||||
if k != len(a.array)-1 {
|
||||
buffer.WriteString(glue)
|
||||
}
|
||||
@ -536,10 +538,7 @@ func (a *SortedStrArray) CountValues() map[string]int {
|
||||
|
||||
// String returns current array as a string.
|
||||
func (a *SortedStrArray) String() string {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
jsonContent, _ := json.Marshal(a.array)
|
||||
return string(jsonContent)
|
||||
return "[" + a.Join(",") + "]"
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
@ -548,3 +547,20 @@ func (a *SortedStrArray) MarshalJSON() ([]byte, error) {
|
||||
defer a.mu.RUnlock()
|
||||
return json.Marshal(a.array)
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
|
||||
func (a *SortedStrArray) UnmarshalJSON(b []byte) error {
|
||||
if a.mu == nil {
|
||||
a.mu = rwmutex.New()
|
||||
a.array = make([]string, 0)
|
||||
a.unique = gtype.NewBool()
|
||||
a.comparator = defaultComparatorStr
|
||||
}
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if err := json.Unmarshal(b, &a.array); err != nil {
|
||||
return err
|
||||
}
|
||||
sort.Strings(a.array)
|
||||
return nil
|
||||
}
|
||||
|
||||
451
container/garray/garray_z_unit_normal_any_array_test.go
Normal file
451
container/garray/garray_z_unit_normal_any_array_test.go
Normal file
@ -0,0 +1,451 @@
|
||||
// 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.
|
||||
|
||||
// go test *.go
|
||||
|
||||
package garray_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/container/garray"
|
||||
"github.com/gogf/gf/test/gtest"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
)
|
||||
|
||||
func Test_Array_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
expect := []interface{}{0, 1, 2, 3}
|
||||
array := garray.NewArrayFrom(expect)
|
||||
array2 := garray.NewArrayFrom(expect)
|
||||
array3 := garray.NewArrayFrom([]interface{}{})
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
array.Set(0, 100)
|
||||
gtest.Assert(array.Get(0), 100)
|
||||
gtest.Assert(array.Get(1), 1)
|
||||
gtest.Assert(array.Search(100), 0)
|
||||
gtest.Assert(array3.Search(100), -1)
|
||||
gtest.Assert(array.Contains(100), true)
|
||||
gtest.Assert(array.Remove(0), 100)
|
||||
|
||||
gtest.Assert(array2.Remove(3), 3)
|
||||
gtest.Assert(array2.Remove(1), 1)
|
||||
|
||||
gtest.Assert(array.Contains(100), false)
|
||||
array.Append(4)
|
||||
gtest.Assert(array.Len(), 4)
|
||||
array.InsertBefore(0, 100)
|
||||
array.InsertAfter(0, 200)
|
||||
gtest.Assert(array.Slice(), []interface{}{100, 200, 2, 2, 3, 4})
|
||||
array.InsertBefore(5, 300)
|
||||
array.InsertAfter(6, 400)
|
||||
gtest.Assert(array.Slice(), []interface{}{100, 200, 2, 2, 3, 300, 4, 400})
|
||||
gtest.Assert(array.Clear().Len(), 0)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Sort(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
expect1 := []interface{}{0, 1, 2, 3}
|
||||
expect2 := []interface{}{3, 2, 1, 0}
|
||||
array := garray.NewArray()
|
||||
for i := 3; i >= 0; i-- {
|
||||
array.Append(i)
|
||||
}
|
||||
array.SortFunc(func(v1, v2 interface{}) bool {
|
||||
return v1.(int) < v2.(int)
|
||||
})
|
||||
gtest.Assert(array.Slice(), expect1)
|
||||
array.SortFunc(func(v1, v2 interface{}) bool {
|
||||
return v1.(int) > v2.(int)
|
||||
})
|
||||
gtest.Assert(array.Slice(), expect2)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Unique(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
expect := []interface{}{1, 1, 2, 3}
|
||||
array := garray.NewArrayFrom(expect)
|
||||
gtest.Assert(array.Unique().Slice(), []interface{}{1, 2, 3})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_PushAndPop(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
expect := []interface{}{0, 1, 2, 3}
|
||||
array := garray.NewArrayFrom(expect)
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
gtest.Assert(array.PopLeft(), 0)
|
||||
gtest.Assert(array.PopRight(), 3)
|
||||
gtest.AssertIN(array.PopRand(), []interface{}{1, 2})
|
||||
gtest.AssertIN(array.PopRand(), []interface{}{1, 2})
|
||||
gtest.Assert(array.Len(), 0)
|
||||
array.PushLeft(1).PushRight(2)
|
||||
gtest.Assert(array.Slice(), []interface{}{1, 2})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_PopRands(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{100, 200, 300, 400, 500, 600}
|
||||
array := garray.NewFromCopy(a1)
|
||||
gtest.AssertIN(array.PopRands(2), []interface{}{100, 200, 300, 400, 500, 600})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_PopLeftsAndPopRights(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
value1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
value2 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewArrayFrom(value1)
|
||||
array2 := garray.NewArrayFrom(value2)
|
||||
gtest.Assert(array1.PopLefts(2), []interface{}{0, 1})
|
||||
gtest.Assert(array1.Slice(), []interface{}{2, 3, 4, 5, 6})
|
||||
gtest.Assert(array1.PopRights(2), []interface{}{5, 6})
|
||||
gtest.Assert(array1.Slice(), []interface{}{2, 3, 4})
|
||||
gtest.Assert(array1.PopRights(20), []interface{}{2, 3, 4})
|
||||
gtest.Assert(array1.Slice(), []interface{}{})
|
||||
gtest.Assert(array2.PopLefts(20), []interface{}{0, 1, 2, 3, 4, 5, 6})
|
||||
gtest.Assert(array2.Slice(), []interface{}{})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Range(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
value1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewArrayFrom(value1)
|
||||
array2 := garray.NewArrayFrom(value1, true)
|
||||
gtest.Assert(array1.Range(0, 1), []interface{}{0})
|
||||
gtest.Assert(array1.Range(1, 2), []interface{}{1})
|
||||
gtest.Assert(array1.Range(0, 2), []interface{}{0, 1})
|
||||
gtest.Assert(array1.Range(-1, 10), value1)
|
||||
gtest.Assert(array1.Range(10, 2), nil)
|
||||
gtest.Assert(array2.Range(1, 3), []interface{}{1, 2})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Merge(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
if gconv.Int(v1) < gconv.Int(v2) {
|
||||
return 0
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
i1 := []interface{}{0, 1, 2, 3}
|
||||
i2 := []interface{}{4, 5, 6, 7}
|
||||
array1 := garray.NewArrayFrom(i1)
|
||||
array2 := garray.NewArrayFrom(i2)
|
||||
gtest.Assert(array1.Merge(array2).Slice(), []interface{}{0, 1, 2, 3, 4, 5, 6, 7})
|
||||
|
||||
//s1 := []string{"a", "b", "c", "d"}
|
||||
s2 := []string{"e", "f"}
|
||||
i3 := garray.NewIntArrayFrom([]int{1, 2, 3})
|
||||
i4 := garray.NewArrayFrom([]interface{}{3})
|
||||
s3 := garray.NewStrArrayFrom([]string{"g", "h"})
|
||||
s4 := garray.NewSortedArrayFrom([]interface{}{4, 5}, func1)
|
||||
s5 := garray.NewSortedStrArrayFrom(s2)
|
||||
s6 := garray.NewSortedIntArrayFrom([]int{1, 2, 3})
|
||||
a1 := garray.NewArrayFrom(i1)
|
||||
|
||||
gtest.Assert(a1.Merge(s2).Len(), 6)
|
||||
gtest.Assert(a1.Merge(i3).Len(), 9)
|
||||
gtest.Assert(a1.Merge(i4).Len(), 10)
|
||||
gtest.Assert(a1.Merge(s3).Len(), 12)
|
||||
gtest.Assert(a1.Merge(s4).Len(), 14)
|
||||
gtest.Assert(a1.Merge(s5).Len(), 16)
|
||||
gtest.Assert(a1.Merge(s6).Len(), 19)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Fill(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0}
|
||||
a2 := []interface{}{0}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
array2 := garray.NewArrayFrom(a2, true)
|
||||
gtest.Assert(array1.Fill(1, 2, 100).Slice(), []interface{}{0, 100, 100})
|
||||
gtest.Assert(array2.Fill(0, 2, 100).Slice(), []interface{}{100, 100})
|
||||
gtest.Assert(array2.Fill(-1, 2, 100).Slice(), []interface{}{100, 100})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Chunk(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{1, 2, 3, 4, 5}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
chunks := array1.Chunk(2)
|
||||
gtest.Assert(len(chunks), 3)
|
||||
gtest.Assert(chunks[0], []interface{}{1, 2})
|
||||
gtest.Assert(chunks[1], []interface{}{3, 4})
|
||||
gtest.Assert(chunks[2], []interface{}{5})
|
||||
gtest.Assert(array1.Chunk(0), nil)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Pad(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
gtest.Assert(array1.Pad(3, 1).Slice(), []interface{}{0, 1, 1})
|
||||
gtest.Assert(array1.Pad(-4, 1).Slice(), []interface{}{1, 0, 1, 1})
|
||||
gtest.Assert(array1.Pad(3, 1).Slice(), []interface{}{1, 0, 1, 1})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_SubSlice(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
array2 := garray.NewArrayFrom(a1, true)
|
||||
gtest.Assert(array1.SubSlice(0, 2), []interface{}{0, 1})
|
||||
gtest.Assert(array1.SubSlice(2, 2), []interface{}{2, 3})
|
||||
gtest.Assert(array1.SubSlice(5, 8), []interface{}{5, 6})
|
||||
gtest.Assert(array1.SubSlice(9, 1), nil)
|
||||
gtest.Assert(array1.SubSlice(-2, 2), []interface{}{5, 6})
|
||||
gtest.Assert(array1.SubSlice(-9, 2), nil)
|
||||
gtest.Assert(array1.SubSlice(1, -2), nil)
|
||||
gtest.Assert(array2.SubSlice(0, 2), []interface{}{0, 1})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Rand(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
gtest.Assert(len(array1.Rands(2)), 2)
|
||||
gtest.Assert(len(array1.Rands(10)), 7)
|
||||
gtest.AssertIN(array1.Rands(1)[0], a1)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
s1 := []interface{}{"a", "b", "c", "d"}
|
||||
a1 := garray.NewArrayFrom(s1)
|
||||
i1 := a1.Rand()
|
||||
gtest.Assert(a1.Contains(i1), true)
|
||||
gtest.Assert(a1.Len(), 4)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Shuffle(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
gtest.Assert(array1.Shuffle().Len(), 7)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Reverse(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
gtest.Assert(array1.Reverse().Slice(), []interface{}{6, 5, 4, 3, 2, 1, 0})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Join(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
gtest.Assert(array1.Join("."), `0.1.2.3.4.5.6`)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, `"a"`, `\a`}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
gtest.Assert(array1.Join("."), `0.1."\"a\""."\\a"`)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_String(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
gtest.Assert(array1.String(), `[0,1,2,3,4,5,6]`)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Replace(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
a2 := []interface{}{"a", "b", "c"}
|
||||
a3 := []interface{}{"m", "n", "p", "z", "x", "y", "d", "u"}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
array2 := array1.Replace(a2)
|
||||
gtest.Assert(array2.Len(), 7)
|
||||
gtest.Assert(array2.Contains("b"), true)
|
||||
gtest.Assert(array2.Contains(4), true)
|
||||
gtest.Assert(array2.Contains("v"), false)
|
||||
array3 := array1.Replace(a3)
|
||||
gtest.Assert(array3.Len(), 7)
|
||||
gtest.Assert(array3.Contains(4), false)
|
||||
gtest.Assert(array3.Contains("p"), true)
|
||||
gtest.Assert(array3.Contains("u"), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_SetArray(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
a2 := []interface{}{"a", "b", "c"}
|
||||
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
array1 = array1.SetArray(a2)
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(array1.Contains("b"), true)
|
||||
gtest.Assert(array1.Contains("5"), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Sum(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3}
|
||||
a2 := []interface{}{"a", "b", "c"}
|
||||
a3 := []interface{}{"a", "1", "2"}
|
||||
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
array2 := garray.NewArrayFrom(a2)
|
||||
array3 := garray.NewArrayFrom(a3)
|
||||
|
||||
gtest.Assert(array1.Sum(), 6)
|
||||
gtest.Assert(array2.Sum(), 0)
|
||||
gtest.Assert(array3.Sum(), 3)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Clone(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
array2 := array1.Clone()
|
||||
|
||||
gtest.Assert(array1.Len(), 4)
|
||||
gtest.Assert(array2.Sum(), 6)
|
||||
gtest.AssertEQ(array1, array2)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_CountValues(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{"a", "b", "c", "d", "e", "d"}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
array2 := array1.CountValues()
|
||||
gtest.Assert(len(array2), 5)
|
||||
gtest.Assert(array2["b"], 1)
|
||||
gtest.Assert(array2["d"], 2)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_LockFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []interface{}{"a", "b", "c", "d"}
|
||||
a1 := garray.NewArrayFrom(s1, true)
|
||||
|
||||
ch1 := make(chan int64, 3)
|
||||
ch2 := make(chan int64, 3)
|
||||
//go1
|
||||
go a1.LockFunc(func(n1 []interface{}) { //读写锁
|
||||
time.Sleep(2 * time.Second) //暂停2秒
|
||||
n1[2] = "g"
|
||||
ch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
})
|
||||
|
||||
//go2
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond) //故意暂停0.01秒,等go1执行锁后,再开始执行.
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
a1.Len()
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
}()
|
||||
|
||||
t1 := <-ch1
|
||||
t2 := <-ch1
|
||||
<-ch2 //等待go1完成
|
||||
|
||||
// 防止ci抖动,以豪秒为单位
|
||||
gtest.AssertGT(t2-t1, 20) //go1加的读写互斥锁,所go2读的时候被阻塞。
|
||||
gtest.Assert(a1.Contains("g"), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_RLockFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []interface{}{"a", "b", "c", "d"}
|
||||
a1 := garray.NewArrayFrom(s1, true)
|
||||
|
||||
ch1 := make(chan int64, 3)
|
||||
ch2 := make(chan int64, 1)
|
||||
//go1
|
||||
go a1.RLockFunc(func(n1 []interface{}) { //读锁
|
||||
time.Sleep(2 * time.Second) //暂停1秒
|
||||
n1[2] = "g"
|
||||
ch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
})
|
||||
|
||||
//go2
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond) //故意暂停0.01秒,等go1执行锁后,再开始执行.
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
a1.Len()
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
}()
|
||||
|
||||
t1 := <-ch1
|
||||
t2 := <-ch1
|
||||
<-ch2 //等待go1完成
|
||||
|
||||
// 防止ci抖动,以豪秒为单位
|
||||
gtest.AssertLT(t2-t1, 20) //go1加的读锁,所go2读的时候,并没有阻塞。
|
||||
gtest.Assert(a1.Contains("g"), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Json(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []interface{}{"a", "b", "d", "c"}
|
||||
a1 := garray.NewArrayFrom(s1)
|
||||
b1, err1 := json.Marshal(a1)
|
||||
b2, err2 := json.Marshal(s1)
|
||||
gtest.Assert(b1, b2)
|
||||
gtest.Assert(err1, err2)
|
||||
|
||||
a2 := garray.New()
|
||||
err2 = json.Unmarshal(b2, &a2)
|
||||
gtest.Assert(err2, nil)
|
||||
gtest.Assert(a2.Slice(), s1)
|
||||
|
||||
var a3 garray.Array
|
||||
err := json.Unmarshal(b2, &a3)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(a3.Slice(), s1)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
type User struct {
|
||||
Name string
|
||||
Scores *garray.Array
|
||||
}
|
||||
data := g.Map{
|
||||
"Name": "john",
|
||||
"Scores": []int{99, 100, 98},
|
||||
}
|
||||
b, err := json.Marshal(data)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
user := new(User)
|
||||
err = json.Unmarshal(b, user)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(user.Name, data["Name"])
|
||||
gtest.Assert(user.Scores, data["Scores"])
|
||||
})
|
||||
}
|
||||
@ -9,6 +9,8 @@
|
||||
package garray_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -260,302 +262,11 @@ func TestIntArray_Join(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewSortedIntArrayFrom(t *testing.T) {
|
||||
func TestIntArray_String(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{0, 3, 2, 1, 4, 5, 6}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1, true)
|
||||
gtest.Assert(array1.Join("."), "0.1.2.3.4.5.6")
|
||||
gtest.Assert(array1.Slice(), a1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewSortedIntArrayFromCopy(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{0, 5, 2, 1, 4, 3, 6}
|
||||
array1 := garray.NewSortedIntArrayFromCopy(a1, false)
|
||||
gtest.Assert(array1.Join("."), "0.1.2.3.4.5.6")
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_SetArray(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{0, 1, 2, 3}
|
||||
a2 := []int{4, 5, 6}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
array2 := array1.SetArray(a2)
|
||||
|
||||
gtest.Assert(array2.Len(), 3)
|
||||
gtest.Assert(array2.Search(3), -1)
|
||||
gtest.Assert(array2.Search(5), 1)
|
||||
gtest.Assert(array2.Search(6), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Sort(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{0, 3, 2, 1}
|
||||
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
array2 := array1.Sort()
|
||||
|
||||
gtest.Assert(array2.Len(), 4)
|
||||
gtest.Assert(array2, []int{0, 1, 2, 3})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Get(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5, 0}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
gtest.Assert(array1.Get(0), 0)
|
||||
gtest.Assert(array1.Get(1), 1)
|
||||
gtest.Assert(array1.Get(3), 5)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Remove(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5, 0}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
i1 := array1.Remove(2)
|
||||
gtest.Assert(i1, 3)
|
||||
gtest.Assert(array1.Search(5), 2)
|
||||
|
||||
// 再次删除剩下的数组中的第一个
|
||||
i2 := array1.Remove(0)
|
||||
gtest.Assert(i2, 0)
|
||||
gtest.Assert(array1.Search(5), 1)
|
||||
|
||||
a2 := []int{1, 3, 4}
|
||||
array2 := garray.NewSortedIntArrayFrom(a2)
|
||||
i3 := array2.Remove(1)
|
||||
gtest.Assert(array2.Search(1), 0)
|
||||
gtest.Assert(i3, 3)
|
||||
i3 = array2.Remove(1)
|
||||
gtest.Assert(array2.Search(4), -1)
|
||||
gtest.Assert(i3, 4)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_PopLeft(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5, 2}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
i1 := array1.PopLeft()
|
||||
gtest.Assert(i1, 1)
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(array1.Search(1), -1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_PopRight(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5, 2}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
i1 := array1.PopRight()
|
||||
gtest.Assert(i1, 5)
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(array1.Search(5), -1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_PopRand(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5, 2}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
i1 := array1.PopRand()
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(array1.Search(i1), -1)
|
||||
gtest.AssertIN(i1, []int{1, 3, 5, 2})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_PopRands(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5, 2}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
ns1 := array1.PopRands(2)
|
||||
gtest.Assert(array1.Len(), 2)
|
||||
gtest.AssertIN(ns1, []int{1, 3, 5, 2})
|
||||
|
||||
a2 := []int{1, 3, 5, 2}
|
||||
array2 := garray.NewSortedIntArrayFrom(a2)
|
||||
ns2 := array2.PopRands(5)
|
||||
gtest.Assert(array2.Len(), 0)
|
||||
gtest.Assert(len(ns2), 4)
|
||||
gtest.AssertIN(ns2, []int{1, 3, 5, 2})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_PopLefts(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5, 2}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
ns1 := array1.PopLefts(2)
|
||||
gtest.Assert(array1.Len(), 2)
|
||||
gtest.Assert(ns1, []int{1, 2})
|
||||
|
||||
a2 := []int{1, 3, 5, 2}
|
||||
array2 := garray.NewSortedIntArrayFrom(a2)
|
||||
ns2 := array2.PopLefts(5)
|
||||
gtest.Assert(array2.Len(), 0)
|
||||
gtest.AssertIN(ns2, []int{1, 3, 5, 2})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_PopRights(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5, 2}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
ns1 := array1.PopRights(2)
|
||||
gtest.Assert(array1.Len(), 2)
|
||||
gtest.Assert(ns1, []int{3, 5})
|
||||
|
||||
a2 := []int{1, 3, 5, 2}
|
||||
array2 := garray.NewSortedIntArrayFrom(a2)
|
||||
ns2 := array2.PopRights(5)
|
||||
gtest.Assert(array2.Len(), 0)
|
||||
gtest.AssertIN(ns2, []int{1, 3, 5, 2})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Range(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5, 2, 6, 7}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
array2 := garray.NewSortedIntArrayFrom(a1, true)
|
||||
ns1 := array1.Range(1, 4)
|
||||
gtest.Assert(len(ns1), 3)
|
||||
gtest.Assert(ns1, []int{2, 3, 5})
|
||||
|
||||
ns2 := array1.Range(5, 4)
|
||||
gtest.Assert(len(ns2), 0)
|
||||
|
||||
ns3 := array1.Range(-1, 4)
|
||||
gtest.Assert(len(ns3), 4)
|
||||
|
||||
nsl := array1.Range(5, 8)
|
||||
gtest.Assert(len(nsl), 1)
|
||||
gtest.Assert(array2.Range(1, 2), []int{2})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Sum(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
n1 := array1.Sum()
|
||||
gtest.Assert(n1, 9)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Contains(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
gtest.Assert(array1.Contains(4), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Clone(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
array2 := array1.Clone()
|
||||
gtest.Assert(array2.Len(), 3)
|
||||
gtest.Assert(array2, array1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Clear(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
array1.Clear()
|
||||
gtest.Assert(array1.Len(), 0)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Chunk(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 2, 3, 4, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
ns1 := array1.Chunk(2) //按每几个元素切成一个数组
|
||||
ns2 := array1.Chunk(-1)
|
||||
gtest.Assert(len(ns1), 3)
|
||||
gtest.Assert(ns1[0], []int{1, 2})
|
||||
gtest.Assert(ns1[2], []int{5})
|
||||
gtest.Assert(len(ns2), 0)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_SubSlice(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 2, 3, 4, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
array2 := garray.NewSortedIntArrayFrom(a1, true)
|
||||
ns1 := array1.SubSlice(1, 2)
|
||||
gtest.Assert(len(ns1), 2)
|
||||
gtest.Assert(ns1, []int{2, 3})
|
||||
|
||||
ns2 := array1.SubSlice(7, 2)
|
||||
gtest.Assert(len(ns2), 0)
|
||||
|
||||
ns3 := array1.SubSlice(3, 5)
|
||||
gtest.Assert(len(ns3), 2)
|
||||
gtest.Assert(ns3, []int{4, 5})
|
||||
|
||||
ns4 := array1.SubSlice(3, 1)
|
||||
gtest.Assert(len(ns4), 1)
|
||||
gtest.Assert(ns4, []int{4})
|
||||
gtest.Assert(array1.SubSlice(-1, 1), []int{5})
|
||||
gtest.Assert(array1.SubSlice(-9, 1), nil)
|
||||
gtest.Assert(array1.SubSlice(1, -9), nil)
|
||||
gtest.Assert(array2.SubSlice(1, 2), []int{2, 3})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Rand(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 2, 3, 4, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
ns1 := array1.Rand() //按每几个元素切成一个数组
|
||||
gtest.AssertIN(ns1, a1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Rands(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 2, 3, 4, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
ns1 := array1.Rands(2) //按每几个元素切成一个数组
|
||||
gtest.AssertIN(ns1, a1)
|
||||
gtest.Assert(len(ns1), 2)
|
||||
|
||||
ns2 := array1.Rands(6) //按每几个元素切成一个数组
|
||||
gtest.AssertIN(ns2, a1)
|
||||
gtest.Assert(len(ns2), 5)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_CountValues(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 2, 3, 4, 5, 3}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
ns1 := array1.CountValues() //按每几个元素切成一个数组
|
||||
gtest.Assert(len(ns1), 5)
|
||||
gtest.Assert(ns1[2], 1)
|
||||
gtest.Assert(ns1[3], 2)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_SetUnique(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 2, 3, 4, 5, 3}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
array1.SetUnique(true)
|
||||
gtest.Assert(array1.Len(), 5)
|
||||
gtest.Assert(array1, []int{1, 2, 3, 4, 5})
|
||||
a1 := []int{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
gtest.Assert(array1.String(), "[0,1,2,3,4,5,6]")
|
||||
})
|
||||
}
|
||||
|
||||
@ -734,93 +445,41 @@ func TestIntArray_RLockFunc(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_LockFunc(t *testing.T) {
|
||||
func TestIntArray_Json(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []int{1, 2, 3, 4}
|
||||
a1 := garray.NewSortedIntArrayFrom(s1, true)
|
||||
ch1 := make(chan int64, 3)
|
||||
ch2 := make(chan int64, 3)
|
||||
//go1
|
||||
go a1.LockFunc(func(n1 []int) { //读写锁
|
||||
time.Sleep(2 * time.Second) //暂停2秒
|
||||
n1[2] = 6
|
||||
ch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
})
|
||||
s1 := []int{1, 4, 3, 2}
|
||||
a1 := garray.NewIntArrayFrom(s1)
|
||||
b1, err1 := json.Marshal(a1)
|
||||
b2, err2 := json.Marshal(s1)
|
||||
gtest.Assert(b1, b2)
|
||||
gtest.Assert(err1, err2)
|
||||
|
||||
//go2
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond) //故意暂停0.01秒,等go1执行锁后,再开始执行.
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
a1.Len()
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
}()
|
||||
a2 := garray.NewIntArray()
|
||||
err1 = json.Unmarshal(b2, &a2)
|
||||
gtest.Assert(a2.Slice(), s1)
|
||||
|
||||
t1 := <-ch1
|
||||
t2 := <-ch1
|
||||
<-ch2 //等待go1完成
|
||||
|
||||
// 防止ci抖动,以豪秒为单位
|
||||
gtest.AssertGT(t2-t1, 20) //go1加的读写互斥锁,所go2读的时候被阻塞。
|
||||
gtest.Assert(a1.Contains(6), true)
|
||||
var a3 garray.IntArray
|
||||
err := json.Unmarshal(b2, &a3)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(a3.Slice(), s1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_RLockFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []int{1, 2, 3, 4}
|
||||
a1 := garray.NewSortedIntArrayFrom(s1, true)
|
||||
|
||||
ch1 := make(chan int64, 3)
|
||||
ch2 := make(chan int64, 1)
|
||||
//go1
|
||||
go a1.RLockFunc(func(n1 []int) { //读锁
|
||||
time.Sleep(2 * time.Second) //暂停1秒
|
||||
n1[2] = 6
|
||||
ch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
})
|
||||
|
||||
//go2
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond) //故意暂停0.01秒,等go1执行锁后,再开始执行.
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
a1.Len()
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
}()
|
||||
|
||||
t1 := <-ch1
|
||||
t2 := <-ch1
|
||||
<-ch2 //等待go1完成
|
||||
|
||||
// 防止ci抖动,以豪秒为单位
|
||||
gtest.AssertLT(t2-t1, 20) //go1加的读锁,所go2读的时候,并没有阻塞。
|
||||
gtest.Assert(a1.Contains(6), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Merge(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
if gconv.Int(v1) < gconv.Int(v2) {
|
||||
return 0
|
||||
}
|
||||
return 1
|
||||
type User struct {
|
||||
Name string
|
||||
Scores *garray.IntArray
|
||||
}
|
||||
i0 := []int{1, 2, 3, 4}
|
||||
s2 := []string{"e", "f"}
|
||||
i1 := garray.NewIntArrayFrom([]int{1, 2, 3})
|
||||
i2 := garray.NewArrayFrom([]interface{}{3})
|
||||
s3 := garray.NewStrArrayFrom([]string{"g", "h"})
|
||||
s4 := garray.NewSortedArrayFrom([]interface{}{4, 5}, func1)
|
||||
s5 := garray.NewSortedStrArrayFrom(s2)
|
||||
s6 := garray.NewSortedIntArrayFrom([]int{1, 2, 3})
|
||||
a1 := garray.NewSortedIntArrayFrom(i0)
|
||||
data := g.Map{
|
||||
"Name": "john",
|
||||
"Scores": []int{99, 100, 98},
|
||||
}
|
||||
b, err := json.Marshal(data)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
gtest.Assert(a1.Merge(s2).Len(), 6)
|
||||
gtest.Assert(a1.Merge(i1).Len(), 9)
|
||||
gtest.Assert(a1.Merge(i2).Len(), 10)
|
||||
gtest.Assert(a1.Merge(s3).Len(), 12)
|
||||
gtest.Assert(a1.Merge(s4).Len(), 14)
|
||||
gtest.Assert(a1.Merge(s5).Len(), 16)
|
||||
gtest.Assert(a1.Merge(s6).Len(), 19)
|
||||
user := new(User)
|
||||
err = json.Unmarshal(b, user)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(user.Name, data["Name"])
|
||||
gtest.Assert(user.Scores, data["Scores"])
|
||||
})
|
||||
}
|
||||
@ -9,6 +9,8 @@
|
||||
package garray_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@ -246,7 +248,20 @@ func TestStrArray_Join(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"0", "1", "2", "3", "4", "5", "6"}
|
||||
array1 := garray.NewStrArrayFrom(a1)
|
||||
gtest.Assert(array1.Join("."), "0.1.2.3.4.5.6")
|
||||
gtest.Assert(array1.Join("."), `"0"."1"."2"."3"."4"."5"."6"`)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"0", "1", `"a"`, `\a`}
|
||||
array1 := garray.NewStrArrayFrom(a1)
|
||||
gtest.Assert(array1.Join("."), `"0"."1"."\"a\""."\\a"`)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStrArray_String(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"0", "1", "2", "3", "4", "5", "6"}
|
||||
array1 := garray.NewStrArrayFrom(a1)
|
||||
gtest.Assert(array1.String(), `["0","1","2","3","4","5","6"]`)
|
||||
})
|
||||
}
|
||||
|
||||
@ -345,315 +360,6 @@ func TestStrArray_CountValues(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewSortedStrArrayFrom(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"a", "d", "c", "b"}
|
||||
s1 := garray.NewSortedStrArrayFrom(a1, true)
|
||||
gtest.Assert(s1, []string{"a", "b", "c", "d"})
|
||||
s2 := garray.NewSortedStrArrayFrom(a1, false)
|
||||
gtest.Assert(s2, []string{"a", "b", "c", "d"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewSortedStrArrayFromCopy(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"a", "d", "c", "b"}
|
||||
s1 := garray.NewSortedStrArrayFromCopy(a1, true)
|
||||
gtest.Assert(s1.Len(), 4)
|
||||
gtest.Assert(s1, []string{"a", "b", "c", "d"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_SetArray(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"a", "d", "c", "b"}
|
||||
a2 := []string{"f", "g", "h"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
array1.SetArray(a2)
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(array1.Contains("d"), false)
|
||||
gtest.Assert(array1.Contains("b"), false)
|
||||
gtest.Assert(array1.Contains("g"), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_Sort(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"a", "d", "c", "b"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
|
||||
gtest.Assert(array1, []string{"a", "b", "c", "d"})
|
||||
array1.Sort()
|
||||
gtest.Assert(array1.Len(), 4)
|
||||
gtest.Assert(array1.Contains("c"), true)
|
||||
gtest.Assert(array1, []string{"a", "b", "c", "d"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_Get(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"a", "d", "c", "b"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
gtest.Assert(array1.Get(2), "c")
|
||||
gtest.Assert(array1.Get(0), "a")
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_Remove(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"a", "d", "c", "b"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
gtest.Assert(array1.Remove(2), "c")
|
||||
gtest.Assert(array1.Get(2), "d")
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(array1.Contains("c"), false)
|
||||
|
||||
gtest.Assert(array1.Remove(0), "a")
|
||||
gtest.Assert(array1.Len(), 2)
|
||||
gtest.Assert(array1.Contains("a"), false)
|
||||
|
||||
// 此时array1里的元素只剩下2个
|
||||
gtest.Assert(array1.Remove(1), "d")
|
||||
gtest.Assert(array1.Len(), 1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_PopLeft(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
s1 := array1.PopLeft()
|
||||
gtest.Assert(s1, "a")
|
||||
gtest.Assert(array1.Len(), 4)
|
||||
gtest.Assert(array1.Contains("a"), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_PopRight(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
s1 := array1.PopRight()
|
||||
gtest.Assert(s1, "e")
|
||||
gtest.Assert(array1.Len(), 4)
|
||||
gtest.Assert(array1.Contains("e"), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_PopRand(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
s1 := array1.PopRand()
|
||||
gtest.AssertIN(s1, []string{"e", "a", "d", "c", "b"})
|
||||
gtest.Assert(array1.Len(), 4)
|
||||
gtest.Assert(array1.Contains(s1), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_PopRands(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
s1 := array1.PopRands(2)
|
||||
gtest.AssertIN(s1, []string{"e", "a", "d", "c", "b"})
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(len(s1), 2)
|
||||
|
||||
s1 = array1.PopRands(4)
|
||||
gtest.Assert(len(s1), 3)
|
||||
gtest.AssertIN(s1, []string{"e", "a", "d", "c", "b"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_PopLefts(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
s1 := array1.PopLefts(2)
|
||||
gtest.Assert(s1, []string{"a", "b"})
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(len(s1), 2)
|
||||
|
||||
s1 = array1.PopLefts(4)
|
||||
gtest.Assert(len(s1), 3)
|
||||
gtest.Assert(s1, []string{"c", "d", "e"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_PopRights(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b", "f", "g"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
s1 := array1.PopRights(2)
|
||||
gtest.Assert(s1, []string{"f", "g"})
|
||||
gtest.Assert(array1.Len(), 5)
|
||||
gtest.Assert(len(s1), 2)
|
||||
s1 = array1.PopRights(6)
|
||||
gtest.Assert(len(s1), 5)
|
||||
gtest.Assert(s1, []string{"a", "b", "c", "d", "e"})
|
||||
gtest.Assert(array1.Len(), 0)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_Range(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b", "f", "g"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
array2 := garray.NewSortedStrArrayFrom(a1, true)
|
||||
s1 := array1.Range(2, 4)
|
||||
gtest.Assert(len(s1), 2)
|
||||
gtest.Assert(s1, []string{"c", "d"})
|
||||
|
||||
s1 = array1.Range(-1, 2)
|
||||
gtest.Assert(len(s1), 2)
|
||||
gtest.Assert(s1, []string{"a", "b"})
|
||||
|
||||
s1 = array1.Range(4, 8)
|
||||
gtest.Assert(len(s1), 3)
|
||||
gtest.Assert(s1, []string{"e", "f", "g"})
|
||||
gtest.Assert(array1.Range(10, 2), nil)
|
||||
|
||||
s2 := array2.Range(2, 4)
|
||||
gtest.Assert(s2, []string{"c", "d"})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_Sum(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b", "f", "g"}
|
||||
a2 := []string{"1", "2", "3", "4", "a"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
array2 := garray.NewSortedStrArrayFrom(a2)
|
||||
gtest.Assert(array1.Sum(), 0)
|
||||
gtest.Assert(array2.Sum(), 10)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_Clone(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b", "f", "g"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
array2 := array1.Clone()
|
||||
gtest.Assert(array1, array2)
|
||||
array1.Remove(1)
|
||||
gtest.Assert(array2.Len(), 7)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_Clear(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b", "f", "g"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
array1.Clear()
|
||||
gtest.Assert(array1.Len(), 0)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_SubSlice(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b", "f", "g"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
array2 := garray.NewSortedStrArrayFrom(a1, true)
|
||||
s1 := array1.SubSlice(1, 3)
|
||||
gtest.Assert(len(s1), 3)
|
||||
gtest.Assert(s1, []string{"b", "c", "d"})
|
||||
gtest.Assert(array1.Len(), 7)
|
||||
|
||||
s2 := array1.SubSlice(1, 10)
|
||||
gtest.Assert(len(s2), 6)
|
||||
|
||||
s3 := array1.SubSlice(10, 2)
|
||||
gtest.Assert(len(s3), 0)
|
||||
|
||||
s3 = array1.SubSlice(-5, 2)
|
||||
gtest.Assert(s3, []string{"c", "d"})
|
||||
|
||||
s3 = array1.SubSlice(-10, 2)
|
||||
gtest.Assert(s3, nil)
|
||||
|
||||
s3 = array1.SubSlice(1, -2)
|
||||
gtest.Assert(s3, nil)
|
||||
|
||||
gtest.Assert(array2.SubSlice(1, 3), []string{"b", "c", "d"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_Len(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b", "f", "g"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
gtest.Assert(array1.Len(), 7)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_Rand(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
gtest.AssertIN(array1.Rand(), []string{"e", "a", "d"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_Rands(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
s1 := array1.Rands(2)
|
||||
|
||||
gtest.AssertIN(s1, []string{"e", "a", "d"})
|
||||
gtest.Assert(len(s1), 2)
|
||||
|
||||
s1 = array1.Rands(4)
|
||||
gtest.AssertIN(s1, []string{"e", "a", "d"})
|
||||
gtest.Assert(len(s1), 3)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_Join(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
gtest.Assert(array1.Join(","), "a,d,e")
|
||||
gtest.Assert(array1.Join("."), "a.d.e")
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_CountValues(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "a", "c"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
m1 := array1.CountValues()
|
||||
gtest.Assert(m1["a"], 2)
|
||||
gtest.Assert(m1["d"], 1)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_Chunk(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "a", "c"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
array2 := array1.Chunk(2)
|
||||
gtest.Assert(len(array2), 3)
|
||||
gtest.Assert(len(array2[0]), 2)
|
||||
gtest.Assert(array2[1], []string{"c", "d"})
|
||||
gtest.Assert(array1.Chunk(0), nil)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_SetUnique(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "a", "c"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
array2 := array1.SetUnique(true)
|
||||
gtest.Assert(array2.Len(), 4)
|
||||
gtest.Assert(array2, []string{"a", "c", "d", "e"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestStrArray_Remove(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "a", "c"}
|
||||
@ -699,99 +405,6 @@ func TestStrArray_RLockFunc(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_LockFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []string{"a", "b", "c", "d"}
|
||||
a1 := garray.NewSortedStrArrayFrom(s1, true)
|
||||
|
||||
ch1 := make(chan int64, 3)
|
||||
ch2 := make(chan int64, 3)
|
||||
//go1
|
||||
go a1.LockFunc(func(n1 []string) { //读写锁
|
||||
time.Sleep(2 * time.Second) //暂停2秒
|
||||
n1[2] = "g"
|
||||
ch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
})
|
||||
|
||||
//go2
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond) //故意暂停0.01秒,等go1执行锁后,再开始执行.
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
a1.Len()
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
}()
|
||||
|
||||
t1 := <-ch1
|
||||
t2 := <-ch1
|
||||
<-ch2 //等待go1完成
|
||||
|
||||
// 防止ci抖动,以豪秒为单位
|
||||
gtest.AssertGT(t2-t1, 20) //go1加的读写互斥锁,所go2读的时候被阻塞。
|
||||
gtest.Assert(a1.Contains("g"), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_RLockFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []string{"a", "b", "c", "d"}
|
||||
a1 := garray.NewSortedStrArrayFrom(s1, true)
|
||||
|
||||
ch1 := make(chan int64, 3)
|
||||
ch2 := make(chan int64, 1)
|
||||
//go1
|
||||
go a1.RLockFunc(func(n1 []string) { //读锁
|
||||
time.Sleep(2 * time.Second) //暂停1秒
|
||||
n1[2] = "g"
|
||||
ch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
})
|
||||
|
||||
//go2
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond) //故意暂停0.01秒,等go1执行锁后,再开始执行.
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
a1.Len()
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
}()
|
||||
|
||||
t1 := <-ch1
|
||||
t2 := <-ch1
|
||||
<-ch2 //等待go1完成
|
||||
|
||||
// 防止ci抖动,以豪秒为单位
|
||||
gtest.AssertLT(t2-t1, 20) //go1加的读锁,所go2读的时候,并没有阻塞。
|
||||
gtest.Assert(a1.Contains("g"), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_Merge(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
if gconv.Int(v1) < gconv.Int(v2) {
|
||||
return 0
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
s1 := []string{"a", "b", "c", "d"}
|
||||
s2 := []string{"e", "f"}
|
||||
i1 := garray.NewIntArrayFrom([]int{1, 2, 3})
|
||||
i2 := garray.NewArrayFrom([]interface{}{3})
|
||||
s3 := garray.NewStrArrayFrom([]string{"g", "h"})
|
||||
s4 := garray.NewSortedArrayFrom([]interface{}{4, 5}, func1)
|
||||
s5 := garray.NewSortedStrArrayFrom(s2)
|
||||
s6 := garray.NewSortedIntArrayFrom([]int{1, 2, 3})
|
||||
a1 := garray.NewSortedStrArrayFrom(s1)
|
||||
|
||||
gtest.Assert(a1.Merge(s2).Len(), 6)
|
||||
gtest.Assert(a1.Merge(i1).Len(), 9)
|
||||
gtest.Assert(a1.Merge(i2).Len(), 10)
|
||||
gtest.Assert(a1.Merge(s3).Len(), 12)
|
||||
gtest.Assert(a1.Merge(s4).Len(), 14)
|
||||
gtest.Assert(a1.Merge(s5).Len(), 16)
|
||||
gtest.Assert(a1.Merge(s6).Len(), 19)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStrArray_SortFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []string{"a", "d", "c", "b"}
|
||||
@ -835,3 +448,42 @@ func TestStrArray_LockFunc(t *testing.T) {
|
||||
gtest.Assert(a1.Contains("g"), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStrArray_Json(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []string{"a", "b", "d", "c"}
|
||||
a1 := garray.NewStrArrayFrom(s1)
|
||||
b1, err1 := json.Marshal(a1)
|
||||
b2, err2 := json.Marshal(s1)
|
||||
gtest.Assert(b1, b2)
|
||||
gtest.Assert(err1, err2)
|
||||
|
||||
a2 := garray.NewStrArray()
|
||||
err1 = json.Unmarshal(b2, &a2)
|
||||
gtest.Assert(a2.Slice(), s1)
|
||||
|
||||
var a3 garray.StrArray
|
||||
err := json.Unmarshal(b2, &a3)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(a3.Slice(), s1)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
type User struct {
|
||||
Name string
|
||||
Scores *garray.StrArray
|
||||
}
|
||||
data := g.Map{
|
||||
"Name": "john",
|
||||
"Scores": []string{"A+", "A", "A"},
|
||||
}
|
||||
b, err := json.Marshal(data)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
user := new(User)
|
||||
err = json.Unmarshal(b, user)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(user.Name, data["Name"])
|
||||
gtest.Assert(user.Scores, data["Scores"])
|
||||
})
|
||||
}
|
||||
@ -9,6 +9,9 @@
|
||||
package garray_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/util/gutil"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@ -18,319 +21,6 @@ import (
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
)
|
||||
|
||||
func Test_Array_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
expect := []interface{}{0, 1, 2, 3}
|
||||
array := garray.NewArrayFrom(expect)
|
||||
array2 := garray.NewArrayFrom(expect)
|
||||
array3 := garray.NewArrayFrom([]interface{}{})
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
array.Set(0, 100)
|
||||
gtest.Assert(array.Get(0), 100)
|
||||
gtest.Assert(array.Get(1), 1)
|
||||
gtest.Assert(array.Search(100), 0)
|
||||
gtest.Assert(array3.Search(100), -1)
|
||||
gtest.Assert(array.Contains(100), true)
|
||||
gtest.Assert(array.Remove(0), 100)
|
||||
|
||||
gtest.Assert(array2.Remove(3), 3)
|
||||
gtest.Assert(array2.Remove(1), 1)
|
||||
|
||||
gtest.Assert(array.Contains(100), false)
|
||||
array.Append(4)
|
||||
gtest.Assert(array.Len(), 4)
|
||||
array.InsertBefore(0, 100)
|
||||
array.InsertAfter(0, 200)
|
||||
gtest.Assert(array.Slice(), []interface{}{100, 200, 2, 2, 3, 4})
|
||||
array.InsertBefore(5, 300)
|
||||
array.InsertAfter(6, 400)
|
||||
gtest.Assert(array.Slice(), []interface{}{100, 200, 2, 2, 3, 300, 4, 400})
|
||||
gtest.Assert(array.Clear().Len(), 0)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Sort(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
expect1 := []interface{}{0, 1, 2, 3}
|
||||
expect2 := []interface{}{3, 2, 1, 0}
|
||||
array := garray.NewArray()
|
||||
for i := 3; i >= 0; i-- {
|
||||
array.Append(i)
|
||||
}
|
||||
array.SortFunc(func(v1, v2 interface{}) bool {
|
||||
return v1.(int) < v2.(int)
|
||||
})
|
||||
gtest.Assert(array.Slice(), expect1)
|
||||
array.SortFunc(func(v1, v2 interface{}) bool {
|
||||
return v1.(int) > v2.(int)
|
||||
})
|
||||
gtest.Assert(array.Slice(), expect2)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Unique(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
expect := []interface{}{1, 1, 2, 3}
|
||||
array := garray.NewArrayFrom(expect)
|
||||
gtest.Assert(array.Unique().Slice(), []interface{}{1, 2, 3})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_PushAndPop(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
expect := []interface{}{0, 1, 2, 3}
|
||||
array := garray.NewArrayFrom(expect)
|
||||
gtest.Assert(array.Slice(), expect)
|
||||
gtest.Assert(array.PopLeft(), 0)
|
||||
gtest.Assert(array.PopRight(), 3)
|
||||
gtest.AssertIN(array.PopRand(), []interface{}{1, 2})
|
||||
gtest.AssertIN(array.PopRand(), []interface{}{1, 2})
|
||||
gtest.Assert(array.Len(), 0)
|
||||
array.PushLeft(1).PushRight(2)
|
||||
gtest.Assert(array.Slice(), []interface{}{1, 2})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_PopRands(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{100, 200, 300, 400, 500, 600}
|
||||
array := garray.NewFromCopy(a1)
|
||||
gtest.AssertIN(array.PopRands(2), []interface{}{100, 200, 300, 400, 500, 600})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_PopLeftsAndPopRights(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
value1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
value2 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewArrayFrom(value1)
|
||||
array2 := garray.NewArrayFrom(value2)
|
||||
gtest.Assert(array1.PopLefts(2), []interface{}{0, 1})
|
||||
gtest.Assert(array1.Slice(), []interface{}{2, 3, 4, 5, 6})
|
||||
gtest.Assert(array1.PopRights(2), []interface{}{5, 6})
|
||||
gtest.Assert(array1.Slice(), []interface{}{2, 3, 4})
|
||||
gtest.Assert(array1.PopRights(20), []interface{}{2, 3, 4})
|
||||
gtest.Assert(array1.Slice(), []interface{}{})
|
||||
gtest.Assert(array2.PopLefts(20), []interface{}{0, 1, 2, 3, 4, 5, 6})
|
||||
gtest.Assert(array2.Slice(), []interface{}{})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Range(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
value1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewArrayFrom(value1)
|
||||
array2 := garray.NewArrayFrom(value1, true)
|
||||
gtest.Assert(array1.Range(0, 1), []interface{}{0})
|
||||
gtest.Assert(array1.Range(1, 2), []interface{}{1})
|
||||
gtest.Assert(array1.Range(0, 2), []interface{}{0, 1})
|
||||
gtest.Assert(array1.Range(-1, 10), value1)
|
||||
gtest.Assert(array1.Range(10, 2), nil)
|
||||
gtest.Assert(array2.Range(1, 3), []interface{}{1, 2})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Merge(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
if gconv.Int(v1) < gconv.Int(v2) {
|
||||
return 0
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
i1 := []interface{}{0, 1, 2, 3}
|
||||
i2 := []interface{}{4, 5, 6, 7}
|
||||
array1 := garray.NewArrayFrom(i1)
|
||||
array2 := garray.NewArrayFrom(i2)
|
||||
gtest.Assert(array1.Merge(array2).Slice(), []interface{}{0, 1, 2, 3, 4, 5, 6, 7})
|
||||
|
||||
//s1 := []string{"a", "b", "c", "d"}
|
||||
s2 := []string{"e", "f"}
|
||||
i3 := garray.NewIntArrayFrom([]int{1, 2, 3})
|
||||
i4 := garray.NewArrayFrom([]interface{}{3})
|
||||
s3 := garray.NewStrArrayFrom([]string{"g", "h"})
|
||||
s4 := garray.NewSortedArrayFrom([]interface{}{4, 5}, func1)
|
||||
s5 := garray.NewSortedStrArrayFrom(s2)
|
||||
s6 := garray.NewSortedIntArrayFrom([]int{1, 2, 3})
|
||||
a1 := garray.NewArrayFrom(i1)
|
||||
|
||||
gtest.Assert(a1.Merge(s2).Len(), 6)
|
||||
gtest.Assert(a1.Merge(i3).Len(), 9)
|
||||
gtest.Assert(a1.Merge(i4).Len(), 10)
|
||||
gtest.Assert(a1.Merge(s3).Len(), 12)
|
||||
gtest.Assert(a1.Merge(s4).Len(), 14)
|
||||
gtest.Assert(a1.Merge(s5).Len(), 16)
|
||||
gtest.Assert(a1.Merge(s6).Len(), 19)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Fill(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0}
|
||||
a2 := []interface{}{0}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
array2 := garray.NewArrayFrom(a2, true)
|
||||
gtest.Assert(array1.Fill(1, 2, 100).Slice(), []interface{}{0, 100, 100})
|
||||
gtest.Assert(array2.Fill(0, 2, 100).Slice(), []interface{}{100, 100})
|
||||
gtest.Assert(array2.Fill(-1, 2, 100).Slice(), []interface{}{100, 100})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Chunk(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{1, 2, 3, 4, 5}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
chunks := array1.Chunk(2)
|
||||
gtest.Assert(len(chunks), 3)
|
||||
gtest.Assert(chunks[0], []interface{}{1, 2})
|
||||
gtest.Assert(chunks[1], []interface{}{3, 4})
|
||||
gtest.Assert(chunks[2], []interface{}{5})
|
||||
gtest.Assert(array1.Chunk(0), nil)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Pad(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
gtest.Assert(array1.Pad(3, 1).Slice(), []interface{}{0, 1, 1})
|
||||
gtest.Assert(array1.Pad(-4, 1).Slice(), []interface{}{1, 0, 1, 1})
|
||||
gtest.Assert(array1.Pad(3, 1).Slice(), []interface{}{1, 0, 1, 1})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_SubSlice(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
array2 := garray.NewArrayFrom(a1, true)
|
||||
gtest.Assert(array1.SubSlice(0, 2), []interface{}{0, 1})
|
||||
gtest.Assert(array1.SubSlice(2, 2), []interface{}{2, 3})
|
||||
gtest.Assert(array1.SubSlice(5, 8), []interface{}{5, 6})
|
||||
gtest.Assert(array1.SubSlice(9, 1), nil)
|
||||
gtest.Assert(array1.SubSlice(-2, 2), []interface{}{5, 6})
|
||||
gtest.Assert(array1.SubSlice(-9, 2), nil)
|
||||
gtest.Assert(array1.SubSlice(1, -2), nil)
|
||||
gtest.Assert(array2.SubSlice(0, 2), []interface{}{0, 1})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Rand(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
gtest.Assert(len(array1.Rands(2)), 2)
|
||||
gtest.Assert(len(array1.Rands(10)), 7)
|
||||
gtest.AssertIN(array1.Rands(1)[0], a1)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
s1 := []interface{}{"a", "b", "c", "d"}
|
||||
a1 := garray.NewArrayFrom(s1)
|
||||
i1 := a1.Rand()
|
||||
gtest.Assert(a1.Contains(i1), true)
|
||||
gtest.Assert(a1.Len(), 4)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Shuffle(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
gtest.Assert(array1.Shuffle().Len(), 7)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Reverse(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
gtest.Assert(array1.Reverse().Slice(), []interface{}{6, 5, 4, 3, 2, 1, 0})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Join(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
gtest.Assert(array1.Join("."), "0.1.2.3.4.5.6")
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Replace(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
a2 := []interface{}{"a", "b", "c"}
|
||||
a3 := []interface{}{"m", "n", "p", "z", "x", "y", "d", "u"}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
array2 := array1.Replace(a2)
|
||||
gtest.Assert(array2.Len(), 7)
|
||||
gtest.Assert(array2.Contains("b"), true)
|
||||
gtest.Assert(array2.Contains(4), true)
|
||||
gtest.Assert(array2.Contains("v"), false)
|
||||
array3 := array1.Replace(a3)
|
||||
gtest.Assert(array3.Len(), 7)
|
||||
gtest.Assert(array3.Contains(4), false)
|
||||
gtest.Assert(array3.Contains("p"), true)
|
||||
gtest.Assert(array3.Contains("u"), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_SetArray(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
a2 := []interface{}{"a", "b", "c"}
|
||||
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
array1 = array1.SetArray(a2)
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(array1.Contains("b"), true)
|
||||
gtest.Assert(array1.Contains("5"), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Sum(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3}
|
||||
a2 := []interface{}{"a", "b", "c"}
|
||||
a3 := []interface{}{"a", "1", "2"}
|
||||
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
array2 := garray.NewArrayFrom(a2)
|
||||
array3 := garray.NewArrayFrom(a3)
|
||||
|
||||
gtest.Assert(array1.Sum(), 6)
|
||||
gtest.Assert(array2.Sum(), 0)
|
||||
gtest.Assert(array3.Sum(), 3)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Clone(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, 2, 3}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
array2 := array1.Clone()
|
||||
|
||||
gtest.Assert(array1.Len(), 4)
|
||||
gtest.Assert(array2.Sum(), 6)
|
||||
gtest.AssertEQ(array1, array2)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_CountValues(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{"a", "b", "c", "d", "e", "d"}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
array2 := array1.CountValues()
|
||||
gtest.Assert(len(array2), 5)
|
||||
gtest.Assert(array2["b"], 1)
|
||||
gtest.Assert(array2["d"], 2)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedArray_NewSortedArrayFrom(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{"a", "f", "c"}
|
||||
@ -700,14 +390,26 @@ func TestSortedArray_Rands(t *testing.T) {
|
||||
func TestSortedArray_Join(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{"a", "d", "c"}
|
||||
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
gtest.Assert(array1.Join(","), "a,c,d")
|
||||
gtest.Assert(array1.Join("."), "a.c.d")
|
||||
gtest.Assert(array1.Join(","), `"a","c","d"`)
|
||||
gtest.Assert(array1.Join("."), `"a"."c"."d"`)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, `"a"`, `\a`}
|
||||
array1 := garray.NewSortedArrayFrom(a1, gutil.ComparatorString)
|
||||
gtest.Assert(array1.Join("."), `"\"a\"".0.1."\\a"`)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedArray_String(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []interface{}{0, 1, "a", "b"}
|
||||
array1 := garray.NewSortedArrayFrom(a1, gutil.ComparatorString)
|
||||
gtest.Assert(array1.String(), `[0,1,"a","b"]`)
|
||||
})
|
||||
}
|
||||
|
||||
@ -838,70 +540,49 @@ func TestSortedArray_Merge(t *testing.T) {
|
||||
gtest.Assert(a1.Merge(s4).Len(), 14)
|
||||
gtest.Assert(a1.Merge(s5).Len(), 16)
|
||||
gtest.Assert(a1.Merge(s6).Len(), 19)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_LockFunc(t *testing.T) {
|
||||
func TestSortedArray_Json(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []interface{}{"a", "b", "c", "d"}
|
||||
a1 := garray.NewArrayFrom(s1, true)
|
||||
s1 := []interface{}{"a", "b", "d", "c"}
|
||||
s2 := []interface{}{"a", "b", "c", "d"}
|
||||
a1 := garray.NewSortedArrayFrom(s1, gutil.ComparatorString)
|
||||
b1, err1 := json.Marshal(a1)
|
||||
b2, err2 := json.Marshal(s1)
|
||||
gtest.Assert(b1, b2)
|
||||
gtest.Assert(err1, err2)
|
||||
|
||||
ch1 := make(chan int64, 3)
|
||||
ch2 := make(chan int64, 3)
|
||||
//go1
|
||||
go a1.LockFunc(func(n1 []interface{}) { //读写锁
|
||||
time.Sleep(2 * time.Second) //暂停2秒
|
||||
n1[2] = "g"
|
||||
ch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
})
|
||||
a2 := garray.NewSortedArray(gutil.ComparatorString)
|
||||
err1 = json.Unmarshal(b2, &a2)
|
||||
gtest.Assert(a2.Slice(), s2)
|
||||
|
||||
//go2
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond) //故意暂停0.01秒,等go1执行锁后,再开始执行.
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
a1.Len()
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
}()
|
||||
|
||||
t1 := <-ch1
|
||||
t2 := <-ch1
|
||||
<-ch2 //等待go1完成
|
||||
|
||||
// 防止ci抖动,以豪秒为单位
|
||||
gtest.AssertGT(t2-t1, 20) //go1加的读写互斥锁,所go2读的时候被阻塞。
|
||||
gtest.Assert(a1.Contains("g"), true)
|
||||
var a3 garray.SortedArray
|
||||
err := json.Unmarshal(b2, &a3)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(a3.Slice(), s1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_RLockFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []interface{}{"a", "b", "c", "d"}
|
||||
a1 := garray.NewArrayFrom(s1, true)
|
||||
type User struct {
|
||||
Name string
|
||||
Scores *garray.SortedArray
|
||||
}
|
||||
data := g.Map{
|
||||
"Name": "john",
|
||||
"Scores": []int{99, 100, 98},
|
||||
}
|
||||
b, err := json.Marshal(data)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
ch1 := make(chan int64, 3)
|
||||
ch2 := make(chan int64, 1)
|
||||
//go1
|
||||
go a1.RLockFunc(func(n1 []interface{}) { //读锁
|
||||
time.Sleep(2 * time.Second) //暂停1秒
|
||||
n1[2] = "g"
|
||||
ch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
})
|
||||
|
||||
//go2
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond) //故意暂停0.01秒,等go1执行锁后,再开始执行.
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
a1.Len()
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
}()
|
||||
|
||||
t1 := <-ch1
|
||||
t2 := <-ch1
|
||||
<-ch2 //等待go1完成
|
||||
|
||||
// 防止ci抖动,以豪秒为单位
|
||||
gtest.AssertLT(t2-t1, 20) //go1加的读锁,所go2读的时候,并没有阻塞。
|
||||
gtest.Assert(a1.Contains("g"), true)
|
||||
user := new(User)
|
||||
err = json.Unmarshal(b, user)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(user.Name, data["Name"])
|
||||
gtest.AssertNE(user.Scores, nil)
|
||||
gtest.Assert(user.Scores.Len(), 3)
|
||||
gtest.AssertIN(user.Scores.PopLeft(), data["Scores"])
|
||||
gtest.AssertIN(user.Scores.PopLeft(), data["Scores"])
|
||||
gtest.AssertIN(user.Scores.PopLeft(), data["Scores"])
|
||||
})
|
||||
}
|
||||
467
container/garray/garray_z_unit_sorted_int_array_test.go
Normal file
467
container/garray/garray_z_unit_sorted_int_array_test.go
Normal file
@ -0,0 +1,467 @@
|
||||
// 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.
|
||||
|
||||
// go test *.go
|
||||
|
||||
package garray_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
|
||||
"github.com/gogf/gf/container/garray"
|
||||
"github.com/gogf/gf/test/gtest"
|
||||
)
|
||||
|
||||
func TestNewSortedIntArrayFrom(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{0, 3, 2, 1, 4, 5, 6}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1, true)
|
||||
gtest.Assert(array1.Join("."), "0.1.2.3.4.5.6")
|
||||
gtest.Assert(array1.Slice(), a1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewSortedIntArrayFromCopy(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{0, 5, 2, 1, 4, 3, 6}
|
||||
array1 := garray.NewSortedIntArrayFromCopy(a1, false)
|
||||
gtest.Assert(array1.Join("."), "0.1.2.3.4.5.6")
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_SetArray(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{0, 1, 2, 3}
|
||||
a2 := []int{4, 5, 6}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
array2 := array1.SetArray(a2)
|
||||
|
||||
gtest.Assert(array2.Len(), 3)
|
||||
gtest.Assert(array2.Search(3), -1)
|
||||
gtest.Assert(array2.Search(5), 1)
|
||||
gtest.Assert(array2.Search(6), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Sort(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{0, 3, 2, 1}
|
||||
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
array2 := array1.Sort()
|
||||
|
||||
gtest.Assert(array2.Len(), 4)
|
||||
gtest.Assert(array2, []int{0, 1, 2, 3})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Get(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5, 0}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
gtest.Assert(array1.Get(0), 0)
|
||||
gtest.Assert(array1.Get(1), 1)
|
||||
gtest.Assert(array1.Get(3), 5)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Remove(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5, 0}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
i1 := array1.Remove(2)
|
||||
gtest.Assert(i1, 3)
|
||||
gtest.Assert(array1.Search(5), 2)
|
||||
|
||||
// 再次删除剩下的数组中的第一个
|
||||
i2 := array1.Remove(0)
|
||||
gtest.Assert(i2, 0)
|
||||
gtest.Assert(array1.Search(5), 1)
|
||||
|
||||
a2 := []int{1, 3, 4}
|
||||
array2 := garray.NewSortedIntArrayFrom(a2)
|
||||
i3 := array2.Remove(1)
|
||||
gtest.Assert(array2.Search(1), 0)
|
||||
gtest.Assert(i3, 3)
|
||||
i3 = array2.Remove(1)
|
||||
gtest.Assert(array2.Search(4), -1)
|
||||
gtest.Assert(i3, 4)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_PopLeft(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5, 2}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
i1 := array1.PopLeft()
|
||||
gtest.Assert(i1, 1)
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(array1.Search(1), -1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_PopRight(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5, 2}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
i1 := array1.PopRight()
|
||||
gtest.Assert(i1, 5)
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(array1.Search(5), -1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_PopRand(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5, 2}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
i1 := array1.PopRand()
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(array1.Search(i1), -1)
|
||||
gtest.AssertIN(i1, []int{1, 3, 5, 2})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_PopRands(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5, 2}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
ns1 := array1.PopRands(2)
|
||||
gtest.Assert(array1.Len(), 2)
|
||||
gtest.AssertIN(ns1, []int{1, 3, 5, 2})
|
||||
|
||||
a2 := []int{1, 3, 5, 2}
|
||||
array2 := garray.NewSortedIntArrayFrom(a2)
|
||||
ns2 := array2.PopRands(5)
|
||||
gtest.Assert(array2.Len(), 0)
|
||||
gtest.Assert(len(ns2), 4)
|
||||
gtest.AssertIN(ns2, []int{1, 3, 5, 2})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_PopLefts(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5, 2}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
ns1 := array1.PopLefts(2)
|
||||
gtest.Assert(array1.Len(), 2)
|
||||
gtest.Assert(ns1, []int{1, 2})
|
||||
|
||||
a2 := []int{1, 3, 5, 2}
|
||||
array2 := garray.NewSortedIntArrayFrom(a2)
|
||||
ns2 := array2.PopLefts(5)
|
||||
gtest.Assert(array2.Len(), 0)
|
||||
gtest.AssertIN(ns2, []int{1, 3, 5, 2})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_PopRights(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5, 2}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
ns1 := array1.PopRights(2)
|
||||
gtest.Assert(array1.Len(), 2)
|
||||
gtest.Assert(ns1, []int{3, 5})
|
||||
|
||||
a2 := []int{1, 3, 5, 2}
|
||||
array2 := garray.NewSortedIntArrayFrom(a2)
|
||||
ns2 := array2.PopRights(5)
|
||||
gtest.Assert(array2.Len(), 0)
|
||||
gtest.AssertIN(ns2, []int{1, 3, 5, 2})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Range(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5, 2, 6, 7}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
array2 := garray.NewSortedIntArrayFrom(a1, true)
|
||||
ns1 := array1.Range(1, 4)
|
||||
gtest.Assert(len(ns1), 3)
|
||||
gtest.Assert(ns1, []int{2, 3, 5})
|
||||
|
||||
ns2 := array1.Range(5, 4)
|
||||
gtest.Assert(len(ns2), 0)
|
||||
|
||||
ns3 := array1.Range(-1, 4)
|
||||
gtest.Assert(len(ns3), 4)
|
||||
|
||||
nsl := array1.Range(5, 8)
|
||||
gtest.Assert(len(nsl), 1)
|
||||
gtest.Assert(array2.Range(1, 2), []int{2})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Sum(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
n1 := array1.Sum()
|
||||
gtest.Assert(n1, 9)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Join(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
gtest.Assert(array1.Join("."), `1.3.5`)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_String(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
gtest.Assert(array1.String(), `[1,3,5]`)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Contains(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
gtest.Assert(array1.Contains(4), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Clone(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
array2 := array1.Clone()
|
||||
gtest.Assert(array2.Len(), 3)
|
||||
gtest.Assert(array2, array1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Clear(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 3, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
array1.Clear()
|
||||
gtest.Assert(array1.Len(), 0)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Chunk(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 2, 3, 4, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
ns1 := array1.Chunk(2) //按每几个元素切成一个数组
|
||||
ns2 := array1.Chunk(-1)
|
||||
gtest.Assert(len(ns1), 3)
|
||||
gtest.Assert(ns1[0], []int{1, 2})
|
||||
gtest.Assert(ns1[2], []int{5})
|
||||
gtest.Assert(len(ns2), 0)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_SubSlice(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 2, 3, 4, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
array2 := garray.NewSortedIntArrayFrom(a1, true)
|
||||
ns1 := array1.SubSlice(1, 2)
|
||||
gtest.Assert(len(ns1), 2)
|
||||
gtest.Assert(ns1, []int{2, 3})
|
||||
|
||||
ns2 := array1.SubSlice(7, 2)
|
||||
gtest.Assert(len(ns2), 0)
|
||||
|
||||
ns3 := array1.SubSlice(3, 5)
|
||||
gtest.Assert(len(ns3), 2)
|
||||
gtest.Assert(ns3, []int{4, 5})
|
||||
|
||||
ns4 := array1.SubSlice(3, 1)
|
||||
gtest.Assert(len(ns4), 1)
|
||||
gtest.Assert(ns4, []int{4})
|
||||
gtest.Assert(array1.SubSlice(-1, 1), []int{5})
|
||||
gtest.Assert(array1.SubSlice(-9, 1), nil)
|
||||
gtest.Assert(array1.SubSlice(1, -9), nil)
|
||||
gtest.Assert(array2.SubSlice(1, 2), []int{2, 3})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Rand(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 2, 3, 4, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
ns1 := array1.Rand() //按每几个元素切成一个数组
|
||||
gtest.AssertIN(ns1, a1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Rands(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 2, 3, 4, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
ns1 := array1.Rands(2) //按每几个元素切成一个数组
|
||||
gtest.AssertIN(ns1, a1)
|
||||
gtest.Assert(len(ns1), 2)
|
||||
|
||||
ns2 := array1.Rands(6) //按每几个元素切成一个数组
|
||||
gtest.AssertIN(ns2, a1)
|
||||
gtest.Assert(len(ns2), 5)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_CountValues(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 2, 3, 4, 5, 3}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
ns1 := array1.CountValues() //按每几个元素切成一个数组
|
||||
gtest.Assert(len(ns1), 5)
|
||||
gtest.Assert(ns1[2], 1)
|
||||
gtest.Assert(ns1[3], 2)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_SetUnique(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []int{1, 2, 3, 4, 5, 3}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
array1.SetUnique(true)
|
||||
gtest.Assert(array1.Len(), 5)
|
||||
gtest.Assert(array1, []int{1, 2, 3, 4, 5})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_LockFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []int{1, 2, 3, 4}
|
||||
a1 := garray.NewSortedIntArrayFrom(s1, true)
|
||||
ch1 := make(chan int64, 3)
|
||||
ch2 := make(chan int64, 3)
|
||||
//go1
|
||||
go a1.LockFunc(func(n1 []int) { //读写锁
|
||||
time.Sleep(2 * time.Second) //暂停2秒
|
||||
n1[2] = 6
|
||||
ch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
})
|
||||
|
||||
//go2
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond) //故意暂停0.01秒,等go1执行锁后,再开始执行.
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
a1.Len()
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
}()
|
||||
|
||||
t1 := <-ch1
|
||||
t2 := <-ch1
|
||||
<-ch2 //等待go1完成
|
||||
|
||||
// 防止ci抖动,以豪秒为单位
|
||||
gtest.AssertGT(t2-t1, 20) //go1加的读写互斥锁,所go2读的时候被阻塞。
|
||||
gtest.Assert(a1.Contains(6), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_RLockFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []int{1, 2, 3, 4}
|
||||
a1 := garray.NewSortedIntArrayFrom(s1, true)
|
||||
|
||||
ch1 := make(chan int64, 3)
|
||||
ch2 := make(chan int64, 1)
|
||||
//go1
|
||||
go a1.RLockFunc(func(n1 []int) { //读锁
|
||||
time.Sleep(2 * time.Second) //暂停1秒
|
||||
n1[2] = 6
|
||||
ch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
})
|
||||
|
||||
//go2
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond) //故意暂停0.01秒,等go1执行锁后,再开始执行.
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
a1.Len()
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
}()
|
||||
|
||||
t1 := <-ch1
|
||||
t2 := <-ch1
|
||||
<-ch2 //等待go1完成
|
||||
|
||||
// 防止ci抖动,以豪秒为单位
|
||||
gtest.AssertLT(t2-t1, 20) //go1加的读锁,所go2读的时候,并没有阻塞。
|
||||
gtest.Assert(a1.Contains(6), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Merge(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
if gconv.Int(v1) < gconv.Int(v2) {
|
||||
return 0
|
||||
}
|
||||
return 1
|
||||
}
|
||||
i0 := []int{1, 2, 3, 4}
|
||||
s2 := []string{"e", "f"}
|
||||
i1 := garray.NewIntArrayFrom([]int{1, 2, 3})
|
||||
i2 := garray.NewArrayFrom([]interface{}{3})
|
||||
s3 := garray.NewStrArrayFrom([]string{"g", "h"})
|
||||
s4 := garray.NewSortedArrayFrom([]interface{}{4, 5}, func1)
|
||||
s5 := garray.NewSortedStrArrayFrom(s2)
|
||||
s6 := garray.NewSortedIntArrayFrom([]int{1, 2, 3})
|
||||
a1 := garray.NewSortedIntArrayFrom(i0)
|
||||
|
||||
gtest.Assert(a1.Merge(s2).Len(), 6)
|
||||
gtest.Assert(a1.Merge(i1).Len(), 9)
|
||||
gtest.Assert(a1.Merge(i2).Len(), 10)
|
||||
gtest.Assert(a1.Merge(s3).Len(), 12)
|
||||
gtest.Assert(a1.Merge(s4).Len(), 14)
|
||||
gtest.Assert(a1.Merge(s5).Len(), 16)
|
||||
gtest.Assert(a1.Merge(s6).Len(), 19)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_Json(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []int{1, 4, 3, 2}
|
||||
s2 := []int{1, 2, 3, 4}
|
||||
a1 := garray.NewSortedIntArrayFrom(s1)
|
||||
b1, err1 := json.Marshal(a1)
|
||||
b2, err2 := json.Marshal(s1)
|
||||
gtest.Assert(b1, b2)
|
||||
gtest.Assert(err1, err2)
|
||||
|
||||
a2 := garray.NewSortedIntArray()
|
||||
err1 = json.Unmarshal(b2, &a2)
|
||||
gtest.Assert(a2.Slice(), s2)
|
||||
|
||||
var a3 garray.SortedIntArray
|
||||
err := json.Unmarshal(b2, &a3)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(a3.Slice(), s1)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
type User struct {
|
||||
Name string
|
||||
Scores *garray.SortedIntArray
|
||||
}
|
||||
data := g.Map{
|
||||
"Name": "john",
|
||||
"Scores": []int{99, 100, 98},
|
||||
}
|
||||
b, err := json.Marshal(data)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
user := new(User)
|
||||
err = json.Unmarshal(b, user)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(user.Name, data["Name"])
|
||||
gtest.Assert(user.Scores, []int{98, 99, 100})
|
||||
})
|
||||
}
|
||||
476
container/garray/garray_z_unit_sorted_str_array_test.go
Normal file
476
container/garray/garray_z_unit_sorted_str_array_test.go
Normal file
@ -0,0 +1,476 @@
|
||||
// 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.
|
||||
|
||||
// go test *.go
|
||||
|
||||
package garray_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/container/garray"
|
||||
"github.com/gogf/gf/test/gtest"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
)
|
||||
|
||||
func TestNewSortedStrArrayFrom(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"a", "d", "c", "b"}
|
||||
s1 := garray.NewSortedStrArrayFrom(a1, true)
|
||||
gtest.Assert(s1, []string{"a", "b", "c", "d"})
|
||||
s2 := garray.NewSortedStrArrayFrom(a1, false)
|
||||
gtest.Assert(s2, []string{"a", "b", "c", "d"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewSortedStrArrayFromCopy(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"a", "d", "c", "b"}
|
||||
s1 := garray.NewSortedStrArrayFromCopy(a1, true)
|
||||
gtest.Assert(s1.Len(), 4)
|
||||
gtest.Assert(s1, []string{"a", "b", "c", "d"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_SetArray(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"a", "d", "c", "b"}
|
||||
a2 := []string{"f", "g", "h"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
array1.SetArray(a2)
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(array1.Contains("d"), false)
|
||||
gtest.Assert(array1.Contains("b"), false)
|
||||
gtest.Assert(array1.Contains("g"), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_Sort(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"a", "d", "c", "b"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
|
||||
gtest.Assert(array1, []string{"a", "b", "c", "d"})
|
||||
array1.Sort()
|
||||
gtest.Assert(array1.Len(), 4)
|
||||
gtest.Assert(array1.Contains("c"), true)
|
||||
gtest.Assert(array1, []string{"a", "b", "c", "d"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_Get(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"a", "d", "c", "b"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
gtest.Assert(array1.Get(2), "c")
|
||||
gtest.Assert(array1.Get(0), "a")
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_Remove(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"a", "d", "c", "b"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
gtest.Assert(array1.Remove(2), "c")
|
||||
gtest.Assert(array1.Get(2), "d")
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(array1.Contains("c"), false)
|
||||
|
||||
gtest.Assert(array1.Remove(0), "a")
|
||||
gtest.Assert(array1.Len(), 2)
|
||||
gtest.Assert(array1.Contains("a"), false)
|
||||
|
||||
// 此时array1里的元素只剩下2个
|
||||
gtest.Assert(array1.Remove(1), "d")
|
||||
gtest.Assert(array1.Len(), 1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_PopLeft(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
s1 := array1.PopLeft()
|
||||
gtest.Assert(s1, "a")
|
||||
gtest.Assert(array1.Len(), 4)
|
||||
gtest.Assert(array1.Contains("a"), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_PopRight(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
s1 := array1.PopRight()
|
||||
gtest.Assert(s1, "e")
|
||||
gtest.Assert(array1.Len(), 4)
|
||||
gtest.Assert(array1.Contains("e"), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_PopRand(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
s1 := array1.PopRand()
|
||||
gtest.AssertIN(s1, []string{"e", "a", "d", "c", "b"})
|
||||
gtest.Assert(array1.Len(), 4)
|
||||
gtest.Assert(array1.Contains(s1), false)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_PopRands(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
s1 := array1.PopRands(2)
|
||||
gtest.AssertIN(s1, []string{"e", "a", "d", "c", "b"})
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(len(s1), 2)
|
||||
|
||||
s1 = array1.PopRands(4)
|
||||
gtest.Assert(len(s1), 3)
|
||||
gtest.AssertIN(s1, []string{"e", "a", "d", "c", "b"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_PopLefts(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
s1 := array1.PopLefts(2)
|
||||
gtest.Assert(s1, []string{"a", "b"})
|
||||
gtest.Assert(array1.Len(), 3)
|
||||
gtest.Assert(len(s1), 2)
|
||||
|
||||
s1 = array1.PopLefts(4)
|
||||
gtest.Assert(len(s1), 3)
|
||||
gtest.Assert(s1, []string{"c", "d", "e"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_PopRights(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b", "f", "g"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
s1 := array1.PopRights(2)
|
||||
gtest.Assert(s1, []string{"f", "g"})
|
||||
gtest.Assert(array1.Len(), 5)
|
||||
gtest.Assert(len(s1), 2)
|
||||
s1 = array1.PopRights(6)
|
||||
gtest.Assert(len(s1), 5)
|
||||
gtest.Assert(s1, []string{"a", "b", "c", "d", "e"})
|
||||
gtest.Assert(array1.Len(), 0)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_Range(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b", "f", "g"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
array2 := garray.NewSortedStrArrayFrom(a1, true)
|
||||
s1 := array1.Range(2, 4)
|
||||
gtest.Assert(len(s1), 2)
|
||||
gtest.Assert(s1, []string{"c", "d"})
|
||||
|
||||
s1 = array1.Range(-1, 2)
|
||||
gtest.Assert(len(s1), 2)
|
||||
gtest.Assert(s1, []string{"a", "b"})
|
||||
|
||||
s1 = array1.Range(4, 8)
|
||||
gtest.Assert(len(s1), 3)
|
||||
gtest.Assert(s1, []string{"e", "f", "g"})
|
||||
gtest.Assert(array1.Range(10, 2), nil)
|
||||
|
||||
s2 := array2.Range(2, 4)
|
||||
gtest.Assert(s2, []string{"c", "d"})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_Sum(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b", "f", "g"}
|
||||
a2 := []string{"1", "2", "3", "4", "a"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
array2 := garray.NewSortedStrArrayFrom(a2)
|
||||
gtest.Assert(array1.Sum(), 0)
|
||||
gtest.Assert(array2.Sum(), 10)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_Clone(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b", "f", "g"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
array2 := array1.Clone()
|
||||
gtest.Assert(array1, array2)
|
||||
array1.Remove(1)
|
||||
gtest.Assert(array2.Len(), 7)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_Clear(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b", "f", "g"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
array1.Clear()
|
||||
gtest.Assert(array1.Len(), 0)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_SubSlice(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b", "f", "g"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
array2 := garray.NewSortedStrArrayFrom(a1, true)
|
||||
s1 := array1.SubSlice(1, 3)
|
||||
gtest.Assert(len(s1), 3)
|
||||
gtest.Assert(s1, []string{"b", "c", "d"})
|
||||
gtest.Assert(array1.Len(), 7)
|
||||
|
||||
s2 := array1.SubSlice(1, 10)
|
||||
gtest.Assert(len(s2), 6)
|
||||
|
||||
s3 := array1.SubSlice(10, 2)
|
||||
gtest.Assert(len(s3), 0)
|
||||
|
||||
s3 = array1.SubSlice(-5, 2)
|
||||
gtest.Assert(s3, []string{"c", "d"})
|
||||
|
||||
s3 = array1.SubSlice(-10, 2)
|
||||
gtest.Assert(s3, nil)
|
||||
|
||||
s3 = array1.SubSlice(1, -2)
|
||||
gtest.Assert(s3, nil)
|
||||
|
||||
gtest.Assert(array2.SubSlice(1, 3), []string{"b", "c", "d"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_Len(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "c", "b", "f", "g"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
gtest.Assert(array1.Len(), 7)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_Rand(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
gtest.AssertIN(array1.Rand(), []string{"e", "a", "d"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_Rands(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
s1 := array1.Rands(2)
|
||||
|
||||
gtest.AssertIN(s1, []string{"e", "a", "d"})
|
||||
gtest.Assert(len(s1), 2)
|
||||
|
||||
s1 = array1.Rands(4)
|
||||
gtest.AssertIN(s1, []string{"e", "a", "d"})
|
||||
gtest.Assert(len(s1), 3)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_Join(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
gtest.Assert(array1.Join(","), `"a","d","e"`)
|
||||
gtest.Assert(array1.Join("."), `"a"."d"."e"`)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"a", `"b"`, `\c`}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
gtest.Assert(array1.Join("."), `"\"b\""."\\c"."a"`)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_String(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
gtest.Assert(array1.String(), `["a","d","e"]`)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_CountValues(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "a", "c"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
m1 := array1.CountValues()
|
||||
gtest.Assert(m1["a"], 2)
|
||||
gtest.Assert(m1["d"], 1)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_Chunk(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "a", "c"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
array2 := array1.Chunk(2)
|
||||
gtest.Assert(len(array2), 3)
|
||||
gtest.Assert(len(array2[0]), 2)
|
||||
gtest.Assert(array2[1], []string{"c", "d"})
|
||||
gtest.Assert(array1.Chunk(0), nil)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_SetUnique(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a1 := []string{"e", "a", "d", "a", "c"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
array2 := array1.SetUnique(true)
|
||||
gtest.Assert(array2.Len(), 4)
|
||||
gtest.Assert(array2, []string{"a", "c", "d", "e"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_LockFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []string{"a", "b", "c", "d"}
|
||||
a1 := garray.NewSortedStrArrayFrom(s1, true)
|
||||
|
||||
ch1 := make(chan int64, 3)
|
||||
ch2 := make(chan int64, 3)
|
||||
//go1
|
||||
go a1.LockFunc(func(n1 []string) { //读写锁
|
||||
time.Sleep(2 * time.Second) //暂停2秒
|
||||
n1[2] = "g"
|
||||
ch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
})
|
||||
|
||||
//go2
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond) //故意暂停0.01秒,等go1执行锁后,再开始执行.
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
a1.Len()
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
}()
|
||||
|
||||
t1 := <-ch1
|
||||
t2 := <-ch1
|
||||
<-ch2 //等待go1完成
|
||||
|
||||
// 防止ci抖动,以豪秒为单位
|
||||
gtest.AssertGT(t2-t1, 20) //go1加的读写互斥锁,所go2读的时候被阻塞。
|
||||
gtest.Assert(a1.Contains("g"), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_RLockFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []string{"a", "b", "c", "d"}
|
||||
a1 := garray.NewSortedStrArrayFrom(s1, true)
|
||||
|
||||
ch1 := make(chan int64, 3)
|
||||
ch2 := make(chan int64, 1)
|
||||
//go1
|
||||
go a1.RLockFunc(func(n1 []string) { //读锁
|
||||
time.Sleep(2 * time.Second) //暂停1秒
|
||||
n1[2] = "g"
|
||||
ch2 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
})
|
||||
|
||||
//go2
|
||||
go func() {
|
||||
time.Sleep(100 * time.Millisecond) //故意暂停0.01秒,等go1执行锁后,再开始执行.
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
a1.Len()
|
||||
ch1 <- gconv.Int64(time.Now().UnixNano() / 1000 / 1000)
|
||||
}()
|
||||
|
||||
t1 := <-ch1
|
||||
t2 := <-ch1
|
||||
<-ch2 //等待go1完成
|
||||
|
||||
// 防止ci抖动,以豪秒为单位
|
||||
gtest.AssertLT(t2-t1, 20) //go1加的读锁,所go2读的时候,并没有阻塞。
|
||||
gtest.Assert(a1.Contains("g"), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_Merge(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
if gconv.Int(v1) < gconv.Int(v2) {
|
||||
return 0
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
||||
s1 := []string{"a", "b", "c", "d"}
|
||||
s2 := []string{"e", "f"}
|
||||
i1 := garray.NewIntArrayFrom([]int{1, 2, 3})
|
||||
i2 := garray.NewArrayFrom([]interface{}{3})
|
||||
s3 := garray.NewStrArrayFrom([]string{"g", "h"})
|
||||
s4 := garray.NewSortedArrayFrom([]interface{}{4, 5}, func1)
|
||||
s5 := garray.NewSortedStrArrayFrom(s2)
|
||||
s6 := garray.NewSortedIntArrayFrom([]int{1, 2, 3})
|
||||
a1 := garray.NewSortedStrArrayFrom(s1)
|
||||
|
||||
gtest.Assert(a1.Merge(s2).Len(), 6)
|
||||
gtest.Assert(a1.Merge(i1).Len(), 9)
|
||||
gtest.Assert(a1.Merge(i2).Len(), 10)
|
||||
gtest.Assert(a1.Merge(s3).Len(), 12)
|
||||
gtest.Assert(a1.Merge(s4).Len(), 14)
|
||||
gtest.Assert(a1.Merge(s5).Len(), 16)
|
||||
gtest.Assert(a1.Merge(s6).Len(), 19)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_Json(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []string{"a", "b", "d", "c"}
|
||||
s2 := []string{"a", "b", "c", "d"}
|
||||
a1 := garray.NewSortedStrArrayFrom(s1)
|
||||
b1, err1 := json.Marshal(a1)
|
||||
b2, err2 := json.Marshal(s1)
|
||||
gtest.Assert(b1, b2)
|
||||
gtest.Assert(err1, err2)
|
||||
|
||||
a2 := garray.NewSortedStrArray()
|
||||
err1 = json.Unmarshal(b2, &a2)
|
||||
gtest.Assert(a2.Slice(), s2)
|
||||
|
||||
var a3 garray.SortedStrArray
|
||||
err := json.Unmarshal(b2, &a3)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(a3.Slice(), s1)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
type User struct {
|
||||
Name string
|
||||
Scores *garray.SortedStrArray
|
||||
}
|
||||
data := g.Map{
|
||||
"Name": "john",
|
||||
"Scores": []string{"A+", "A", "A"},
|
||||
}
|
||||
b, err := json.Marshal(data)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
user := new(User)
|
||||
err = json.Unmarshal(b, user)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(user.Name, data["Name"])
|
||||
gtest.Assert(user.Scores, []string{"A", "A", "A+"})
|
||||
})
|
||||
}
|
||||
@ -9,8 +9,11 @@
|
||||
package glist
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"container/list"
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
|
||||
"github.com/gogf/gf/internal/rwmutex"
|
||||
)
|
||||
@ -32,6 +35,20 @@ func New(safe ...bool) *List {
|
||||
}
|
||||
}
|
||||
|
||||
// NewFrom creates and returns a list from a copy of given slice <array>.
|
||||
// The parameter <safe> used to specify whether using list in concurrent-safety,
|
||||
// which is false in default.
|
||||
func NewFrom(array []interface{}, safe ...bool) *List {
|
||||
l := list.New()
|
||||
for _, v := range array {
|
||||
l.PushBack(v)
|
||||
}
|
||||
return &List{
|
||||
mu: rwmutex.New(safe...),
|
||||
list: l,
|
||||
}
|
||||
}
|
||||
|
||||
// PushFront inserts a new element <e> with value <v> at the front of list <l> and returns <e>.
|
||||
func (l *List) PushFront(v interface{}) (e *Element) {
|
||||
l.mu.Lock()
|
||||
@ -275,7 +292,7 @@ func (l *List) PushFrontList(other *List) {
|
||||
// InsertAfter inserts a new element <e> with value <v> immediately after <p> and returns <e>.
|
||||
// If <p> is not an element of <l>, the list is not modified.
|
||||
// The <p> must not be nil.
|
||||
func (l *List) InsertAfter(v interface{}, p *Element) (e *Element) {
|
||||
func (l *List) InsertAfter(p *Element, v interface{}) (e *Element) {
|
||||
l.mu.Lock()
|
||||
e = l.list.InsertAfter(v, p)
|
||||
l.mu.Unlock()
|
||||
@ -285,7 +302,7 @@ func (l *List) InsertAfter(v interface{}, p *Element) (e *Element) {
|
||||
// InsertBefore inserts a new element <e> with value <v> immediately before <p> and returns <e>.
|
||||
// If <p> is not an element of <l>, the list is not modified.
|
||||
// The <p> must not be nil.
|
||||
func (l *List) InsertBefore(v interface{}, p *Element) (e *Element) {
|
||||
func (l *List) InsertBefore(p *Element, v interface{}) (e *Element) {
|
||||
l.mu.Lock()
|
||||
e = l.list.InsertBefore(v, p)
|
||||
l.mu.Unlock()
|
||||
@ -373,7 +390,51 @@ func (l *List) IteratorDesc(f func(e *Element) bool) {
|
||||
l.mu.RUnlock()
|
||||
}
|
||||
|
||||
// Join joins list elements with a string <glue>.
|
||||
func (l *List) Join(glue string) string {
|
||||
l.mu.RLock()
|
||||
defer l.mu.RUnlock()
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
length := l.list.Len()
|
||||
if length > 0 {
|
||||
s := ""
|
||||
for i, e := 0, l.list.Front(); i < length; i, e = i+1, e.Next() {
|
||||
s = gconv.String(e.Value)
|
||||
if gstr.IsNumeric(s) {
|
||||
buffer.WriteString(s)
|
||||
} else {
|
||||
buffer.WriteString(`"` + gstr.QuoteMeta(s, `"\`) + `"`)
|
||||
}
|
||||
if i != length-1 {
|
||||
buffer.WriteString(glue)
|
||||
}
|
||||
}
|
||||
}
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
// String returns current list as a string.
|
||||
func (l *List) String() string {
|
||||
return "[" + l.Join(",") + "]"
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
func (l *List) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(l.FrontAll())
|
||||
}
|
||||
|
||||
// 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{}
|
||||
if err := json.Unmarshal(b, &array); err != nil {
|
||||
return err
|
||||
}
|
||||
l.PushBacks(array)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ package glist
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/test/gtest"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
|
||||
@ -120,23 +120,23 @@ func TestList(t *testing.T) {
|
||||
l.MoveToBack(e3) // should be no-op
|
||||
checkListPointers(t, l, []*Element{e1, e4, e3})
|
||||
|
||||
e2 = l.InsertBefore(2, e1) // insert before front
|
||||
e2 = l.InsertBefore(e1, 2) // insert before front
|
||||
checkListPointers(t, l, []*Element{e2, e1, e4, e3})
|
||||
l.Remove(e2)
|
||||
e2 = l.InsertBefore(2, e4) // insert before middle
|
||||
e2 = l.InsertBefore(e4, 2) // insert before middle
|
||||
checkListPointers(t, l, []*Element{e1, e2, e4, e3})
|
||||
l.Remove(e2)
|
||||
e2 = l.InsertBefore(2, e3) // insert before back
|
||||
e2 = l.InsertBefore(e3, 2) // insert before back
|
||||
checkListPointers(t, l, []*Element{e1, e4, e2, e3})
|
||||
l.Remove(e2)
|
||||
|
||||
e2 = l.InsertAfter(2, e1) // insert after front
|
||||
e2 = l.InsertAfter(e1, 2) // insert after front
|
||||
checkListPointers(t, l, []*Element{e1, e2, e4, e3})
|
||||
l.Remove(e2)
|
||||
e2 = l.InsertAfter(2, e4) // insert after middle
|
||||
e2 = l.InsertAfter(e4, 2) // insert after middle
|
||||
checkListPointers(t, l, []*Element{e1, e4, e2, e3})
|
||||
l.Remove(e2)
|
||||
e2 = l.InsertAfter(2, e3) // insert after back
|
||||
e2 = l.InsertAfter(e3, 2) // insert after back
|
||||
checkListPointers(t, l, []*Element{e1, e4, e3, e2})
|
||||
l.Remove(e2)
|
||||
|
||||
@ -264,7 +264,7 @@ func TestIssue4103(t *testing.T) {
|
||||
t.Errorf("l2.Len() = %d, want 2", n)
|
||||
}
|
||||
|
||||
l1.InsertBefore(8, e)
|
||||
l1.InsertBefore(e, 8)
|
||||
if n := l1.Len(); n != 3 {
|
||||
t.Errorf("l1.Len() = %d, want 3", n)
|
||||
}
|
||||
@ -347,7 +347,7 @@ func TestInsertBeforeUnknownMark(t *testing.T) {
|
||||
l.PushBack(1)
|
||||
l.PushBack(2)
|
||||
l.PushBack(3)
|
||||
l.InsertBefore(1, new(Element))
|
||||
l.InsertBefore(new(Element), 1)
|
||||
checkList(t, l, []interface{}{1, 2, 3})
|
||||
}
|
||||
|
||||
@ -357,7 +357,7 @@ func TestInsertAfterUnknownMark(t *testing.T) {
|
||||
l.PushBack(1)
|
||||
l.PushBack(2)
|
||||
l.PushBack(3)
|
||||
l.InsertAfter(1, new(Element))
|
||||
l.InsertAfter(new(Element), 1)
|
||||
checkList(t, l, []interface{}{1, 2, 3})
|
||||
}
|
||||
|
||||
@ -583,3 +583,52 @@ func TestList_Iterator(t *testing.T) {
|
||||
l.Iterator(fun1)
|
||||
checkList(t, l, []interface{}{"e", "d", "c", "b", "a"})
|
||||
}
|
||||
|
||||
func TestList_Join(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
l := NewFrom([]interface{}{1, 2, "a", `"b"`, `\c`})
|
||||
gtest.Assert(l.Join(","), `1,2,"a","\"b\"","\\c"`)
|
||||
gtest.Assert(l.Join("."), `1.2."a"."\"b\""."\\c"`)
|
||||
})
|
||||
}
|
||||
|
||||
func TestList_String(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
l := NewFrom([]interface{}{1, 2, "a", `"b"`, `\c`})
|
||||
gtest.Assert(l.String(), `[1,2,"a","\"b\"","\\c"]`)
|
||||
})
|
||||
}
|
||||
|
||||
func TestList_Json(t *testing.T) {
|
||||
// Marshal
|
||||
gtest.Case(t, func() {
|
||||
a := []interface{}{"a", "b", "c"}
|
||||
l := New()
|
||||
l.PushBacks(a)
|
||||
b1, err1 := json.Marshal(l)
|
||||
b2, err2 := json.Marshal(a)
|
||||
gtest.Assert(err1, err2)
|
||||
gtest.Assert(b1, b2)
|
||||
})
|
||||
// Unmarshal
|
||||
gtest.Case(t, func() {
|
||||
a := []interface{}{"a", "b", "c"}
|
||||
l := New()
|
||||
b, err := json.Marshal(a)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
err = json.Unmarshal(b, l)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(l.FrontAll(), a)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
var l List
|
||||
a := []interface{}{"a", "b", "c"}
|
||||
b, err := json.Marshal(a)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
err = json.Unmarshal(b, &l)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(l.FrontAll(), a)
|
||||
})
|
||||
}
|
||||
|
||||
@ -9,6 +9,8 @@ package gmap
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/gogf/gf/internal/empty"
|
||||
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
|
||||
"github.com/gogf/gf/container/gvar"
|
||||
@ -54,17 +56,33 @@ func (m *AnyAnyMap) Iterator(f func(k interface{}, v interface{}) bool) {
|
||||
|
||||
// Clone returns a new hash map with copy of current map data.
|
||||
func (m *AnyAnyMap) Clone(safe ...bool) *AnyAnyMap {
|
||||
return NewFrom(m.Map(), safe...)
|
||||
return NewFrom(m.MapCopy(), safe...)
|
||||
}
|
||||
|
||||
// Map returns a copy of the data of the hash map.
|
||||
// Map returns the underlying data map.
|
||||
// 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 (m *AnyAnyMap) Map() map[interface{}]interface{} {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
if !m.mu.IsSafe() {
|
||||
return m.data
|
||||
}
|
||||
data := make(map[interface{}]interface{}, len(m.data))
|
||||
for k, v := range m.data {
|
||||
data[k] = v
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// MapCopy returns a copy of the data of the hash map.
|
||||
func (m *AnyAnyMap) MapCopy() map[interface{}]interface{} {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
data := make(map[interface{}]interface{}, len(m.data))
|
||||
for k, v := range m.data {
|
||||
data[k] = v
|
||||
}
|
||||
m.mu.RUnlock()
|
||||
return data
|
||||
}
|
||||
|
||||
@ -79,6 +97,17 @@ func (m *AnyAnyMap) MapStrAny() map[string]interface{} {
|
||||
return data
|
||||
}
|
||||
|
||||
// FilterEmpty deletes all key-value pair of which the value is empty.
|
||||
func (m *AnyAnyMap) FilterEmpty() {
|
||||
m.mu.Lock()
|
||||
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{}) {
|
||||
m.mu.Lock()
|
||||
@ -348,3 +377,21 @@ func (m *AnyAnyMap) Merge(other *AnyAnyMap) {
|
||||
func (m *AnyAnyMap) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(gconv.Map(m.Map()))
|
||||
}
|
||||
|
||||
// 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()
|
||||
var data map[string]interface{}
|
||||
if err := json.Unmarshal(b, &data); err != nil {
|
||||
return err
|
||||
}
|
||||
for k, v := range data {
|
||||
m.data[k] = v
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -10,6 +10,8 @@ package gmap
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/gogf/gf/internal/empty"
|
||||
|
||||
"github.com/gogf/gf/container/gvar"
|
||||
"github.com/gogf/gf/internal/rwmutex"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
@ -54,20 +56,58 @@ func (m *IntAnyMap) Iterator(f func(k int, v interface{}) bool) {
|
||||
|
||||
// Clone returns a new hash map with copy of current map data.
|
||||
func (m *IntAnyMap) Clone() *IntAnyMap {
|
||||
return NewIntAnyMapFrom(m.Map(), !m.mu.IsSafe())
|
||||
return NewIntAnyMapFrom(m.MapCopy(), !m.mu.IsSafe())
|
||||
}
|
||||
|
||||
// Map returns a copy of the data of the hash map.
|
||||
// Map returns the underlying data map.
|
||||
// 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 (m *IntAnyMap) Map() map[int]interface{} {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
if !m.mu.IsSafe() {
|
||||
return m.data
|
||||
}
|
||||
data := make(map[int]interface{}, len(m.data))
|
||||
for k, v := range m.data {
|
||||
data[k] = v
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// MapStrAny returns a copy of the data of the map as map[string]interface{}.
|
||||
func (m *IntAnyMap) MapStrAny() map[string]interface{} {
|
||||
m.mu.RLock()
|
||||
data := make(map[string]interface{}, len(m.data))
|
||||
for k, v := range m.data {
|
||||
data[gconv.String(k)] = v
|
||||
}
|
||||
m.mu.RUnlock()
|
||||
return data
|
||||
}
|
||||
|
||||
// MapCopy returns a copy of the data of the hash map.
|
||||
func (m *IntAnyMap) MapCopy() map[int]interface{} {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
data := make(map[int]interface{}, len(m.data))
|
||||
for k, v := range m.data {
|
||||
data[k] = v
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// FilterEmpty deletes all key-value pair of which the value is empty.
|
||||
func (m *IntAnyMap) FilterEmpty() {
|
||||
m.mu.Lock()
|
||||
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 *IntAnyMap) Set(key int, val interface{}) {
|
||||
m.mu.Lock()
|
||||
@ -339,3 +379,17 @@ func (m *IntAnyMap) MarshalJSON() ([]byte, error) {
|
||||
defer m.mu.RUnlock()
|
||||
return json.Marshal(m.data)
|
||||
}
|
||||
|
||||
// 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 err := json.Unmarshal(b, &m.data); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -8,6 +8,9 @@ package gmap
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
|
||||
"github.com/gogf/gf/internal/empty"
|
||||
|
||||
"github.com/gogf/gf/internal/rwmutex"
|
||||
)
|
||||
@ -51,20 +54,58 @@ func (m *IntIntMap) Iterator(f func(k int, v int) bool) {
|
||||
|
||||
// Clone returns a new hash map with copy of current map data.
|
||||
func (m *IntIntMap) Clone() *IntIntMap {
|
||||
return NewIntIntMapFrom(m.Map(), !m.mu.IsSafe())
|
||||
return NewIntIntMapFrom(m.MapCopy(), !m.mu.IsSafe())
|
||||
}
|
||||
|
||||
// Map returns a copy of the data of the hash map.
|
||||
// Map returns the underlying data map.
|
||||
// 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 (m *IntIntMap) Map() map[int]int {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
if !m.mu.IsSafe() {
|
||||
return m.data
|
||||
}
|
||||
data := make(map[int]int, len(m.data))
|
||||
for k, v := range m.data {
|
||||
data[k] = v
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// MapStrAny returns a copy of the data of the map as map[string]interface{}.
|
||||
func (m *IntIntMap) MapStrAny() map[string]interface{} {
|
||||
m.mu.RLock()
|
||||
data := make(map[string]interface{}, len(m.data))
|
||||
for k, v := range m.data {
|
||||
data[gconv.String(k)] = v
|
||||
}
|
||||
m.mu.RUnlock()
|
||||
return data
|
||||
}
|
||||
|
||||
// MapCopy returns a copy of the data of the hash map.
|
||||
func (m *IntIntMap) MapCopy() map[int]int {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
data := make(map[int]int, len(m.data))
|
||||
for k, v := range m.data {
|
||||
data[k] = v
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// FilterEmpty deletes all key-value pair of which the value is empty.
|
||||
func (m *IntIntMap) FilterEmpty() {
|
||||
m.mu.Lock()
|
||||
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 *IntIntMap) Set(key int, val int) {
|
||||
m.mu.Lock()
|
||||
@ -315,3 +356,17 @@ func (m *IntIntMap) MarshalJSON() ([]byte, error) {
|
||||
defer m.mu.RUnlock()
|
||||
return json.Marshal(m.data)
|
||||
}
|
||||
|
||||
// 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 err := json.Unmarshal(b, &m.data); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -9,6 +9,8 @@ package gmap
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/gogf/gf/internal/empty"
|
||||
|
||||
"github.com/gogf/gf/internal/rwmutex"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
)
|
||||
@ -52,20 +54,58 @@ func (m *IntStrMap) Iterator(f func(k int, v string) bool) {
|
||||
|
||||
// Clone returns a new hash map with copy of current map data.
|
||||
func (m *IntStrMap) Clone() *IntStrMap {
|
||||
return NewIntStrMapFrom(m.Map(), !m.mu.IsSafe())
|
||||
return NewIntStrMapFrom(m.MapCopy(), !m.mu.IsSafe())
|
||||
}
|
||||
|
||||
// Map returns a copy of the data of the hash map.
|
||||
// Map returns the underlying data map.
|
||||
// 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 (m *IntStrMap) Map() map[int]string {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
if !m.mu.IsSafe() {
|
||||
return m.data
|
||||
}
|
||||
data := make(map[int]string, len(m.data))
|
||||
for k, v := range m.data {
|
||||
data[k] = v
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// MapStrAny returns a copy of the data of the map as map[string]interface{}.
|
||||
func (m *IntStrMap) MapStrAny() map[string]interface{} {
|
||||
m.mu.RLock()
|
||||
data := make(map[string]interface{}, len(m.data))
|
||||
for k, v := range m.data {
|
||||
data[gconv.String(k)] = v
|
||||
}
|
||||
m.mu.RUnlock()
|
||||
return data
|
||||
}
|
||||
|
||||
// MapCopy returns a copy of the data of the hash map.
|
||||
func (m *IntStrMap) MapCopy() map[int]string {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
data := make(map[int]string, len(m.data))
|
||||
for k, v := range m.data {
|
||||
data[k] = v
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// FilterEmpty deletes all key-value pair of which the value is empty.
|
||||
func (m *IntStrMap) FilterEmpty() {
|
||||
m.mu.Lock()
|
||||
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 *IntStrMap) Set(key int, val string) {
|
||||
m.mu.Lock()
|
||||
@ -316,3 +356,17 @@ func (m *IntStrMap) MarshalJSON() ([]byte, error) {
|
||||
defer m.mu.RUnlock()
|
||||
return json.Marshal(m.data)
|
||||
}
|
||||
|
||||
// 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 err := json.Unmarshal(b, &m.data); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -10,6 +10,8 @@ package gmap
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/gogf/gf/internal/empty"
|
||||
|
||||
"github.com/gogf/gf/container/gvar"
|
||||
"github.com/gogf/gf/internal/rwmutex"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
@ -54,20 +56,52 @@ func (m *StrAnyMap) Iterator(f func(k string, v interface{}) bool) {
|
||||
|
||||
// Clone returns a new hash map with copy of current map data.
|
||||
func (m *StrAnyMap) Clone() *StrAnyMap {
|
||||
return NewStrAnyMapFrom(m.Map(), !m.mu.IsSafe())
|
||||
return NewStrAnyMapFrom(m.MapCopy(), !m.mu.IsSafe())
|
||||
}
|
||||
|
||||
// Map returns a copy of the data of the hash map.
|
||||
// Map returns the underlying data map.
|
||||
// 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 (m *StrAnyMap) Map() map[string]interface{} {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
if !m.mu.IsSafe() {
|
||||
return m.data
|
||||
}
|
||||
data := make(map[string]interface{}, len(m.data))
|
||||
for k, v := range m.data {
|
||||
data[k] = v
|
||||
}
|
||||
m.mu.RUnlock()
|
||||
return data
|
||||
}
|
||||
|
||||
// MapStrAny returns a copy of the data of the map as map[string]interface{}.
|
||||
func (m *StrAnyMap) MapStrAny() map[string]interface{} {
|
||||
return m.Map()
|
||||
}
|
||||
|
||||
// MapCopy returns a copy of the data of the hash map.
|
||||
func (m *StrAnyMap) MapCopy() 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
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// FilterEmpty deletes all key-value pair of which the value is empty.
|
||||
func (m *StrAnyMap) FilterEmpty() {
|
||||
m.mu.Lock()
|
||||
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 *StrAnyMap) Set(key string, val interface{}) {
|
||||
m.mu.Lock()
|
||||
@ -341,3 +375,17 @@ func (m *StrAnyMap) MarshalJSON() ([]byte, error) {
|
||||
defer m.mu.RUnlock()
|
||||
return json.Marshal(m.data)
|
||||
}
|
||||
|
||||
// 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 err := json.Unmarshal(b, &m.data); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ package gmap
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/gogf/gf/internal/empty"
|
||||
"github.com/gogf/gf/internal/rwmutex"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
)
|
||||
@ -53,20 +54,58 @@ func (m *StrIntMap) Iterator(f func(k string, v int) bool) {
|
||||
|
||||
// Clone returns a new hash map with copy of current map data.
|
||||
func (m *StrIntMap) Clone() *StrIntMap {
|
||||
return NewStrIntMapFrom(m.Map(), !m.mu.IsSafe())
|
||||
return NewStrIntMapFrom(m.MapCopy(), !m.mu.IsSafe())
|
||||
}
|
||||
|
||||
// Map returns a copy of the data of the hash map.
|
||||
// Map returns the underlying data map.
|
||||
// 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 (m *StrIntMap) Map() map[string]int {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
if !m.mu.IsSafe() {
|
||||
return m.data
|
||||
}
|
||||
data := make(map[string]int, len(m.data))
|
||||
for k, v := range m.data {
|
||||
data[k] = v
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// MapStrAny returns a copy of the data of the map as map[string]interface{}.
|
||||
func (m *StrIntMap) MapStrAny() map[string]interface{} {
|
||||
m.mu.RLock()
|
||||
data := make(map[string]interface{}, len(m.data))
|
||||
for k, v := range m.data {
|
||||
data[k] = v
|
||||
}
|
||||
m.mu.RUnlock()
|
||||
return data
|
||||
}
|
||||
|
||||
// MapCopy returns a copy of the data of the hash map.
|
||||
func (m *StrIntMap) MapCopy() map[string]int {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
data := make(map[string]int, len(m.data))
|
||||
for k, v := range m.data {
|
||||
data[k] = v
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// FilterEmpty deletes all key-value pair of which the value is empty.
|
||||
func (m *StrIntMap) FilterEmpty() {
|
||||
m.mu.Lock()
|
||||
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 *StrIntMap) Set(key string, val int) {
|
||||
m.mu.Lock()
|
||||
@ -319,3 +358,17 @@ func (m *StrIntMap) MarshalJSON() ([]byte, error) {
|
||||
defer m.mu.RUnlock()
|
||||
return json.Marshal(m.data)
|
||||
}
|
||||
|
||||
// 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 err := json.Unmarshal(b, &m.data); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -10,6 +10,8 @@ package gmap
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/gogf/gf/internal/empty"
|
||||
|
||||
"github.com/gogf/gf/internal/rwmutex"
|
||||
)
|
||||
|
||||
@ -52,20 +54,58 @@ func (m *StrStrMap) Iterator(f func(k string, v string) bool) {
|
||||
|
||||
// Clone returns a new hash map with copy of current map data.
|
||||
func (m *StrStrMap) Clone() *StrStrMap {
|
||||
return NewStrStrMapFrom(m.Map(), !m.mu.IsSafe())
|
||||
return NewStrStrMapFrom(m.MapCopy(), !m.mu.IsSafe())
|
||||
}
|
||||
|
||||
// Map returns a copy of the data of the hash map.
|
||||
// Map returns the underlying data map.
|
||||
// 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 (m *StrStrMap) Map() map[string]string {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
if !m.mu.IsSafe() {
|
||||
return m.data
|
||||
}
|
||||
data := make(map[string]string, len(m.data))
|
||||
for k, v := range m.data {
|
||||
data[k] = v
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// MapStrAny returns a copy of the data of the map as map[string]interface{}.
|
||||
func (m *StrStrMap) MapStrAny() map[string]interface{} {
|
||||
m.mu.RLock()
|
||||
data := make(map[string]interface{}, len(m.data))
|
||||
for k, v := range m.data {
|
||||
data[k] = v
|
||||
}
|
||||
m.mu.RUnlock()
|
||||
return data
|
||||
}
|
||||
|
||||
// MapCopy returns a copy of the data of the hash map.
|
||||
func (m *StrStrMap) MapCopy() map[string]string {
|
||||
m.mu.RLock()
|
||||
defer m.mu.RUnlock()
|
||||
data := make(map[string]string, len(m.data))
|
||||
for k, v := range m.data {
|
||||
data[k] = v
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// FilterEmpty deletes all key-value pair of which the value is empty.
|
||||
func (m *StrStrMap) FilterEmpty() {
|
||||
m.mu.Lock()
|
||||
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 *StrStrMap) Set(key string, val string) {
|
||||
m.mu.Lock()
|
||||
@ -318,3 +358,17 @@ func (m *StrStrMap) MarshalJSON() ([]byte, error) {
|
||||
defer m.mu.RUnlock()
|
||||
return json.Marshal(m.data)
|
||||
}
|
||||
|
||||
// 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 err := json.Unmarshal(b, &m.data); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -9,6 +9,8 @@ package gmap
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/gogf/gf/internal/empty"
|
||||
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
|
||||
"github.com/gogf/gf/container/glist"
|
||||
@ -118,6 +120,29 @@ func (m *ListMap) MapStrAny() map[string]interface{} {
|
||||
return data
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
// Set sets key-value to the map.
|
||||
func (m *ListMap) Set(key interface{}, value interface{}) {
|
||||
m.mu.Lock()
|
||||
@ -387,3 +412,26 @@ func (m *ListMap) Merge(other *ListMap) {
|
||||
func (m *ListMap) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(gconv.Map(m.Map()))
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
|
||||
func (m *ListMap) UnmarshalJSON(b []byte) error {
|
||||
if m.mu == nil {
|
||||
m.mu = rwmutex.New()
|
||||
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
|
||||
}
|
||||
for key, value := range data {
|
||||
if e, ok := m.data[key]; !ok {
|
||||
m.data[key] = m.list.PushBack(&gListMapNode{key, value})
|
||||
} else {
|
||||
e.Value = &gListMapNode{key, value}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
223
container/gmap/gmap_z_unit_any_any_test.go
Normal file
223
container/gmap/gmap_z_unit_any_any_test.go
Normal file
@ -0,0 +1,223 @@
|
||||
// Copyright 2017-2019 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 gm file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gmap_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/container/gmap"
|
||||
"github.com/gogf/gf/test/gtest"
|
||||
)
|
||||
|
||||
func anyAnyCallBack(int, interface{}) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func Test_AnyAnyMap_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
m := gmap.NewAnyAnyMap()
|
||||
m.Set(1, 1)
|
||||
|
||||
gtest.Assert(m.Get(1), 1)
|
||||
gtest.Assert(m.Size(), 1)
|
||||
gtest.Assert(m.IsEmpty(), false)
|
||||
|
||||
gtest.Assert(m.GetOrSet(2, "2"), "2")
|
||||
gtest.Assert(m.SetIfNotExist(2, "2"), false)
|
||||
|
||||
gtest.Assert(m.SetIfNotExist(3, 3), true)
|
||||
|
||||
gtest.Assert(m.Remove(2), "2")
|
||||
gtest.Assert(m.Contains(2), false)
|
||||
|
||||
gtest.AssertIN(3, m.Keys())
|
||||
gtest.AssertIN(1, m.Keys())
|
||||
gtest.AssertIN(3, m.Values())
|
||||
gtest.AssertIN(1, m.Values())
|
||||
m.Flip()
|
||||
gtest.Assert(m.Map(), map[interface{}]int{1: 1, 3: 3})
|
||||
|
||||
m.Clear()
|
||||
gtest.Assert(m.Size(), 0)
|
||||
gtest.Assert(m.IsEmpty(), true)
|
||||
|
||||
m2 := gmap.NewAnyAnyMapFrom(map[interface{}]interface{}{1: 1, 2: "2"})
|
||||
gtest.Assert(m2.Map(), map[interface{}]interface{}{1: 1, 2: "2"})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_AnyAnyMap_Set_Fun(t *testing.T) {
|
||||
m := gmap.NewAnyAnyMap()
|
||||
|
||||
m.GetOrSetFunc(1, getAny)
|
||||
m.GetOrSetFuncLock(2, getAny)
|
||||
gtest.Assert(m.Get(1), 123)
|
||||
gtest.Assert(m.Get(2), 123)
|
||||
|
||||
gtest.Assert(m.SetIfNotExistFunc(1, getAny), false)
|
||||
gtest.Assert(m.SetIfNotExistFunc(3, getAny), true)
|
||||
|
||||
gtest.Assert(m.SetIfNotExistFuncLock(2, getAny), false)
|
||||
gtest.Assert(m.SetIfNotExistFuncLock(4, getAny), true)
|
||||
|
||||
}
|
||||
|
||||
func Test_AnyAnyMap_Batch(t *testing.T) {
|
||||
m := gmap.NewAnyAnyMap()
|
||||
|
||||
m.Sets(map[interface{}]interface{}{1: 1, 2: "2", 3: 3})
|
||||
gtest.Assert(m.Map(), map[interface{}]interface{}{1: 1, 2: "2", 3: 3})
|
||||
m.Removes([]interface{}{1, 2})
|
||||
gtest.Assert(m.Map(), map[interface{}]interface{}{3: 3})
|
||||
}
|
||||
|
||||
func Test_AnyAnyMap_Iterator(t *testing.T) {
|
||||
expect := map[interface{}]interface{}{1: 1, 2: "2"}
|
||||
m := gmap.NewAnyAnyMapFrom(expect)
|
||||
m.Iterator(func(k interface{}, v interface{}) bool {
|
||||
gtest.Assert(expect[k], v)
|
||||
return true
|
||||
})
|
||||
// 断言返回值对遍历控制
|
||||
i := 0
|
||||
j := 0
|
||||
m.Iterator(func(k interface{}, v interface{}) bool {
|
||||
i++
|
||||
return true
|
||||
})
|
||||
m.Iterator(func(k interface{}, v interface{}) bool {
|
||||
j++
|
||||
return false
|
||||
})
|
||||
gtest.Assert(i, "2")
|
||||
gtest.Assert(j, 1)
|
||||
|
||||
}
|
||||
|
||||
func Test_AnyAnyMap_Lock(t *testing.T) {
|
||||
expect := map[interface{}]interface{}{1: 1, 2: "2"}
|
||||
m := gmap.NewAnyAnyMapFrom(expect)
|
||||
m.LockFunc(func(m map[interface{}]interface{}) {
|
||||
gtest.Assert(m, expect)
|
||||
})
|
||||
m.RLockFunc(func(m map[interface{}]interface{}) {
|
||||
gtest.Assert(m, expect)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_AnyAnyMap_Clone(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
//clone 方法是深克隆
|
||||
m := gmap.NewAnyAnyMapFrom(map[interface{}]interface{}{1: 1, 2: "2"})
|
||||
|
||||
m_clone := m.Clone()
|
||||
m.Remove(1)
|
||||
//修改原 map,clone 后的 map 不影响
|
||||
gtest.AssertIN(1, m_clone.Keys())
|
||||
|
||||
m_clone.Remove(2)
|
||||
//修改clone map,原 map 不影响
|
||||
gtest.AssertIN(2, m.Keys())
|
||||
})
|
||||
}
|
||||
|
||||
func Test_AnyAnyMap_Merge(t *testing.T) {
|
||||
m1 := gmap.NewAnyAnyMap()
|
||||
m2 := gmap.NewAnyAnyMap()
|
||||
m1.Set(1, 1)
|
||||
m2.Set(2, "2")
|
||||
m1.Merge(m2)
|
||||
gtest.Assert(m1.Map(), map[interface{}]interface{}{1: 1, 2: "2"})
|
||||
}
|
||||
|
||||
func Test_AnyAnyMap_Map(t *testing.T) {
|
||||
m := gmap.NewAnyAnyMap()
|
||||
m.Set(1, 0)
|
||||
m.Set(2, 2)
|
||||
gtest.Assert(m.Get(1), 0)
|
||||
gtest.Assert(m.Get(2), 2)
|
||||
data := m.Map()
|
||||
gtest.Assert(data[1], 0)
|
||||
gtest.Assert(data[2], 2)
|
||||
data[3] = 3
|
||||
gtest.Assert(m.Get(3), 3)
|
||||
m.Set(4, 4)
|
||||
gtest.Assert(data[4], 4)
|
||||
}
|
||||
|
||||
func Test_AnyAnyMap_MapCopy(t *testing.T) {
|
||||
m := gmap.NewAnyAnyMap()
|
||||
m.Set(1, 0)
|
||||
m.Set(2, 2)
|
||||
gtest.Assert(m.Get(1), 0)
|
||||
gtest.Assert(m.Get(2), 2)
|
||||
data := m.MapCopy()
|
||||
gtest.Assert(data[1], 0)
|
||||
gtest.Assert(data[2], 2)
|
||||
data[3] = 3
|
||||
gtest.Assert(m.Get(3), nil)
|
||||
m.Set(4, 4)
|
||||
gtest.Assert(data[4], nil)
|
||||
}
|
||||
|
||||
func Test_AnyAnyMap_FilterEmpty(t *testing.T) {
|
||||
m := gmap.NewAnyAnyMap()
|
||||
m.Set(1, 0)
|
||||
m.Set(2, 2)
|
||||
gtest.Assert(m.Get(1), 0)
|
||||
gtest.Assert(m.Get(2), 2)
|
||||
m.FilterEmpty()
|
||||
gtest.Assert(m.Get(1), nil)
|
||||
gtest.Assert(m.Get(2), 2)
|
||||
}
|
||||
|
||||
func Test_AnyAnyMap_Json(t *testing.T) {
|
||||
// Marshal
|
||||
gtest.Case(t, func() {
|
||||
data := g.MapAnyAny{
|
||||
"k1": "v1",
|
||||
"k2": "v2",
|
||||
}
|
||||
m1 := gmap.NewAnyAnyMapFrom(data)
|
||||
b1, err1 := json.Marshal(m1)
|
||||
b2, err2 := json.Marshal(gconv.Map(data))
|
||||
gtest.Assert(err1, err2)
|
||||
gtest.Assert(b1, b2)
|
||||
})
|
||||
// Unmarshal
|
||||
gtest.Case(t, func() {
|
||||
data := g.MapAnyAny{
|
||||
"k1": "v1",
|
||||
"k2": "v2",
|
||||
}
|
||||
b, err := json.Marshal(gconv.Map(data))
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
m := gmap.New()
|
||||
err = json.Unmarshal(b, m)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(m.Get("k1"), data["k1"])
|
||||
gtest.Assert(m.Get("k2"), data["k2"])
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
data := g.MapAnyAny{
|
||||
"k1": "v1",
|
||||
"k2": "v2",
|
||||
}
|
||||
b, err := json.Marshal(gconv.Map(data))
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
var m gmap.Map
|
||||
err = json.Unmarshal(b, &m)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(m.Get("k1"), data["k1"])
|
||||
gtest.Assert(m.Get("k2"), data["k2"])
|
||||
})
|
||||
}
|
||||
@ -7,6 +7,8 @@
|
||||
package gmap_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/container/gmap"
|
||||
@ -129,3 +131,75 @@ func Test_IntAnyMap_Merge(t *testing.T) {
|
||||
m1.Merge(m2)
|
||||
gtest.Assert(m1.Map(), map[int]interface{}{1: 1, 2: "2"})
|
||||
}
|
||||
|
||||
func Test_IntAnyMap_Map(t *testing.T) {
|
||||
m := gmap.NewIntAnyMap()
|
||||
m.Set(1, 0)
|
||||
m.Set(2, 2)
|
||||
gtest.Assert(m.Get(1), 0)
|
||||
gtest.Assert(m.Get(2), 2)
|
||||
data := m.Map()
|
||||
gtest.Assert(data[1], 0)
|
||||
gtest.Assert(data[2], 2)
|
||||
data[3] = 3
|
||||
gtest.Assert(m.Get(3), 3)
|
||||
m.Set(4, 4)
|
||||
gtest.Assert(data[4], 4)
|
||||
}
|
||||
|
||||
func Test_IntAnyMap_MapCopy(t *testing.T) {
|
||||
m := gmap.NewIntAnyMap()
|
||||
m.Set(1, 0)
|
||||
m.Set(2, 2)
|
||||
gtest.Assert(m.Get(1), 0)
|
||||
gtest.Assert(m.Get(2), 2)
|
||||
data := m.MapCopy()
|
||||
gtest.Assert(data[1], 0)
|
||||
gtest.Assert(data[2], 2)
|
||||
data[3] = 3
|
||||
gtest.Assert(m.Get(3), nil)
|
||||
m.Set(4, 4)
|
||||
gtest.Assert(data[4], nil)
|
||||
}
|
||||
|
||||
func Test_IntAnyMap_FilterEmpty(t *testing.T) {
|
||||
m := gmap.NewIntAnyMap()
|
||||
m.Set(1, 0)
|
||||
m.Set(2, 2)
|
||||
gtest.Assert(m.Size(), 2)
|
||||
gtest.Assert(m.Get(1), 0)
|
||||
gtest.Assert(m.Get(2), 2)
|
||||
m.FilterEmpty()
|
||||
gtest.Assert(m.Size(), 1)
|
||||
gtest.Assert(m.Get(2), 2)
|
||||
}
|
||||
|
||||
func Test_IntAnyMap_Json(t *testing.T) {
|
||||
// Marshal
|
||||
gtest.Case(t, func() {
|
||||
data := g.MapIntAny{
|
||||
1: "v1",
|
||||
2: "v2",
|
||||
}
|
||||
m1 := gmap.NewIntAnyMapFrom(data)
|
||||
b1, err1 := json.Marshal(m1)
|
||||
b2, err2 := json.Marshal(data)
|
||||
gtest.Assert(err1, err2)
|
||||
gtest.Assert(b1, b2)
|
||||
})
|
||||
// Unmarshal
|
||||
gtest.Case(t, func() {
|
||||
data := g.MapIntAny{
|
||||
1: "v1",
|
||||
2: "v2",
|
||||
}
|
||||
b, err := json.Marshal(data)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
m := gmap.NewIntAnyMap()
|
||||
err = json.Unmarshal(b, m)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(m.Get(1), data[1])
|
||||
gtest.Assert(m.Get(2), data[2])
|
||||
})
|
||||
}
|
||||
@ -7,6 +7,8 @@
|
||||
package gmap_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/container/gmap"
|
||||
@ -109,6 +111,7 @@ func Test_IntIntMap_Lock(t *testing.T) {
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func Test_IntIntMap_Clone(t *testing.T) {
|
||||
//clone 方法是深克隆
|
||||
m := gmap.NewIntIntMapFrom(map[int]int{1: 1, 2: 2})
|
||||
@ -122,6 +125,7 @@ func Test_IntIntMap_Clone(t *testing.T) {
|
||||
//修改clone map,原 map 不影响
|
||||
gtest.AssertIN(2, m.Keys())
|
||||
}
|
||||
|
||||
func Test_IntIntMap_Merge(t *testing.T) {
|
||||
m1 := gmap.NewIntIntMap()
|
||||
m2 := gmap.NewIntIntMap()
|
||||
@ -130,3 +134,75 @@ func Test_IntIntMap_Merge(t *testing.T) {
|
||||
m1.Merge(m2)
|
||||
gtest.Assert(m1.Map(), map[int]int{1: 1, 2: 2})
|
||||
}
|
||||
|
||||
func Test_IntIntMap_Map(t *testing.T) {
|
||||
m := gmap.NewIntIntMap()
|
||||
m.Set(1, 0)
|
||||
m.Set(2, 2)
|
||||
gtest.Assert(m.Get(1), 0)
|
||||
gtest.Assert(m.Get(2), 2)
|
||||
data := m.Map()
|
||||
gtest.Assert(data[1], 0)
|
||||
gtest.Assert(data[2], 2)
|
||||
data[3] = 3
|
||||
gtest.Assert(m.Get(3), 3)
|
||||
m.Set(4, 4)
|
||||
gtest.Assert(data[4], 4)
|
||||
}
|
||||
|
||||
func Test_IntIntMap_MapCopy(t *testing.T) {
|
||||
m := gmap.NewIntIntMap()
|
||||
m.Set(1, 0)
|
||||
m.Set(2, 2)
|
||||
gtest.Assert(m.Get(1), 0)
|
||||
gtest.Assert(m.Get(2), 2)
|
||||
data := m.MapCopy()
|
||||
gtest.Assert(data[1], 0)
|
||||
gtest.Assert(data[2], 2)
|
||||
data[3] = 3
|
||||
gtest.Assert(m.Get(3), 0)
|
||||
m.Set(4, 4)
|
||||
gtest.Assert(data[4], 0)
|
||||
}
|
||||
|
||||
func Test_IntIntMap_FilterEmpty(t *testing.T) {
|
||||
m := gmap.NewIntIntMap()
|
||||
m.Set(1, 0)
|
||||
m.Set(2, 2)
|
||||
gtest.Assert(m.Size(), 2)
|
||||
gtest.Assert(m.Get(1), 0)
|
||||
gtest.Assert(m.Get(2), 2)
|
||||
m.FilterEmpty()
|
||||
gtest.Assert(m.Size(), 1)
|
||||
gtest.Assert(m.Get(2), 2)
|
||||
}
|
||||
|
||||
func Test_IntIntMap_Json(t *testing.T) {
|
||||
// Marshal
|
||||
gtest.Case(t, func() {
|
||||
data := g.MapIntInt{
|
||||
1: 10,
|
||||
2: 20,
|
||||
}
|
||||
m1 := gmap.NewIntIntMapFrom(data)
|
||||
b1, err1 := json.Marshal(m1)
|
||||
b2, err2 := json.Marshal(data)
|
||||
gtest.Assert(err1, err2)
|
||||
gtest.Assert(b1, b2)
|
||||
})
|
||||
// Unmarshal
|
||||
gtest.Case(t, func() {
|
||||
data := g.MapIntInt{
|
||||
1: 10,
|
||||
2: 20,
|
||||
}
|
||||
b, err := json.Marshal(data)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
m := gmap.NewIntIntMap()
|
||||
err = json.Unmarshal(b, m)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(m.Get(1), data[1])
|
||||
gtest.Assert(m.Get(2), data[2])
|
||||
})
|
||||
}
|
||||
@ -7,6 +7,8 @@
|
||||
package gmap_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/container/gmap"
|
||||
@ -134,3 +136,74 @@ func Test_IntStrMap_Merge(t *testing.T) {
|
||||
m1.Merge(m2)
|
||||
gtest.Assert(m1.Map(), map[int]string{1: "a", 2: "b"})
|
||||
}
|
||||
|
||||
func Test_IntStrMap_Map(t *testing.T) {
|
||||
m := gmap.NewIntStrMap()
|
||||
m.Set(1, "0")
|
||||
m.Set(2, "2")
|
||||
gtest.Assert(m.Get(1), "0")
|
||||
gtest.Assert(m.Get(2), "2")
|
||||
data := m.Map()
|
||||
gtest.Assert(data[1], "0")
|
||||
gtest.Assert(data[2], "2")
|
||||
data[3] = "3"
|
||||
gtest.Assert(m.Get(3), "3")
|
||||
m.Set(4, "4")
|
||||
gtest.Assert(data[4], "4")
|
||||
}
|
||||
|
||||
func Test_IntStrMap_MapCopy(t *testing.T) {
|
||||
m := gmap.NewIntStrMap()
|
||||
m.Set(1, "0")
|
||||
m.Set(2, "2")
|
||||
gtest.Assert(m.Get(1), "0")
|
||||
gtest.Assert(m.Get(2), "2")
|
||||
data := m.MapCopy()
|
||||
gtest.Assert(data[1], "0")
|
||||
gtest.Assert(data[2], "2")
|
||||
data[3] = "3"
|
||||
gtest.Assert(m.Get(3), "")
|
||||
m.Set(4, "4")
|
||||
gtest.Assert(data[4], "")
|
||||
}
|
||||
|
||||
func Test_IntStrMap_FilterEmpty(t *testing.T) {
|
||||
m := gmap.NewIntStrMap()
|
||||
m.Set(1, "")
|
||||
m.Set(2, "2")
|
||||
gtest.Assert(m.Size(), 2)
|
||||
gtest.Assert(m.Get(2), "2")
|
||||
m.FilterEmpty()
|
||||
gtest.Assert(m.Size(), 1)
|
||||
gtest.Assert(m.Get(2), "2")
|
||||
}
|
||||
|
||||
func Test_IntStrMap_Json(t *testing.T) {
|
||||
// Marshal
|
||||
gtest.Case(t, func() {
|
||||
data := g.MapIntStr{
|
||||
1: "v1",
|
||||
2: "v2",
|
||||
}
|
||||
m1 := gmap.NewIntStrMapFrom(data)
|
||||
b1, err1 := json.Marshal(m1)
|
||||
b2, err2 := json.Marshal(data)
|
||||
gtest.Assert(err1, err2)
|
||||
gtest.Assert(b1, b2)
|
||||
})
|
||||
// Unmarshal
|
||||
gtest.Case(t, func() {
|
||||
data := g.MapIntStr{
|
||||
1: "v1",
|
||||
2: "v2",
|
||||
}
|
||||
b, err := json.Marshal(data)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
m := gmap.NewIntStrMap()
|
||||
err = json.Unmarshal(b, m)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(m.Get(1), data[1])
|
||||
gtest.Assert(m.Get(2), data[2])
|
||||
})
|
||||
}
|
||||
@ -7,6 +7,8 @@
|
||||
package gmap_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/container/gmap"
|
||||
@ -14,7 +16,7 @@ import (
|
||||
"github.com/gogf/gf/test/gtest"
|
||||
)
|
||||
|
||||
func Test_List_Map_Basic(t *testing.T) {
|
||||
func Test_ListMap_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
m := gmap.NewListMap()
|
||||
m.Set("key1", "val1")
|
||||
@ -48,7 +50,7 @@ func Test_List_Map_Basic(t *testing.T) {
|
||||
gtest.Assert(m2.Map(), map[interface{}]interface{}{1: 1, "key1": "val1"})
|
||||
})
|
||||
}
|
||||
func Test_List_Map_Set_Fun(t *testing.T) {
|
||||
func Test_ListMap_Set_Fun(t *testing.T) {
|
||||
m := gmap.NewListMap()
|
||||
m.GetOrSetFunc("fun", getValue)
|
||||
m.GetOrSetFuncLock("funlock", getValue)
|
||||
@ -59,14 +61,14 @@ func Test_List_Map_Set_Fun(t *testing.T) {
|
||||
gtest.Assert(m.SetIfNotExistFuncLock("funlock", getValue), false)
|
||||
}
|
||||
|
||||
func Test_List_Map_Batch(t *testing.T) {
|
||||
func Test_ListMap_Batch(t *testing.T) {
|
||||
m := gmap.NewListMap()
|
||||
m.Sets(map[interface{}]interface{}{1: 1, "key1": "val1", "key2": "val2", "key3": "val3"})
|
||||
gtest.Assert(m.Map(), map[interface{}]interface{}{1: 1, "key1": "val1", "key2": "val2", "key3": "val3"})
|
||||
m.Removes([]interface{}{"key1", 1})
|
||||
gtest.Assert(m.Map(), map[interface{}]interface{}{"key2": "val2", "key3": "val3"})
|
||||
}
|
||||
func Test_List_Map_Iterator(t *testing.T) {
|
||||
func Test_ListMap_Iterator(t *testing.T) {
|
||||
expect := map[interface{}]interface{}{1: 1, "key1": "val1"}
|
||||
|
||||
m := gmap.NewListMapFrom(expect)
|
||||
@ -89,7 +91,7 @@ func Test_List_Map_Iterator(t *testing.T) {
|
||||
gtest.Assert(j, 1)
|
||||
}
|
||||
|
||||
func Test_List_Map_Clone(t *testing.T) {
|
||||
func Test_ListMap_Clone(t *testing.T) {
|
||||
//clone 方法是深克隆
|
||||
m := gmap.NewListMapFrom(map[interface{}]interface{}{1: 1, "key1": "val1"})
|
||||
m_clone := m.Clone()
|
||||
@ -102,7 +104,7 @@ func Test_List_Map_Clone(t *testing.T) {
|
||||
gtest.AssertIN("key1", m.Keys())
|
||||
}
|
||||
|
||||
func Test_List_Map_Basic_Merge(t *testing.T) {
|
||||
func Test_ListMap_Basic_Merge(t *testing.T) {
|
||||
m1 := gmap.NewListMap()
|
||||
m2 := gmap.NewListMap()
|
||||
m1.Set("key1", "val1")
|
||||
@ -111,7 +113,7 @@ func Test_List_Map_Basic_Merge(t *testing.T) {
|
||||
gtest.Assert(m1.Map(), map[interface{}]interface{}{"key1": "val1", "key2": "val2"})
|
||||
}
|
||||
|
||||
func Test_List_Map_Order(t *testing.T) {
|
||||
func Test_ListMap_Order(t *testing.T) {
|
||||
m := gmap.NewListMap()
|
||||
m.Set("k1", "v1")
|
||||
m.Set("k2", "v2")
|
||||
@ -119,3 +121,59 @@ func Test_List_Map_Order(t *testing.T) {
|
||||
gtest.Assert(m.Keys(), g.Slice{"k1", "k2", "k3"})
|
||||
gtest.Assert(m.Values(), g.Slice{"v1", "v2", "v3"})
|
||||
}
|
||||
|
||||
func Test_ListMap_FilterEmpty(t *testing.T) {
|
||||
m := gmap.NewListMap()
|
||||
m.Set(1, "")
|
||||
m.Set(2, "2")
|
||||
gtest.Assert(m.Size(), 2)
|
||||
gtest.Assert(m.Get(2), "2")
|
||||
m.FilterEmpty()
|
||||
gtest.Assert(m.Size(), 1)
|
||||
gtest.Assert(m.Get(2), "2")
|
||||
}
|
||||
|
||||
func Test_ListMap_Json(t *testing.T) {
|
||||
// Marshal
|
||||
gtest.Case(t, func() {
|
||||
data := g.MapAnyAny{
|
||||
"k1": "v1",
|
||||
"k2": "v2",
|
||||
}
|
||||
m1 := gmap.NewListMapFrom(data)
|
||||
b1, err1 := json.Marshal(m1)
|
||||
b2, err2 := json.Marshal(gconv.Map(data))
|
||||
gtest.Assert(err1, err2)
|
||||
gtest.Assert(b1, b2)
|
||||
})
|
||||
// Unmarshal
|
||||
gtest.Case(t, func() {
|
||||
data := g.MapAnyAny{
|
||||
"k1": "v1",
|
||||
"k2": "v2",
|
||||
}
|
||||
b, err := json.Marshal(gconv.Map(data))
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
m := gmap.NewListMap()
|
||||
err = json.Unmarshal(b, m)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(m.Get("k1"), data["k1"])
|
||||
gtest.Assert(m.Get("k2"), data["k2"])
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
data := g.MapAnyAny{
|
||||
"k1": "v1",
|
||||
"k2": "v2",
|
||||
}
|
||||
b, err := json.Marshal(gconv.Map(data))
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
var m gmap.ListMap
|
||||
err = json.Unmarshal(b, &m)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(m.Get("k1"), data["k1"])
|
||||
gtest.Assert(m.Get("k2"), data["k2"])
|
||||
})
|
||||
}
|
||||
@ -7,6 +7,8 @@
|
||||
package gmap_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/container/gmap"
|
||||
@ -127,3 +129,89 @@ func Test_StrAnyMap_Merge(t *testing.T) {
|
||||
m1.Merge(m2)
|
||||
gtest.Assert(m1.Map(), map[string]interface{}{"a": 1, "b": "2"})
|
||||
}
|
||||
|
||||
func Test_StrAnyMap_Map(t *testing.T) {
|
||||
m := gmap.NewStrAnyMap()
|
||||
m.Set("1", 1)
|
||||
m.Set("2", 2)
|
||||
gtest.Assert(m.Get("1"), 1)
|
||||
gtest.Assert(m.Get("2"), 2)
|
||||
data := m.Map()
|
||||
gtest.Assert(data["1"], 1)
|
||||
gtest.Assert(data["2"], 2)
|
||||
data["3"] = 3
|
||||
gtest.Assert(m.Get("3"), 3)
|
||||
m.Set("4", 4)
|
||||
gtest.Assert(data["4"], 4)
|
||||
}
|
||||
|
||||
func Test_StrAnyMap_MapCopy(t *testing.T) {
|
||||
m := gmap.NewStrAnyMap()
|
||||
m.Set("1", 1)
|
||||
m.Set("2", 2)
|
||||
gtest.Assert(m.Get("1"), 1)
|
||||
gtest.Assert(m.Get("2"), 2)
|
||||
data := m.MapCopy()
|
||||
gtest.Assert(data["1"], 1)
|
||||
gtest.Assert(data["2"], 2)
|
||||
data["3"] = 3
|
||||
gtest.Assert(m.Get("3"), nil)
|
||||
m.Set("4", 4)
|
||||
gtest.Assert(data["4"], nil)
|
||||
}
|
||||
|
||||
func Test_StrAnyMap_FilterEmpty(t *testing.T) {
|
||||
m := gmap.NewStrAnyMap()
|
||||
m.Set("1", 0)
|
||||
m.Set("2", 2)
|
||||
gtest.Assert(m.Size(), 2)
|
||||
gtest.Assert(m.Get("1"), 0)
|
||||
gtest.Assert(m.Get("2"), 2)
|
||||
m.FilterEmpty()
|
||||
gtest.Assert(m.Size(), 1)
|
||||
gtest.Assert(m.Get("2"), 2)
|
||||
}
|
||||
|
||||
func Test_StrAnyMap_Json(t *testing.T) {
|
||||
// Marshal
|
||||
gtest.Case(t, func() {
|
||||
data := g.MapStrAny{
|
||||
"k1": "v1",
|
||||
"k2": "v2",
|
||||
}
|
||||
m1 := gmap.NewStrAnyMapFrom(data)
|
||||
b1, err1 := json.Marshal(m1)
|
||||
b2, err2 := json.Marshal(data)
|
||||
gtest.Assert(err1, err2)
|
||||
gtest.Assert(b1, b2)
|
||||
})
|
||||
// Unmarshal
|
||||
gtest.Case(t, func() {
|
||||
data := g.MapStrAny{
|
||||
"k1": "v1",
|
||||
"k2": "v2",
|
||||
}
|
||||
b, err := json.Marshal(data)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
m := gmap.NewStrAnyMap()
|
||||
err = json.Unmarshal(b, m)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(m.Get("k1"), data["k1"])
|
||||
gtest.Assert(m.Get("k2"), data["k2"])
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
data := g.MapStrAny{
|
||||
"k1": "v1",
|
||||
"k2": "v2",
|
||||
}
|
||||
b, err := json.Marshal(data)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
var m gmap.StrAnyMap
|
||||
err = json.Unmarshal(b, &m)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(m.Get("k1"), data["k1"])
|
||||
gtest.Assert(m.Get("k2"), data["k2"])
|
||||
})
|
||||
}
|
||||
@ -7,6 +7,8 @@
|
||||
package gmap_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/container/gmap"
|
||||
@ -130,3 +132,89 @@ func Test_StrIntMap_Merge(t *testing.T) {
|
||||
m1.Merge(m2)
|
||||
gtest.Assert(m1.Map(), map[string]int{"a": 1, "b": 2})
|
||||
}
|
||||
|
||||
func Test_StrIntMap_Map(t *testing.T) {
|
||||
m := gmap.NewStrIntMap()
|
||||
m.Set("1", 1)
|
||||
m.Set("2", 2)
|
||||
gtest.Assert(m.Get("1"), 1)
|
||||
gtest.Assert(m.Get("2"), 2)
|
||||
data := m.Map()
|
||||
gtest.Assert(data["1"], 1)
|
||||
gtest.Assert(data["2"], 2)
|
||||
data["3"] = 3
|
||||
gtest.Assert(m.Get("3"), 3)
|
||||
m.Set("4", 4)
|
||||
gtest.Assert(data["4"], 4)
|
||||
}
|
||||
|
||||
func Test_StrIntMap_MapCopy(t *testing.T) {
|
||||
m := gmap.NewStrIntMap()
|
||||
m.Set("1", 1)
|
||||
m.Set("2", 2)
|
||||
gtest.Assert(m.Get("1"), 1)
|
||||
gtest.Assert(m.Get("2"), 2)
|
||||
data := m.MapCopy()
|
||||
gtest.Assert(data["1"], 1)
|
||||
gtest.Assert(data["2"], 2)
|
||||
data["3"] = 3
|
||||
gtest.Assert(m.Get("3"), 0)
|
||||
m.Set("4", 4)
|
||||
gtest.Assert(data["4"], 0)
|
||||
}
|
||||
|
||||
func Test_StrIntMap_FilterEmpty(t *testing.T) {
|
||||
m := gmap.NewStrIntMap()
|
||||
m.Set("1", 0)
|
||||
m.Set("2", 2)
|
||||
gtest.Assert(m.Size(), 2)
|
||||
gtest.Assert(m.Get("1"), 0)
|
||||
gtest.Assert(m.Get("2"), 2)
|
||||
m.FilterEmpty()
|
||||
gtest.Assert(m.Size(), 1)
|
||||
gtest.Assert(m.Get("2"), 2)
|
||||
}
|
||||
|
||||
func Test_StrIntMap_Json(t *testing.T) {
|
||||
// Marshal
|
||||
gtest.Case(t, func() {
|
||||
data := g.MapStrInt{
|
||||
"k1": 1,
|
||||
"k2": 2,
|
||||
}
|
||||
m1 := gmap.NewStrIntMapFrom(data)
|
||||
b1, err1 := json.Marshal(m1)
|
||||
b2, err2 := json.Marshal(data)
|
||||
gtest.Assert(err1, err2)
|
||||
gtest.Assert(b1, b2)
|
||||
})
|
||||
// Unmarshal
|
||||
gtest.Case(t, func() {
|
||||
data := g.MapStrInt{
|
||||
"k1": 1,
|
||||
"k2": 2,
|
||||
}
|
||||
b, err := json.Marshal(data)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
m := gmap.NewStrIntMap()
|
||||
err = json.Unmarshal(b, m)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(m.Get("k1"), data["k1"])
|
||||
gtest.Assert(m.Get("k2"), data["k2"])
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
data := g.MapStrInt{
|
||||
"k1": 1,
|
||||
"k2": 2,
|
||||
}
|
||||
b, err := json.Marshal(data)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
var m gmap.StrIntMap
|
||||
err = json.Unmarshal(b, &m)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(m.Get("k1"), data["k1"])
|
||||
gtest.Assert(m.Get("k2"), data["k2"])
|
||||
})
|
||||
}
|
||||
@ -7,6 +7,8 @@
|
||||
package gmap_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/container/gmap"
|
||||
@ -127,3 +129,89 @@ func Test_StrStrMap_Merge(t *testing.T) {
|
||||
m1.Merge(m2)
|
||||
gtest.Assert(m1.Map(), map[string]string{"a": "a", "b": "b"})
|
||||
}
|
||||
|
||||
func Test_StrStrMap_Map(t *testing.T) {
|
||||
m := gmap.NewStrStrMap()
|
||||
m.Set("1", "1")
|
||||
m.Set("2", "2")
|
||||
gtest.Assert(m.Get("1"), "1")
|
||||
gtest.Assert(m.Get("2"), "2")
|
||||
data := m.Map()
|
||||
gtest.Assert(data["1"], "1")
|
||||
gtest.Assert(data["2"], "2")
|
||||
data["3"] = "3"
|
||||
gtest.Assert(m.Get("3"), "3")
|
||||
m.Set("4", "4")
|
||||
gtest.Assert(data["4"], "4")
|
||||
}
|
||||
|
||||
func Test_StrStrMap_MapCopy(t *testing.T) {
|
||||
m := gmap.NewStrStrMap()
|
||||
m.Set("1", "1")
|
||||
m.Set("2", "2")
|
||||
gtest.Assert(m.Get("1"), "1")
|
||||
gtest.Assert(m.Get("2"), "2")
|
||||
data := m.MapCopy()
|
||||
gtest.Assert(data["1"], "1")
|
||||
gtest.Assert(data["2"], "2")
|
||||
data["3"] = "3"
|
||||
gtest.Assert(m.Get("3"), "")
|
||||
m.Set("4", "4")
|
||||
gtest.Assert(data["4"], "")
|
||||
}
|
||||
|
||||
func Test_StrStrMap_FilterEmpty(t *testing.T) {
|
||||
m := gmap.NewStrStrMap()
|
||||
m.Set("1", "")
|
||||
m.Set("2", "2")
|
||||
gtest.Assert(m.Size(), 2)
|
||||
gtest.Assert(m.Get("1"), "")
|
||||
gtest.Assert(m.Get("2"), "2")
|
||||
m.FilterEmpty()
|
||||
gtest.Assert(m.Size(), 1)
|
||||
gtest.Assert(m.Get("2"), "2")
|
||||
}
|
||||
|
||||
func Test_StrStrMap_Json(t *testing.T) {
|
||||
// Marshal
|
||||
gtest.Case(t, func() {
|
||||
data := g.MapStrStr{
|
||||
"k1": "v1",
|
||||
"k2": "v2",
|
||||
}
|
||||
m1 := gmap.NewStrStrMapFrom(data)
|
||||
b1, err1 := json.Marshal(m1)
|
||||
b2, err2 := json.Marshal(data)
|
||||
gtest.Assert(err1, err2)
|
||||
gtest.Assert(b1, b2)
|
||||
})
|
||||
// Unmarshal
|
||||
gtest.Case(t, func() {
|
||||
data := g.MapStrStr{
|
||||
"k1": "v1",
|
||||
"k2": "v2",
|
||||
}
|
||||
b, err := json.Marshal(data)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
m := gmap.NewStrStrMap()
|
||||
err = json.Unmarshal(b, m)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(m.Get("k1"), data["k1"])
|
||||
gtest.Assert(m.Get("k2"), data["k2"])
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
data := g.MapStrStr{
|
||||
"k1": "v1",
|
||||
"k2": "v2",
|
||||
}
|
||||
b, err := json.Marshal(data)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
var m gmap.StrStrMap
|
||||
err = json.Unmarshal(b, &m)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(m.Get("k1"), data["k1"])
|
||||
gtest.Assert(m.Get("k2"), data["k2"])
|
||||
})
|
||||
}
|
||||
@ -7,6 +7,9 @@
|
||||
package gmap_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/container/gmap"
|
||||
@ -14,7 +17,7 @@ import (
|
||||
"github.com/gogf/gf/util/gutil"
|
||||
)
|
||||
|
||||
func Test_Tree_Map_Basic(t *testing.T) {
|
||||
func Test_TreeMap_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
m := gmap.NewTreeMap(gutil.ComparatorString)
|
||||
m.Set("key1", "val1")
|
||||
@ -48,7 +51,7 @@ func Test_Tree_Map_Basic(t *testing.T) {
|
||||
gtest.Assert(m2.Map(), map[interface{}]interface{}{1: 1, "key1": "val1"})
|
||||
})
|
||||
}
|
||||
func Test_Tree_Map_Set_Fun(t *testing.T) {
|
||||
func Test_TreeMap_Set_Fun(t *testing.T) {
|
||||
m := gmap.NewTreeMap(gutil.ComparatorString)
|
||||
m.GetOrSetFunc("fun", getValue)
|
||||
m.GetOrSetFuncLock("funlock", getValue)
|
||||
@ -59,14 +62,14 @@ func Test_Tree_Map_Set_Fun(t *testing.T) {
|
||||
gtest.Assert(m.SetIfNotExistFuncLock("funlock", getValue), false)
|
||||
}
|
||||
|
||||
func Test_Tree_Map_Batch(t *testing.T) {
|
||||
func Test_TreeMap_Batch(t *testing.T) {
|
||||
m := gmap.NewTreeMap(gutil.ComparatorString)
|
||||
m.Sets(map[interface{}]interface{}{1: 1, "key1": "val1", "key2": "val2", "key3": "val3"})
|
||||
gtest.Assert(m.Map(), map[interface{}]interface{}{1: 1, "key1": "val1", "key2": "val2", "key3": "val3"})
|
||||
m.Removes([]interface{}{"key1", 1})
|
||||
gtest.Assert(m.Map(), map[interface{}]interface{}{"key2": "val2", "key3": "val3"})
|
||||
}
|
||||
func Test_Tree_Map_Iterator(t *testing.T) {
|
||||
func Test_TreeMap_Iterator(t *testing.T) {
|
||||
expect := map[interface{}]interface{}{1: 1, "key1": "val1"}
|
||||
|
||||
m := gmap.NewTreeMapFrom(gutil.ComparatorString, expect)
|
||||
@ -89,7 +92,7 @@ func Test_Tree_Map_Iterator(t *testing.T) {
|
||||
gtest.Assert(j, 1)
|
||||
}
|
||||
|
||||
func Test_Tree_Map_Clone(t *testing.T) {
|
||||
func Test_TreeMap_Clone(t *testing.T) {
|
||||
//clone 方法是深克隆
|
||||
m := gmap.NewTreeMapFrom(gutil.ComparatorString, map[interface{}]interface{}{1: 1, "key1": "val1"})
|
||||
m_clone := m.Clone()
|
||||
@ -101,3 +104,47 @@ func Test_Tree_Map_Clone(t *testing.T) {
|
||||
//修改clone map,原 map 不影响
|
||||
gtest.AssertIN("key1", m.Keys())
|
||||
}
|
||||
|
||||
func Test_TreeMap_Json(t *testing.T) {
|
||||
// Marshal
|
||||
gtest.Case(t, func() {
|
||||
data := g.MapAnyAny{
|
||||
"k1": "v1",
|
||||
"k2": "v2",
|
||||
}
|
||||
m1 := gmap.NewTreeMapFrom(gutil.ComparatorString, data)
|
||||
b1, err1 := json.Marshal(m1)
|
||||
b2, err2 := json.Marshal(gconv.Map(data))
|
||||
gtest.Assert(err1, err2)
|
||||
gtest.Assert(b1, b2)
|
||||
})
|
||||
// Unmarshal
|
||||
gtest.Case(t, func() {
|
||||
data := g.MapAnyAny{
|
||||
"k1": "v1",
|
||||
"k2": "v2",
|
||||
}
|
||||
b, err := json.Marshal(gconv.Map(data))
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
m := gmap.NewTreeMap(gutil.ComparatorString)
|
||||
err = json.Unmarshal(b, m)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(m.Get("k1"), data["k1"])
|
||||
gtest.Assert(m.Get("k2"), data["k2"])
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
data := g.MapAnyAny{
|
||||
"k1": "v1",
|
||||
"k2": "v2",
|
||||
}
|
||||
b, err := json.Marshal(gconv.Map(data))
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
var m gmap.TreeMap
|
||||
err = json.Unmarshal(b, &m)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(m.Get("k1"), data["k1"])
|
||||
gtest.Assert(m.Get("k2"), data["k2"])
|
||||
})
|
||||
}
|
||||
@ -8,16 +8,16 @@
|
||||
package gset
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/internal/rwmutex"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
)
|
||||
|
||||
type Set struct {
|
||||
mu *rwmutex.RWMutex
|
||||
m map[interface{}]struct{}
|
||||
mu *rwmutex.RWMutex
|
||||
data map[interface{}]struct{}
|
||||
}
|
||||
|
||||
// New create and returns a new set, which contains un-repeated items.
|
||||
@ -30,8 +30,8 @@ func New(safe ...bool) *Set {
|
||||
// See New.
|
||||
func NewSet(safe ...bool) *Set {
|
||||
return &Set{
|
||||
m: make(map[interface{}]struct{}),
|
||||
mu: rwmutex.New(safe...),
|
||||
data: make(map[interface{}]struct{}),
|
||||
mu: rwmutex.New(safe...),
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,8 +43,8 @@ func NewFrom(items interface{}, safe ...bool) *Set {
|
||||
m[v] = struct{}{}
|
||||
}
|
||||
return &Set{
|
||||
m: m,
|
||||
mu: rwmutex.New(safe...),
|
||||
data: m,
|
||||
mu: rwmutex.New(safe...),
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,7 +53,7 @@ func NewFrom(items interface{}, safe ...bool) *Set {
|
||||
func (set *Set) Iterator(f func(v interface{}) bool) *Set {
|
||||
set.mu.RLock()
|
||||
defer set.mu.RUnlock()
|
||||
for k, _ := range set.m {
|
||||
for k, _ := range set.data {
|
||||
if !f(k) {
|
||||
break
|
||||
}
|
||||
@ -65,7 +65,7 @@ func (set *Set) Iterator(f func(v interface{}) bool) *Set {
|
||||
func (set *Set) Add(item ...interface{}) *Set {
|
||||
set.mu.Lock()
|
||||
for _, v := range item {
|
||||
set.m[v] = struct{}{}
|
||||
set.data[v] = struct{}{}
|
||||
}
|
||||
set.mu.Unlock()
|
||||
return set
|
||||
@ -74,7 +74,7 @@ func (set *Set) Add(item ...interface{}) *Set {
|
||||
// Contains checks whether the set contains <item>.
|
||||
func (set *Set) Contains(item interface{}) bool {
|
||||
set.mu.RLock()
|
||||
_, exists := set.m[item]
|
||||
_, exists := set.data[item]
|
||||
set.mu.RUnlock()
|
||||
return exists
|
||||
}
|
||||
@ -82,7 +82,7 @@ func (set *Set) Contains(item interface{}) bool {
|
||||
// Remove deletes <item> from set.
|
||||
func (set *Set) Remove(item interface{}) *Set {
|
||||
set.mu.Lock()
|
||||
delete(set.m, item)
|
||||
delete(set.data, item)
|
||||
set.mu.Unlock()
|
||||
return set
|
||||
}
|
||||
@ -90,7 +90,7 @@ func (set *Set) Remove(item interface{}) *Set {
|
||||
// Size returns the size of the set.
|
||||
func (set *Set) Size() int {
|
||||
set.mu.RLock()
|
||||
l := len(set.m)
|
||||
l := len(set.data)
|
||||
set.mu.RUnlock()
|
||||
return l
|
||||
}
|
||||
@ -98,7 +98,7 @@ func (set *Set) Size() int {
|
||||
// Clear deletes all items of the set.
|
||||
func (set *Set) Clear() *Set {
|
||||
set.mu.Lock()
|
||||
set.m = make(map[interface{}]struct{})
|
||||
set.data = make(map[interface{}]struct{})
|
||||
set.mu.Unlock()
|
||||
return set
|
||||
}
|
||||
@ -107,8 +107,8 @@ func (set *Set) Clear() *Set {
|
||||
func (set *Set) Slice() []interface{} {
|
||||
set.mu.RLock()
|
||||
i := 0
|
||||
ret := make([]interface{}, len(set.m))
|
||||
for item := range set.m {
|
||||
ret := make([]interface{}, len(set.data))
|
||||
for item := range set.data {
|
||||
ret[i] = item
|
||||
i++
|
||||
}
|
||||
@ -118,26 +118,44 @@ func (set *Set) Slice() []interface{} {
|
||||
|
||||
// Join joins items with a string <glue>.
|
||||
func (set *Set) Join(glue string) string {
|
||||
return strings.Join(gconv.Strings(set.Slice()), ",")
|
||||
set.mu.RLock()
|
||||
defer set.mu.RUnlock()
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
s := ""
|
||||
l := len(set.data)
|
||||
i := 0
|
||||
for k, _ := range set.data {
|
||||
s = gconv.String(k)
|
||||
if gstr.IsNumeric(s) {
|
||||
buffer.WriteString(s)
|
||||
} else {
|
||||
buffer.WriteString(`"` + gstr.QuoteMeta(s, `"\`) + `"`)
|
||||
}
|
||||
if i != l-1 {
|
||||
buffer.WriteString(glue)
|
||||
}
|
||||
i++
|
||||
}
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
// String returns items as a string, which are joined by char ','.
|
||||
func (set *Set) String() string {
|
||||
return set.Join(",")
|
||||
return "[" + set.Join(",") + "]"
|
||||
}
|
||||
|
||||
// LockFunc locks writing with callback function <f>.
|
||||
func (set *Set) LockFunc(f func(m map[interface{}]struct{})) {
|
||||
set.mu.Lock()
|
||||
defer set.mu.Unlock()
|
||||
f(set.m)
|
||||
f(set.data)
|
||||
}
|
||||
|
||||
// RLockFunc locks reading with callback function <f>.
|
||||
func (set *Set) RLockFunc(f func(m map[interface{}]struct{})) {
|
||||
set.mu.RLock()
|
||||
defer set.mu.RUnlock()
|
||||
f(set.m)
|
||||
f(set.data)
|
||||
}
|
||||
|
||||
// Equal checks whether the two sets equal.
|
||||
@ -149,11 +167,11 @@ func (set *Set) Equal(other *Set) bool {
|
||||
defer set.mu.RUnlock()
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
if len(set.m) != len(other.m) {
|
||||
if len(set.data) != len(other.data) {
|
||||
return false
|
||||
}
|
||||
for key := range set.m {
|
||||
if _, ok := other.m[key]; !ok {
|
||||
for key := range set.data {
|
||||
if _, ok := other.data[key]; !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -169,8 +187,8 @@ func (set *Set) IsSubsetOf(other *Set) bool {
|
||||
defer set.mu.RUnlock()
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
for key := range set.m {
|
||||
if _, ok := other.m[key]; !ok {
|
||||
for key := range set.data {
|
||||
if _, ok := other.data[key]; !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -187,12 +205,12 @@ func (set *Set) Union(others ...*Set) (newSet *Set) {
|
||||
if set != other {
|
||||
other.mu.RLock()
|
||||
}
|
||||
for k, v := range set.m {
|
||||
newSet.m[k] = v
|
||||
for k, v := range set.data {
|
||||
newSet.data[k] = v
|
||||
}
|
||||
if set != other {
|
||||
for k, v := range other.m {
|
||||
newSet.m[k] = v
|
||||
for k, v := range other.data {
|
||||
newSet.data[k] = v
|
||||
}
|
||||
}
|
||||
if set != other {
|
||||
@ -214,9 +232,9 @@ func (set *Set) Diff(others ...*Set) (newSet *Set) {
|
||||
continue
|
||||
}
|
||||
other.mu.RLock()
|
||||
for k, v := range set.m {
|
||||
if _, ok := other.m[k]; !ok {
|
||||
newSet.m[k] = v
|
||||
for k, v := range set.data {
|
||||
if _, ok := other.data[k]; !ok {
|
||||
newSet.data[k] = v
|
||||
}
|
||||
}
|
||||
other.mu.RUnlock()
|
||||
@ -234,9 +252,9 @@ func (set *Set) Intersect(others ...*Set) (newSet *Set) {
|
||||
if set != other {
|
||||
other.mu.RLock()
|
||||
}
|
||||
for k, v := range set.m {
|
||||
if _, ok := other.m[k]; ok {
|
||||
newSet.m[k] = v
|
||||
for k, v := range set.data {
|
||||
if _, ok := other.data[k]; ok {
|
||||
newSet.data[k] = v
|
||||
}
|
||||
}
|
||||
if set != other {
|
||||
@ -259,9 +277,9 @@ func (set *Set) Complement(full *Set) (newSet *Set) {
|
||||
full.mu.RLock()
|
||||
defer full.mu.RUnlock()
|
||||
}
|
||||
for k, v := range full.m {
|
||||
if _, ok := set.m[k]; !ok {
|
||||
newSet.m[k] = v
|
||||
for k, v := range full.data {
|
||||
if _, ok := set.data[k]; !ok {
|
||||
newSet.data[k] = v
|
||||
}
|
||||
}
|
||||
return
|
||||
@ -275,8 +293,8 @@ func (set *Set) Merge(others ...*Set) *Set {
|
||||
if set != other {
|
||||
other.mu.RLock()
|
||||
}
|
||||
for k, v := range other.m {
|
||||
set.m[k] = v
|
||||
for k, v := range other.data {
|
||||
set.data[k] = v
|
||||
}
|
||||
if set != other {
|
||||
other.mu.RUnlock()
|
||||
@ -291,7 +309,7 @@ func (set *Set) Merge(others ...*Set) *Set {
|
||||
func (set *Set) Sum() (sum int) {
|
||||
set.mu.RLock()
|
||||
defer set.mu.RUnlock()
|
||||
for k, _ := range set.m {
|
||||
for k, _ := range set.data {
|
||||
sum += gconv.Int(k)
|
||||
}
|
||||
return
|
||||
@ -301,7 +319,7 @@ func (set *Set) Sum() (sum int) {
|
||||
func (set *Set) Pop() interface{} {
|
||||
set.mu.RLock()
|
||||
defer set.mu.RUnlock()
|
||||
for k, _ := range set.m {
|
||||
for k, _ := range set.data {
|
||||
return k
|
||||
}
|
||||
return nil
|
||||
@ -311,12 +329,12 @@ func (set *Set) Pop() interface{} {
|
||||
func (set *Set) Pops(size int) []interface{} {
|
||||
set.mu.RLock()
|
||||
defer set.mu.RUnlock()
|
||||
if size > len(set.m) {
|
||||
size = len(set.m)
|
||||
if size > len(set.data) {
|
||||
size = len(set.data)
|
||||
}
|
||||
index := 0
|
||||
array := make([]interface{}, size)
|
||||
for k, _ := range set.m {
|
||||
for k, _ := range set.data {
|
||||
array[index] = k
|
||||
index++
|
||||
if index == size {
|
||||
@ -330,3 +348,21 @@ func (set *Set) Pops(size int) []interface{} {
|
||||
func (set *Set) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(set.Slice())
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
|
||||
func (set *Set) UnmarshalJSON(b []byte) error {
|
||||
if set.mu == nil {
|
||||
set.mu = rwmutex.New()
|
||||
set.data = make(map[interface{}]struct{})
|
||||
}
|
||||
set.mu.Lock()
|
||||
defer set.mu.Unlock()
|
||||
var array []interface{}
|
||||
if err := json.Unmarshal(b, &array); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range array {
|
||||
set.data[v] = struct{}{}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -8,16 +8,15 @@
|
||||
package gset
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/internal/rwmutex"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
)
|
||||
|
||||
type IntSet struct {
|
||||
mu *rwmutex.RWMutex
|
||||
m map[int]struct{}
|
||||
mu *rwmutex.RWMutex
|
||||
data map[int]struct{}
|
||||
}
|
||||
|
||||
// New create and returns a new set, which contains un-repeated items.
|
||||
@ -25,8 +24,8 @@ type IntSet struct {
|
||||
// which is false in default.
|
||||
func NewIntSet(safe ...bool) *IntSet {
|
||||
return &IntSet{
|
||||
m: make(map[int]struct{}),
|
||||
mu: rwmutex.New(safe...),
|
||||
mu: rwmutex.New(safe...),
|
||||
data: make(map[int]struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,8 +36,8 @@ func NewIntSetFrom(items []int, safe ...bool) *IntSet {
|
||||
m[v] = struct{}{}
|
||||
}
|
||||
return &IntSet{
|
||||
m: m,
|
||||
mu: rwmutex.New(safe...),
|
||||
mu: rwmutex.New(safe...),
|
||||
data: m,
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,7 +46,7 @@ func NewIntSetFrom(items []int, safe ...bool) *IntSet {
|
||||
func (set *IntSet) Iterator(f func(v int) bool) *IntSet {
|
||||
set.mu.RLock()
|
||||
defer set.mu.RUnlock()
|
||||
for k, _ := range set.m {
|
||||
for k, _ := range set.data {
|
||||
if !f(k) {
|
||||
break
|
||||
}
|
||||
@ -59,7 +58,7 @@ func (set *IntSet) Iterator(f func(v int) bool) *IntSet {
|
||||
func (set *IntSet) Add(item ...int) *IntSet {
|
||||
set.mu.Lock()
|
||||
for _, v := range item {
|
||||
set.m[v] = struct{}{}
|
||||
set.data[v] = struct{}{}
|
||||
}
|
||||
set.mu.Unlock()
|
||||
return set
|
||||
@ -68,7 +67,7 @@ func (set *IntSet) Add(item ...int) *IntSet {
|
||||
// Contains checks whether the set contains <item>.
|
||||
func (set *IntSet) Contains(item int) bool {
|
||||
set.mu.RLock()
|
||||
_, exists := set.m[item]
|
||||
_, exists := set.data[item]
|
||||
set.mu.RUnlock()
|
||||
return exists
|
||||
}
|
||||
@ -76,7 +75,7 @@ func (set *IntSet) Contains(item int) bool {
|
||||
// Remove deletes <item> from set.
|
||||
func (set *IntSet) Remove(item int) *IntSet {
|
||||
set.mu.Lock()
|
||||
delete(set.m, item)
|
||||
delete(set.data, item)
|
||||
set.mu.Unlock()
|
||||
return set
|
||||
}
|
||||
@ -84,7 +83,7 @@ func (set *IntSet) Remove(item int) *IntSet {
|
||||
// Size returns the size of the set.
|
||||
func (set *IntSet) Size() int {
|
||||
set.mu.RLock()
|
||||
l := len(set.m)
|
||||
l := len(set.data)
|
||||
set.mu.RUnlock()
|
||||
return l
|
||||
}
|
||||
@ -92,7 +91,7 @@ func (set *IntSet) Size() int {
|
||||
// Clear deletes all items of the set.
|
||||
func (set *IntSet) Clear() *IntSet {
|
||||
set.mu.Lock()
|
||||
set.m = make(map[int]struct{})
|
||||
set.data = make(map[int]struct{})
|
||||
set.mu.Unlock()
|
||||
return set
|
||||
}
|
||||
@ -100,9 +99,9 @@ func (set *IntSet) Clear() *IntSet {
|
||||
// Slice returns the a of items of the set as slice.
|
||||
func (set *IntSet) Slice() []int {
|
||||
set.mu.RLock()
|
||||
ret := make([]int, len(set.m))
|
||||
ret := make([]int, len(set.data))
|
||||
i := 0
|
||||
for k, _ := range set.m {
|
||||
for k, _ := range set.data {
|
||||
ret[i] = k
|
||||
i++
|
||||
}
|
||||
@ -112,26 +111,38 @@ func (set *IntSet) Slice() []int {
|
||||
|
||||
// Join joins items with a string <glue>.
|
||||
func (set *IntSet) Join(glue string) string {
|
||||
return strings.Join(gconv.Strings(set.Slice()), ",")
|
||||
set.mu.RLock()
|
||||
defer set.mu.RUnlock()
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
l := len(set.data)
|
||||
i := 0
|
||||
for k, _ := range set.data {
|
||||
buffer.WriteString(gconv.String(k))
|
||||
if i != l-1 {
|
||||
buffer.WriteString(glue)
|
||||
}
|
||||
i++
|
||||
}
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
// String returns items as a string, which are joined by char ','.
|
||||
func (set *IntSet) String() string {
|
||||
return set.Join(",")
|
||||
return "[" + set.Join(",") + "]"
|
||||
}
|
||||
|
||||
// LockFunc locks writing with callback function <f>.
|
||||
func (set *IntSet) LockFunc(f func(m map[int]struct{})) {
|
||||
set.mu.Lock()
|
||||
defer set.mu.Unlock()
|
||||
f(set.m)
|
||||
f(set.data)
|
||||
}
|
||||
|
||||
// RLockFunc locks reading with callback function <f>.
|
||||
func (set *IntSet) RLockFunc(f func(m map[int]struct{})) {
|
||||
set.mu.RLock()
|
||||
defer set.mu.RUnlock()
|
||||
f(set.m)
|
||||
f(set.data)
|
||||
}
|
||||
|
||||
// Equal checks whether the two sets equal.
|
||||
@ -143,11 +154,11 @@ func (set *IntSet) Equal(other *IntSet) bool {
|
||||
defer set.mu.RUnlock()
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
if len(set.m) != len(other.m) {
|
||||
if len(set.data) != len(other.data) {
|
||||
return false
|
||||
}
|
||||
for key := range set.m {
|
||||
if _, ok := other.m[key]; !ok {
|
||||
for key := range set.data {
|
||||
if _, ok := other.data[key]; !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -163,8 +174,8 @@ func (set *IntSet) IsSubsetOf(other *IntSet) bool {
|
||||
defer set.mu.RUnlock()
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
for key := range set.m {
|
||||
if _, ok := other.m[key]; !ok {
|
||||
for key := range set.data {
|
||||
if _, ok := other.data[key]; !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -181,12 +192,12 @@ func (set *IntSet) Union(others ...*IntSet) (newSet *IntSet) {
|
||||
if set != other {
|
||||
other.mu.RLock()
|
||||
}
|
||||
for k, v := range set.m {
|
||||
newSet.m[k] = v
|
||||
for k, v := range set.data {
|
||||
newSet.data[k] = v
|
||||
}
|
||||
if set != other {
|
||||
for k, v := range other.m {
|
||||
newSet.m[k] = v
|
||||
for k, v := range other.data {
|
||||
newSet.data[k] = v
|
||||
}
|
||||
}
|
||||
if set != other {
|
||||
@ -208,9 +219,9 @@ func (set *IntSet) Diff(others ...*IntSet) (newSet *IntSet) {
|
||||
continue
|
||||
}
|
||||
other.mu.RLock()
|
||||
for k, v := range set.m {
|
||||
if _, ok := other.m[k]; !ok {
|
||||
newSet.m[k] = v
|
||||
for k, v := range set.data {
|
||||
if _, ok := other.data[k]; !ok {
|
||||
newSet.data[k] = v
|
||||
}
|
||||
}
|
||||
other.mu.RUnlock()
|
||||
@ -228,9 +239,9 @@ func (set *IntSet) Intersect(others ...*IntSet) (newSet *IntSet) {
|
||||
if set != other {
|
||||
other.mu.RLock()
|
||||
}
|
||||
for k, v := range set.m {
|
||||
if _, ok := other.m[k]; ok {
|
||||
newSet.m[k] = v
|
||||
for k, v := range set.data {
|
||||
if _, ok := other.data[k]; ok {
|
||||
newSet.data[k] = v
|
||||
}
|
||||
}
|
||||
if set != other {
|
||||
@ -253,9 +264,9 @@ func (set *IntSet) Complement(full *IntSet) (newSet *IntSet) {
|
||||
full.mu.RLock()
|
||||
defer full.mu.RUnlock()
|
||||
}
|
||||
for k, v := range full.m {
|
||||
if _, ok := set.m[k]; !ok {
|
||||
newSet.m[k] = v
|
||||
for k, v := range full.data {
|
||||
if _, ok := set.data[k]; !ok {
|
||||
newSet.data[k] = v
|
||||
}
|
||||
}
|
||||
return
|
||||
@ -269,8 +280,8 @@ func (set *IntSet) Merge(others ...*IntSet) *IntSet {
|
||||
if set != other {
|
||||
other.mu.RLock()
|
||||
}
|
||||
for k, v := range other.m {
|
||||
set.m[k] = v
|
||||
for k, v := range other.data {
|
||||
set.data[k] = v
|
||||
}
|
||||
if set != other {
|
||||
other.mu.RUnlock()
|
||||
@ -285,7 +296,7 @@ func (set *IntSet) Merge(others ...*IntSet) *IntSet {
|
||||
func (set *IntSet) Sum() (sum int) {
|
||||
set.mu.RLock()
|
||||
defer set.mu.RUnlock()
|
||||
for k, _ := range set.m {
|
||||
for k, _ := range set.data {
|
||||
sum += k
|
||||
}
|
||||
return
|
||||
@ -295,7 +306,7 @@ func (set *IntSet) Sum() (sum int) {
|
||||
func (set *IntSet) Pop() int {
|
||||
set.mu.RLock()
|
||||
defer set.mu.RUnlock()
|
||||
for k, _ := range set.m {
|
||||
for k, _ := range set.data {
|
||||
return k
|
||||
}
|
||||
return 0
|
||||
@ -305,12 +316,12 @@ func (set *IntSet) Pop() int {
|
||||
func (set *IntSet) Pops(size int) []int {
|
||||
set.mu.RLock()
|
||||
defer set.mu.RUnlock()
|
||||
if size > len(set.m) {
|
||||
size = len(set.m)
|
||||
if size > len(set.data) {
|
||||
size = len(set.data)
|
||||
}
|
||||
index := 0
|
||||
array := make([]int, size)
|
||||
for k, _ := range set.m {
|
||||
for k, _ := range set.data {
|
||||
array[index] = k
|
||||
index++
|
||||
if index == size {
|
||||
@ -324,3 +335,21 @@ func (set *IntSet) Pops(size int) []int {
|
||||
func (set *IntSet) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(set.Slice())
|
||||
}
|
||||
|
||||
// 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()
|
||||
var array []int
|
||||
if err := json.Unmarshal(b, &array); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range array {
|
||||
set.data[v] = struct{}{}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -8,16 +8,16 @@
|
||||
package gset
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/internal/rwmutex"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
)
|
||||
|
||||
type StrSet struct {
|
||||
mu *rwmutex.RWMutex
|
||||
m map[string]struct{}
|
||||
mu *rwmutex.RWMutex
|
||||
data map[string]struct{}
|
||||
}
|
||||
|
||||
// New create and returns a new set, which contains un-repeated items.
|
||||
@ -25,8 +25,8 @@ type StrSet struct {
|
||||
// which is false in default.
|
||||
func NewStrSet(safe ...bool) *StrSet {
|
||||
return &StrSet{
|
||||
m: make(map[string]struct{}),
|
||||
mu: rwmutex.New(safe...),
|
||||
mu: rwmutex.New(safe...),
|
||||
data: make(map[string]struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,8 +37,8 @@ func NewStrSetFrom(items []string, safe ...bool) *StrSet {
|
||||
m[v] = struct{}{}
|
||||
}
|
||||
return &StrSet{
|
||||
m: m,
|
||||
mu: rwmutex.New(safe...),
|
||||
mu: rwmutex.New(safe...),
|
||||
data: m,
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,7 +47,7 @@ func NewStrSetFrom(items []string, safe ...bool) *StrSet {
|
||||
func (set *StrSet) Iterator(f func(v string) bool) *StrSet {
|
||||
set.mu.RLock()
|
||||
defer set.mu.RUnlock()
|
||||
for k, _ := range set.m {
|
||||
for k, _ := range set.data {
|
||||
if !f(k) {
|
||||
break
|
||||
}
|
||||
@ -59,7 +59,7 @@ func (set *StrSet) Iterator(f func(v string) bool) *StrSet {
|
||||
func (set *StrSet) Add(item ...string) *StrSet {
|
||||
set.mu.Lock()
|
||||
for _, v := range item {
|
||||
set.m[v] = struct{}{}
|
||||
set.data[v] = struct{}{}
|
||||
}
|
||||
set.mu.Unlock()
|
||||
return set
|
||||
@ -68,7 +68,7 @@ func (set *StrSet) Add(item ...string) *StrSet {
|
||||
// Contains checks whether the set contains <item>.
|
||||
func (set *StrSet) Contains(item string) bool {
|
||||
set.mu.RLock()
|
||||
_, exists := set.m[item]
|
||||
_, exists := set.data[item]
|
||||
set.mu.RUnlock()
|
||||
return exists
|
||||
}
|
||||
@ -76,7 +76,7 @@ func (set *StrSet) Contains(item string) bool {
|
||||
// Remove deletes <item> from set.
|
||||
func (set *StrSet) Remove(item string) *StrSet {
|
||||
set.mu.Lock()
|
||||
delete(set.m, item)
|
||||
delete(set.data, item)
|
||||
set.mu.Unlock()
|
||||
return set
|
||||
}
|
||||
@ -84,7 +84,7 @@ func (set *StrSet) Remove(item string) *StrSet {
|
||||
// Size returns the size of the set.
|
||||
func (set *StrSet) Size() int {
|
||||
set.mu.RLock()
|
||||
l := len(set.m)
|
||||
l := len(set.data)
|
||||
set.mu.RUnlock()
|
||||
return l
|
||||
}
|
||||
@ -92,7 +92,7 @@ func (set *StrSet) Size() int {
|
||||
// Clear deletes all items of the set.
|
||||
func (set *StrSet) Clear() *StrSet {
|
||||
set.mu.Lock()
|
||||
set.m = make(map[string]struct{})
|
||||
set.data = make(map[string]struct{})
|
||||
set.mu.Unlock()
|
||||
return set
|
||||
}
|
||||
@ -100,9 +100,9 @@ func (set *StrSet) Clear() *StrSet {
|
||||
// Slice returns the a of items of the set as slice.
|
||||
func (set *StrSet) Slice() []string {
|
||||
set.mu.RLock()
|
||||
ret := make([]string, len(set.m))
|
||||
ret := make([]string, len(set.data))
|
||||
i := 0
|
||||
for item := range set.m {
|
||||
for item := range set.data {
|
||||
ret[i] = item
|
||||
i++
|
||||
}
|
||||
@ -113,26 +113,42 @@ func (set *StrSet) Slice() []string {
|
||||
|
||||
// Join joins items with a string <glue>.
|
||||
func (set *StrSet) Join(glue string) string {
|
||||
return strings.Join(set.Slice(), ",")
|
||||
set.mu.RLock()
|
||||
defer set.mu.RUnlock()
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
l := len(set.data)
|
||||
i := 0
|
||||
for k, _ := range set.data {
|
||||
if gstr.IsNumeric(k) {
|
||||
buffer.WriteString(k)
|
||||
} else {
|
||||
buffer.WriteString(`"` + gstr.QuoteMeta(k, `"\`) + `"`)
|
||||
}
|
||||
if i != l-1 {
|
||||
buffer.WriteString(glue)
|
||||
}
|
||||
i++
|
||||
}
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
// String returns items as a string, which are joined by char ','.
|
||||
func (set *StrSet) String() string {
|
||||
return set.Join(",")
|
||||
return "[" + set.Join(",") + "]"
|
||||
}
|
||||
|
||||
// LockFunc locks writing with callback function <f>.
|
||||
func (set *StrSet) LockFunc(f func(m map[string]struct{})) {
|
||||
set.mu.Lock()
|
||||
defer set.mu.Unlock()
|
||||
f(set.m)
|
||||
f(set.data)
|
||||
}
|
||||
|
||||
// RLockFunc locks reading with callback function <f>.
|
||||
func (set *StrSet) RLockFunc(f func(m map[string]struct{})) {
|
||||
set.mu.RLock()
|
||||
defer set.mu.RUnlock()
|
||||
f(set.m)
|
||||
f(set.data)
|
||||
}
|
||||
|
||||
// Equal checks whether the two sets equal.
|
||||
@ -144,11 +160,11 @@ func (set *StrSet) Equal(other *StrSet) bool {
|
||||
defer set.mu.RUnlock()
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
if len(set.m) != len(other.m) {
|
||||
if len(set.data) != len(other.data) {
|
||||
return false
|
||||
}
|
||||
for key := range set.m {
|
||||
if _, ok := other.m[key]; !ok {
|
||||
for key := range set.data {
|
||||
if _, ok := other.data[key]; !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -164,8 +180,8 @@ func (set *StrSet) IsSubsetOf(other *StrSet) bool {
|
||||
defer set.mu.RUnlock()
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
for key := range set.m {
|
||||
if _, ok := other.m[key]; !ok {
|
||||
for key := range set.data {
|
||||
if _, ok := other.data[key]; !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -182,12 +198,12 @@ func (set *StrSet) Union(others ...*StrSet) (newSet *StrSet) {
|
||||
if set != other {
|
||||
other.mu.RLock()
|
||||
}
|
||||
for k, v := range set.m {
|
||||
newSet.m[k] = v
|
||||
for k, v := range set.data {
|
||||
newSet.data[k] = v
|
||||
}
|
||||
if set != other {
|
||||
for k, v := range other.m {
|
||||
newSet.m[k] = v
|
||||
for k, v := range other.data {
|
||||
newSet.data[k] = v
|
||||
}
|
||||
}
|
||||
if set != other {
|
||||
@ -209,9 +225,9 @@ func (set *StrSet) Diff(others ...*StrSet) (newSet *StrSet) {
|
||||
continue
|
||||
}
|
||||
other.mu.RLock()
|
||||
for k, v := range set.m {
|
||||
if _, ok := other.m[k]; !ok {
|
||||
newSet.m[k] = v
|
||||
for k, v := range set.data {
|
||||
if _, ok := other.data[k]; !ok {
|
||||
newSet.data[k] = v
|
||||
}
|
||||
}
|
||||
other.mu.RUnlock()
|
||||
@ -229,9 +245,9 @@ func (set *StrSet) Intersect(others ...*StrSet) (newSet *StrSet) {
|
||||
if set != other {
|
||||
other.mu.RLock()
|
||||
}
|
||||
for k, v := range set.m {
|
||||
if _, ok := other.m[k]; ok {
|
||||
newSet.m[k] = v
|
||||
for k, v := range set.data {
|
||||
if _, ok := other.data[k]; ok {
|
||||
newSet.data[k] = v
|
||||
}
|
||||
}
|
||||
if set != other {
|
||||
@ -254,9 +270,9 @@ func (set *StrSet) Complement(full *StrSet) (newSet *StrSet) {
|
||||
full.mu.RLock()
|
||||
defer full.mu.RUnlock()
|
||||
}
|
||||
for k, v := range full.m {
|
||||
if _, ok := set.m[k]; !ok {
|
||||
newSet.m[k] = v
|
||||
for k, v := range full.data {
|
||||
if _, ok := set.data[k]; !ok {
|
||||
newSet.data[k] = v
|
||||
}
|
||||
}
|
||||
return
|
||||
@ -270,8 +286,8 @@ func (set *StrSet) Merge(others ...*StrSet) *StrSet {
|
||||
if set != other {
|
||||
other.mu.RLock()
|
||||
}
|
||||
for k, v := range other.m {
|
||||
set.m[k] = v
|
||||
for k, v := range other.data {
|
||||
set.data[k] = v
|
||||
}
|
||||
if set != other {
|
||||
other.mu.RUnlock()
|
||||
@ -286,7 +302,7 @@ func (set *StrSet) Merge(others ...*StrSet) *StrSet {
|
||||
func (set *StrSet) Sum() (sum int) {
|
||||
set.mu.RLock()
|
||||
defer set.mu.RUnlock()
|
||||
for k, _ := range set.m {
|
||||
for k, _ := range set.data {
|
||||
sum += gconv.Int(k)
|
||||
}
|
||||
return
|
||||
@ -296,7 +312,7 @@ func (set *StrSet) Sum() (sum int) {
|
||||
func (set *StrSet) Pop() string {
|
||||
set.mu.RLock()
|
||||
defer set.mu.RUnlock()
|
||||
for k, _ := range set.m {
|
||||
for k, _ := range set.data {
|
||||
return k
|
||||
}
|
||||
return ""
|
||||
@ -306,12 +322,12 @@ func (set *StrSet) Pop() string {
|
||||
func (set *StrSet) Pops(size int) []string {
|
||||
set.mu.RLock()
|
||||
defer set.mu.RUnlock()
|
||||
if size > len(set.m) {
|
||||
size = len(set.m)
|
||||
if size > len(set.data) {
|
||||
size = len(set.data)
|
||||
}
|
||||
index := 0
|
||||
array := make([]string, size)
|
||||
for k, _ := range set.m {
|
||||
for k, _ := range set.data {
|
||||
array[index] = k
|
||||
index++
|
||||
if index == size {
|
||||
@ -325,3 +341,21 @@ func (set *StrSet) Pops(size int) []string {
|
||||
func (set *StrSet) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(set.Slice())
|
||||
}
|
||||
|
||||
// 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()
|
||||
var array []string
|
||||
if err := json.Unmarshal(b, &array); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range array {
|
||||
set.data[v] = struct{}{}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
package gset_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@ -189,8 +190,22 @@ func TestIntSet_Join(t *testing.T) {
|
||||
s1 := gset.NewIntSet()
|
||||
s1.Add(1).Add(2).Add(3)
|
||||
s3 := s1.Join(",")
|
||||
gtest.Assert(strings.Contains(s3, "1"), true)
|
||||
gtest.Assert(strings.Contains(s3, "2"), true)
|
||||
gtest.Assert(strings.Contains(s3, "3"), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntSet_String(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewIntSet()
|
||||
s1.Add(1).Add(2).Add(3)
|
||||
s3 := s1.String()
|
||||
gtest.Assert(strings.Contains(s3, "["), true)
|
||||
gtest.Assert(strings.Contains(s3, "]"), true)
|
||||
gtest.Assert(strings.Contains(s3, "1"), true)
|
||||
gtest.Assert(strings.Contains(s3, "2"), true)
|
||||
gtest.Assert(strings.Contains(s3, "3"), true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -215,3 +230,32 @@ func TestIntSet_Pop(t *testing.T) {
|
||||
gtest.Assert(s1.Size(), 3)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntSet_Json(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []int{1, 3, 2, 4}
|
||||
a1 := gset.NewIntSetFrom(s1)
|
||||
b1, err1 := json.Marshal(a1)
|
||||
b2, err2 := json.Marshal(s1)
|
||||
gtest.Assert(len(b1), len(b2))
|
||||
gtest.Assert(err1, err2)
|
||||
|
||||
a2 := gset.NewIntSet()
|
||||
err2 = json.Unmarshal(b2, &a2)
|
||||
gtest.Assert(err2, nil)
|
||||
gtest.Assert(a2.Contains(1), true)
|
||||
gtest.Assert(a2.Contains(2), true)
|
||||
gtest.Assert(a2.Contains(3), true)
|
||||
gtest.Assert(a2.Contains(4), true)
|
||||
gtest.Assert(a2.Contains(5), false)
|
||||
|
||||
var a3 gset.IntSet
|
||||
err := json.Unmarshal(b2, &a3)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(a2.Contains(1), true)
|
||||
gtest.Assert(a2.Contains(2), true)
|
||||
gtest.Assert(a2.Contains(3), true)
|
||||
gtest.Assert(a2.Contains(4), true)
|
||||
gtest.Assert(a2.Contains(5), false)
|
||||
})
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
package gset_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@ -195,10 +196,21 @@ func TestNewStrSetFrom(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestStrSet_Join(t *testing.T) {
|
||||
s1 := gset.NewStrSetFrom([]string{"a", "b", "c"}, true)
|
||||
str1 := s1.Join(",")
|
||||
gtest.Assert(strings.Contains(str1, "b"), true)
|
||||
gtest.Assert(strings.Contains(str1, "d"), false)
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewStrSetFrom([]string{"a", "b", "c"}, true)
|
||||
str1 := s1.Join(",")
|
||||
gtest.Assert(strings.Contains(str1, "b"), true)
|
||||
gtest.Assert(strings.Contains(str1, "d"), false)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.NewStrSet()
|
||||
s1.Add("a").Add(`"b"`).Add(`\c`)
|
||||
str1 := s1.Join(",")
|
||||
gtest.Assert(strings.Contains(str1, `\"b\"`), true)
|
||||
gtest.Assert(strings.Contains(str1, `\\c`), true)
|
||||
gtest.Assert(strings.Contains(str1, `a`), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStrSet_String(t *testing.T) {
|
||||
@ -209,6 +221,14 @@ func TestStrSet_String(t *testing.T) {
|
||||
gtest.Assert(strings.Contains(str1, "d"), false)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.New(true)
|
||||
s1.Add("a").Add("a2").Add("b").Add("c")
|
||||
str1 := s1.String()
|
||||
gtest.Assert(strings.Contains(str1, "["), true)
|
||||
gtest.Assert(strings.Contains(str1, "]"), true)
|
||||
gtest.Assert(strings.Contains(str1, "a2"), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStrSet_Sum(t *testing.T) {
|
||||
@ -255,3 +275,32 @@ func TestStrSet_Pops(t *testing.T) {
|
||||
gtest.AssertIN(str2, []string{"a", "b", "c"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestStrSet_Json(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []string{"a", "b", "d", "c"}
|
||||
a1 := gset.NewStrSetFrom(s1)
|
||||
b1, err1 := json.Marshal(a1)
|
||||
b2, err2 := json.Marshal(s1)
|
||||
gtest.Assert(len(b1), len(b2))
|
||||
gtest.Assert(err1, err2)
|
||||
|
||||
a2 := gset.NewStrSet()
|
||||
err2 = json.Unmarshal(b2, &a2)
|
||||
gtest.Assert(err2, nil)
|
||||
gtest.Assert(a2.Contains("a"), true)
|
||||
gtest.Assert(a2.Contains("b"), true)
|
||||
gtest.Assert(a2.Contains("c"), true)
|
||||
gtest.Assert(a2.Contains("d"), true)
|
||||
gtest.Assert(a2.Contains("e"), false)
|
||||
|
||||
var a3 gset.StrSet
|
||||
err := json.Unmarshal(b2, &a3)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(a3.Contains("a"), true)
|
||||
gtest.Assert(a3.Contains("b"), true)
|
||||
gtest.Assert(a3.Contains("c"), true)
|
||||
gtest.Assert(a3.Contains("d"), true)
|
||||
gtest.Assert(a3.Contains("e"), false)
|
||||
})
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user