Compare commits

...

48 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
ef4e128af7 fix issue in cors 2019-09-26 15:54:13 +08:00
cb7c3a9fa4 fix issue in index folder feature for ghttp.Server 2019-09-25 10:56:44 +08:00
b0f859cc91 improve example codes 2019-09-24 23:41:18 +08:00
6d4da529ee add websocket unit test case for ghttp 2019-09-24 21:08:28 +08:00
6c7e536eeb fix issue in gbase64/ghttp 2019-09-24 20:39:00 +08:00
36c2648be8 improve ghttp.Response; move gflock to new repo 2019-09-24 20:19:18 +08:00
a876b6133d fix issue in unit test case og grand 2019-09-23 23:24:36 +08:00
03ff358da8 update ci/readme/donator 2019-09-23 23:08:58 +08:00
037f74c549 Create FUNDING.yml 2019-09-23 22:32:31 +08:00
a8caf4ad21 RELEASE updates 2019-09-23 22:00:04 +08:00
51d9fe5253 add AllowDomain option for ghttp.CORS; add IsSubDomain function for gstr; improve grand.Intn 2019-09-23 19:25:03 +08:00
3218c89f17 improve gfile/gstr/ghttp 2019-09-23 16:21:19 +08:00
259 changed files with 8319 additions and 3879 deletions

View File

@ -1,16 +0,0 @@
package main
import "fmt"
func main() {
array := []uint{1, 1, 2, 3, 3, 4, 4, 5, 5, 6, 6}
for i := 0; i < len(array)-1; i++ {
for j := i + 1; j < len(array); j++ {
if array[i] == array[j] {
array = append(array[:j], array[j+1:]...)
}
}
}
fmt.Println(array)
}

View File

@ -0,0 +1,46 @@
package main
import (
"fmt"
"github.com/gogf/gf/container/garray"
)
func main() {
// Create a int array, which is concurrent-unsafe in default.
a := garray.NewIntArray()
// Appending items.
for i := 0; i < 10; i++ {
a.Append(i)
}
// Get the length of the array.
fmt.Println(a.Len())
// Get the slice of the array.
fmt.Println(a.Slice())
// Get the item of specified index.
fmt.Println(a.Get(6))
// Insert after/before specified index.
a.InsertAfter(9, 11)
a.InsertBefore(10, 10)
fmt.Println(a.Slice())
a.Set(0, 100)
fmt.Println(a.Slice())
// Searching the item and returning the index.
fmt.Println(a.Search(5))
// Remove item of specified index.
a.Remove(0)
fmt.Println(a.Slice())
// Clearing the array.
fmt.Println(a.Slice())
a.Clear()
fmt.Println(a.Slice())
}

View File

@ -1,59 +0,0 @@
package main
import (
"fmt"
"github.com/gogf/gf/container/garray"
)
func main() {
// 创建普通的int类型数组并关闭默认的并发安全特性
a := garray.NewIntArray(true)
// 添加数据项
for i := 0; i < 10; i++ {
a.Append(i)
}
// 获取当前数组长度
fmt.Println(a.Len())
// 获取当前数据项列表
fmt.Println(a.Slice())
// 获取指定索引项
fmt.Println(a.Get(6))
// 在指定索引前插入数据项
a.InsertAfter(9, 11)
// 在指定索引后插入数据项
a.InsertBefore(10, 10)
fmt.Println(a.Slice())
// 修改指定索引的数据项
a.Set(0, 100)
fmt.Println(a.Slice())
// 搜索数据项,返回搜索到的索引位置
fmt.Println(a.Search(5))
// 删除指定索引的数据项
a.Remove(0)
fmt.Println(a.Slice())
// 并发安全,写锁操作
a.LockFunc(func(array []int) {
// 将末尾项改为100
array[len(array)-1] = 100
})
// 并发安全,读锁操作
a.RLockFunc(func(array []int) {
fmt.Println(array[len(array)-1])
})
// 清空数组
fmt.Println(a.Slice())
a.Clear()
fmt.Println(a.Slice())
}

View File

@ -1,17 +0,0 @@
package main
import (
"github.com/gogf/gf/container/garray"
"github.com/gogf/gf/frame/g"
)
func main() {
a := garray.NewIntArray()
a.Append(1, 2, 3)
v := a.Slice()
v[0] = 4
g.Dump(a.Slice())
g.Dump(v)
}

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

@ -1,20 +1,23 @@
package main
import (
"fmt"
"github.com/gogf/gf/container/garray"
"github.com/gogf/gf/frame/g"
)
func main() {
array := garray.NewSortedStringArray()
array.Add("1")
array.Add("2")
array.Add("3")
array.Add("4")
array.Add("5")
array.Add("6")
array.Add("7")
array.Add("8")
array := garray.NewSortedStrArray()
array.Add("9")
g.Dump(array.Slice())
array.Add("8")
array.Add("7")
array.Add("6")
array.Add("5")
array.Add("4")
array.Add("3")
array.Add("2")
array.Add("1")
fmt.Println(array.Slice())
// output:
// [1 2 3 4 5 6 7 8 9]
}

View File

@ -1,27 +0,0 @@
package main
import (
"fmt"
"strings"
"github.com/gogf/gf/container/garray"
"github.com/gogf/gf/frame/g"
)
func main() {
array := garray.NewSortedStringArray()
array.Add("/api/ctl/show")
array.Add("/api/ctl/post")
array.Add("/api/obj/rest")
array.Add("/api/handler")
array.Add("/api/obj/delete")
array.Add("/api/obj/show")
array.Add("/api/obj/my-show")
array.Add("/api/*")
array.Add("/api/ctl/rest")
array.Add("/api/ctl/my-show")
g.Dump(array.Slice())
fmt.Println(strings.Compare("/api/ctl/post", "/api/*"))
fmt.Println(strings.Compare("/api/*", "/api/ctl/my-show"))
}

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,24 +0,0 @@
package main
import (
"encoding/json"
"fmt"
"github.com/gogf/gf/container/gmap"
)
func main() {
//m := gmap.New()
//m.Set("k", "v")
//m.Set("1", "2")
//b, err := json.Marshal(m)
//fmt.Println(err)
//fmt.Println(string(b))
m := gmap.NewIntIntMap()
m.Set(1, 2)
m.Set(3, 4)
b, err := json.Marshal(m)
fmt.Println(err)
fmt.Println(string(b))
}

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,26 @@
package main
import (
"github.com/gogf/gf/container/gmap"
"github.com/gogf/gf/frame/g"
)
func main() {
m1 := gmap.New()
m1.Set("1", "1")
m2 := m1.Map()
m2["2"] = "2"
g.Dump(m1.Clone())
g.Dump(m2)
//output:
//{
// "1": "1"
//}
//
//{
// "1": "1",
// "2": "2"
//}
}

View File

@ -1,17 +0,0 @@
package main
import (
"github.com/gogf/gf/container/gmap"
"github.com/gogf/gf/frame/g"
)
func main() {
m := gmap.New()
m.Set("1", "1")
m1 := m.Map()
m1["2"] = "2"
g.Dump(m.Clone())
g.Dump(m1)
}

View File

@ -10,9 +10,9 @@ import (
func main() {
array := g.Slice{2, 3, 1, 5, 4, 6, 8, 7, 9}
hashMap := gmap.New(true)
linkMap := gmap.NewLinkMap(true)
treeMap := gmap.NewTreeMap(gutil.ComparatorInt, true)
hashMap := gmap.New()
linkMap := gmap.NewListMap()
treeMap := gmap.NewTreeMap(gutil.ComparatorInt)
for _, v := range array {
hashMap.Set(v, v)
}

View File

@ -1,39 +0,0 @@
package main
import (
"fmt"
"sync"
"time"
)
// 验证 map 的delete方法是否并发安全
func main() {
// 创建一个初始化的map
m := make(map[int]int)
for i := 0; i < 10000; i++ {
m[i] = i
}
fmt.Println("map size:", len(m))
wg := sync.WaitGroup{}
ev := make(chan struct{}, 0)
// 创建10个并发的goroutine使用ev控制并发开始事件更容易模拟data race
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
<-ev
fmt.Println("start")
for i := 0; i < 10000; i++ {
delete(m, i)
}
wg.Done()
}()
}
time.Sleep(time.Second)
close(ev)
wg.Wait()
}

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

@ -30,8 +30,4 @@ func main() {
s := new(Score)
v.Struct(s)
fmt.Println(s)
// 只读接口
r := v.ReadOnly()
fmt.Println(r.String())
}

View File

@ -519,7 +519,6 @@ func getQueriedSqls() {
fmt.Println("Sql :", v.Sql)
fmt.Println("Args :", v.Args)
fmt.Println("Error:", v.Error)
fmt.Println("Func :", v.Func)
}
}

View File

@ -8,9 +8,9 @@ import (
func main() {
db := g.DB()
db.SetMaxIdleConns(10)
db.SetMaxOpenConns(10)
db.SetConnMaxLifetime(10)
db.SetMaxIdleConnCount(10)
db.SetMaxOpenConnCount(10)
db.SetMaxConnLifetime(time.Minute)
// 开启调试模式以便于记录所有执行的SQL
db.SetDebug(true)

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

@ -520,7 +520,6 @@ func getQueriedSqls() {
fmt.Println("Sql :", v.Sql)
fmt.Println("Args :", v.Args)
fmt.Println("Error:", v.Error)
fmt.Println("Func :", v.Func)
}
}

View File

@ -1,47 +1,47 @@
package main
//import (
// _ "github.com/mattn/go-sqlite3"
// "github.com/gogf/gf/database/gdb"
// "github.com/gogf/gf/frame/g"
// "fmt"
//)
//
//func main() {
// gdb.SetConfig(gdb.Config{
// "default": gdb.ConfigGroup{
// gdb.ConfigNode{
// Name: "/tmp/my.db",
// Type: "sqlite",
// },
// },
// })
// db := g.Database()
// if db == nil {
// panic("db create failed")
// }
// defer db.Close()
//
// // 创建表
// sql := `CREATE TABLE user (
// uid INT PRIMARY KEY NOT NULL,
// name VARCHAR(30) NOT NULL
// );`
// if _, err := db.Exec(sql); err != nil {
// fmt.Println(err)
// }
//
// // 写入数据
// result, err := db.Table("user").Data(g.Map{"uid" : 1, "name" : "john"}).Save()
// if err == nil {
// fmt.Println(result.RowsAffected())
// } else {
// fmt.Println(err)
// }
//
// // 删除表
// sql = `DROP TABLE user;`
// if _, err := db.Exec(sql); err != nil {
// fmt.Println(err)
// }
//}
import (
"fmt"
"github.com/gogf/gf/database/gdb"
"github.com/gogf/gf/frame/g"
_ "github.com/mattn/go-sqlite3"
)
func main() {
gdb.SetConfig(gdb.Config{
"default": gdb.ConfigGroup{
gdb.ConfigNode{
Name: "/tmp/my.db",
Type: "sqlite",
},
},
})
db := g.DB()
if db == nil {
panic("db create failed")
}
// 创建表
sql := `CREATE TABLE user (
uid INT PRIMARY KEY NOT NULL,
name VARCHAR(30) NOT NULL
);`
if _, err := db.Exec(sql); err != nil {
fmt.Println(err)
}
// 写入数据
result, err := db.Table("user").Data(g.Map{"uid": 1, "name": "john"}).Save()
if err == nil {
fmt.Println(result.RowsAffected())
} else {
fmt.Println(err)
}
// 删除表
sql = `DROP TABLE user;`
if _, err := db.Exec(sql); err != nil {
fmt.Println(err)
}
}

View File

@ -1,60 +0,0 @@
package main
import (
"fmt"
"github.com/gogf/gf/util/gconv"
"github.com/gogf/gf/os/gcmd"
"github.com/gogf/gf/container/garray"
"github.com/gogf/gf/database/gredis"
"github.com/gogf/gf/frame/g"
)
func main() {
batchNumber := 1000
redis1Config, err := gredis.ConfigFromStr("im-redis-slave:6379,9")
if err != nil {
panic(err)
}
redis2Config, err := gredis.ConfigFromStr("r-bp1f0a5d4efd8744.redis.rds.aliyuncs.com:6379,9")
if err != nil {
panic(err)
}
gredis.SetConfig(redis1Config)
v, err := g.Redis().DoVar("keys", "*")
if err != nil {
panic(err)
}
array := garray.NewStrArrayFrom(v.Strings())
for {
slice := array.PopLefts(batchNumber)
if len(slice) > 0 {
// `migrate %s %d "" 0 2000 copy replace auth %s keys %s`,
params := g.Slice{
redis2Config.Host,
redis2Config.Port,
"",
redis2Config.Db,
2000,
"copy",
"replace",
"keys",
}
params = append(params, gconv.Interfaces(slice)...)
fmt.Println(params)
if gcmd.GetOpt("dryrun") == "0" {
if v, err := g.Redis().DoVar("migrate", params...); err != nil {
panic(err)
} else {
fmt.Println(v.String())
}
}
} else {
break
}
}
fmt.Println("done")
}

View File

@ -1,4 +1,4 @@
package main
package gbase64
import (
"fmt"

View File

@ -9,26 +9,19 @@ import (
func main() {
// 使用gbinary.Encoded对基本数据类型进行二进制打包
if buffer, err := gbinary.Encode(18, 300, 1.01); err != nil {
glog.Error(err)
} else {
fmt.Println(buffer)
}
fmt.Println(gbinary.Encode(18, 300, 1.01))
// 使用gbinary.Decode对整形二进制解包注意第二个及其后参数为字长确定的整形变量的指针地址字长确定的类型
// 例如int8/16/32/64、uint8/16/32/64、float32/64
// 这里的1.01默认为float64类型(64位系统下)
if buffer, err := gbinary.Encode(18, 300, 1.01); err != nil {
buffer := gbinary.Encode(18, 300, 1.01)
var i1 int8
var i2 int16
var f3 float64
if err := gbinary.Decode(buffer, &i1, &i2, &f3); err != nil {
glog.Error(err)
} else {
var i1 int8
var i2 int16
var f3 float64
if err := gbinary.Decode(buffer, &i1, &i2, &f3); err != nil {
glog.Error(err)
} else {
fmt.Println(i1, i2, f3)
}
fmt.Println(i1, i2, f3)
}
// 编码/解析 int自动识别变量长度

View File

@ -15,6 +15,6 @@ func main() {
}
redisCfg := new(RedisConfig)
fmt.Println(g.Config().GetToStruct("redis", redisCfg))
fmt.Println(g.Config().GetStruct("redis", redisCfg))
fmt.Println(redisCfg)
}

View File

@ -15,4 +15,6 @@ func main() {
panic(err)
}
fmt.Println(str)
// output:
// 花间一壶酒,独酌无相亲。
}

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

@ -19,7 +19,7 @@ func getWithPattern1() {
}
}`
if p, e := gparser.LoadContent([]byte(data), "json"); e != nil {
if p, e := gparser.LoadContent([]byte(data)); e != nil {
glog.Error(e)
} else {
fmt.Println("John Score:", p.GetFloat32("users.list.1.score"))
@ -36,7 +36,7 @@ func getWithPattern2() {
<body>Don't forget me this weekend!</body>
</note>`
if p, e := gparser.LoadContent([]byte(data), "xml"); e != nil {
if p, e := gparser.LoadContent([]byte(data)); e != nil {
glog.Error(e)
} else {
fmt.Println("Heading:", p.GetString("note.heading"))
@ -52,7 +52,7 @@ func multiDots1() {
},
"users.count" : 101
}`
if p, e := gparser.LoadContent([]byte(data), "json"); e != nil {
if p, e := gparser.LoadContent([]byte(data)); e != nil {
glog.Error(e)
} else {
fmt.Println("Users Count:", p.Get("users.count"))
@ -70,7 +70,7 @@ func multiDots2() {
"count.type1" : 100
}
}`
if p, e := gparser.LoadContent([]byte(data), "json"); e != nil {
if p, e := gparser.LoadContent([]byte(data)); e != nil {
glog.Error(e)
} else {
fmt.Println("Users Count:", p.Get("users.count.type1"))
@ -88,7 +88,7 @@ func set1() {
<list><title>gf article2</title><content>gf content2</content></list>
<list><title>gf article3</title><content>gf content3</content></list>
</article>`
if p, e := gparser.LoadContent([]byte(data), "xml"); e != nil {
if p, e := gparser.LoadContent([]byte(data)); e != nil {
glog.Error(e)
} else {
p.Set("article.list.0", nil)
@ -105,7 +105,7 @@ func set2() {
"count" : 100
}
}`
if p, e := gparser.LoadContent([]byte(data), "json"); e != nil {
if p, e := gparser.LoadContent([]byte(data)); e != nil {
glog.Error(e)
} else {
p.Set("users.count", 1)
@ -116,7 +116,7 @@ func set2() {
}
func makeXml1() {
p := gparser.New()
p := gparser.New(nil)
p.Set("name", "john")
p.Set("age", 18)
p.Set("scores", map[string]int{
@ -133,7 +133,7 @@ func makeJson1() {
Id int `json:"id"`
Price float32 `json:"price"`
}
p := gparser.New()
p := gparser.New(nil)
p.Set("orders.list.0", Order{1, 100})
p.Set("orders.list.1", Order{2, 666})
p.Set("orders.list.2", Order{3, 999.99})

View File

@ -1,4 +0,0 @@
# MySQL数据库配置
[database]
link = "mysql:root:12345678@tcp(127.0.0.1:3306)/test"

View File

@ -1,13 +0,0 @@
package main
import (
"github.com/gogf/gf/.example/frame/mvc/model/test"
"github.com/gogf/gf/frame/g"
)
func main() {
g.DB().SetDebug(true)
user, err := test.ModelUser().One()
g.Dump(err)
g.Dump(user)
}

View File

@ -7,7 +7,7 @@ import (
func main() {
s := g.Server()
s.SetNameToUriType(ghttp.NAME_TO_URI_TYPE_FULLNAME)
s.SetNameToUriType(ghttp.URI_TYPE_FULLNAME)
s.EnableAdmin()
s.BindHandler("/", func(r *ghttp.Request) {
r.Response.Write("hello world")

View File

@ -0,0 +1,25 @@
package main
import (
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/net/ghttp"
)
func MiddlewareCORS(r *ghttp.Request) {
r.Response.CORSDefault()
r.Middleware.Next()
}
func Order(r *ghttp.Request) {
r.Response.Write("GET")
}
func main() {
s := g.Server()
s.Group("/api.v1", func(g *ghttp.RouterGroup) {
g.Middleware(MiddlewareCORS)
g.GET("/order", Order)
})
s.SetPort(8199)
s.Run()
}

View File

@ -0,0 +1,27 @@
package main
import (
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/net/ghttp"
)
func MiddlewareCORS(r *ghttp.Request) {
corsOptions := r.Response.DefaultCORSOptions()
corsOptions.AllowDomain = []string{"goframe.org", "baidu.com"}
r.Response.CORS(corsOptions)
r.Middleware.Next()
}
func Order(r *ghttp.Request) {
r.Response.Write("GET")
}
func main() {
s := g.Server()
s.Group("/api.v1", func(g *ghttp.RouterGroup) {
g.Middleware(MiddlewareCORS)
g.GET("/order", Order)
})
s.SetPort(8199)
s.Run()
}

View File

@ -0,0 +1,33 @@
package main
import (
"net/http"
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/net/ghttp"
)
func MiddlewareCORS(r *ghttp.Request) {
corsOptions := r.Response.DefaultCORSOptions()
corsOptions.AllowDomain = []string{"goframe.org"}
if !r.Response.CORSAllowedOrigin(corsOptions) {
r.Response.WriteStatus(http.StatusForbidden)
return
}
r.Response.CORS(corsOptions)
r.Middleware.Next()
}
func Order(r *ghttp.Request) {
r.Response.Write("GET")
}
func main() {
s := g.Server()
s.Group("/api.v1", func(g *ghttp.RouterGroup) {
g.Middleware(MiddlewareCORS)
g.GET("/order", Order)
})
s.SetPort(8199)
s.Run()
}

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

@ -17,10 +17,10 @@ func main() {
s3 := g.Server(3)
s4 := g.Server(4)
s1.SetNameToUriType(ghttp.NAME_TO_URI_TYPE_DEFAULT)
s2.SetNameToUriType(ghttp.NAME_TO_URI_TYPE_FULLNAME)
s3.SetNameToUriType(ghttp.NAME_TO_URI_TYPE_ALLLOWER)
s4.SetNameToUriType(ghttp.NAME_TO_URI_TYPE_CAMEL)
s1.SetNameToUriType(ghttp.URI_TYPE_DEFAULT)
s2.SetNameToUriType(ghttp.URI_TYPE_FULLNAME)
s3.SetNameToUriType(ghttp.URI_TYPE_ALLLOWER)
s4.SetNameToUriType(ghttp.URI_TYPE_CAMEL)
s1.BindObject("/{.struct}/{.method}", new(User))
s2.BindObject("/{.struct}/{.method}", new(User))

View File

@ -6,7 +6,7 @@ import "github.com/gogf/gf/frame/g"
func main() {
s := g.Server()
s.SetIndexFolder(true)
s.SetServerRoot("/Users/john/Temp")
s.SetServerRoot("/Users/john/Downloads")
s.AddSearchPath("/Users/john/Documents")
s.SetPort(8199)
s.Run()

View File

@ -9,7 +9,7 @@ import (
func main() {
s := g.Server()
s.SetServerRoot("public")
s.SetNameToUriType(ghttp.NAME_TO_URI_TYPE_ALLLOWER)
s.SetNameToUriType(ghttp.URI_TYPE_ALLLOWER)
s.SetErrorLogEnabled(true)
s.SetAccessLogEnabled(true)
s.SetPort(2333)

View File

@ -1,16 +0,0 @@
package main
import (
"fmt"
"time"
)
func main() {
l := flock.NewFlock("/tmp/go-lock.lock")
l.Lock()
fmt.Printf("lock 1")
l.Lock()
fmt.Printf("lock 1")
time.Sleep(time.Hour)
}

View File

@ -1,18 +0,0 @@
package main
import (
"time"
"github.com/gogf/gf/os/gflock"
"github.com/gogf/gf/os/glog"
"github.com/gogf/gf/os/gproc"
)
func main() {
l := gflock.New("demo.lock")
l.Lock()
glog.Printf("locked by pid: %d", gproc.Pid())
time.Sleep(10 * time.Second)
l.UnLock()
glog.Printf("unlocked by pid: %d", gproc.Pid())
}

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,12 +1,12 @@
package main
import (
"github.com/gogf/gf/os/gcmd"
"github.com/gogf/gf/os/glog"
"encoding/json"
"fmt"
"github.com/gogf/gf/util/gconv"
)
func main() {
glog.SetFlags(glog.F_TIME_DATE | glog.F_TIME_TIME | glog.F_FILE_SHORT)
glog.Debug("dd")
glog.Println("timeout", gcmd.GetOpt("timeout"))
b, _ := json.Marshal([]interface{}{1, 2, 3, 4, 5, 123.456, "a"})
fmt.Println(gconv.String(b))
}

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

12
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1,12 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: https://github.com/gogf/gf#donators

1
.gitignore vendored
View File

@ -14,3 +14,4 @@ bin/
cbuild
**/.DS_Store
.vscode/
go.sum

View File

@ -13,6 +13,7 @@
|[zfan_codes](https://gitee.com/zfan_codes)|gitee|¥10.00
|[arden](https://github.com/arden)|alipay|¥10.00
|[macnie](https://www.macnie.com)|wechat|¥100.00
|lah|wechat|¥100.00
|x*z|wechat|¥20.00
|潘兄|wechat|¥100.00
|Fly的狐狸|wechat|¥100.00

193
README.MD
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`:
```
@ -38,7 +38,6 @@ golang version >= 1.10
# Quick Start
## Hello World
```go
package main
@ -55,196 +54,6 @@ func main() {
s.Run()
}
```
## Router & Middleware
```go
package main
import (
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/net/ghttp"
)
func main() {
s := g.Server()
s.Group("/api.v2", func(g *ghttp.RouterGroup) {
g.Middleware(func(r *ghttp.Request) {
r.Response.Write("start")
r.Middleware.Next()
r.Response.Write("end")
})
g.Group("/order", func(g *ghttp.RouterGroup) {
g.GET("/list", func(r *ghttp.Request) {
r.Response.Write("list")
})
})
g.Group("/user", func(g *ghttp.RouterGroup) {
g.GET("/info", func(r *ghttp.Request) {
r.Response.Write("info")
})
g.POST("/edit", func(r *ghttp.Request) {
r.Response.Write("edit")
})
})
g.Group("/hook", func(g *ghttp.RouterGroup) {
g.Hook("/*", ghttp.HOOK_BEFORE_SERVE, func(r *ghttp.Request) {
r.Response.Write("hook any")
})
g.Hook("/:name", ghttp.HOOK_BEFORE_SERVE, func(r *ghttp.Request) {
r.Response.Write("hook name")
})
})
})
s.SetPort(8199)
s.Run()
}
```
## Multi ports & domains
```go
package main
import (
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/net/ghttp"
)
func Hello1(r *ghttp.Request) {
r.Response.Write("127.0.0.1: Hello1!")
}
func Hello2(r *ghttp.Request) {
r.Response.Write("localhost: Hello2!")
}
func main() {
s := g.Server()
s.Domain("127.0.0.1").BindHandler("/", Hello1)
s.Domain("localhost").BindHandler("/", Hello2)
s.SetPort(8100, 8200, 8300)
s.Run()
}
```
## Template Engine
```go
package main
import (
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/net/ghttp"
)
func main() {
s := g.Server()
s.BindHandler("/template", func(r *ghttp.Request) {
r.Response.WriteTpl("index.tpl", g.Map{
"id": 123,
"name": "john",
})
})
s.SetPort(8199)
s.Run()
}
```
## File Uploading
```go
func Upload(r *ghttp.Request) {
if f, h, e := r.FormFile("upload-file"); e == nil {
defer f.Close()
name := gfile.Basename(h.Filename)
buffer := make([]byte, h.Size)
f.Read(buffer)
gfile.PutBytes("/tmp/" + name, buffer)
r.Response.Write(name + " uploaded successly")
} else {
r.Response.Write(e.Error())
}
}
```
## ORM Operations
### 1. Retrieving instance
```go
db := g.DB()
db := g.DB("user-center")
```
### 2. Chaining Operations
`Where + string`
```go
// SELECT * FROM user WHERE uid>1 LIMIT 0,10
r, err := db.Table("user").Where("uid > ?", 1).Limit(0, 10).Select()
// SELECT uid,name FROM user WHERE uid>1 LIMIT 0,10
r, err := db.Table("user").Fileds("uid,name").Where("uid > ?", 1).Limit(0, 10).Select()
// SELECT * FROM user WHERE uid=1
r, err := db.Table("user").Where("u.uid=1",).One()
r, err := db.Table("user").Where("u.uid", 1).One()
r, err := db.Table("user").Where("u.uid=?", 1).One()
// SELECT * FROM user WHERE (uid=1) AND (name='john')
r, err := db.Table("user").Where("uid", 1).Where("name", "john").One()
r, err := db.Table("user").Where("uid=?", 1).And("name=?", "john").One()
// SELECT * FROM user WHERE (uid=1) OR (name='john')
r, err := db.Table("user").Where("uid=?", 1).Or("name=?", "john").One()
```
`Where + map`
```go
// SELECT * FROM user WHERE uid=1 AND name='john'
r, err := db.Table("user").Where(g.Map{"uid" : 1, "name" : "john"}).One()
// SELECT * FROM user WHERE uid=1 AND age>18
r, err := db.Table("user").Where(g.Map{"uid" : 1, "age>" : 18}).One()
```
`Where + struct/*struct`
```go
type User struct {
Id int `json:"uid"`
UserName string `gconv:"name"`
}
// SELECT * FROM user WHERE uid =1 AND name='john'
r, err := db.Table("user").Where(User{ Id : 1, UserName : "john"}).One()
// SELECT * FROM user WHERE uid =1
r, err := db.Table("user").Where(&User{ Id : 1}).One()
```
### 3. Update & Delete
```go
// UPDATE user SET name='john guo' WHERE name='john'
r, err := db.Table("user").Data(gdb.Map{"name" : "john guo"}).Where("name=?", "john").Update()
r, err := db.Table("user").Data("name='john guo'").Where("name=?", "john").Update()
// UPDATE user SET status=1 ORDER BY login_time asc LIMIT 10
r, err := db.Table("user").Data("status", 1).OrderBy("login_time asc").Limit(10).Update
// DELETE FROM user WHERE uid=10
r, err := db.Table("user").Where("uid=?", 10).Delete()
// DELETE FROM user ORDER BY login_time asc LIMIT 10
r, err := db.Table("user").OrderBy("login_time asc").Limit(10).Delete()
```
### 4. Insert & Replace & Save
```go
r, err := db.Table("user").Data(g.Map{"name": "john"}).Insert()
r, err := db.Table("user").Data(g.Map{"uid": 10000, "name": "john"}).Replace()
r, err := db.Table("user").Data(g.Map{"uid": 10001, "name": "john"}).Save()
```
### 5. Transaction
```go
if tx, err := db.Begin(); err == nil {
r, err := tx.Save("user", g.Map{
"uid" : 1,
"name" : "john",
})
tx.Commit()
}
```
### 6. Error Handling
```go
func GetOrderInfo(id int) (order *Order, err error) {
err = g.DB().Table("order").Where("id", id).Struct(&order)
if err != nil && err == sql.ErrNoRows {
err = nil
}
return
}
```
[More Features...](https://goframe.org/start/index)

View File

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

View File

@ -1,6 +1,6 @@
# `v1.9.0`
# `v1.9.3`
该版本实际为`v2.0.0`的大版本发布,为避免`go module`机制严格要求`v2`版本以上需要修改`import`并加上`v2`后缀,因此使用了`v1.9.0`进行发布。
该版本实际为`v2.0`的大版本发布,为避免`go module`机制严格要求`v2`版本以上需要修改`import`并加上`v2`后缀,因此使用了`v1.9`版本进行发布。
## 新特性
@ -29,6 +29,7 @@
1. `ghttp`
- 改进`Request`参数解析方式https://goframe.org/net/ghttp/request
- 改进跨域请求功能,新增`Origin`设置及校验功能https://goframe.org/net/ghttp/cors
- `Cookie`及`Session`的`TTL`配置数据类型修改为`time.Duration`;
- 新增允许同时通过`Header/Cookie`传递`SessionId`
- 新增`ConfigFromMap/SetConfigWithMap`方法,支持通过`map`参数设置WebServer

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

Some files were not shown because too many files have changed in this diff Show More