From b24322bc6acd2ffd70ef650c562768c233498c4e Mon Sep 17 00:00:00 2001 From: zxysilent Date: Sat, 7 Dec 2019 13:43:34 +0800 Subject: [PATCH 01/23] [A] template --- testdata/views/index.html | 10 +++++++++ testdata/views/subtmpl/subtmpl.html | 1 + testdata/views/subtmpl/subtmpl.tpl | 0 testdata/views/test.html | 10 +++++++++ tmpl.go | 35 +++++++++++++++++++++++++++++ tmpl_test.go | 34 ++++++++++++++++++++++++++++ 6 files changed, 90 insertions(+) create mode 100644 testdata/views/index.html create mode 100644 testdata/views/subtmpl/subtmpl.html create mode 100644 testdata/views/subtmpl/subtmpl.tpl create mode 100644 testdata/views/test.html create mode 100644 tmpl.go create mode 100644 tmpl_test.go diff --git a/testdata/views/index.html b/testdata/views/index.html new file mode 100644 index 0000000..3bd2e95 --- /dev/null +++ b/testdata/views/index.html @@ -0,0 +1,10 @@ + + + + + index + + + + + \ No newline at end of file diff --git a/testdata/views/subtmpl/subtmpl.html b/testdata/views/subtmpl/subtmpl.html new file mode 100644 index 0000000..50f76e6 --- /dev/null +++ b/testdata/views/subtmpl/subtmpl.html @@ -0,0 +1 @@ +name{{.Name}} \ No newline at end of file diff --git a/testdata/views/subtmpl/subtmpl.tpl b/testdata/views/subtmpl/subtmpl.tpl new file mode 100644 index 0000000..e69de29 diff --git a/testdata/views/test.html b/testdata/views/test.html new file mode 100644 index 0000000..9144d53 --- /dev/null +++ b/testdata/views/test.html @@ -0,0 +1,10 @@ + + + + + test + + + + + \ No newline at end of file diff --git a/tmpl.go b/tmpl.go new file mode 100644 index 0000000..058aa96 --- /dev/null +++ b/tmpl.go @@ -0,0 +1,35 @@ +package utils + +import ( + "io/ioutil" + "os" + "path/filepath" + "strings" + "text/template" +) + +// LoadTmpl 加载指定目录解析为模板 仅限 .html 文件 +// eg: views/index.html ,views/subtmpl/subtmpl.html +// tmpl:=LoadTmpl("./views") +// tmpl.ExecuteTemplate(yourWriter, "index.html", yourData)、tmpl.ExecuteTemplate(yourWriter, "subtmpl/subtmpl.html", yourData) +func LoadTmpl(root string) *template.Template { + tmpl := template.New("LoadTmpl") + rln := len(root) + filepath.Walk(root, func(path string, fi os.FileInfo, err error) error { + pln := len(path) + // 是文件 并且是 .html 结尾 + if !fi.IsDir() && pln > 4 && path[pln-5:] == ".html" { + buf, err := ioutil.ReadFile(path) + if err != nil { + panic("read file :" + path + ". error :" + err.Error()) + } + name := strings.ReplaceAll(path, "\\", "/") + _, err = tmpl.New(name[rln-1:]).Parse(string(buf)) + if err != nil { + panic("parse file :" + path + ". error :" + err.Error()) + } + } + return nil + }) + return tmpl +} diff --git a/tmpl_test.go b/tmpl_test.go new file mode 100644 index 0000000..9bf98a4 --- /dev/null +++ b/tmpl_test.go @@ -0,0 +1,34 @@ +package utils + +import ( + "bytes" + "testing" +) + +func TestLoadTmpl(t *testing.T) { + tmpl := LoadTmpl("./testdata/views") + if tmpl == nil { + t.Error("error") + } + tmpls := tmpl.Templates() + for i := 0; i < len(tmpls); i++ { + t.Log(tmpls[i].Name()) + } +} + +func TestLoadTmplExec(t *testing.T) { + mod := struct { + Name string + Arr []int + }{ + Name: "testName", + Arr: []int{1, 3, 5, 7}, + } + tmpl := LoadTmpl("./testdata/views") + if tmpl == nil { + t.Error("error") + } + w := bytes.NewBuffer(nil) + tmpl.ExecuteTemplate(w, "subtmpl/subtmpl.html", mod) + t.Log(w.String()) +} From 6ef07bfa10fa034019c11d5804f745dcb72993bb Mon Sep 17 00:00:00 2001 From: zxysilent Date: Sat, 7 Dec 2019 13:58:17 +0800 Subject: [PATCH 02/23] =?UTF-8?q?[U]=20=E6=9B=B4=E6=B3=A8=E9=87=8A?= =?UTF-8?q?=E5=92=8C=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- reply.go | 184 +++++++++++++++++++++++++++--------------------------- result.go | 152 ++++++++++++++++++-------------------------- 2 files changed, 152 insertions(+), 184 deletions(-) diff --git a/reply.go b/reply.go index 8759d4d..1271e8f 100644 --- a/reply.go +++ b/reply.go @@ -1,92 +1,92 @@ -package utils - -//Reply format -type Reply struct { - Code int `json:"code"` - Msg string `json:"msg"` - Data interface{} `json:"data,omitempty"` -} - -//page format -//Message -type page struct { - Count int `json:"count"` - Items interface{} `json:"items"` -} - -const ( - stSucc int = 200 //正常 - stFail int = 300 //失败 - stErrIpt int = 310 //输入数据有误 - stErrOpt int = 320 //无数据返回 - stErrDeny int = 330 //没有权限 - stErrJwt int = 340 //jwt未通过验证 - stErrSvr int = 350 //服务端错误 - stExt int = 400 //其他约定 //eg 更新 token -) - -func newRes(code int, msg string, data ...interface{}) (int, Reply) { - if len(data) > 0 { - return 200, Reply{ - Code: code, - Msg: msg, - Data: data[0], - } - } - return 200, Reply{ - Code: code, - Msg: msg, - } -} - -//Succ 返回一个成功标识的结果格式 -func Succ(msg string, data ...interface{}) (int, Reply) { - return newRes(stSucc, msg, data...) -} - -//Fail 返回一个失败标识的结果格式 -func Fail(msg string, data ...interface{}) (int, Reply) { - return newRes(stFail, msg, data...) -} - -//Page 返回一个带有分页数据的结果格式 -func Page(msg string, items interface{}, count int) (int, Reply) { - return 200, Reply{ - Code: stSucc, - Msg: msg, - Data: page{ - Items: items, - Count: count, - }, - } -} - -//ErrIpt 返回一个输入错误的结果格式 -func ErrIpt(msg string, data ...interface{}) (int, Reply) { - return newRes(stErrIpt, msg, data...) -} - -//ErrOpt 返回一个输出错误的结果格式 -func ErrOpt(msg string, data ...interface{}) (int, Reply) { - return newRes(stErrOpt, msg, data...) -} - -//ErrDeny 返回一个没有权限的结果格式 -func ErrDeny(msg string, data ...interface{}) (int, Reply) { - return newRes(stErrDeny, msg, data...) -} - -//ErrJwt 返回一个通过验证的结果格式 -func ErrJwt(msg string, data ...interface{}) (int, Reply) { - return newRes(stErrJwt, msg, data...) -} - -//ErrSvr 返回一个服务端错误的结果格式 -func ErrSvr(msg string, data ...interface{}) (int, Reply) { - return newRes(stErrSvr, msg, data...) -} - -//Ext 返回一个其他约定的结果格式 -func Ext(msg string, data ...interface{}) (int, Reply) { - return newRes(stExt, msg, data...) -} +package utils + +// Reply format +type Reply struct { + Code int `json:"code"` + Msg string `json:"msg"` + Data interface{} `json:"data,omitempty"` +} + +// page format +// Message +type page struct { + Count int `json:"count"` + Items interface{} `json:"items"` +} + +const ( + stSucc int = 200 //正常 + stFail int = 300 //失败 + stErrIpt int = 310 //输入数据有误 + stErrOpt int = 320 //无数据返回 + stErrDeny int = 330 //没有权限 + stErrJwt int = 340 //jwt未通过验证 + stErrSvr int = 350 //服务端错误 + stExt int = 400 //其他约定 //eg 更新 token +) + +func newReply(code int, msg string, data ...interface{}) (int, Reply) { + if len(data) > 0 { + return 200, Reply{ + Code: code, + Msg: msg, + Data: data[0], + } + } + return 200, Reply{ + Code: code, + Msg: msg, + } +} + +// Succ 返回一个成功标识的结果格式 +func Succ(msg string, data ...interface{}) (int, Reply) { + return newReply(stSucc, msg, data...) +} + +// Fail 返回一个失败标识的结果格式 +func Fail(msg string, data ...interface{}) (int, Reply) { + return newReply(stFail, msg, data...) +} + +// Page 返回一个带有分页数据的结果格式 +func Page(msg string, items interface{}, count int) (int, Reply) { + return 200, Reply{ + Code: stSucc, + Msg: msg, + Data: page{ + Items: items, + Count: count, + }, + } +} + +// ErrIpt 返回一个输入错误的结果格式 +func ErrIpt(msg string, data ...interface{}) (int, Reply) { + return newReply(stErrIpt, msg, data...) +} + +// ErrOpt 返回一个输出错误的结果格式 +func ErrOpt(msg string, data ...interface{}) (int, Reply) { + return newReply(stErrOpt, msg, data...) +} + +// ErrDeny 返回一个没有权限的结果格式 +func ErrDeny(msg string, data ...interface{}) (int, Reply) { + return newReply(stErrDeny, msg, data...) +} + +// ErrJwt 返回一个通过验证的结果格式 +func ErrJwt(msg string, data ...interface{}) (int, Reply) { + return newReply(stErrJwt, msg, data...) +} + +// ErrSvr 返回一个服务端错误的结果格式 +func ErrSvr(msg string, data ...interface{}) (int, Reply) { + return newReply(stErrSvr, msg, data...) +} + +// Ext 返回一个其他约定的结果格式 +func Ext(msg string, data ...interface{}) (int, Reply) { + return newReply(stExt, msg, data...) +} diff --git a/result.go b/result.go index 18ae5bb..c4aed87 100644 --- a/result.go +++ b/result.go @@ -1,92 +1,60 @@ -package utils - -// //Reply format -// type Reply struct { -// Code int `json:"code"` -// Msg string `json:"msg"` -// Data interface{} `json:"data,omitempty"` -// } - -// //page format -// //Message -// type page struct { -// Count int `json:"count"` -// Items interface{} `json:"items"` -// } - -// const ( -// stSucc int = 200 //正常 -// stFail int = 300 //失败 -// stErrIpt int = 310 //输入数据有误 -// stErrOpt int = 320 //无数据返回 -// stErrDeny int = 330 //没有权限 -// stErrJwt int = 340 //jwt未通过验证 -// stErrSvr int = 350 //服务端错误 -// stExt int = 400 //其他约定 //eg 更新 token -// ) - -// func newRes(code int, msg string, data ...interface{}) (int, Reply) { -// if len(data) > 0 { -// return 200, Reply{ -// Code: code, -// Msg: msg, -// Data: data[0], -// } -// } -// return 200, Reply{ -// Code: code, -// Msg: msg, -// } -// } - -//NewSucc 返回一个成功标识的结果格式 -func NewSucc(msg string, data ...interface{}) (int, Reply) { - return newRes(stSucc, msg, data...) -} - -//NewFail 返回一个失败标识的结果格式 -func NewFail(msg string, data ...interface{}) (int, Reply) { - return newRes(stFail, msg, data...) -} - -//NewPage 返回一个带有分页数据的结果格式 -func NewPage(msg string, items interface{}, count int) (int, Reply) { - return 200, Reply{ - Code: stSucc, - Msg: msg, - Data: page{ - Items: items, - Count: count, - }, - } -} - -//NewErrIpt 返回一个输入错误的结果格式 -func NewErrIpt(msg string, data ...interface{}) (int, Reply) { - return newRes(stErrIpt, msg, data...) -} - -//NewErrOpt 返回一个输出错误的结果格式 -func NewErrOpt(msg string, data ...interface{}) (int, Reply) { - return newRes(stErrOpt, msg, data...) -} - -//NewErrDeny 返回一个没有权限的结果格式 -func NewErrDeny(msg string, data ...interface{}) (int, Reply) { - return newRes(stErrDeny, msg, data...) -} - -//NewErrJwt 返回一个通过验证的结果格式 -func NewErrJwt(msg string, data ...interface{}) (int, Reply) { - return newRes(stErrJwt, msg, data...) -} - -//NewErrSvr 返回一个服务端错误的结果格式 -func NewErrSvr(msg string, data ...interface{}) (int, Reply) { - return newRes(stErrSvr, msg, data...) -} - -//NewExt 返回一个其他约定的结果格式 -func NewExt(msg string, data ...interface{}) (int, Reply) { - return newRes(stExt, msg, data...) -} +package utils + +// NewSucc 返回一个成功标识的结果格式 +// 推荐使用 Succ +func NewSucc(msg string, data ...interface{}) (int, Reply) { + return newReply(stSucc, msg, data...) +} + +// NewFail 返回一个失败标识的结果格式 +// 推荐使用 Fail +func NewFail(msg string, data ...interface{}) (int, Reply) { + return newReply(stFail, msg, data...) +} + +// NewPage 返回一个带有分页数据的结果格式 +// 推荐使用 Page +func NewPage(msg string, items interface{}, count int) (int, Reply) { + return 200, Reply{ + Code: stSucc, + Msg: msg, + Data: page{ + Items: items, + Count: count, + }, + } +} + +// NewErrIpt 返回一个输入错误的结果格式 +// 推荐使用 ErrIpt +func NewErrIpt(msg string, data ...interface{}) (int, Reply) { + return newReply(stErrIpt, msg, data...) +} + +// NewErrOpt 返回一个输出错误的结果格式 +// 推荐使用 ErrOpt +func NewErrOpt(msg string, data ...interface{}) (int, Reply) { + return newReply(stErrOpt, msg, data...) +} + +// NewErrDeny 返回一个没有权限的结果格式 +// 推荐使用 ErrDeny +func NewErrDeny(msg string, data ...interface{}) (int, Reply) { + return newReply(stErrDeny, msg, data...) +} + +// NewErrJwt 返回一个通过验证的结果格式 +// 推荐使用 ErrJwt +func NewErrJwt(msg string, data ...interface{}) (int, Reply) { + return newReply(stErrJwt, msg, data...) +} + +// NewErrSvr 返回一个服务端错误的结果格式 +func NewErrSvr(msg string, data ...interface{}) (int, Reply) { + return newReply(stErrSvr, msg, data...) +} + +// NewExt 返回一个其他约定的结果格式 +func NewExt(msg string, data ...interface{}) (int, Reply) { + return newReply(stExt, msg, data...) +} From 518bec19be8d04098f649a17fee7e1ee94b8708b Mon Sep 17 00:00:00 2001 From: zxysilent Date: Mon, 16 Dec 2019 13:12:42 +0800 Subject: [PATCH 03/23] =?UTF-8?q?[U]=20text=E8=B0=83=E6=95=B4=E4=B8=BA=20h?= =?UTF-8?q?tml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tmpl.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmpl.go b/tmpl.go index 058aa96..c7e2f81 100644 --- a/tmpl.go +++ b/tmpl.go @@ -5,7 +5,7 @@ import ( "os" "path/filepath" "strings" - "text/template" + "html/template" ) // LoadTmpl 加载指定目录解析为模板 仅限 .html 文件 From b4e160be18946cc9b16f27edc6b5f12ca5a46f5f Mon Sep 17 00:00:00 2001 From: zxysilent Date: Mon, 16 Dec 2019 13:26:48 +0800 Subject: [PATCH 04/23] [F] Funcs must be called before the template is parsed. --- tmpl.go | 9 ++++++--- tmpl_test.go | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/tmpl.go b/tmpl.go index c7e2f81..0c9a335 100644 --- a/tmpl.go +++ b/tmpl.go @@ -1,19 +1,22 @@ package utils import ( + "html/template" "io/ioutil" "os" "path/filepath" "strings" - "html/template" ) // LoadTmpl 加载指定目录解析为模板 仅限 .html 文件 // eg: views/index.html ,views/subtmpl/subtmpl.html -// tmpl:=LoadTmpl("./views") +// tmpl:=LoadTmpl("./views",funcs) // tmpl.ExecuteTemplate(yourWriter, "index.html", yourData)、tmpl.ExecuteTemplate(yourWriter, "subtmpl/subtmpl.html", yourData) -func LoadTmpl(root string) *template.Template { +func LoadTmpl(root string, funcs template.FuncMap) *template.Template { tmpl := template.New("LoadTmpl") + if funcs != nil { + tmpl.Funcs(funcs) + } rln := len(root) filepath.Walk(root, func(path string, fi os.FileInfo, err error) error { pln := len(path) diff --git a/tmpl_test.go b/tmpl_test.go index 9bf98a4..134abaf 100644 --- a/tmpl_test.go +++ b/tmpl_test.go @@ -6,7 +6,7 @@ import ( ) func TestLoadTmpl(t *testing.T) { - tmpl := LoadTmpl("./testdata/views") + tmpl := LoadTmpl("./testdata/views",nil) if tmpl == nil { t.Error("error") } @@ -24,7 +24,7 @@ func TestLoadTmplExec(t *testing.T) { Name: "testName", Arr: []int{1, 3, 5, 7}, } - tmpl := LoadTmpl("./testdata/views") + tmpl := LoadTmpl("./testdata/views",nil) if tmpl == nil { t.Error("error") } From 7edd045e6ba900771d9ffa375815462b34bad516 Mon Sep 17 00:00:00 2001 From: zxysilent Date: Fri, 13 Mar 2020 12:39:24 +0800 Subject: [PATCH 05/23] [A] go.mod --- go.mod | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 go.mod diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..482aa86 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/zxysilent/utils + +go 1.14 From 6db4b4795a7c32c0789b083d4b8a54f0a75bdecf Mon Sep 17 00:00:00 2001 From: zxysilent Date: Wed, 24 Jun 2020 11:51:17 +0800 Subject: [PATCH 06/23] =?UTF-8?q?[A]=20=E9=9A=8F=E6=9C=BA=E7=BA=AF?= =?UTF-8?q?=E6=95=B0=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- rand.go | 58 ++++++++++++++++++++++++++++++++++++ util_test.go => rand_test.go | 16 ++++++++++ util.go | 54 --------------------------------- 3 files changed, 74 insertions(+), 54 deletions(-) create mode 100644 rand.go rename util_test.go => rand_test.go (51%) diff --git a/rand.go b/rand.go new file mode 100644 index 0000000..277f396 --- /dev/null +++ b/rand.go @@ -0,0 +1,58 @@ +package utils + +import ( + "math/rand" + "time" + "unsafe" +) + +const ( + digit = "0123456789" + capital = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + lowercase = "abcdefghijklmnopqrstuvwxyz" + chars = digit + lowercase + charsLen = len(chars) + digitLen = len(digit) + charsMask = 1<<6 - 1 + digitMask = 1<<4 - 1 +) + +var rng = rand.NewSource(time.Now().UnixNano()) + +// RandStr 返回指定长度的随机字符串 +// 包含数字 小写字母 +func RandStr(ln int) string { + /* chars 36个字符 + * rng.Int63() 每次产出64bit的随机数,每次我们使用6bit(2^6=64) 可以使用10次 + */ + buf := make([]byte, ln) + for idx, cache, remain := 0, rng.Int63(), 10; idx < ln; { + if remain == 0 { + cache, remain = rng.Int63(), 10 + } + buf[idx] = chars[int(cache&charsMask)%charsLen] + cache >>= 6 + remain-- + idx++ + } + return *(*string)(unsafe.Pointer(&buf)) +} + +// RandDigitStr 返回指定长度的随机字符串 +// 只包含数字 +func RandDigitStr(ln int) string { + /* digits 10个字符 + * rng.Int63() 每次产出64bit的随机数,每次我们使用4bit(2^4=16) 可以使用16次 + */ + buf := make([]byte, ln) + for idx, cache, remain := 0, rng.Int63(), 10; idx < ln; { + if remain == 0 { + cache, remain = rng.Int63(), 10 + } + buf[idx] = chars[int(cache&digitMask)%digitLen] + cache >>= 4 + remain-- + idx++ + } + return *(*string)(unsafe.Pointer(&buf)) +} diff --git a/util_test.go b/rand_test.go similarity index 51% rename from util_test.go rename to rand_test.go index 579826b..5681fce 100644 --- a/util_test.go +++ b/rand_test.go @@ -21,3 +21,19 @@ func BenchmarkRandStr16(b *testing.B) { RandStr(16) } } +func BenchmarkRandDigitStr8(b *testing.B) { + for i := 0; i < b.N; i++ { + RandDigitStr(8) + } +} + +func BenchmarkRandDigitStr10(b *testing.B) { + for i := 0; i < b.N; i++ { + RandDigitStr(10) + } +} +func BenchmarkRandDigitStr16(b *testing.B) { + for i := 0; i < b.N; i++ { + RandDigitStr(16) + } +} diff --git a/util.go b/util.go index 7c8ea62..3f0b73b 100644 --- a/util.go +++ b/util.go @@ -1,62 +1,8 @@ package utils -import ( - "math/rand" - "strconv" - "time" - "unsafe" -) - const ( // FormatDateTime 标准日期格式化 FormatDateTime = "2006-01-02 15:04:05" // FmtyyyyMMdd 年月日 FmtyyyyMMdd = "20060102" - digit = "0123456789" - capital = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - lowercase = "abcdefghijklmnopqrstuvwxyz" - chars = digit + lowercase //ABCDEFGHIJKLMNOPQRSTUVWXYZ - charsLen = len(chars) - mask = 1<<6 - 1 ) - -//0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ - -var rng = rand.NewSource(time.Now().UnixNano()) - -// RandStr 返回指定长度的随机字符串 -func RandStr(ln int) string { - /* chars 36个字符 - * rng.Int63() 每次产出64bit的随机数,每次我们使用6bit(2^6=64) 可以使用10次 - */ - buf := make([]byte, ln) - for idx, cache, remain := 0, rng.Int63(), 10; idx < ln; { - if remain == 0 { - cache, remain = rng.Int63(), 10 - } - buf[idx] = chars[int(cache&mask)%charsLen] - cache >>= 6 - remain-- - idx++ - } - return *(*string)(unsafe.Pointer(&buf)) -} - -// Atoi 字符串转数字 def 默认值 -func Atoi(s string, def ...int) (int, error) { - rtn, err := strconv.Atoi(s) - if err != nil && len(def) > 0 { - return def[0], err - } - return rtn, nil -} - -// InOf 目标是否在数组中 -func InOf(in int, arr []int) bool { - for idx := range arr { - if in == arr[idx] { - return true - } - } - return false -} From ffac71e131cb5ded1ec105a45889511ca58368b3 Mon Sep 17 00:00:00 2001 From: zxysilent Date: Thu, 18 Feb 2021 09:39:03 +0800 Subject: [PATCH 07/23] =?UTF-8?q?[F]=20=E6=AC=A1=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- rand.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rand.go b/rand.go index 277f396..7fcb106 100644 --- a/rand.go +++ b/rand.go @@ -45,9 +45,9 @@ func RandDigitStr(ln int) string { * rng.Int63() 每次产出64bit的随机数,每次我们使用4bit(2^4=16) 可以使用16次 */ buf := make([]byte, ln) - for idx, cache, remain := 0, rng.Int63(), 10; idx < ln; { + for idx, cache, remain := 0, rng.Int63(), 16; idx < ln; { if remain == 0 { - cache, remain = rng.Int63(), 10 + cache, remain = rng.Int63(), 16 } buf[idx] = chars[int(cache&digitMask)%digitLen] cache >>= 4 From 3f6f07234528ec8e15e3d1cd36f898f15a8e4739 Mon Sep 17 00:00:00 2001 From: zxysilent Date: Mon, 22 Feb 2021 22:23:13 +0800 Subject: [PATCH 08/23] =?UTF-8?q?[F]=20=E9=94=99=E8=AF=AF=E5=88=A4?= =?UTF-8?q?=E6=96=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tmpl.go | 13 ++++++++----- tmpl_test.go | 14 ++++++++++---- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/tmpl.go b/tmpl.go index 0c9a335..1581687 100644 --- a/tmpl.go +++ b/tmpl.go @@ -12,27 +12,30 @@ import ( // eg: views/index.html ,views/subtmpl/subtmpl.html // tmpl:=LoadTmpl("./views",funcs) // tmpl.ExecuteTemplate(yourWriter, "index.html", yourData)、tmpl.ExecuteTemplate(yourWriter, "subtmpl/subtmpl.html", yourData) -func LoadTmpl(root string, funcs template.FuncMap) *template.Template { +func LoadTmpl(root string, funcs template.FuncMap) (*template.Template, error) { tmpl := template.New("LoadTmpl") if funcs != nil { tmpl.Funcs(funcs) } rln := len(root) - filepath.Walk(root, func(path string, fi os.FileInfo, err error) error { + err := filepath.Walk(root, func(path string, fi os.FileInfo, err error) error { + if err != nil { + return err + } pln := len(path) // 是文件 并且是 .html 结尾 if !fi.IsDir() && pln > 4 && path[pln-5:] == ".html" { buf, err := ioutil.ReadFile(path) if err != nil { - panic("read file :" + path + ". error :" + err.Error()) + return err } name := strings.ReplaceAll(path, "\\", "/") _, err = tmpl.New(name[rln-1:]).Parse(string(buf)) if err != nil { - panic("parse file :" + path + ". error :" + err.Error()) + return err } } return nil }) - return tmpl + return tmpl, err } diff --git a/tmpl_test.go b/tmpl_test.go index 134abaf..1143215 100644 --- a/tmpl_test.go +++ b/tmpl_test.go @@ -5,10 +5,16 @@ import ( "testing" ) +func TestLoadTmpl1(t *testing.T) { + _, err := LoadTmpl("./testdata/views1", nil) + if err != nil { + t.Error(err.Error()) + } +} func TestLoadTmpl(t *testing.T) { - tmpl := LoadTmpl("./testdata/views",nil) - if tmpl == nil { - t.Error("error") + tmpl, err := LoadTmpl("./testdata/views", nil) + if err != nil { + t.Error(err.Error()) } tmpls := tmpl.Templates() for i := 0; i < len(tmpls); i++ { @@ -24,7 +30,7 @@ func TestLoadTmplExec(t *testing.T) { Name: "testName", Arr: []int{1, 3, 5, 7}, } - tmpl := LoadTmpl("./testdata/views",nil) + tmpl, _ := LoadTmpl("./testdata/views", nil) if tmpl == nil { t.Error("error") } From 1c810f649ea636f219b83a599229777bb54ac841 Mon Sep 17 00:00:00 2001 From: zxysilent Date: Sat, 10 Apr 2021 15:15:45 +0800 Subject: [PATCH 09/23] =?UTF-8?q?[A]=20=E6=B7=BB=E5=8A=A0=E8=AF=B4?= =?UTF-8?q?=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 5316168..bea247b 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,9 @@ # utils 通用go工具类 + +- rand + 随机相关 +- reply + echo/gin框架返回值 +- tmpl + 模板相关 \ No newline at end of file From 1c6622f94b34d68385371d88dc3f53da51cc982f Mon Sep 17 00:00:00 2001 From: zxysilent Date: Tue, 11 May 2021 17:36:38 +0800 Subject: [PATCH 10/23] =?UTF-8?q?[U]=20=E4=BC=98=E5=8C=96=E4=BB=A3?= =?UTF-8?q?=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- reply.go | 24 +++++++++++++++--------- result.go | 2 +- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/reply.go b/reply.go index 1271e8f..61b22c5 100644 --- a/reply.go +++ b/reply.go @@ -15,14 +15,14 @@ type page struct { } const ( - stSucc int = 200 //正常 - stFail int = 300 //失败 - stErrIpt int = 310 //输入数据有误 - stErrOpt int = 320 //无数据返回 - stErrDeny int = 330 //没有权限 - stErrJwt int = 340 //jwt未通过验证 - stErrSvr int = 350 //服务端错误 - stExt int = 400 //其他约定 //eg 更新 token + stSucc int = 200 //正常 + stFail int = 300 //失败 + stErrIpt int = 310 //输入数据有误 + stErrOpt int = 320 //无数据返回 + stErrDeny int = 330 //没有权限 + stErrToken int = 340 //token错误 + stErrSvr int = 350 //服务端错误 + stExt int = 400 //其他约定 //eg 更新 token ) func newReply(code int, msg string, data ...interface{}) (int, Reply) { @@ -77,8 +77,14 @@ func ErrDeny(msg string, data ...interface{}) (int, Reply) { } // ErrJwt 返回一个通过验证的结果格式 +// 推荐使用 ErrToken func ErrJwt(msg string, data ...interface{}) (int, Reply) { - return newReply(stErrJwt, msg, data...) + return newReply(stErrToken, msg, data...) +} + +// ErrJwt 返回一个通过验证的结果格式 +func ErrToken(msg string, data ...interface{}) (int, Reply) { + return newReply(stErrToken, msg, data...) } // ErrSvr 返回一个服务端错误的结果格式 diff --git a/result.go b/result.go index c4aed87..25fcdb2 100644 --- a/result.go +++ b/result.go @@ -46,7 +46,7 @@ func NewErrDeny(msg string, data ...interface{}) (int, Reply) { // NewErrJwt 返回一个通过验证的结果格式 // 推荐使用 ErrJwt func NewErrJwt(msg string, data ...interface{}) (int, Reply) { - return newReply(stErrJwt, msg, data...) + return newReply(stErrToken, msg, data...) } // NewErrSvr 返回一个服务端错误的结果格式 From ae1d9ac1b73c743c282b4d9fd02e5e09a35de554 Mon Sep 17 00:00:00 2001 From: zxysilent Date: Mon, 5 Jul 2021 13:29:04 +0800 Subject: [PATCH 11/23] =?UTF-8?q?[U]=20=E5=8D=87=E7=BA=A7=E7=89=88?= =?UTF-8?q?=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 482aa86..ec8bcad 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ module github.com/zxysilent/utils -go 1.14 +go 1.15 From 71f19b4782303ec3edf4252a3ab27389d82cd4af Mon Sep 17 00:00:00 2001 From: zxysilent Date: Mon, 5 Jul 2021 13:29:30 +0800 Subject: [PATCH 12/23] =?UTF-8?q?[U]=20=E5=88=A0=E9=99=A4=E5=85=BC?= =?UTF-8?q?=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- result.go | 60 ------------------------------------------------------- 1 file changed, 60 deletions(-) delete mode 100644 result.go diff --git a/result.go b/result.go deleted file mode 100644 index 25fcdb2..0000000 --- a/result.go +++ /dev/null @@ -1,60 +0,0 @@ -package utils - -// NewSucc 返回一个成功标识的结果格式 -// 推荐使用 Succ -func NewSucc(msg string, data ...interface{}) (int, Reply) { - return newReply(stSucc, msg, data...) -} - -// NewFail 返回一个失败标识的结果格式 -// 推荐使用 Fail -func NewFail(msg string, data ...interface{}) (int, Reply) { - return newReply(stFail, msg, data...) -} - -// NewPage 返回一个带有分页数据的结果格式 -// 推荐使用 Page -func NewPage(msg string, items interface{}, count int) (int, Reply) { - return 200, Reply{ - Code: stSucc, - Msg: msg, - Data: page{ - Items: items, - Count: count, - }, - } -} - -// NewErrIpt 返回一个输入错误的结果格式 -// 推荐使用 ErrIpt -func NewErrIpt(msg string, data ...interface{}) (int, Reply) { - return newReply(stErrIpt, msg, data...) -} - -// NewErrOpt 返回一个输出错误的结果格式 -// 推荐使用 ErrOpt -func NewErrOpt(msg string, data ...interface{}) (int, Reply) { - return newReply(stErrOpt, msg, data...) -} - -// NewErrDeny 返回一个没有权限的结果格式 -// 推荐使用 ErrDeny -func NewErrDeny(msg string, data ...interface{}) (int, Reply) { - return newReply(stErrDeny, msg, data...) -} - -// NewErrJwt 返回一个通过验证的结果格式 -// 推荐使用 ErrJwt -func NewErrJwt(msg string, data ...interface{}) (int, Reply) { - return newReply(stErrToken, msg, data...) -} - -// NewErrSvr 返回一个服务端错误的结果格式 -func NewErrSvr(msg string, data ...interface{}) (int, Reply) { - return newReply(stErrSvr, msg, data...) -} - -// NewExt 返回一个其他约定的结果格式 -func NewExt(msg string, data ...interface{}) (int, Reply) { - return newReply(stExt, msg, data...) -} From c78b34799bcaa026d66a09718691b34322a696ed Mon Sep 17 00:00:00 2001 From: zxysilent Date: Mon, 5 Jul 2021 13:29:50 +0800 Subject: [PATCH 13/23] =?UTF-8?q?[U]=20=E4=BF=AE=E6=94=B9=E5=8F=98?= =?UTF-8?q?=E9=87=8F=E5=90=8D-=E4=BC=98=E5=8C=96=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- reply.go | 57 ++++++++++++++++++++++++++------------------------------ 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/reply.go b/reply.go index 61b22c5..84eb16b 100644 --- a/reply.go +++ b/reply.go @@ -1,28 +1,29 @@ package utils // Reply format +// 统一返回格式 type Reply struct { Code int `json:"code"` Msg string `json:"msg"` Data interface{} `json:"data,omitempty"` } -// page format -// Message +// page format Message +// 数据分页附加数据 type page struct { Count int `json:"count"` Items interface{} `json:"items"` } const ( - stSucc int = 200 //正常 - stFail int = 300 //失败 - stErrIpt int = 310 //输入数据有误 - stErrOpt int = 320 //无数据返回 - stErrDeny int = 330 //没有权限 - stErrToken int = 340 //token错误 - stErrSvr int = 350 //服务端错误 - stExt int = 400 //其他约定 //eg 更新 token + codeSucc int = 200 //正常 + codeFail int = 300 //失败 + codeErrIpt int = 310 //输入数据有误 + codeErrOpt int = 320 //无数据返回 + codeErrDeny int = 330 //没有权限 + codeErrToken int = 340 //token错误 + codeErrSvr int = 350 //服务端错误 + codeExt int = 400 //其他约定,eg 更新token ) func newReply(code int, msg string, data ...interface{}) (int, Reply) { @@ -41,18 +42,18 @@ func newReply(code int, msg string, data ...interface{}) (int, Reply) { // Succ 返回一个成功标识的结果格式 func Succ(msg string, data ...interface{}) (int, Reply) { - return newReply(stSucc, msg, data...) + return newReply(codeSucc, msg, data...) } // Fail 返回一个失败标识的结果格式 func Fail(msg string, data ...interface{}) (int, Reply) { - return newReply(stFail, msg, data...) + return newReply(codeFail, msg, data...) } // Page 返回一个带有分页数据的结果格式 func Page(msg string, items interface{}, count int) (int, Reply) { return 200, Reply{ - Code: stSucc, + Code: codeSucc, Msg: msg, Data: page{ Items: items, @@ -61,38 +62,32 @@ func Page(msg string, items interface{}, count int) (int, Reply) { } } -// ErrIpt 返回一个输入错误的结果格式 +// ErrIpt 返回一个输入错误的结果 func ErrIpt(msg string, data ...interface{}) (int, Reply) { - return newReply(stErrIpt, msg, data...) + return newReply(codeErrIpt, msg, data...) } -// ErrOpt 返回一个输出错误的结果格式 +// ErrOpt 返回一个输出错误的结果 func ErrOpt(msg string, data ...interface{}) (int, Reply) { - return newReply(stErrOpt, msg, data...) + return newReply(codeErrOpt, msg, data...) } -// ErrDeny 返回一个没有权限的结果格式 +// ErrDeny 返回一个没有权限的结果 func ErrDeny(msg string, data ...interface{}) (int, Reply) { - return newReply(stErrDeny, msg, data...) + return newReply(codeErrDeny, msg, data...) } -// ErrJwt 返回一个通过验证的结果格式 -// 推荐使用 ErrToken -func ErrJwt(msg string, data ...interface{}) (int, Reply) { - return newReply(stErrToken, msg, data...) -} - -// ErrJwt 返回一个通过验证的结果格式 +// ErrToken 返回一个验证失败的结果 func ErrToken(msg string, data ...interface{}) (int, Reply) { - return newReply(stErrToken, msg, data...) + return newReply(codeErrToken, msg, data...) } -// ErrSvr 返回一个服务端错误的结果格式 +// ErrSvr 返回一个服务端错误的结果 func ErrSvr(msg string, data ...interface{}) (int, Reply) { - return newReply(stErrSvr, msg, data...) + return newReply(codeErrSvr, msg, data...) } -// Ext 返回一个其他约定的结果格式 +// Ext 返回一个其他约定的结果 func Ext(msg string, data ...interface{}) (int, Reply) { - return newReply(stExt, msg, data...) + return newReply(codeExt, msg, data...) } From 9c7cf664f262e9c80e67bc9ded7f820e2712dd11 Mon Sep 17 00:00:00 2001 From: zxysilent Date: Mon, 5 Jul 2021 13:30:55 +0800 Subject: [PATCH 14/23] =?UTF-8?q?[U]=20=E6=96=87=E4=BB=B6=E5=90=8D-?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=91=BD=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- util.go | 8 -------- utils.go | 8 ++++++++ 2 files changed, 8 insertions(+), 8 deletions(-) delete mode 100644 util.go create mode 100644 utils.go diff --git a/util.go b/util.go deleted file mode 100644 index 3f0b73b..0000000 --- a/util.go +++ /dev/null @@ -1,8 +0,0 @@ -package utils - -const ( - // FormatDateTime 标准日期格式化 - FormatDateTime = "2006-01-02 15:04:05" - // FmtyyyyMMdd 年月日 - FmtyyyyMMdd = "20060102" -) diff --git a/utils.go b/utils.go new file mode 100644 index 0000000..42939c1 --- /dev/null +++ b/utils.go @@ -0,0 +1,8 @@ +package utils + +const ( + // StdDateTime 标准日期格式化 + StdDateTime = "2006-01-02 15:04:05" + // StdyyyyMMdd 年月日 + StdyyyyMMdd = "20060102" +) From 98050967bce1583a30b69d8e3c9425ce819bb2b6 Mon Sep 17 00:00:00 2001 From: zxysilent Date: Mon, 5 Jul 2021 13:32:35 +0800 Subject: [PATCH 15/23] =?UTF-8?q?[U]=20=E4=BC=98=E5=8C=96=E5=91=BD?= =?UTF-8?q?=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/utils.go b/utils.go index 42939c1..1263171 100644 --- a/utils.go +++ b/utils.go @@ -3,6 +3,8 @@ package utils const ( // StdDateTime 标准日期格式化 StdDateTime = "2006-01-02 15:04:05" - // StdyyyyMMdd 年月日 - StdyyyyMMdd = "20060102" + // StdDate 年月日 + StdDate = "20060102" + // StdTime 时分秒 + StdTime = "15:04:05" ) From a62d02bc79a51c0e15aef00d46a6e6dd8d0b856a Mon Sep 17 00:00:00 2001 From: zxysilent Date: Mon, 30 Aug 2021 13:24:07 +0800 Subject: [PATCH 16/23] =?UTF-8?q?[A]=20int=E5=B9=B3=E5=8F=B0=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E6=9E=81=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/utils.go b/utils.go index 1263171..c290ad6 100644 --- a/utils.go +++ b/utils.go @@ -7,4 +7,12 @@ const ( StdDate = "20060102" // StdTime 时分秒 StdTime = "15:04:05" + // 更加编译平台判断int大小 + intSize = 32 << (^uint(0) >> 63) // 32 or 64 + // 最大Uint + MaxUint = 1< Date: Sun, 17 Oct 2021 13:49:21 +0800 Subject: [PATCH 17/23] =?UTF-8?q?[D]=20=E6=9C=AA=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- rand.go | 1 - 1 file changed, 1 deletion(-) diff --git a/rand.go b/rand.go index 7fcb106..257ffd5 100644 --- a/rand.go +++ b/rand.go @@ -8,7 +8,6 @@ import ( const ( digit = "0123456789" - capital = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" lowercase = "abcdefghijklmnopqrstuvwxyz" chars = digit + lowercase charsLen = len(chars) From cf09ef0bf8840f175ba9a14d0d547b2de6b34b05 Mon Sep 17 00:00:00 2001 From: zxysilent Date: Thu, 4 Nov 2021 10:31:11 +0800 Subject: [PATCH 18/23] =?UTF-8?q?[A]=20=E6=B5=8B=E8=AF=95=E8=A6=86?= =?UTF-8?q?=E7=9B=96=E7=8E=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 2 ++ cover.sh | 8 ++++++++ rand_test.go | 7 +++++++ reply_test.go | 26 ++++++++++++++++++++++++++ tmpl_test.go | 12 ++++++++---- 5 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 .gitignore create mode 100644 cover.sh create mode 100644 reply_test.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..614586c --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +cover.out +cover.html \ No newline at end of file diff --git a/cover.sh b/cover.sh new file mode 100644 index 0000000..9aba124 --- /dev/null +++ b/cover.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +# 覆盖率测试 + +go test -v -coverprofile cover.out . +go tool cover -html=cover.out -o cover.html + +echo "cover end" \ No newline at end of file diff --git a/rand_test.go b/rand_test.go index 5681fce..401f599 100644 --- a/rand_test.go +++ b/rand_test.go @@ -37,3 +37,10 @@ func BenchmarkRandDigitStr16(b *testing.B) { RandDigitStr(16) } } + +func TestRandDigitStr(t *testing.T) { + RandDigitStr(20) +} +func TestRandStr(t *testing.T) { + RandStr(16) +} diff --git a/reply_test.go b/reply_test.go new file mode 100644 index 0000000..c7d1d56 --- /dev/null +++ b/reply_test.go @@ -0,0 +1,26 @@ +package utils + +import "testing" + +func TestReply(t *testing.T) { + Succ("succ") + Fail("fail") + Page("page", []int{}, 0) + ErrDeny("deny") + ErrIpt("ipt") + ErrOpt("opt") + ErrSvr("svr") + ErrToken("token") + Ext("ext") +} +func TestReplyData(t *testing.T) { + Succ("succ", struct{ A, b int }{}) + Fail("fail", struct{ A, b int }{}) + Page("page", []int{}, 0) + ErrDeny("deny", struct{ A, b int }{}) + ErrIpt("ipt", struct{ A, b int }{}) + ErrOpt("opt", struct{ A, b int }{}) + ErrSvr("svr", struct{ A, b int }{}) + ErrToken("token") + Ext("ext", struct{ A, b int }{}) +} diff --git a/tmpl_test.go b/tmpl_test.go index 1143215..e334d00 100644 --- a/tmpl_test.go +++ b/tmpl_test.go @@ -7,8 +7,8 @@ import ( func TestLoadTmpl1(t *testing.T) { _, err := LoadTmpl("./testdata/views1", nil) - if err != nil { - t.Error(err.Error()) + if err == nil { + t.Error("must be error") } } func TestLoadTmpl(t *testing.T) { @@ -18,7 +18,9 @@ func TestLoadTmpl(t *testing.T) { } tmpls := tmpl.Templates() for i := 0; i < len(tmpls); i++ { - t.Log(tmpls[i].Name()) + if tmpls[i].Name() == "" { + t.Error("name eq ''") + } } } @@ -36,5 +38,7 @@ func TestLoadTmplExec(t *testing.T) { } w := bytes.NewBuffer(nil) tmpl.ExecuteTemplate(w, "subtmpl/subtmpl.html", mod) - t.Log(w.String()) + if w.String() != "nametestName" { + t.Error("name neq 'nametestName'") + } } From bef1628209709c45460be78177e086b0e27de0f4 Mon Sep 17 00:00:00 2001 From: zxysilent Date: Mon, 26 Dec 2022 11:32:48 +0800 Subject: [PATCH 19/23] =?UTF-8?q?=E7=AE=80=E7=9F=ADuid=E7=94=9F=E6=88=90?= =?UTF-8?q?=EF=BC=8C=E6=AF=8F=E6=AF=AB=E7=A7=9210=E4=BA=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- uuid.go | 46 ++++++++++++++++++++++++++++++++++++++++++++++ uuid_test.go | 14 ++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 uuid.go create mode 100644 uuid_test.go diff --git a/uuid.go b/uuid.go new file mode 100644 index 0000000..dd8f551 --- /dev/null +++ b/uuid.go @@ -0,0 +1,46 @@ +package utils + +import ( + "unsafe" +) + +const ( + uuidStr = "23456789abcdefghijkmnpqrstuvwxyz" //32 + uuidMask = 1<<5 - 1 //11111 +) + +// UUID UUID生成-16bit +// 10-times '-' 6-random string '-' 6-random string +func SUID() string { + buf := make([]byte, 16) + idx := 15 + // 15-begin 32*32*32*32*32*32==1073741824 + rand := fastRand() //6 + for ; idx > 9; idx-- { + buf[idx] = uuidStr[rand&uuidMask] + rand >>= 5 + } + now := nowms() //10 + // 50bit + // 10000-01-01 01:00:00 => 253402246800000 ms + // 111001100111011111001110111001111110001010000000 48bit + for idx = 9; idx >= 0; idx-- { + buf[idx] = uuidStr[now&uuidMask] + now >>= 5 + } + return *(*string)(unsafe.Pointer(&buf)) +} + +//go:linkname fastRand runtime.fastrand +func fastRand() uint32 + +//go:noescape +//go:linkname now time.now +func now() (sec int64, nsec int32, mono int64) + +// for runtime.walltime +func nowms() int64 { + sec, nsec, _ := now() + return sec*1e3 + int64(nsec)/1e6 + // return time.Now().UnixMilli() +} diff --git a/uuid_test.go b/uuid_test.go new file mode 100644 index 0000000..a4cbbce --- /dev/null +++ b/uuid_test.go @@ -0,0 +1,14 @@ +package utils + +import ( + "testing" +) + +func BenchmarkSUID(b *testing.B) { + for i := 0; i < b.N; i++ { + SUID() + } +} +func TestSUID(t *testing.T) { + t.Log(SUID()) +} From 8f78ff497965213302c637b5aea0e05d7b9f1d2d Mon Sep 17 00:00:00 2001 From: zxysilent Date: Tue, 17 Jan 2023 20:57:57 +0800 Subject: [PATCH 20/23] =?UTF-8?q?=E4=BC=98=E5=8C=96=EF=BC=8C=E5=B9=B6?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0uuid?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- rand.go | 14 ++++++-------- uuid.go | 39 +++++++++++++++++++++++++++++++++++---- uuid_test.go | 12 ++++++++++++ 3 files changed, 53 insertions(+), 12 deletions(-) diff --git a/rand.go b/rand.go index 257ffd5..056259c 100644 --- a/rand.go +++ b/rand.go @@ -7,12 +7,10 @@ import ( ) const ( - digit = "0123456789" - lowercase = "abcdefghijklmnopqrstuvwxyz" - chars = digit + lowercase - charsLen = len(chars) - digitLen = len(digit) - charsMask = 1<<6 - 1 + digitStr = "0123456789" + randStr = "23456789abcdefghijkmnpqrstuvwxyz" //32 + randMask = 1<<5 - 1 //11111 + digitLen = len(digitStr) digitMask = 1<<4 - 1 ) @@ -29,7 +27,7 @@ func RandStr(ln int) string { if remain == 0 { cache, remain = rng.Int63(), 10 } - buf[idx] = chars[int(cache&charsMask)%charsLen] + buf[idx] = randStr[cache&randMask] cache >>= 6 remain-- idx++ @@ -48,7 +46,7 @@ func RandDigitStr(ln int) string { if remain == 0 { cache, remain = rng.Int63(), 16 } - buf[idx] = chars[int(cache&digitMask)%digitLen] + buf[idx] = digitStr[int(cache&digitMask)%digitLen] cache >>= 4 remain-- idx++ diff --git a/uuid.go b/uuid.go index dd8f551..fd6820d 100644 --- a/uuid.go +++ b/uuid.go @@ -5,8 +5,10 @@ import ( ) const ( - uuidStr = "23456789abcdefghijkmnpqrstuvwxyz" //32 - uuidMask = 1<<5 - 1 //11111 + suidStr = "23456789abcdefghijkmnpqrstuvwxyz" //32 + suidMask = 1<<5 - 1 //11111 + uuidStr = "0123456789abcdef" //16 + uuidMask = 1<<4 - 1 //1111 ) // UUID UUID生成-16bit @@ -17,7 +19,7 @@ func SUID() string { // 15-begin 32*32*32*32*32*32==1073741824 rand := fastRand() //6 for ; idx > 9; idx-- { - buf[idx] = uuidStr[rand&uuidMask] + buf[idx] = suidStr[rand&suidMask] rand >>= 5 } now := nowms() //10 @@ -25,12 +27,41 @@ func SUID() string { // 10000-01-01 01:00:00 => 253402246800000 ms // 111001100111011111001110111001111110001010000000 48bit for idx = 9; idx >= 0; idx-- { - buf[idx] = uuidStr[now&uuidMask] + buf[idx] = suidStr[now&suidMask] now >>= 5 } return *(*string)(unsafe.Pointer(&buf)) } +// UUID +// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. +func UUID() string { + buf := make([]byte, 36) + for idx, cache, remain := 10, fastRand(), 8; idx < 36; { + if remain == 0 { + cache, remain = fastRand(), 8 + } + buf[idx] = uuidStr[cache&uuidMask] + cache >>= 4 + remain-- + idx++ + } + // 50bit + // 10000-01-01 01:00:00 => 253402246800000 ms + // 111001100111011111001110111001111110001010000000 48bit + now := nowms() >> 4 //10 + for idx := 9; idx >= 0; idx-- { + buf[idx] = uuidStr[now&uuidMask] + now >>= 4 + } + buf[8] = '-' + buf[13] = '-' + buf[14] = '4' + buf[18] = '-' + buf[23] = '-' + return *(*string)(unsafe.Pointer(&buf)) +} + //go:linkname fastRand runtime.fastrand func fastRand() uint32 diff --git a/uuid_test.go b/uuid_test.go index a4cbbce..005dfe1 100644 --- a/uuid_test.go +++ b/uuid_test.go @@ -12,3 +12,15 @@ func BenchmarkSUID(b *testing.B) { func TestSUID(t *testing.T) { t.Log(SUID()) } + +func BenchmarkUUID(b *testing.B) { + for i := 0; i < b.N; i++ { + UUID() + } +} +func TestUUID(t *testing.T) { + t.Log(UUID()) +} +func TestBits(t *testing.T) { + t.Logf("%b\n", 253402246800000/16) +} From d834f93d3656ad7ba523e5776fcc1cd8fddbb2c6 Mon Sep 17 00:00:00 2001 From: zxysilent Date: Thu, 16 Nov 2023 14:24:04 +0800 Subject: [PATCH 21/23] =?UTF-8?q?=E4=BC=98=E5=8C=96=E9=9A=8F=E6=9C=BA?= =?UTF-8?q?=E6=95=B0=EF=BC=8C=E5=92=8C=E6=9C=80=E5=B0=8F=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 2 +- rand.go | 92 +++++++++++++++++++++++++++++++++++++------------ rand_test.go | 96 +++++++++++++++++++++++++++------------------------- tmpl.go | 3 +- uuid.go | 77 ----------------------------------------- uuid_test.go | 26 -------------- 6 files changed, 122 insertions(+), 174 deletions(-) delete mode 100644 uuid.go delete mode 100644 uuid_test.go diff --git a/go.mod b/go.mod index ec8bcad..ea9e3de 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ module github.com/zxysilent/utils -go 1.15 +go 1.16 diff --git a/rand.go b/rand.go index 056259c..79ebc75 100644 --- a/rand.go +++ b/rand.go @@ -1,55 +1,103 @@ package utils import ( - "math/rand" - "time" "unsafe" ) +// go clean -testcache // Delete all cached test results + const ( + randStr = "23456789abcdefghijkmnpqrstuvwxyz" //32 + randMask = 1<<5 - 1 //11111 + _suid = 8 //LEQ 12 + + uuidStr = "0123456789abcdef" //16 + uuidMask = 1<<4 - 1 //1111 + digitStr = "0123456789" - randStr = "23456789abcdefghijkmnpqrstuvwxyz" //32 - randMask = 1<<5 - 1 //11111 - digitLen = len(digitStr) digitMask = 1<<4 - 1 ) -var rng = rand.NewSource(time.Now().UnixNano()) +// SUID SUID生成 +func SUID() string { + buf := make([]byte, _suid) + for idx, cache := 0, fastRand(); idx < _suid; { + buf[idx] = randStr[cache&randMask] + cache >>= 5 + idx++ + } + // return unsafe.String(&buf[0], len(buf)) + return *(*string)(unsafe.Pointer(&buf)) +} -// RandStr 返回指定长度的随机字符串 +// RUID 返回指定长度的随机字符串 // 包含数字 小写字母 -func RandStr(ln int) string { - /* chars 36个字符 - * rng.Int63() 每次产出64bit的随机数,每次我们使用6bit(2^6=64) 可以使用10次 - */ +func RUID(ln int) string { buf := make([]byte, ln) - for idx, cache, remain := 0, rng.Int63(), 10; idx < ln; { + for idx, cache, remain := 0, fastRand(), 12; idx < ln; { if remain == 0 { - cache, remain = rng.Int63(), 10 + cache, remain = fastRand(), 12 } buf[idx] = randStr[cache&randMask] - cache >>= 6 + cache >>= 5 remain-- idx++ } return *(*string)(unsafe.Pointer(&buf)) } -// RandDigitStr 返回指定长度的随机字符串 +// DUID 返回指定长度的随机字符串 // 只包含数字 -func RandDigitStr(ln int) string { - /* digits 10个字符 - * rng.Int63() 每次产出64bit的随机数,每次我们使用4bit(2^4=16) 可以使用16次 - */ +func DUID(ln int) string { buf := make([]byte, ln) - for idx, cache, remain := 0, rng.Int63(), 16; idx < ln; { + for idx, cache, remain := 0, fastRand(), 16; idx < ln; { if remain == 0 { - cache, remain = rng.Int63(), 16 + cache, remain = fastRand(), 16 } - buf[idx] = digitStr[int(cache&digitMask)%digitLen] + buf[idx] = digitStr[int(cache&digitMask)%10] cache >>= 4 remain-- idx++ } return *(*string)(unsafe.Pointer(&buf)) } + +// UUID +// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. +func UUID() string { + buf := make([]byte, 36) + for idx, cache, remain := 0, fastRand(), 16; idx < 32; { + if remain == 0 { + cache, remain = fastRand(), 16 + } + buf[idx] = uuidStr[cache&uuidMask] + cache >>= 4 + remain-- + idx++ + } + buf[32] = buf[8] + buf[33] = buf[13] + buf[34] = buf[18] + buf[35] = buf[23] + buf[8] = '-' + buf[13] = '-' + buf[14] = '4' + buf[18] = '-' + buf[23] = '-' + return *(*string)(unsafe.Pointer(&buf)) + // return unsafe.String(&buf[0], len(buf)) +} + +//go:linkname fastRand runtime.fastrand64 +func fastRand() uint64 + +//go:noescape +//go:linkname now time.now +func now() (sec int64, nsec int32, mono int64) + +// for runtime.walltime +func Now() int64 { + sec, nsec, _ := now() + return sec*1e3 + int64(nsec)/1e6 + // return time.Now().Unix() +} diff --git a/rand_test.go b/rand_test.go index 401f599..025a814 100644 --- a/rand_test.go +++ b/rand_test.go @@ -1,46 +1,50 @@ -package utils - -import ( - "testing" -) - -// 性能测试 -func BenchmarkRandStr8(b *testing.B) { - for i := 0; i < b.N; i++ { - RandStr(8) - } -} - -func BenchmarkRandStr10(b *testing.B) { - for i := 0; i < b.N; i++ { - RandStr(10) - } -} -func BenchmarkRandStr16(b *testing.B) { - for i := 0; i < b.N; i++ { - RandStr(16) - } -} -func BenchmarkRandDigitStr8(b *testing.B) { - for i := 0; i < b.N; i++ { - RandDigitStr(8) - } -} - -func BenchmarkRandDigitStr10(b *testing.B) { - for i := 0; i < b.N; i++ { - RandDigitStr(10) - } -} -func BenchmarkRandDigitStr16(b *testing.B) { - for i := 0; i < b.N; i++ { - RandDigitStr(16) - } -} - -func TestRandDigitStr(t *testing.T) { - RandDigitStr(20) -} -func TestRandStr(t *testing.T) { - RandStr(16) -} +package utils + +import ( + "testing" +) + +func BenchmarkUUID(b *testing.B) { + for i := 0; i < b.N; i++ { + UUID() + } +} +func TestUUID(t *testing.T) { + t.Log(UUID()) +} +func BenchmarkSUID(b *testing.B) { + for i := 0; i < b.N; i++ { + SUID() + } +} +func TestSUID(t *testing.T) { + t.Log(SUID()) +} + +func BenchmarkRUID16(b *testing.B) { + for i := 0; i < b.N; i++ { + RUID(16) + } +} + +func TestRUID16(t *testing.T) { + t.Log(RUID(16)) +} + +func BenchmarkRUID8(b *testing.B) { + for i := 0; i < b.N; i++ { + RUID(8) + } +} + +func TestRUID8(t *testing.T) { + t.Log(RUID(8)) +} +func BenchmarkDUID(b *testing.B) { + for i := 0; i < b.N; i++ { + DUID(8) + } +} +func TestDUID(t *testing.T) { + t.Log(DUID(8)) +} diff --git a/tmpl.go b/tmpl.go index 1581687..c93143b 100644 --- a/tmpl.go +++ b/tmpl.go @@ -2,7 +2,6 @@ package utils import ( "html/template" - "io/ioutil" "os" "path/filepath" "strings" @@ -25,7 +24,7 @@ func LoadTmpl(root string, funcs template.FuncMap) (*template.Template, error) { pln := len(path) // 是文件 并且是 .html 结尾 if !fi.IsDir() && pln > 4 && path[pln-5:] == ".html" { - buf, err := ioutil.ReadFile(path) + buf, err := os.ReadFile(path) if err != nil { return err } diff --git a/uuid.go b/uuid.go deleted file mode 100644 index fd6820d..0000000 --- a/uuid.go +++ /dev/null @@ -1,77 +0,0 @@ -package utils - -import ( - "unsafe" -) - -const ( - suidStr = "23456789abcdefghijkmnpqrstuvwxyz" //32 - suidMask = 1<<5 - 1 //11111 - uuidStr = "0123456789abcdef" //16 - uuidMask = 1<<4 - 1 //1111 -) - -// UUID UUID生成-16bit -// 10-times '-' 6-random string '-' 6-random string -func SUID() string { - buf := make([]byte, 16) - idx := 15 - // 15-begin 32*32*32*32*32*32==1073741824 - rand := fastRand() //6 - for ; idx > 9; idx-- { - buf[idx] = suidStr[rand&suidMask] - rand >>= 5 - } - now := nowms() //10 - // 50bit - // 10000-01-01 01:00:00 => 253402246800000 ms - // 111001100111011111001110111001111110001010000000 48bit - for idx = 9; idx >= 0; idx-- { - buf[idx] = suidStr[now&suidMask] - now >>= 5 - } - return *(*string)(unsafe.Pointer(&buf)) -} - -// UUID -// xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. -func UUID() string { - buf := make([]byte, 36) - for idx, cache, remain := 10, fastRand(), 8; idx < 36; { - if remain == 0 { - cache, remain = fastRand(), 8 - } - buf[idx] = uuidStr[cache&uuidMask] - cache >>= 4 - remain-- - idx++ - } - // 50bit - // 10000-01-01 01:00:00 => 253402246800000 ms - // 111001100111011111001110111001111110001010000000 48bit - now := nowms() >> 4 //10 - for idx := 9; idx >= 0; idx-- { - buf[idx] = uuidStr[now&uuidMask] - now >>= 4 - } - buf[8] = '-' - buf[13] = '-' - buf[14] = '4' - buf[18] = '-' - buf[23] = '-' - return *(*string)(unsafe.Pointer(&buf)) -} - -//go:linkname fastRand runtime.fastrand -func fastRand() uint32 - -//go:noescape -//go:linkname now time.now -func now() (sec int64, nsec int32, mono int64) - -// for runtime.walltime -func nowms() int64 { - sec, nsec, _ := now() - return sec*1e3 + int64(nsec)/1e6 - // return time.Now().UnixMilli() -} diff --git a/uuid_test.go b/uuid_test.go deleted file mode 100644 index 005dfe1..0000000 --- a/uuid_test.go +++ /dev/null @@ -1,26 +0,0 @@ -package utils - -import ( - "testing" -) - -func BenchmarkSUID(b *testing.B) { - for i := 0; i < b.N; i++ { - SUID() - } -} -func TestSUID(t *testing.T) { - t.Log(SUID()) -} - -func BenchmarkUUID(b *testing.B) { - for i := 0; i < b.N; i++ { - UUID() - } -} -func TestUUID(t *testing.T) { - t.Log(UUID()) -} -func TestBits(t *testing.T) { - t.Logf("%b\n", 253402246800000/16) -} From af7695a78d6a76f18620f17035e10bc7c9470f45 Mon Sep 17 00:00:00 2001 From: zxysilent Date: Mon, 20 Nov 2023 22:37:25 +0800 Subject: [PATCH 22/23] fix uuidv4 variant --- rand.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rand.go b/rand.go index 79ebc75..a317dc7 100644 --- a/rand.go +++ b/rand.go @@ -16,6 +16,7 @@ const ( digitStr = "0123456789" digitMask = 1<<4 - 1 + variant = "89ab" ) // SUID SUID生成 @@ -83,6 +84,7 @@ func UUID() string { buf[13] = '-' buf[14] = '4' buf[18] = '-' + buf[19] = variant[buf[19]%4] buf[23] = '-' return *(*string)(unsafe.Pointer(&buf)) // return unsafe.String(&buf[0], len(buf)) From b5a549e7639cea3b45a8f6ddc588a2e723830821 Mon Sep 17 00:00:00 2001 From: zxysilent Date: Thu, 18 Jul 2024 13:31:19 +0800 Subject: [PATCH 23/23] =?UTF-8?q?:art:=20=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index ea9e3de..6ea213d 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ module github.com/zxysilent/utils -go 1.16 +go 1.20