mirror of
https://gitee.com/johng/gf
synced 2026-06-09 02:57:43 +08:00
Compare commits
36 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2dc2610621 | |||
| 1736e71e6b | |||
| 69ee5375b9 | |||
| 3ac0a66887 | |||
| 20e873a1fc | |||
| 142484d89c | |||
| 76a9f4ca14 | |||
| c4e5679d5c | |||
| b08d7c3c38 | |||
| 5092d8e6c5 | |||
| 74d625ff97 | |||
| f1119e28e8 | |||
| 3082c7f761 | |||
| 5f36614dd7 | |||
| 1dcc7a4887 | |||
| 41e9d35487 | |||
| 977c8b7ee3 | |||
| 939e6244ee | |||
| e764b2393d | |||
| 6384e75ed9 | |||
| 195cae6577 | |||
| c8cf46a5a7 | |||
| eba97277b2 | |||
| 4e19fbc5fb | |||
| 494b5bbae2 | |||
| 987ce709e5 | |||
| 35ad4d869f | |||
| 39d654e3f2 | |||
| 7fe9c641f4 | |||
| ee1414c010 | |||
| 8eb1b685a5 | |||
| 46768d6f91 | |||
| bb6fed3dc2 | |||
| 47e74d27bf | |||
| b830f9b96d | |||
| c85162a8a0 |
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)
|
||||
}
|
||||
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,17 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/container/gmap"
|
||||
)
|
||||
|
||||
func main() {
|
||||
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())
|
||||
}
|
||||
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)
|
||||
}
|
||||
@ -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)
|
||||
|
||||
}
|
||||
|
||||
19
.example/encoding/gjson/issue360.go
Normal file
19
.example/encoding/gjson/issue360.go
Normal file
@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/encoding/gjson"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := `
|
||||
{"apiVersion":"v1","kind":"Service","metadata":{"labels":{"name":"http-daemon"},"name":"http-daemon","namespace":"default"},"spec":{"ports":[{"name":"http-daemon","port":8080,"protocol":"TCP","targetPort":9212}],"selector":{"app":"http-daemon","version":"v0930-082326"}}}
|
||||
`
|
||||
js, err := gjson.DecodeToJson(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
//g.Dump(js.ToMap())
|
||||
y, _ := js.ToYamlString()
|
||||
fmt.Println(y)
|
||||
}
|
||||
@ -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()
|
||||
}
|
||||
|
||||
21
.example/net/ghttp/server/middleware/issue355.go
Normal file
21
.example/net/ghttp/server/middleware/issue355.go
Normal file
@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindMiddlewareDefault(func(r *ghttp.Request) {
|
||||
fmt.Println("cors")
|
||||
r.Response.CORSDefault()
|
||||
r.Middleware.Next()
|
||||
})
|
||||
s.BindHandler("/api/captcha", func(r *ghttp.Request) {
|
||||
r.Response.Write("captcha")
|
||||
})
|
||||
s.SetPort(8010)
|
||||
s.Run()
|
||||
}
|
||||
16
.example/os/gview/build_in_funcs/issue359-1.go
Normal file
16
.example/os/gview/build_in_funcs/issue359-1.go
Normal file
@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
tplContent := `
|
||||
{{"我是中国人我是中国人我是中国人我是中国人我是中国人我是中国人我是中国人我是中国人我是中国人我是中国人我是中国人我是中国人我是中国人我是中国人我是中国人我是中国人我是中国人我是中国人"| strlimit 10 "..."}}
|
||||
`
|
||||
content, err := g.View().ParseContent(tplContent, nil)
|
||||
fmt.Println(err)
|
||||
fmt.Println(content)
|
||||
}
|
||||
19
.example/os/gview/build_in_funcs/issue359-2.go
Normal file
19
.example/os/gview/build_in_funcs/issue359-2.go
Normal file
@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/frame/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := "我是中国人我是中国人我是中国人我是中国人我是中国人我是中国人我是中国人我是中国人我是中国人我是中国人我是中国人我是中国人我是中国人我是中国人我是中国人我是中国人我是中国人我是中国人"
|
||||
tplContent := `
|
||||
{{.str | strlimit 10 "..."}}
|
||||
`
|
||||
content, err := g.View().ParseContent(tplContent, g.Map{
|
||||
"str": s,
|
||||
})
|
||||
fmt.Println(err)
|
||||
fmt.Println(content)
|
||||
}
|
||||
@ -1,48 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
|
||||
"github.com/gogf/gf/debug/gdebug"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cdnUrl := "http://localhost"
|
||||
content := `
|
||||
<link rel="stylesheet" href="/plugin/amazeui-2.7.2/css/amazeui.min.css">
|
||||
<link rel="stylesheet" href="/plugin/markdown-css/github-markdown.min.js">
|
||||
<link rel="stylesheet" href="/plugin/prism/prism.css">
|
||||
<link rel="stylesheet" href="/resource/css/document/style.css">
|
||||
<link rel="icon" href="/resource/image/favicon.ico" type="image/x-icon">
|
||||
`
|
||||
s, err := gregex.ReplaceStringFuncMatch(`(href|src)=['"](.+?)['"]`, content, func(match []string) string {
|
||||
link := match[2]
|
||||
if len(link) == 0 {
|
||||
return match[0]
|
||||
}
|
||||
if link[0:1] != "/" && link[0:1] != "#" {
|
||||
if len(link) > 10 && link[0:10] == "javascript" {
|
||||
return match[0]
|
||||
}
|
||||
if len(link) > 7 && link[0:7] == "mailto:" {
|
||||
return match[0]
|
||||
}
|
||||
if len(link) > 4 && link[0:4] == "http" {
|
||||
return match[0]
|
||||
}
|
||||
link = "/" + link
|
||||
}
|
||||
if link[0:1] == "/" {
|
||||
switch gfile.ExtName(link) {
|
||||
case "png", "jpg", "jpeg", "gif", "js", "css", "otf", "eot", "ttf", "woff", "woff2":
|
||||
return fmt.Sprintf(`%s="%s%s?%s"`, match[1], cdnUrl, link, gdebug.BinVersion())
|
||||
}
|
||||
}
|
||||
return match[0]
|
||||
})
|
||||
fmt.Println(err)
|
||||
fmt.Println(s)
|
||||
b, _ := json.Marshal([]interface{}{1, 2, 3, 4, 5, 123.456, "a"})
|
||||
fmt.Println(gconv.String(b))
|
||||
}
|
||||
|
||||
@ -1,32 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
)
|
||||
|
||||
// 演示slice类型属性的赋值
|
||||
func main() {
|
||||
type User struct {
|
||||
Scores []int
|
||||
}
|
||||
|
||||
user := new(User)
|
||||
scores := []interface{}{99, 100, 60, 140}
|
||||
|
||||
// 通过map映射转换
|
||||
if err := gconv.Struct(g.Map{"Scores": scores}, user); err != nil {
|
||||
fmt.Println(err)
|
||||
} else {
|
||||
g.Dump(user)
|
||||
}
|
||||
|
||||
// 通过变量映射转换,直接slice赋值
|
||||
if err := gconv.Struct(scores, user); err != nil {
|
||||
fmt.Println(err)
|
||||
} else {
|
||||
g.Dump(user)
|
||||
}
|
||||
}
|
||||
@ -21,8 +21,8 @@ func main() {
|
||||
|
||||
user1 := new(User1)
|
||||
user2 := new(User2)
|
||||
scores := map[string]interface{}{
|
||||
"Scores": map[string]interface{}{
|
||||
scores := g.Map{
|
||||
"Scores": g.Map{
|
||||
"Name": "john",
|
||||
"Result": 100,
|
||||
},
|
||||
|
||||
@ -17,8 +17,8 @@ func main() {
|
||||
}
|
||||
|
||||
user := new(User)
|
||||
scores := map[string]interface{}{
|
||||
"Scores": map[string]interface{}{
|
||||
scores := g.Map{
|
||||
"Scores": g.Map{
|
||||
"Name": "john",
|
||||
"Result": 100,
|
||||
},
|
||||
|
||||
@ -17,13 +17,13 @@ func main() {
|
||||
}
|
||||
|
||||
user := new(User)
|
||||
scores := map[string]interface{}{
|
||||
"Scores": []interface{}{
|
||||
map[string]interface{}{
|
||||
scores := g.Map{
|
||||
"Scores": g.Slice{
|
||||
g.Map{
|
||||
"Name": "john",
|
||||
"Result": 100,
|
||||
},
|
||||
map[string]interface{}{
|
||||
g.Map{
|
||||
"Name": "smith",
|
||||
"Result": 60,
|
||||
},
|
||||
|
||||
@ -14,7 +14,7 @@ English | [简体中文](README_ZH.MD)
|
||||
|
||||
# Installation
|
||||
```
|
||||
go get -u github.com/gogf/gf
|
||||
go get -u -v github.com/gogf/gf
|
||||
```
|
||||
suggested using `go.mod`:
|
||||
```
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
# 特点
|
||||
* 模块化、松耦合设计;
|
||||
* 模块丰富,开箱即用;
|
||||
* 简便及可维护性为宗旨;
|
||||
* 详尽的开发文档及示例;
|
||||
* 完善的本地中文化支持;
|
||||
* 致力于项目的通用方案;
|
||||
|
||||
@ -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.
|
||||
@ -604,12 +604,26 @@ func (a *Array) CountValues() map[interface{}]int {
|
||||
return m
|
||||
}
|
||||
|
||||
// String returns current array as a string.
|
||||
// String returns current array as a string, which implements like json.Marshal does.
|
||||
func (a *Array) String() string {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
jsonContent, _ := json.Marshal(a.array)
|
||||
return string(jsonContent)
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
buffer.WriteByte('[')
|
||||
s := ""
|
||||
for k, v := range a.array {
|
||||
s = gconv.String(v)
|
||||
if gstr.IsNumeric(s) {
|
||||
buffer.WriteString(s)
|
||||
} else {
|
||||
buffer.WriteString(`"` + gstr.QuoteMeta(s, `"\`) + `"`)
|
||||
}
|
||||
if k != len(a.array)-1 {
|
||||
buffer.WriteByte(',')
|
||||
}
|
||||
}
|
||||
buffer.WriteByte(']')
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
@ -618,3 +632,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() {
|
||||
@ -610,12 +610,9 @@ func (a *IntArray) CountValues() map[int]int {
|
||||
return m
|
||||
}
|
||||
|
||||
// String returns current array as a string.
|
||||
// String returns current array as a string, which implements like json.Marshal does.
|
||||
func (a *IntArray) String() string {
|
||||
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(v)
|
||||
if k != len(a.array)-1 {
|
||||
buffer.WriteString(glue)
|
||||
}
|
||||
@ -610,12 +611,20 @@ func (a *StrArray) CountValues() map[string]int {
|
||||
return m
|
||||
}
|
||||
|
||||
// String returns current array as a string.
|
||||
// String returns current array as a string, which implements like json.Marshal does.
|
||||
func (a *StrArray) String() string {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
jsonContent, _ := json.Marshal(a.array)
|
||||
return string(jsonContent)
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
buffer.WriteByte('[')
|
||||
for k, v := range a.array {
|
||||
buffer.WriteString(`"` + gstr.QuoteMeta(v, `"\`) + `"`)
|
||||
if k != len(a.array)-1 {
|
||||
buffer.WriteByte(',')
|
||||
}
|
||||
}
|
||||
buffer.WriteByte(']')
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
@ -624,3 +633,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() {
|
||||
@ -536,12 +549,26 @@ func (a *SortedArray) CountValues() map[interface{}]int {
|
||||
return m
|
||||
}
|
||||
|
||||
// String returns current array as a string.
|
||||
// String returns current array as a string, which implements like json.Marshal does.
|
||||
func (a *SortedArray) String() string {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
jsonContent, _ := json.Marshal(a.array)
|
||||
return string(jsonContent)
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
buffer.WriteByte('[')
|
||||
s := ""
|
||||
for k, v := range a.array {
|
||||
s = gconv.String(v)
|
||||
if gstr.IsNumeric(s) {
|
||||
buffer.WriteString(s)
|
||||
} else {
|
||||
buffer.WriteString(`"` + gstr.QuoteMeta(s, `"\`) + `"`)
|
||||
}
|
||||
if k != len(a.array)-1 {
|
||||
buffer.WriteByte(',')
|
||||
}
|
||||
}
|
||||
buffer.WriteByte(']')
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
@ -550,3 +577,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() {
|
||||
@ -535,12 +535,9 @@ func (a *SortedIntArray) CountValues() map[int]int {
|
||||
return m
|
||||
}
|
||||
|
||||
// String returns current array as a string.
|
||||
// String returns current array as a string, which implements like json.Marshal does.
|
||||
func (a *SortedIntArray) String() string {
|
||||
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(v)
|
||||
if k != len(a.array)-1 {
|
||||
buffer.WriteString(glue)
|
||||
}
|
||||
@ -534,12 +536,20 @@ func (a *SortedStrArray) CountValues() map[string]int {
|
||||
return m
|
||||
}
|
||||
|
||||
// String returns current array as a string.
|
||||
// String returns current array as a string, which implements like json.Marshal does.
|
||||
func (a *SortedStrArray) String() string {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
jsonContent, _ := json.Marshal(a.array)
|
||||
return string(jsonContent)
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
buffer.WriteByte('[')
|
||||
for k, v := range a.array {
|
||||
buffer.WriteString(`"` + gstr.QuoteMeta(v, `"\`) + `"`)
|
||||
if k != len(a.array)-1 {
|
||||
buffer.WriteByte(',')
|
||||
}
|
||||
}
|
||||
buffer.WriteByte(']')
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
@ -548,3 +558,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,16 +65,58 @@ 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
|
||||
}
|
||||
|
||||
// AddIfNotExistFunc adds the returned value of callback function <f> to the set
|
||||
// if <item> does not exit in the set.
|
||||
func (set *Set) AddIfNotExistFunc(item interface{}, f func() interface{}) *Set {
|
||||
if !set.Contains(item) {
|
||||
set.doAddWithLockCheck(item, f())
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
// AddIfNotExistFuncLock adds the returned value of callback function <f> to the set
|
||||
// if <item> does not exit in the set.
|
||||
//
|
||||
// Note that the callback function <f> is executed in the mutex.Lock of the set.
|
||||
func (set *Set) AddIfNotExistFuncLock(item interface{}, f func() interface{}) *Set {
|
||||
if !set.Contains(item) {
|
||||
set.doAddWithLockCheck(item, f)
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
// doAddWithLockCheck checks whether item exists with mutex.Lock,
|
||||
// if not exists, it adds item to the set or else just returns the existing value.
|
||||
//
|
||||
// If <value> is type of <func() interface {}>,
|
||||
// it will be executed with mutex.Lock of the set,
|
||||
// and its return value will be added to the set.
|
||||
//
|
||||
// It returns item successfully added..
|
||||
func (set *Set) doAddWithLockCheck(item interface{}, value interface{}) interface{} {
|
||||
set.mu.Lock()
|
||||
defer set.mu.Unlock()
|
||||
if _, ok := set.data[item]; !ok && value != nil {
|
||||
if f, ok := value.(func() interface{}); ok {
|
||||
item = f()
|
||||
} else {
|
||||
item = value
|
||||
}
|
||||
}
|
||||
set.data[item] = struct{}{}
|
||||
return item
|
||||
}
|
||||
|
||||
// Contains checks whether the set contains <item>.
|
||||
func (set *Set) Contains(item interface{}) bool {
|
||||
set.mu.RLock()
|
||||
_, exists := set.m[item]
|
||||
_, exists := set.data[item]
|
||||
set.mu.RUnlock()
|
||||
return exists
|
||||
}
|
||||
@ -82,7 +124,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 +132,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 +140,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 +149,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 +160,58 @@ 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)
|
||||
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 ','.
|
||||
// String returns items as a string, which implements like json.Marshal does.
|
||||
func (set *Set) String() string {
|
||||
return set.Join(",")
|
||||
set.mu.RLock()
|
||||
defer set.mu.RUnlock()
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
buffer.WriteByte('[')
|
||||
s := ""
|
||||
l := len(set.data)
|
||||
i := 0
|
||||
for k, _ := range set.data {
|
||||
s = gconv.String(k)
|
||||
if gstr.IsNumeric(s) {
|
||||
buffer.WriteString(s)
|
||||
} else {
|
||||
buffer.WriteString(`"` + gstr.QuoteMeta(s, `"\`) + `"`)
|
||||
}
|
||||
if i != l-1 {
|
||||
buffer.WriteByte(',')
|
||||
}
|
||||
i++
|
||||
}
|
||||
buffer.WriteByte(']')
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
// LockFunc locks writing with callback function <f>.
|
||||
func (set *Set) LockFunc(f func(m map[interface{}]struct{})) {
|
||||
set.mu.Lock()
|
||||
defer set.mu.Unlock()
|
||||
f(set.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 +223,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 +243,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 +261,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 +288,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 +308,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 +333,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 +349,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 +365,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 +375,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 +385,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 +404,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,16 +58,58 @@ 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
|
||||
}
|
||||
|
||||
// AddIfNotExistFunc adds the returned value of callback function <f> to the set
|
||||
// if <item> does not exit in the set.
|
||||
func (set *IntSet) AddIfNotExistFunc(item int, f func() int) *IntSet {
|
||||
if !set.Contains(item) {
|
||||
set.doAddWithLockCheck(item, f())
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
// AddIfNotExistFuncLock adds the returned value of callback function <f> to the set
|
||||
// if <item> does not exit in the set.
|
||||
//
|
||||
// Note that the callback function <f> is executed in the mutex.Lock of the set.
|
||||
func (set *IntSet) AddIfNotExistFuncLock(item int, f func() int) *IntSet {
|
||||
if !set.Contains(item) {
|
||||
set.doAddWithLockCheck(item, f)
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
// doAddWithLockCheck checks whether item exists with mutex.Lock,
|
||||
// if not exists, it adds item to the set or else just returns the existing value.
|
||||
//
|
||||
// If <value> is type of <func() interface {}>,
|
||||
// it will be executed with mutex.Lock of the set,
|
||||
// and its return value will be added to the set.
|
||||
//
|
||||
// It returns item successfully added..
|
||||
func (set *IntSet) doAddWithLockCheck(item int, value interface{}) int {
|
||||
set.mu.Lock()
|
||||
defer set.mu.Unlock()
|
||||
if _, ok := set.data[item]; !ok && value != nil {
|
||||
if f, ok := value.(func() int); ok {
|
||||
item = f()
|
||||
} else {
|
||||
item = value.(int)
|
||||
}
|
||||
}
|
||||
set.data[item] = struct{}{}
|
||||
return item
|
||||
}
|
||||
|
||||
// Contains checks whether the set contains <item>.
|
||||
func (set *IntSet) Contains(item int) bool {
|
||||
set.mu.RLock()
|
||||
_, exists := set.m[item]
|
||||
_, exists := set.data[item]
|
||||
set.mu.RUnlock()
|
||||
return exists
|
||||
}
|
||||
@ -76,7 +117,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 +125,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 +133,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 +141,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 +153,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 ','.
|
||||
// String returns items as a string, which implements like json.Marshal does.
|
||||
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 +196,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 +216,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 +234,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 +261,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 +281,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 +306,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 +322,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 +338,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 +348,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 +358,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 +377,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,16 +59,58 @@ 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
|
||||
}
|
||||
|
||||
// AddIfNotExistFunc adds the returned value of callback function <f> to the set
|
||||
// if <item> does not exit in the set.
|
||||
func (set *StrSet) AddIfNotExistFunc(item string, f func() string) *StrSet {
|
||||
if !set.Contains(item) {
|
||||
set.doAddWithLockCheck(item, f())
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
// AddIfNotExistFuncLock adds the returned value of callback function <f> to the set
|
||||
// if <item> does not exit in the set.
|
||||
//
|
||||
// Note that the callback function <f> is executed in the mutex.Lock of the set.
|
||||
func (set *StrSet) AddIfNotExistFuncLock(item string, f func() string) *StrSet {
|
||||
if !set.Contains(item) {
|
||||
set.doAddWithLockCheck(item, f)
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
// doAddWithLockCheck checks whether item exists with mutex.Lock,
|
||||
// if not exists, it adds item to the set or else just returns the existing value.
|
||||
//
|
||||
// If <value> is type of <func() interface {}>,
|
||||
// it will be executed with mutex.Lock of the set,
|
||||
// and its return value will be added to the set.
|
||||
//
|
||||
// It returns item successfully added..
|
||||
func (set *StrSet) doAddWithLockCheck(item string, value interface{}) string {
|
||||
set.mu.Lock()
|
||||
defer set.mu.Unlock()
|
||||
if _, ok := set.data[item]; !ok && value != nil {
|
||||
if f, ok := value.(func() string); ok {
|
||||
item = f()
|
||||
} else {
|
||||
item = value.(string)
|
||||
}
|
||||
}
|
||||
set.data[item] = struct{}{}
|
||||
return item
|
||||
}
|
||||
|
||||
// Contains checks whether the set contains <item>.
|
||||
func (set *StrSet) Contains(item string) bool {
|
||||
set.mu.RLock()
|
||||
_, exists := set.m[item]
|
||||
_, exists := set.data[item]
|
||||
set.mu.RUnlock()
|
||||
return exists
|
||||
}
|
||||
@ -76,7 +118,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 +126,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 +134,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 +142,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 +155,50 @@ 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 {
|
||||
buffer.WriteString(k)
|
||||
if i != l-1 {
|
||||
buffer.WriteString(glue)
|
||||
}
|
||||
i++
|
||||
}
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
// String returns items as a string, which are joined by char ','.
|
||||
// String returns items as a string, which implements like json.Marshal does.
|
||||
func (set *StrSet) String() string {
|
||||
return set.Join(",")
|
||||
set.mu.RLock()
|
||||
defer set.mu.RUnlock()
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
l := len(set.data)
|
||||
i := 0
|
||||
for k, _ := range set.data {
|
||||
buffer.WriteString(`"` + gstr.QuoteMeta(k, `"\`) + `"`)
|
||||
if i != l-1 {
|
||||
buffer.WriteByte(',')
|
||||
}
|
||||
i++
|
||||
}
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
// LockFunc locks writing with callback function <f>.
|
||||
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 +210,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 +230,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 +248,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 +275,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 +295,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 +320,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 +336,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 +352,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 +362,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 +372,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 +391,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"
|
||||
|
||||
"github.com/gogf/gf/container/garray"
|
||||
@ -214,7 +215,14 @@ func TestSet_Join(t *testing.T) {
|
||||
s1.Add("a").Add("a1").Add("b").Add("c")
|
||||
str1 := s1.Join(",")
|
||||
gtest.Assert(strings.Contains(str1, "a1"), true)
|
||||
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
s1 := gset.New(true)
|
||||
s1.Add("a").Add(`"b"`).Add(`\c`)
|
||||
str1 := s1.Join(",")
|
||||
gtest.Assert(strings.Contains(str1, `"b"`), true)
|
||||
gtest.Assert(strings.Contains(str1, `\c`), true)
|
||||
gtest.Assert(strings.Contains(str1, `a`), true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -223,8 +231,9 @@ func TestSet_String(t *testing.T) {
|
||||
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)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@ -267,3 +276,72 @@ func TestSet_Pops(t *testing.T) {
|
||||
gtest.Assert(len(s1.Pops(2)), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSet_Json(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s1 := []interface{}{"a", "b", "d", "c"}
|
||||
a1 := gset.NewFrom(s1)
|
||||
b1, err1 := json.Marshal(a1)
|
||||
b2, err2 := json.Marshal(s1)
|
||||
gtest.Assert(len(b1), len(b2))
|
||||
gtest.Assert(err1, err2)
|
||||
|
||||
a2 := gset.New()
|
||||
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.Set
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSet_AddIfNotExistFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s := gset.New(true)
|
||||
s.Add(1)
|
||||
gtest.Assert(s.Contains(1), true)
|
||||
gtest.Assert(s.Contains(2), false)
|
||||
|
||||
s.AddIfNotExistFunc(2, func() interface{} {
|
||||
return 3
|
||||
})
|
||||
gtest.Assert(s.Contains(2), false)
|
||||
gtest.Assert(s.Contains(3), true)
|
||||
|
||||
s.AddIfNotExistFunc(3, func() interface{} {
|
||||
return 4
|
||||
})
|
||||
gtest.Assert(s.Contains(3), true)
|
||||
gtest.Assert(s.Contains(4), false)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
s := gset.New(true)
|
||||
s.Add(1)
|
||||
gtest.Assert(s.Contains(1), true)
|
||||
gtest.Assert(s.Contains(2), false)
|
||||
|
||||
s.AddIfNotExistFuncLock(2, func() interface{} {
|
||||
return 3
|
||||
})
|
||||
gtest.Assert(s.Contains(2), false)
|
||||
gtest.Assert(s.Contains(3), true)
|
||||
|
||||
s.AddIfNotExistFuncLock(3, func() interface{} {
|
||||
return 4
|
||||
})
|
||||
gtest.Assert(s.Contains(3), true)
|
||||
gtest.Assert(s.Contains(4), false)
|
||||
})
|
||||
}
|
||||
@ -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,72 @@ 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)
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntSet_AddIfNotExistFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s := gset.NewIntSet(true)
|
||||
s.Add(1)
|
||||
gtest.Assert(s.Contains(1), true)
|
||||
gtest.Assert(s.Contains(2), false)
|
||||
|
||||
s.AddIfNotExistFunc(2, func() int {
|
||||
return 3
|
||||
})
|
||||
gtest.Assert(s.Contains(2), false)
|
||||
gtest.Assert(s.Contains(3), true)
|
||||
|
||||
s.AddIfNotExistFunc(3, func() int {
|
||||
return 4
|
||||
})
|
||||
gtest.Assert(s.Contains(3), true)
|
||||
gtest.Assert(s.Contains(4), false)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
s := gset.NewIntSet(true)
|
||||
s.Add(1)
|
||||
gtest.Assert(s.Contains(1), true)
|
||||
gtest.Assert(s.Contains(2), false)
|
||||
|
||||
s.AddIfNotExistFuncLock(2, func() int {
|
||||
return 3
|
||||
})
|
||||
gtest.Assert(s.Contains(2), false)
|
||||
gtest.Assert(s.Contains(3), true)
|
||||
|
||||
s.AddIfNotExistFuncLock(3, func() int {
|
||||
return 4
|
||||
})
|
||||
gtest.Assert(s.Contains(3), true)
|
||||
gtest.Assert(s.Contains(4), false)
|
||||
})
|
||||
}
|
||||
|
||||
@ -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,72 @@ 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)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStrSet_AddIfNotExistFunc(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
s := gset.NewStrSet(true)
|
||||
s.Add("1")
|
||||
gtest.Assert(s.Contains("1"), true)
|
||||
gtest.Assert(s.Contains("2"), false)
|
||||
|
||||
s.AddIfNotExistFunc("2", func() string {
|
||||
return "3"
|
||||
})
|
||||
gtest.Assert(s.Contains("2"), false)
|
||||
gtest.Assert(s.Contains("3"), true)
|
||||
|
||||
s.AddIfNotExistFunc("3", func() string {
|
||||
return "4"
|
||||
})
|
||||
gtest.Assert(s.Contains("3"), true)
|
||||
gtest.Assert(s.Contains("4"), false)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
s := gset.NewStrSet(true)
|
||||
s.Add("1")
|
||||
gtest.Assert(s.Contains("1"), true)
|
||||
gtest.Assert(s.Contains("2"), false)
|
||||
|
||||
s.AddIfNotExistFuncLock("2", func() string {
|
||||
return "3"
|
||||
})
|
||||
gtest.Assert(s.Contains("2"), false)
|
||||
gtest.Assert(s.Contains("3"), true)
|
||||
|
||||
s.AddIfNotExistFuncLock("3", func() string {
|
||||
return "4"
|
||||
})
|
||||
gtest.Assert(s.Contains("3"), true)
|
||||
gtest.Assert(s.Contains("4"), false)
|
||||
})
|
||||
}
|
||||
|
||||
@ -9,8 +9,8 @@ package gtree
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"github.com/gogf/gf/util/gutil"
|
||||
|
||||
"github.com/gogf/gf/container/gvar"
|
||||
"github.com/gogf/gf/internal/rwmutex"
|
||||
@ -61,6 +61,26 @@ func NewRedBlackTreeFrom(comparator func(v1, v2 interface{}) int, data map[inter
|
||||
return tree
|
||||
}
|
||||
|
||||
// SetComparator sets/changes the comparator for sorting.
|
||||
func (tree *RedBlackTree) SetComparator(comparator func(a, b interface{}) int) {
|
||||
tree.mu.Lock()
|
||||
defer tree.mu.Unlock()
|
||||
tree.comparator = comparator
|
||||
if tree.size > 0 {
|
||||
data := make(map[interface{}]interface{}, tree.size)
|
||||
tree.doIteratorAsc(tree.leftNode(), func(key, value interface{}) bool {
|
||||
data[key] = value
|
||||
return true
|
||||
})
|
||||
// Resort the tree if comparator is changed.
|
||||
tree.root = nil
|
||||
tree.size = 0
|
||||
for k, v := range data {
|
||||
tree.doSet(k, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clone returns a new tree with a copy of current tree.
|
||||
func (tree *RedBlackTree) Clone(safe ...bool) *RedBlackTree {
|
||||
newTree := NewRedBlackTree(tree.comparator, !tree.mu.IsSafe())
|
||||
@ -889,5 +909,23 @@ func (tree *RedBlackTree) nodeColor(node *RedBlackTreeNode) color {
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
func (tree *RedBlackTree) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(tree.Map())
|
||||
return json.Marshal(gconv.Map(tree.Map()))
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
|
||||
func (tree *RedBlackTree) UnmarshalJSON(b []byte) error {
|
||||
if tree.mu == nil {
|
||||
tree.mu = rwmutex.New()
|
||||
tree.comparator = gutil.ComparatorString
|
||||
}
|
||||
tree.mu.Lock()
|
||||
defer tree.mu.Unlock()
|
||||
var data map[string]interface{}
|
||||
if err := json.Unmarshal(b, &data); err != nil {
|
||||
return err
|
||||
}
|
||||
for k, v := range data {
|
||||
tree.doSet(k, v)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -7,6 +7,8 @@
|
||||
package gtype
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
@ -14,6 +16,11 @@ type Bool struct {
|
||||
value int32
|
||||
}
|
||||
|
||||
var (
|
||||
bytesTrue = []byte("true")
|
||||
bytesFalse = []byte("false")
|
||||
)
|
||||
|
||||
// NewBool returns a concurrent-safe object for bool type,
|
||||
// with given initial value <value>.
|
||||
func NewBool(value ...bool) *Bool {
|
||||
@ -59,3 +66,26 @@ func (v *Bool) Cas(old, new bool) bool {
|
||||
}
|
||||
return atomic.CompareAndSwapInt32(&v.value, oldInt32, newInt32)
|
||||
}
|
||||
|
||||
// String implements String interface for string printing.
|
||||
func (v *Bool) String() string {
|
||||
if v.Val() {
|
||||
return "true"
|
||||
}
|
||||
return "false"
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
func (v *Bool) MarshalJSON() ([]byte, error) {
|
||||
if v.Val() {
|
||||
return bytesTrue, nil
|
||||
} else {
|
||||
return bytesFalse, nil
|
||||
}
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
|
||||
func (v *Bool) UnmarshalJSON(b []byte) error {
|
||||
v.Set(gconv.Bool(bytes.Trim(b, `"`)))
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -7,6 +7,8 @@
|
||||
package gtype
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
@ -49,3 +51,19 @@ func (v *Byte) Add(delta byte) (new byte) {
|
||||
func (v *Byte) Cas(old, new byte) bool {
|
||||
return atomic.CompareAndSwapInt32(&v.value, int32(old), int32(new))
|
||||
}
|
||||
|
||||
// String implements String interface for string printing.
|
||||
func (v *Byte) String() string {
|
||||
return strconv.FormatUint(uint64(v.Val()), 10)
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
func (v *Byte) MarshalJSON() ([]byte, error) {
|
||||
return gconv.UnsafeStrToBytes(strconv.FormatUint(uint64(v.Val()), 10)), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
|
||||
func (v *Byte) UnmarshalJSON(b []byte) error {
|
||||
v.Set(gconv.Uint8(gconv.UnsafeBytesToStr(b)))
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -6,7 +6,12 @@
|
||||
|
||||
package gtype
|
||||
|
||||
import "sync/atomic"
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
type Bytes struct {
|
||||
value atomic.Value
|
||||
@ -42,3 +47,27 @@ func (v *Bytes) Val() []byte {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// String implements String interface for string printing.
|
||||
func (v *Bytes) String() string {
|
||||
return string(v.Val())
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
func (v *Bytes) MarshalJSON() ([]byte, error) {
|
||||
val := v.Val()
|
||||
dst := make([]byte, base64.StdEncoding.EncodedLen(len(val)))
|
||||
base64.StdEncoding.Encode(dst, val)
|
||||
return gconv.UnsafeStrToBytes(`"` + gconv.UnsafeBytesToStr(dst) + `"`), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
|
||||
func (v *Bytes) UnmarshalJSON(b []byte) error {
|
||||
src := make([]byte, base64.StdEncoding.DecodedLen(len(b)))
|
||||
n, err := base64.StdEncoding.Decode(src, bytes.Trim(b, `"`))
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
v.Set(src[:n])
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -7,7 +7,9 @@
|
||||
package gtype
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"math"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
)
|
||||
@ -60,5 +62,21 @@ func (v *Float32) Add(delta float32) (new float32) {
|
||||
|
||||
// Cas executes the compare-and-swap operation for value.
|
||||
func (v *Float32) Cas(old, new float32) bool {
|
||||
return atomic.CompareAndSwapUint32(&v.value, uint32(old), uint32(new))
|
||||
return atomic.CompareAndSwapUint32(&v.value, math.Float32bits(old), math.Float32bits(new))
|
||||
}
|
||||
|
||||
// String implements String interface for string printing.
|
||||
func (v *Float32) String() string {
|
||||
return strconv.FormatFloat(float64(v.Val()), 'g', -1, 32)
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
func (v *Float32) MarshalJSON() ([]byte, error) {
|
||||
return gconv.UnsafeStrToBytes(strconv.FormatFloat(float64(v.Val()), 'g', -1, 32)), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
|
||||
func (v *Float32) UnmarshalJSON(b []byte) error {
|
||||
v.Set(gconv.Float32(gconv.UnsafeBytesToStr(b)))
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -7,7 +7,9 @@
|
||||
package gtype
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"math"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
)
|
||||
@ -60,5 +62,21 @@ func (v *Float64) Add(delta float64) (new float64) {
|
||||
|
||||
// Cas executes the compare-and-swap operation for value.
|
||||
func (v *Float64) Cas(old, new float64) bool {
|
||||
return atomic.CompareAndSwapUint64(&v.value, uint64(old), uint64(new))
|
||||
return atomic.CompareAndSwapUint64(&v.value, math.Float64bits(old), math.Float64bits(new))
|
||||
}
|
||||
|
||||
// String implements String interface for string printing.
|
||||
func (v *Float64) String() string {
|
||||
return strconv.FormatFloat(v.Val(), 'g', -1, 64)
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
func (v *Float64) MarshalJSON() ([]byte, error) {
|
||||
return gconv.UnsafeStrToBytes(strconv.FormatFloat(v.Val(), 'g', -1, 64)), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
|
||||
func (v *Float64) UnmarshalJSON(b []byte) error {
|
||||
v.Set(gconv.Float64(gconv.UnsafeBytesToStr(b)))
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -7,8 +7,10 @@
|
||||
// Package gtype provides kinds of high performance and concurrent-safe basic variable types.
|
||||
package gtype
|
||||
|
||||
// Type is alias of Interface.
|
||||
type Type = Interface
|
||||
|
||||
// New is alias of NewInterface.
|
||||
// See NewInterface.
|
||||
func New(value ...interface{}) *Type {
|
||||
return NewInterface(value...)
|
||||
|
||||
@ -7,6 +7,8 @@
|
||||
package gtype
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
@ -49,3 +51,19 @@ func (v *Int) Add(delta int) (new int) {
|
||||
func (v *Int) Cas(old, new int) bool {
|
||||
return atomic.CompareAndSwapInt64(&v.value, int64(old), int64(new))
|
||||
}
|
||||
|
||||
// String implements String interface for string printing.
|
||||
func (v *Int) String() string {
|
||||
return strconv.Itoa(v.Val())
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
func (v *Int) MarshalJSON() ([]byte, error) {
|
||||
return gconv.UnsafeStrToBytes(strconv.Itoa(v.Val())), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
|
||||
func (v *Int) UnmarshalJSON(b []byte) error {
|
||||
v.Set(gconv.Int(gconv.UnsafeBytesToStr(b)))
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -7,6 +7,8 @@
|
||||
package gtype
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
@ -49,3 +51,19 @@ func (v *Int32) Add(delta int32) (new int32) {
|
||||
func (v *Int32) Cas(old, new int32) bool {
|
||||
return atomic.CompareAndSwapInt32(&v.value, old, new)
|
||||
}
|
||||
|
||||
// String implements String interface for string printing.
|
||||
func (v *Int32) String() string {
|
||||
return strconv.Itoa(int(v.Val()))
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
func (v *Int32) MarshalJSON() ([]byte, error) {
|
||||
return gconv.UnsafeStrToBytes(strconv.Itoa(int(v.Val()))), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
|
||||
func (v *Int32) UnmarshalJSON(b []byte) error {
|
||||
v.Set(gconv.Int32(gconv.UnsafeBytesToStr(b)))
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -7,6 +7,8 @@
|
||||
package gtype
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
@ -49,3 +51,19 @@ func (v *Int64) Add(delta int64) (new int64) {
|
||||
func (v *Int64) Cas(old, new int64) bool {
|
||||
return atomic.CompareAndSwapInt64(&v.value, old, new)
|
||||
}
|
||||
|
||||
// String implements String interface for string printing.
|
||||
func (v *Int64) String() string {
|
||||
return strconv.FormatInt(v.Val(), 10)
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
func (v *Int64) MarshalJSON() ([]byte, error) {
|
||||
return gconv.UnsafeStrToBytes(strconv.FormatInt(v.Val(), 10)), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
|
||||
func (v *Int64) UnmarshalJSON(b []byte) error {
|
||||
v.Set(gconv.Int64(gconv.UnsafeBytesToStr(b)))
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -7,6 +7,8 @@
|
||||
package gtype
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
@ -41,3 +43,24 @@ func (v *Interface) Set(value interface{}) (old interface{}) {
|
||||
func (v *Interface) Val() interface{} {
|
||||
return v.value.Load()
|
||||
}
|
||||
|
||||
// String implements String interface for string printing.
|
||||
func (v *Interface) String() string {
|
||||
return gconv.String(v.Val())
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
func (v *Interface) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(v.Val())
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
|
||||
func (v *Interface) UnmarshalJSON(b []byte) error {
|
||||
var i interface{}
|
||||
err := json.Unmarshal(b, &i)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.Set(i)
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -7,6 +7,8 @@
|
||||
package gtype
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
@ -44,3 +46,19 @@ func (v *String) Val() string {
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// String implements String interface for string printing.
|
||||
func (v *String) String() string {
|
||||
return v.Val()
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
func (v *String) MarshalJSON() ([]byte, error) {
|
||||
return gconv.UnsafeStrToBytes(`"` + v.Val() + `"`), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
|
||||
func (v *String) UnmarshalJSON(b []byte) error {
|
||||
v.Set(gconv.UnsafeBytesToStr(bytes.Trim(b, `"`)))
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -7,6 +7,8 @@
|
||||
package gtype
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
@ -49,3 +51,19 @@ func (v *Uint) Add(delta uint) (new uint) {
|
||||
func (v *Uint) Cas(old, new uint) bool {
|
||||
return atomic.CompareAndSwapUint64(&v.value, uint64(old), uint64(new))
|
||||
}
|
||||
|
||||
// String implements String interface for string printing.
|
||||
func (v *Uint) String() string {
|
||||
return strconv.FormatUint(uint64(v.Val()), 10)
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
func (v *Uint) MarshalJSON() ([]byte, error) {
|
||||
return gconv.UnsafeStrToBytes(strconv.FormatUint(uint64(v.Val()), 10)), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
|
||||
func (v *Uint) UnmarshalJSON(b []byte) error {
|
||||
v.Set(gconv.Uint(gconv.UnsafeBytesToStr(b)))
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -7,6 +7,8 @@
|
||||
package gtype
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
@ -49,3 +51,19 @@ func (v *Uint32) Add(delta uint32) (new uint32) {
|
||||
func (v *Uint32) Cas(old, new uint32) bool {
|
||||
return atomic.CompareAndSwapUint32(&v.value, old, new)
|
||||
}
|
||||
|
||||
// String implements String interface for string printing.
|
||||
func (v *Uint32) String() string {
|
||||
return strconv.FormatUint(uint64(v.Val()), 10)
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
func (v *Uint32) MarshalJSON() ([]byte, error) {
|
||||
return gconv.UnsafeStrToBytes(strconv.FormatUint(uint64(v.Val()), 10)), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
|
||||
func (v *Uint32) UnmarshalJSON(b []byte) error {
|
||||
v.Set(gconv.Uint32(gconv.UnsafeBytesToStr(b)))
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -7,6 +7,8 @@
|
||||
package gtype
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
)
|
||||
|
||||
@ -49,3 +51,19 @@ func (v *Uint64) Add(delta uint64) (new uint64) {
|
||||
func (v *Uint64) Cas(old, new uint64) bool {
|
||||
return atomic.CompareAndSwapUint64(&v.value, old, new)
|
||||
}
|
||||
|
||||
// String implements String interface for string printing.
|
||||
func (v *Uint64) String() string {
|
||||
return strconv.FormatUint(v.Val(), 10)
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
func (v *Uint64) MarshalJSON() ([]byte, error) {
|
||||
return gconv.UnsafeStrToBytes(strconv.FormatUint(v.Val(), 10)), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
|
||||
func (v *Uint64) UnmarshalJSON(b []byte) error {
|
||||
v.Set(gconv.Uint64(gconv.UnsafeBytesToStr(b)))
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -6,9 +6,10 @@
|
||||
|
||||
// go test *.go -bench=".*" -benchmem
|
||||
|
||||
package gtype
|
||||
package gtype_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/container/gtype"
|
||||
"strconv"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
@ -16,18 +17,19 @@ import (
|
||||
"github.com/gogf/gf/encoding/gbinary"
|
||||
)
|
||||
|
||||
var it = NewInt()
|
||||
var it32 = NewInt32()
|
||||
var it64 = NewInt64()
|
||||
var uit = NewUint()
|
||||
var uit32 = NewUint32()
|
||||
var uit64 = NewUint64()
|
||||
var bl = NewBool()
|
||||
var bytes = NewBytes()
|
||||
var str = NewString()
|
||||
var inf = NewInterface()
|
||||
|
||||
var at = atomic.Value{}
|
||||
var (
|
||||
it = gtype.NewInt()
|
||||
it32 = gtype.NewInt32()
|
||||
it64 = gtype.NewInt64()
|
||||
uit = gtype.NewUint()
|
||||
uit32 = gtype.NewUint32()
|
||||
uit64 = gtype.NewUint64()
|
||||
bl = gtype.NewBool()
|
||||
vbytes = gtype.NewBytes()
|
||||
str = gtype.NewString()
|
||||
inf = gtype.NewInterface()
|
||||
at = atomic.Value{}
|
||||
)
|
||||
|
||||
func BenchmarkInt_Set(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
@ -163,13 +165,13 @@ func BenchmarkString_Val(b *testing.B) {
|
||||
|
||||
func BenchmarkBytes_Set(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
bytes.Set(gbinary.EncodeInt(i))
|
||||
vbytes.Set(gbinary.EncodeInt(i))
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkBytes_Val(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
bytes.Val()
|
||||
vbytes.Val()
|
||||
}
|
||||
}
|
||||
|
||||
103
container/gtype/z_bench_json_test.go
Normal file
103
container/gtype/z_bench_json_test.go
Normal file
@ -0,0 +1,103 @@
|
||||
// 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 -bench=".+\_Json" -benchmem
|
||||
|
||||
package gtype_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/gogf/gf/container/gtype"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
vBool = gtype.NewBool()
|
||||
vByte = gtype.NewByte()
|
||||
vBytes = gtype.NewBytes()
|
||||
vFloat32 = gtype.NewFloat32()
|
||||
vFloat64 = gtype.NewFloat64()
|
||||
vInt = gtype.NewInt()
|
||||
vInt32 = gtype.NewInt32()
|
||||
vInt64 = gtype.NewInt64()
|
||||
vInterface = gtype.NewInterface()
|
||||
vString = gtype.NewString()
|
||||
vUint = gtype.NewUint()
|
||||
vUint32 = gtype.NewUint32()
|
||||
vUint64 = gtype.NewUint64()
|
||||
)
|
||||
|
||||
func Benchmark_Bool_Json(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
json.Marshal(vBool)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Byte_Json(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
json.Marshal(vByte)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Bytes_Json(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
json.Marshal(vBytes)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Float32_Json(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
json.Marshal(vFloat32)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Float64_Json(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
json.Marshal(vFloat64)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Int_Json(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
json.Marshal(vInt)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Int32_Json(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
json.Marshal(vInt32)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Int64_Json(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
json.Marshal(vInt64)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Interface_Json(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
json.Marshal(vInterface)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_String_Json(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
json.Marshal(vString)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Uint_Json(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
json.Marshal(vUint)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Uint32_Json(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
json.Marshal(vUint64)
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,8 @@
|
||||
package gtype_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
@ -35,6 +37,68 @@ func Test_Bool(t *testing.T) {
|
||||
i2 := gtype.NewBool()
|
||||
gtest.AssertEQ(i2.Val(), false)
|
||||
})
|
||||
|
||||
// Marshal
|
||||
gtest.Case(t, func() {
|
||||
i := gtype.NewBool(true)
|
||||
b1, err1 := json.Marshal(i)
|
||||
b2, err2 := json.Marshal(i.Val())
|
||||
gtest.Assert(err1, nil)
|
||||
gtest.Assert(err2, nil)
|
||||
gtest.Assert(b1, b2)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
i := gtype.NewBool(false)
|
||||
b1, err1 := json.Marshal(i)
|
||||
b2, err2 := json.Marshal(i.Val())
|
||||
gtest.Assert(err1, nil)
|
||||
gtest.Assert(err2, nil)
|
||||
gtest.Assert(b1, b2)
|
||||
})
|
||||
// Unmarshal
|
||||
gtest.Case(t, func() {
|
||||
var err error
|
||||
i := gtype.NewBool()
|
||||
err = json.Unmarshal([]byte("true"), &i)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(i.Val(), true)
|
||||
err = json.Unmarshal([]byte("false"), &i)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(i.Val(), false)
|
||||
err = json.Unmarshal([]byte("1"), &i)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(i.Val(), true)
|
||||
err = json.Unmarshal([]byte("0"), &i)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(i.Val(), false)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
i := gtype.NewBool(true)
|
||||
b1, err1 := json.Marshal(i)
|
||||
b2, err2 := json.Marshal(i.Val())
|
||||
gtest.Assert(err1, nil)
|
||||
gtest.Assert(err2, nil)
|
||||
gtest.Assert(b1, b2)
|
||||
|
||||
i2 := gtype.NewBool()
|
||||
err := json.Unmarshal(b2, &i2)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(i2.Val(), i.Val())
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
i := gtype.NewBool(false)
|
||||
b1, err1 := json.Marshal(i)
|
||||
b2, err2 := json.Marshal(i.Val())
|
||||
gtest.Assert(err1, nil)
|
||||
gtest.Assert(err2, nil)
|
||||
gtest.Assert(b1, b2)
|
||||
|
||||
i2 := gtype.NewBool()
|
||||
err := json.Unmarshal(b2, &i2)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(i2.Val(), i.Val())
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Byte(t *testing.T) {
|
||||
@ -59,6 +123,22 @@ func Test_Byte(t *testing.T) {
|
||||
i1 := gtype.NewByte()
|
||||
gtest.AssertEQ(i1.Val(), byte(0))
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
i := gtype.NewByte(49)
|
||||
b1, err1 := json.Marshal(i)
|
||||
b2, err2 := json.Marshal(i.Val())
|
||||
gtest.Assert(err1, nil)
|
||||
gtest.Assert(err2, nil)
|
||||
gtest.Assert(b1, b2)
|
||||
})
|
||||
// Unmarshal
|
||||
gtest.Case(t, func() {
|
||||
var err error
|
||||
i := gtype.NewByte()
|
||||
err = json.Unmarshal([]byte("49"), &i)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(i.Val(), "49")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Bytes(t *testing.T) {
|
||||
@ -72,6 +152,20 @@ func Test_Bytes(t *testing.T) {
|
||||
i1 := gtype.NewBytes()
|
||||
gtest.AssertEQ(i1.Val(), nil)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
b := []byte("i love gf")
|
||||
i := gtype.NewBytes(b)
|
||||
b1, err1 := json.Marshal(i)
|
||||
b2, err2 := json.Marshal(i.Val())
|
||||
gtest.Assert(err1, nil)
|
||||
gtest.Assert(err2, nil)
|
||||
gtest.Assert(b1, b2)
|
||||
|
||||
i2 := gtype.NewBytes()
|
||||
err := json.Unmarshal(b2, &i2)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(i2.Val(), b)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_String(t *testing.T) {
|
||||
@ -85,6 +179,20 @@ func Test_String(t *testing.T) {
|
||||
i1 := gtype.NewString()
|
||||
gtest.AssertEQ(i1.Val(), "")
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
s := "i love gf"
|
||||
i1 := gtype.NewString(s)
|
||||
b1, err1 := json.Marshal(i1)
|
||||
b2, err2 := json.Marshal(i1.Val())
|
||||
gtest.Assert(err1, nil)
|
||||
gtest.Assert(err2, nil)
|
||||
gtest.Assert(b1, b2)
|
||||
|
||||
i2 := gtype.NewString()
|
||||
err := json.Unmarshal(b2, &i2)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(i2.Val(), s)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Interface(t *testing.T) {
|
||||
@ -100,6 +208,20 @@ func Test_Interface(t *testing.T) {
|
||||
i1 := gtype.New()
|
||||
gtest.AssertEQ(i1.Val(), nil)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
s := "i love gf"
|
||||
i := gtype.New(s)
|
||||
b1, err1 := json.Marshal(i)
|
||||
b2, err2 := json.Marshal(i.Val())
|
||||
gtest.Assert(err1, nil)
|
||||
gtest.Assert(err2, nil)
|
||||
gtest.Assert(b1, b2)
|
||||
|
||||
i2 := gtype.New()
|
||||
err := json.Unmarshal(b2, &i2)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(i2.Val(), s)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Float32(t *testing.T) {
|
||||
@ -125,6 +247,21 @@ func Test_Float32(t *testing.T) {
|
||||
i1 := gtype.NewFloat32()
|
||||
gtest.AssertEQ(i1.Val(), float32(0))
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
v := float32(math.MaxFloat32)
|
||||
i := gtype.NewFloat32(v)
|
||||
b1, err1 := json.Marshal(i)
|
||||
b2, err2 := json.Marshal(i.Val())
|
||||
|
||||
gtest.Assert(err1, nil)
|
||||
gtest.Assert(err2, nil)
|
||||
gtest.Assert(b1, b2)
|
||||
|
||||
i2 := gtype.NewFloat32()
|
||||
err := json.Unmarshal(b2, &i2)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(i2.Val(), v)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Float64(t *testing.T) {
|
||||
@ -150,6 +287,20 @@ func Test_Float64(t *testing.T) {
|
||||
i1 := gtype.NewFloat64()
|
||||
gtest.AssertEQ(i1.Val(), float64(0))
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
v := math.MaxFloat64
|
||||
i := gtype.NewFloat64(v)
|
||||
b1, err1 := json.Marshal(i)
|
||||
b2, err2 := json.Marshal(i.Val())
|
||||
gtest.Assert(err1, nil)
|
||||
gtest.Assert(err2, nil)
|
||||
gtest.Assert(b1, b2)
|
||||
|
||||
i2 := gtype.NewFloat64()
|
||||
err := json.Unmarshal(b2, &i2)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(i2.Val(), v)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Int(t *testing.T) {
|
||||
@ -174,6 +325,20 @@ func Test_Int(t *testing.T) {
|
||||
i1 := gtype.NewInt()
|
||||
gtest.AssertEQ(i1.Val(), 0)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
v := 666
|
||||
i := gtype.NewInt(v)
|
||||
b1, err1 := json.Marshal(i)
|
||||
b2, err2 := json.Marshal(i.Val())
|
||||
gtest.Assert(err1, nil)
|
||||
gtest.Assert(err2, nil)
|
||||
gtest.Assert(b1, b2)
|
||||
|
||||
i2 := gtype.NewInt()
|
||||
err := json.Unmarshal(b2, &i2)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(i2.Val(), v)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Int32(t *testing.T) {
|
||||
@ -198,6 +363,20 @@ func Test_Int32(t *testing.T) {
|
||||
i1 := gtype.NewInt32()
|
||||
gtest.AssertEQ(i1.Val(), int32(0))
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
v := int32(math.MaxInt32)
|
||||
i := gtype.NewInt32(v)
|
||||
b1, err1 := json.Marshal(i)
|
||||
b2, err2 := json.Marshal(i.Val())
|
||||
gtest.Assert(err1, nil)
|
||||
gtest.Assert(err2, nil)
|
||||
gtest.Assert(b1, b2)
|
||||
|
||||
i2 := gtype.NewInt32()
|
||||
err := json.Unmarshal(b2, &i2)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(i2.Val(), v)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Int64(t *testing.T) {
|
||||
@ -222,6 +401,19 @@ func Test_Int64(t *testing.T) {
|
||||
i1 := gtype.NewInt64()
|
||||
gtest.AssertEQ(i1.Val(), int64(0))
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
i := gtype.NewInt64(math.MaxInt64)
|
||||
b1, err1 := json.Marshal(i)
|
||||
b2, err2 := json.Marshal(i.Val())
|
||||
gtest.Assert(err1, nil)
|
||||
gtest.Assert(err2, nil)
|
||||
gtest.Assert(b1, b2)
|
||||
|
||||
i2 := gtype.NewInt64()
|
||||
err := json.Unmarshal(b2, &i2)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(i2.Val(), i)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Uint(t *testing.T) {
|
||||
@ -246,6 +438,19 @@ func Test_Uint(t *testing.T) {
|
||||
i1 := gtype.NewUint()
|
||||
gtest.AssertEQ(i1.Val(), uint(0))
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
i := gtype.NewUint(666)
|
||||
b1, err1 := json.Marshal(i)
|
||||
b2, err2 := json.Marshal(i.Val())
|
||||
gtest.Assert(err1, nil)
|
||||
gtest.Assert(err2, nil)
|
||||
gtest.Assert(b1, b2)
|
||||
|
||||
i2 := gtype.NewUint()
|
||||
err := json.Unmarshal(b2, &i2)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(i2.Val(), i)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Uint32(t *testing.T) {
|
||||
@ -270,6 +475,19 @@ func Test_Uint32(t *testing.T) {
|
||||
i1 := gtype.NewUint32()
|
||||
gtest.AssertEQ(i1.Val(), uint32(0))
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
i := gtype.NewUint32(math.MaxUint32)
|
||||
b1, err1 := json.Marshal(i)
|
||||
b2, err2 := json.Marshal(i.Val())
|
||||
gtest.Assert(err1, nil)
|
||||
gtest.Assert(err2, nil)
|
||||
gtest.Assert(b1, b2)
|
||||
|
||||
i2 := gtype.NewUint32()
|
||||
err := json.Unmarshal(b2, &i2)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(i2.Val(), i)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Uint64(t *testing.T) {
|
||||
@ -294,4 +512,17 @@ func Test_Uint64(t *testing.T) {
|
||||
i1 := gtype.NewUint64()
|
||||
gtest.AssertEQ(i1.Val(), uint64(0))
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
i := gtype.NewUint64(math.MaxUint64)
|
||||
b1, err1 := json.Marshal(i)
|
||||
b2, err2 := json.Marshal(i.Val())
|
||||
gtest.Assert(err1, nil)
|
||||
gtest.Assert(err2, nil)
|
||||
gtest.Assert(b1, b2)
|
||||
|
||||
i2 := gtype.NewUint64()
|
||||
err := json.Unmarshal(b2, &i2)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(i2.Val(), i)
|
||||
})
|
||||
}
|
||||
|
||||
@ -24,11 +24,19 @@ type Var struct {
|
||||
safe bool // Concurrent safe or not.
|
||||
}
|
||||
|
||||
// New returns a new Var with given <value>.
|
||||
// The parameter <safe> used to specify whether using Var in concurrent-safety,
|
||||
// New creates and returns a new *Var with given <value>.
|
||||
// The optional parameter <safe> specifies whether Var is used in concurrent-safety,
|
||||
// which is false in default.
|
||||
func New(value interface{}, safe ...bool) *Var {
|
||||
v := &Var{}
|
||||
v := Create(value, safe...)
|
||||
return &v
|
||||
}
|
||||
|
||||
// Create creates and returns a new Var with given <value>.
|
||||
// The optional parameter <safe> specifies whether Var is used in concurrent-safety,
|
||||
// which is false in default.
|
||||
func Create(value interface{}, safe ...bool) Var {
|
||||
v := Var{}
|
||||
if len(safe) > 0 && !safe[0] {
|
||||
v.safe = true
|
||||
v.value = gtype.NewInterface(value)
|
||||
@ -38,11 +46,6 @@ func New(value interface{}, safe ...bool) *Var {
|
||||
return v
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
func (v *Var) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(v.Val())
|
||||
}
|
||||
|
||||
// Set sets <value> to <v>, and returns the old value.
|
||||
func (v *Var) Set(value interface{}) (old interface{}) {
|
||||
if v.safe {
|
||||
@ -56,6 +59,9 @@ func (v *Var) Set(value interface{}) (old interface{}) {
|
||||
|
||||
// Val returns the current value of <v>.
|
||||
func (v *Var) Val() interface{} {
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
if v.safe {
|
||||
return v.value.(*gtype.Interface).Val()
|
||||
}
|
||||
@ -97,6 +103,11 @@ func (v *Var) Int() int {
|
||||
return gconv.Int(v.Val())
|
||||
}
|
||||
|
||||
// Ints converts and returns <v> as []int.
|
||||
func (v *Var) Ints() []int {
|
||||
return gconv.Ints(v.Val())
|
||||
}
|
||||
|
||||
// Int8 converts and returns <v> as int8.
|
||||
func (v *Var) Int8() int8 {
|
||||
return gconv.Int8(v.Val())
|
||||
@ -122,6 +133,11 @@ func (v *Var) Uint() uint {
|
||||
return gconv.Uint(v.Val())
|
||||
}
|
||||
|
||||
// Uints converts and returns <v> as []uint.
|
||||
func (v *Var) Uints() []uint {
|
||||
return gconv.Uints(v.Val())
|
||||
}
|
||||
|
||||
// Uint8 converts and returns <v> as uint8.
|
||||
func (v *Var) Uint8() uint8 {
|
||||
return gconv.Uint8(v.Val())
|
||||
@ -152,11 +168,6 @@ func (v *Var) Float64() float64 {
|
||||
return gconv.Float64(v.Val())
|
||||
}
|
||||
|
||||
// Ints converts and returns <v> as []int.
|
||||
func (v *Var) Ints() []int {
|
||||
return gconv.Ints(v.Val())
|
||||
}
|
||||
|
||||
// Floats converts and returns <v> as []float64.
|
||||
func (v *Var) Floats() []float64 {
|
||||
return gconv.Floats(v.Val())
|
||||
@ -324,3 +335,19 @@ func (v *Var) MapToMaps(pointer interface{}, mapping ...map[string]string) (err
|
||||
func (v *Var) MapToMapsDeep(pointer interface{}, mapping ...map[string]string) (err error) {
|
||||
return gconv.MapToMapsDeep(v.Val(), pointer, mapping...)
|
||||
}
|
||||
|
||||
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
|
||||
func (v *Var) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(v.Val())
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
|
||||
func (v *Var) UnmarshalJSON(b []byte) error {
|
||||
var i interface{}
|
||||
err := json.Unmarshal(b, &i)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v.Set(i)
|
||||
return nil
|
||||
}
|
||||
|
||||
145
container/gvar/gvar_z_bench_obj_test.go
Normal file
145
container/gvar/gvar_z_bench_obj_test.go
Normal file
@ -0,0 +1,145 @@
|
||||
// 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 -bench=".*" -benchmem
|
||||
|
||||
package gvar
|
||||
|
||||
import "testing"
|
||||
|
||||
var varObj = Create(nil)
|
||||
|
||||
func Benchmark_Obj_Set(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varObj.Set(i)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Obj_Val(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varObj.Val()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Obj_IsNil(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varObj.IsNil()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Obj_Bytes(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varObj.Bytes()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Obj_String(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varObj.String()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Obj_Bool(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varObj.Bool()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Obj_Int(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varObj.Int()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Obj_Int8(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varObj.Int8()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Obj_Int16(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varObj.Int16()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Obj_Int32(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varObj.Int32()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Obj_Int64(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varObj.Int64()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Obj_Uint(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varObj.Uint()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Obj_Uint8(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varObj.Uint8()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Obj_Uint16(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varObj.Uint16()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Obj_Uint32(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varObj.Uint32()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Obj_Uint64(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varObj.Uint64()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Obj_Float32(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varObj.Float32()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Obj_Float64(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varObj.Float64()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Obj_Ints(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varObj.Ints()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Obj_Strings(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varObj.Strings()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Obj_Floats(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varObj.Floats()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Obj_Interfaces(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varObj.Interfaces()
|
||||
}
|
||||
}
|
||||
145
container/gvar/gvar_z_bench_ptr_test.go
Normal file
145
container/gvar/gvar_z_bench_ptr_test.go
Normal file
@ -0,0 +1,145 @@
|
||||
// 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 -bench=".*" -benchmem
|
||||
|
||||
package gvar
|
||||
|
||||
import "testing"
|
||||
|
||||
var varPtr = New(nil)
|
||||
|
||||
func Benchmark_Ptr_Set(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varPtr.Set(i)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Ptr_Val(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varPtr.Val()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Ptr_IsNil(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varPtr.IsNil()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Ptr_Bytes(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varPtr.Bytes()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Ptr_String(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varPtr.String()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Ptr_Bool(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varPtr.Bool()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Ptr_Int(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varPtr.Int()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Ptr_Int8(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varPtr.Int8()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Ptr_Int16(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varPtr.Int16()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Ptr_Int32(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varPtr.Int32()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Ptr_Int64(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varPtr.Int64()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Ptr_Uint(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varPtr.Uint()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Ptr_Uint8(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varPtr.Uint8()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Ptr_Uint16(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varPtr.Uint16()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Ptr_Uint32(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varPtr.Uint32()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Ptr_Uint64(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varPtr.Uint64()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Ptr_Float32(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varPtr.Float32()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Ptr_Float64(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varPtr.Float64()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Ptr_Ints(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varPtr.Ints()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Ptr_Strings(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varPtr.Strings()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Ptr_Floats(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varPtr.Floats()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Ptr_Interfaces(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
varPtr.Interfaces()
|
||||
}
|
||||
}
|
||||
@ -1,145 +0,0 @@
|
||||
// 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 -bench=".*" -benchmem
|
||||
|
||||
package gvar
|
||||
|
||||
import "testing"
|
||||
|
||||
var vn = New(nil)
|
||||
|
||||
func Benchmark_Set(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
vn.Set(i)
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Val(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
vn.Val()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_IsNil(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
vn.IsNil()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Bytes(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
vn.Bytes()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_String(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
vn.String()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Bool(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
vn.Bool()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Int(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
vn.Int()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Int8(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
vn.Int8()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Int16(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
vn.Int16()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Int32(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
vn.Int32()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Int64(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
vn.Int64()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Uint(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
vn.Uint()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Uint8(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
vn.Uint8()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Uint16(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
vn.Uint16()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Uint32(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
vn.Uint32()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Uint64(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
vn.Uint64()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Float32(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
vn.Float32()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Float64(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
vn.Float64()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Ints(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
vn.Ints()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Strings(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
vn.Strings()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Floats(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
vn.Floats()
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_Interfaces(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
vn.Interfaces()
|
||||
}
|
||||
}
|
||||
@ -9,6 +9,8 @@ package gvar_test
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"math"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -19,6 +21,20 @@ import (
|
||||
)
|
||||
|
||||
func Test_Set(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var v gvar.Var
|
||||
v.Set(123.456)
|
||||
gtest.Assert(v.Val(), 123.456)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
var v gvar.Var
|
||||
v.Set(123.456)
|
||||
gtest.Assert(v.Val(), 123.456)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
v := gvar.Create(123.456)
|
||||
gtest.Assert(v.Val(), 123.456)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
objOne := gvar.New("old", true)
|
||||
objOneOld, _ := objOne.Set("new").(string)
|
||||
@ -300,12 +316,12 @@ func Test_Map(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
type StTest struct {
|
||||
Test int
|
||||
}
|
||||
|
||||
func Test_Struct(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
type StTest struct {
|
||||
Test int
|
||||
}
|
||||
|
||||
Kv := make(map[string]int, 1)
|
||||
Kv["Test"] = 100
|
||||
|
||||
@ -318,3 +334,47 @@ func Test_Struct(t *testing.T) {
|
||||
gtest.Assert(testObj.Test, Kv["Test"])
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Json(t *testing.T) {
|
||||
// Marshal
|
||||
gtest.Case(t, func() {
|
||||
s := "i love gf"
|
||||
v := gvar.New(s)
|
||||
b1, err1 := json.Marshal(v)
|
||||
b2, err2 := json.Marshal(s)
|
||||
gtest.Assert(err1, err2)
|
||||
gtest.Assert(b1, b2)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
s := int64(math.MaxInt64)
|
||||
v := gvar.New(s)
|
||||
b1, err1 := json.Marshal(v)
|
||||
b2, err2 := json.Marshal(s)
|
||||
gtest.Assert(err1, err2)
|
||||
gtest.Assert(b1, b2)
|
||||
})
|
||||
|
||||
// Unmarshal
|
||||
gtest.Case(t, func() {
|
||||
s := "i love gf"
|
||||
v := gvar.New(nil)
|
||||
b, err := json.Marshal(s)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
err = json.Unmarshal(b, v)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(v.String(), s)
|
||||
})
|
||||
|
||||
gtest.Case(t, func() {
|
||||
var v gvar.Var
|
||||
s := "i love gf"
|
||||
b, err := json.Marshal(s)
|
||||
gtest.Assert(err, nil)
|
||||
|
||||
err = json.Unmarshal(b, &v)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(v.String(), s)
|
||||
})
|
||||
}
|
||||
|
||||
@ -13,7 +13,6 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/gogf/gf/errors/gerror"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
)
|
||||
|
||||
@ -43,9 +42,7 @@ func EncryptFile(path string) (encrypt string, err error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer func() {
|
||||
err = gerror.Wrap(f.Close(), "file closing error")
|
||||
}()
|
||||
defer f.Close()
|
||||
h := md5.New()
|
||||
_, err = io.Copy(h, f)
|
||||
if err != nil {
|
||||
|
||||
@ -13,7 +13,6 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/gogf/gf/errors/gerror"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
)
|
||||
|
||||
@ -30,9 +29,7 @@ func EncryptFile(path string) (encrypt string, err error) {
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer func() {
|
||||
err = gerror.Wrap(f.Close(), "file closing error")
|
||||
}()
|
||||
defer f.Close()
|
||||
h := sha1.New()
|
||||
_, err = io.Copy(h, f)
|
||||
if err != nil {
|
||||
|
||||
@ -165,10 +165,10 @@ type Map = map[string]interface{}
|
||||
type List = []Map
|
||||
|
||||
const (
|
||||
OPTION_INSERT = 0
|
||||
OPTION_REPLACE = 1
|
||||
OPTION_SAVE = 2
|
||||
OPTION_IGNORE = 3
|
||||
gINSERT_OPTION_DEFAULT = 0
|
||||
gINSERT_OPTION_REPLACE = 1
|
||||
gINSERT_OPTION_SAVE = 2
|
||||
gINSERT_OPTION_IGNORE = 3
|
||||
gDEFAULT_BATCH_NUM = 10 // Per count for batch insert/replace/save
|
||||
gDEFAULT_CONN_MAX_LIFE_TIME = 30 // Max life time for per connection in pool.
|
||||
)
|
||||
|
||||
@ -217,7 +217,7 @@ func (bs *dbBase) GetStruct(pointer interface{}, query string, args ...interface
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return one.ToStruct(pointer)
|
||||
return one.Struct(pointer)
|
||||
}
|
||||
|
||||
// 数据库查询,查询多条记录,并自动转换为指定的slice对象, 如: []struct/[]*struct。
|
||||
@ -226,7 +226,7 @@ func (bs *dbBase) GetStructs(pointer interface{}, query string, args ...interfac
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return all.ToStructs(pointer)
|
||||
return all.Structs(pointer)
|
||||
}
|
||||
|
||||
// 将结果转换为指定的struct/*struct/[]struct/[]*struct,
|
||||
@ -312,21 +312,21 @@ func (bs *dbBase) Begin() (*TX, error) {
|
||||
// 参数data支持map/struct/*struct/slice类型,
|
||||
// 当为slice(例如[]map/[]struct/[]*struct)类型时,batch参数生效,并自动切换为批量操作。
|
||||
func (bs *dbBase) Insert(table string, data interface{}, batch ...int) (sql.Result, error) {
|
||||
return bs.db.doInsert(nil, table, data, OPTION_INSERT, batch...)
|
||||
return bs.db.doInsert(nil, table, data, gINSERT_OPTION_DEFAULT, batch...)
|
||||
}
|
||||
|
||||
// CURD操作:单条数据写入, 如果数据存在(主键或者唯一索引),那么删除后重新写入一条。
|
||||
// 参数data支持map/struct/*struct/slice类型,
|
||||
// 当为slice(例如[]map/[]struct/[]*struct)类型时,batch参数生效,并自动切换为批量操作。
|
||||
func (bs *dbBase) Replace(table string, data interface{}, batch ...int) (sql.Result, error) {
|
||||
return bs.db.doInsert(nil, table, data, OPTION_REPLACE, batch...)
|
||||
return bs.db.doInsert(nil, table, data, gINSERT_OPTION_REPLACE, batch...)
|
||||
}
|
||||
|
||||
// CURD操作:单条数据写入, 如果数据存在(主键或者唯一索引),那么更新,否则写入一条新数据。
|
||||
// 参数data支持map/struct/*struct/slice类型,
|
||||
// 当为slice(例如[]map/[]struct/[]*struct)类型时,batch参数生效,并自动切换为批量操作。
|
||||
func (bs *dbBase) Save(table string, data interface{}, batch ...int) (sql.Result, error) {
|
||||
return bs.db.doInsert(nil, table, data, OPTION_SAVE, batch...)
|
||||
return bs.db.doInsert(nil, table, data, gINSERT_OPTION_SAVE, batch...)
|
||||
}
|
||||
|
||||
// 支持insert、replace, save, ignore操作。
|
||||
@ -351,17 +351,16 @@ func (bs *dbBase) doInsert(link dbLink, table string, data interface{}, option i
|
||||
kind = rv.Kind()
|
||||
}
|
||||
switch kind {
|
||||
case reflect.Slice:
|
||||
fallthrough
|
||||
case reflect.Array:
|
||||
case reflect.Slice, reflect.Array:
|
||||
return bs.db.doBatchInsert(link, table, data, option, batch...)
|
||||
case reflect.Map:
|
||||
fallthrough
|
||||
case reflect.Struct:
|
||||
case reflect.Map, reflect.Struct:
|
||||
dataMap = structToMap(data)
|
||||
default:
|
||||
return result, errors.New(fmt.Sprint("unsupported data type:", kind))
|
||||
}
|
||||
if len(dataMap) == 0 {
|
||||
return nil, errors.New("data cannot be empty")
|
||||
}
|
||||
charL, charR := bs.db.getChars()
|
||||
for k, v := range dataMap {
|
||||
fields = append(fields, charL+k+charR)
|
||||
@ -370,7 +369,7 @@ func (bs *dbBase) doInsert(link dbLink, table string, data interface{}, option i
|
||||
}
|
||||
operation := getInsertOperationByOption(option)
|
||||
updateStr := ""
|
||||
if option == OPTION_SAVE {
|
||||
if option == gINSERT_OPTION_SAVE {
|
||||
for k, _ := range dataMap {
|
||||
if len(updateStr) > 0 {
|
||||
updateStr += ","
|
||||
@ -395,31 +394,30 @@ func (bs *dbBase) doInsert(link dbLink, table string, data interface{}, option i
|
||||
|
||||
// CURD操作:批量数据指定批次量写入
|
||||
func (bs *dbBase) BatchInsert(table string, list interface{}, batch ...int) (sql.Result, error) {
|
||||
return bs.db.doBatchInsert(nil, table, list, OPTION_INSERT, batch...)
|
||||
return bs.db.doBatchInsert(nil, table, list, gINSERT_OPTION_DEFAULT, batch...)
|
||||
}
|
||||
|
||||
// CURD操作:批量数据指定批次量写入, 如果数据存在(主键或者唯一索引),那么删除后重新写入一条
|
||||
func (bs *dbBase) BatchReplace(table string, list interface{}, batch ...int) (sql.Result, error) {
|
||||
return bs.db.doBatchInsert(nil, table, list, OPTION_REPLACE, batch...)
|
||||
return bs.db.doBatchInsert(nil, table, list, gINSERT_OPTION_REPLACE, batch...)
|
||||
}
|
||||
|
||||
// CURD操作:批量数据指定批次量写入, 如果数据存在(主键或者唯一索引),那么更新,否则写入一条新数据
|
||||
func (bs *dbBase) BatchSave(table string, list interface{}, batch ...int) (sql.Result, error) {
|
||||
return bs.db.doBatchInsert(nil, table, list, OPTION_SAVE, batch...)
|
||||
return bs.db.doBatchInsert(nil, table, list, gINSERT_OPTION_SAVE, batch...)
|
||||
}
|
||||
|
||||
// 批量写入数据, 参数list支持slice类型,例如: []map/[]struct/[]*struct。
|
||||
func (bs *dbBase) doBatchInsert(link dbLink, table string, list interface{}, option int, batch ...int) (result sql.Result, err error) {
|
||||
var keys []string
|
||||
var values []string
|
||||
var keys, values []string
|
||||
var params []interface{}
|
||||
table = bs.db.quoteWord(table)
|
||||
listMap := (List)(nil)
|
||||
switch v := list.(type) {
|
||||
case Result:
|
||||
listMap = v.ToList()
|
||||
listMap = v.List()
|
||||
case Record:
|
||||
listMap = List{v.ToMap()}
|
||||
listMap = List{v.Map()}
|
||||
case List:
|
||||
listMap = v
|
||||
case Map:
|
||||
@ -432,45 +430,41 @@ func (bs *dbBase) doBatchInsert(link dbLink, table string, list interface{}, opt
|
||||
kind = rv.Kind()
|
||||
}
|
||||
switch kind {
|
||||
// 如果是slice,那么转换为List类型
|
||||
case reflect.Slice:
|
||||
fallthrough
|
||||
case reflect.Array:
|
||||
// If it's slice type, it then converts it to List type.
|
||||
case reflect.Slice, reflect.Array:
|
||||
listMap = make(List, rv.Len())
|
||||
for i := 0; i < rv.Len(); i++ {
|
||||
listMap[i] = structToMap(rv.Index(i).Interface())
|
||||
}
|
||||
case reflect.Map:
|
||||
fallthrough
|
||||
case reflect.Struct:
|
||||
listMap = List{Map(structToMap(list))}
|
||||
case reflect.Map, reflect.Struct:
|
||||
listMap = List{structToMap(list)}
|
||||
default:
|
||||
return result, errors.New(fmt.Sprint("unsupported list type:", kind))
|
||||
}
|
||||
}
|
||||
// 判断长度
|
||||
if len(listMap) < 1 {
|
||||
return result, errors.New("empty data list")
|
||||
return result, errors.New("data list cannot be empty")
|
||||
}
|
||||
if link == nil {
|
||||
if link, err = bs.db.Master(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
// 首先获取字段名称及记录长度
|
||||
// Handle the field names and place holders.
|
||||
holders := []string(nil)
|
||||
for k, _ := range listMap[0] {
|
||||
keys = append(keys, k)
|
||||
holders = append(holders, "?")
|
||||
}
|
||||
// Prepare the result pointer.
|
||||
batchResult := new(batchSqlResult)
|
||||
charL, charR := bs.db.getChars()
|
||||
keyStr := charL + strings.Join(keys, charR+","+charL) + charR
|
||||
keysStr := charL + strings.Join(keys, charR+","+charL) + charR
|
||||
valueHolderStr := "(" + strings.Join(holders, ",") + ")"
|
||||
// 操作判断
|
||||
|
||||
operation := getInsertOperationByOption(option)
|
||||
updateStr := ""
|
||||
if option == OPTION_SAVE {
|
||||
if option == gINSERT_OPTION_SAVE {
|
||||
for _, k := range keys {
|
||||
if len(updateStr) > 0 {
|
||||
updateStr += ","
|
||||
@ -489,15 +483,25 @@ func (bs *dbBase) doBatchInsert(link dbLink, table string, list interface{}, opt
|
||||
}
|
||||
listMapLen := len(listMap)
|
||||
for i := 0; i < listMapLen; i++ {
|
||||
// Note that the map type is unordered,
|
||||
// so it should use slice+key to retrieve the value.
|
||||
for _, k := range keys {
|
||||
params = append(params, convertParam(listMap[i][k]))
|
||||
}
|
||||
values = append(values, valueHolderStr)
|
||||
if len(values) == batchNum || (i == listMapLen-1 && len(values) > 0) {
|
||||
r, err := bs.db.doExec(link, fmt.Sprintf("%s INTO %s(%s) VALUES%s %s",
|
||||
operation, table, keyStr, strings.Join(values, ","),
|
||||
updateStr),
|
||||
params...)
|
||||
r, err := bs.db.doExec(
|
||||
link,
|
||||
fmt.Sprintf(
|
||||
"%s INTO %s(%s) VALUES%s %s",
|
||||
operation,
|
||||
table,
|
||||
keysStr,
|
||||
strings.Join(values, ","),
|
||||
updateStr,
|
||||
),
|
||||
params...,
|
||||
)
|
||||
if err != nil {
|
||||
return r, err
|
||||
}
|
||||
@ -550,10 +554,13 @@ func (bs *dbBase) doUpdate(link dbLink, table string, data interface{}, conditio
|
||||
default:
|
||||
updates = gconv.String(data)
|
||||
}
|
||||
if len(updates) == 0 {
|
||||
return nil, errors.New("data cannot be empty")
|
||||
}
|
||||
if len(params) > 0 {
|
||||
args = append(params, args...)
|
||||
}
|
||||
// 如果没有传递link,那么使用默认的写库对象
|
||||
// If no link passed, it then uses the master link.
|
||||
if link == nil {
|
||||
if link, err = bs.db.Master(); err != nil {
|
||||
return nil, err
|
||||
@ -680,12 +687,16 @@ func (bs *dbBase) formatWhere(where interface{}, args []interface{}) (newWhere s
|
||||
if value == nil {
|
||||
buffer.WriteString(key)
|
||||
} else {
|
||||
// 支持key带操作符号
|
||||
// 支持key带操作符号,注意like也算是操作符号
|
||||
key = gstr.Trim(key)
|
||||
if gstr.Pos(key, "?") == -1 {
|
||||
if gstr.Pos(key, "<") == -1 && gstr.Pos(key, ">") == -1 && gstr.Pos(key, "=") == -1 {
|
||||
like := " like"
|
||||
if len(key) > len(like) && gstr.Equal(key[len(key)-len(like):], like) {
|
||||
buffer.WriteString(key + " ?")
|
||||
} else if key[len(key)-1] != '<' && key[len(key)-1] != '>' && key[len(key)-1] != '=' {
|
||||
buffer.WriteString(key + "=?")
|
||||
} else {
|
||||
buffer.WriteString(key + "?")
|
||||
buffer.WriteString(key + " ?")
|
||||
}
|
||||
} else {
|
||||
buffer.WriteString(key)
|
||||
|
||||
@ -146,12 +146,7 @@ func convertParam(value interface{}) interface{} {
|
||||
// 格式化错误信息
|
||||
func formatError(err error, query string, args ...interface{}) error {
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
errStr := fmt.Sprintf("DB ERROR: %s\n", err.Error())
|
||||
errStr += fmt.Sprintf("DB QUERY: %s\n", query)
|
||||
if len(args) > 0 {
|
||||
errStr += fmt.Sprintf("DB PARAM: %v\n", args)
|
||||
}
|
||||
err = errors.New(errStr)
|
||||
return errors.New(fmt.Sprintf("%s, %s\n", err.Error(), bindArgsToQuery(query, args)))
|
||||
}
|
||||
return err
|
||||
}
|
||||
@ -160,10 +155,10 @@ func formatError(err error, query string, args ...interface{}) error {
|
||||
func getInsertOperationByOption(option int) string {
|
||||
operator := "INSERT"
|
||||
switch option {
|
||||
case OPTION_REPLACE:
|
||||
case gINSERT_OPTION_REPLACE:
|
||||
operator = "REPLACE"
|
||||
case OPTION_SAVE:
|
||||
case OPTION_IGNORE:
|
||||
case gINSERT_OPTION_SAVE:
|
||||
case gINSERT_OPTION_IGNORE:
|
||||
operator = "INSERT IGNORE"
|
||||
}
|
||||
return operator
|
||||
@ -209,6 +204,9 @@ func bindArgsToQuery(query string, args []interface{}) string {
|
||||
newQuery, _ := gregex.ReplaceStringFunc(`\?`, query, func(s string) string {
|
||||
index++
|
||||
if len(args) > index {
|
||||
if args[index] == nil {
|
||||
return "null"
|
||||
}
|
||||
rv := reflect.ValueOf(args[index])
|
||||
kind := rv.Kind()
|
||||
if kind == reflect.Ptr {
|
||||
@ -217,7 +215,7 @@ func bindArgsToQuery(query string, args []interface{}) string {
|
||||
}
|
||||
switch kind {
|
||||
case reflect.String, reflect.Map, reflect.Slice, reflect.Array:
|
||||
return "'" + gstr.QuoteMeta(gconv.String(args[index]), "'") + "'"
|
||||
return `'` + gstr.QuoteMeta(gconv.String(args[index]), `'`) + `'`
|
||||
}
|
||||
return gconv.String(args[index])
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user