Compare commits

...

36 Commits

Author SHA1 Message Date
2dc2610621 improve gdb; README update 2019-10-13 23:05:48 +08:00
1736e71e6b add debug for unit test case of 2019-10-13 22:40:23 +08:00
69ee5375b9 improve Join/String functions for garray/gset/gmap; add AddIfNotExistFunc/AddIfNotExistFuncLock functions for gset 2019-10-13 22:31:28 +08:00
3ac0a66887 improve unit test cases for gspath 2019-10-13 21:42:04 +08:00
20e873a1fc version updates 2019-10-13 00:40:06 +08:00
142484d89c add support for like statement in map key for Where function, improve error format for gdb 2019-10-13 00:37:25 +08:00
76a9f4ca14 fix security issue in static file feature for ghttp.Server 2019-10-12 23:56:03 +08:00
c4e5679d5c fix issue in missing passing MaxIdle/MaxActive configuration to underlying redis pool for gredis; add extra output for unit test cases of ghttp.Server 2019-10-11 23:33:21 +08:00
b08d7c3c38 change Join function feature for garray 2019-10-11 23:17:29 +08:00
5092d8e6c5 improve status handling and add error logger for ghttp.Server; fix issue in defer error warpping for some packages 2019-10-11 22:54:25 +08:00
74d625ff97 add Get*Int32/Get*Int64/Get*Uint32/Get*Uint64 functions for ghttp.Request 2019-10-10 10:40:38 +08:00
f1119e28e8 add Get*Int32/Get*Int64/Get*Uint32/Get*Uint64 functions for ghttp.Request 2019-10-10 10:33:14 +08:00
3082c7f761 fix issue in StrLimit for gstr 2019-10-10 00:04:38 +08:00
5f36614dd7 remove UseNumber for json decoding in package gjson 2019-10-09 20:33:26 +08:00
1dcc7a4887 improve http status handling for middleware of ghttp.Server 2019-10-09 15:26:50 +08:00
41e9d35487 improve middleware feature for ghttp.Server; fix issue memory usage in big file downloading 2019-10-09 00:33:58 +08:00
977c8b7ee3 version updates 2019-10-01 17:54:29 +08:00
939e6244ee comment update for gtcp/gudp 2019-10-01 17:53:49 +08:00
e764b2393d change params order of Insert* functions for glist; improve gstr.IsNumber 2019-10-01 16:35:44 +08:00
6384e75ed9 improva container for json marshal/unmarshal interface 2019-10-01 16:03:18 +08:00
195cae6577 add new functions and mark deprecated for some functions for gdb 2019-10-01 11:29:02 +08:00
c8cf46a5a7 add Create function for gvar; add Uints/SliceUint function for gconv 2019-10-01 10:42:34 +08:00
eba97277b2 add more unit test cases for ghttp 2019-10-01 09:33:26 +08:00
4e19fbc5fb add separate put/delete functions for ghttp.Request 2019-10-01 09:06:35 +08:00
494b5bbae2 fix issue in unit test case for gvar 2019-09-30 17:30:24 +08:00
987ce709e5 add UnmarshalJSON for gtime; add ineterface MapStrAny support for gjson.New 2019-09-30 17:23:23 +08:00
35ad4d869f fix issue in cycle import for gtime 2019-09-30 15:51:15 +08:00
39d654e3f2 update comment for gtime 2019-09-30 15:26:32 +08:00
7fe9c641f4 add UnmarshalJSON func tion for gset 2019-09-30 14:37:05 +08:00
ee1414c010 add UnmarshalJSON func tion for gmap/gvar 2019-09-30 14:23:15 +08:00
8eb1b685a5 improve UnmarshalJSON function for garray 2019-09-29 22:16:36 +08:00
46768d6f91 add UnmarshalJSON function and corresponding unit test cases for package grray 2019-09-29 20:47:59 +08:00
bb6fed3dc2 add UnmarshalJSON function and corresponding unit test cases for package gtype 2019-09-29 20:12:59 +08:00
47e74d27bf add MarshalJSON function to implement the interface MarshalJSON for json.Marshal for gtype 2019-09-29 15:59:09 +08:00
b830f9b96d improve ghttp.Server.Request for parameter retrieving; add Option feature for gdb; update example for hook feature of ghttp.Server 2019-09-29 14:27:09 +08:00
c85162a8a0 improving gdb.Model/gmap 2019-09-26 20:01:48 +08:00
199 changed files with 7541 additions and 2878 deletions

View 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))
}

View 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)
}

View 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)
}

View 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))
}

View 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)
}

View File

@ -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))
}

View 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))
}

View 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())
}

View 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))
}

View 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)
}

View 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))
}

View 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)
}

View 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))
}

View 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)
}

View File

@ -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)
}

View 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)
}

View File

@ -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()
}

View File

@ -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()
}

View File

@ -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"))

View File

@ -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()
}

View File

@ -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()

View File

@ -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) {

View File

@ -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()
}

View 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()
}

View 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)
}

View 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)
}

View File

@ -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))
}

View File

@ -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)
}
}

View File

@ -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,
},

View File

@ -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,
},

View File

@ -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,
},

View File

@ -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`:
```

View File

@ -15,6 +15,7 @@
# 特点
* 模块化、松耦合设计;
* 模块丰富,开箱即用;
* 简便及可维护性为宗旨;
* 详尽的开发文档及示例;
* 完善的本地中文化支持;
* 致力于项目的通用方案;

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View 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"])
})
}

View File

@ -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"])
})
}

View File

@ -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"])
})
}

View File

@ -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"])
})
}

View 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})
})
}

View 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+"})
})
}

View File

@ -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
}

View File

@ -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)
})
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View 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"])
})
}

View File

@ -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])
})
}

View File

@ -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])
})
}

View File

@ -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])
})
}

View File

@ -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"])
})
}

View File

@ -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"])
})
}

View File

@ -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"])
})
}

View File

@ -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"])
})
}

View File

@ -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"])
})
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
})
}

View File

@ -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)
})
}

View File

@ -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)
})
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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...)

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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()
}
}

View 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)
}
}

View File

@ -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)
})
}

View File

@ -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
}

View 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()
}
}

View 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()
}
}

View File

@ -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()
}
}

View File

@ -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)
})
}

View File

@ -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 {

View File

@ -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 {

View File

@ -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.
)

View File

@ -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)

View File

@ -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