add iterate example for glist; improve variable name for ghttp.Server

This commit is contained in:
John
2019-12-18 19:37:07 +08:00
parent 5f2be10563
commit 18892fb66d
12 changed files with 225 additions and 72 deletions

View File

@ -10,10 +10,10 @@ func main() {
// Push
l.PushBack(1)
l.PushBack(2)
e0 := l.PushFront(0)
e := l.PushFront(0)
// Insert
l.InsertBefore(e0, -1)
l.InsertAfter(e0, "a")
l.InsertBefore(e, -1)
l.InsertAfter(e, "a")
fmt.Println(l)
// Pop
fmt.Println(l.PopFront())

View File

@ -1,10 +1,48 @@
package main
import (
"container/list"
"fmt"
"github.com/gogf/gf/os/gtime"
"github.com/gogf/gf/container/garray"
"github.com/gogf/gf/container/glist"
)
func main() {
fmt.Println(gtime.Timestamp())
// concurrent-safe list.
l := glist.NewFrom(garray.NewArrayRange(1, 10, 1).Slice(), true)
// iterate reading from head.
l.RLockFunc(func(list *list.List) {
length := list.Len()
if length > 0 {
for i, e := 0, list.Front(); i < length; i, e = i+1, e.Next() {
fmt.Print(e.Value)
}
}
})
fmt.Println()
// iterate reading from tail.
l.RLockFunc(func(list *list.List) {
length := list.Len()
if length > 0 {
for i, e := 0, list.Back(); i < length; i, e = i+1, e.Prev() {
fmt.Print(e.Value)
}
}
})
fmt.Println()
// iterate writing from head.
l.LockFunc(func(list *list.List) {
length := list.Len()
if length > 0 {
for i, e := 0, list.Front(); i < length; i, e = i+1, e.Next() {
if e.Value == 6 {
e.Value = "M"
break
}
}
}
})
fmt.Println(l)
}

View File

@ -9,6 +9,7 @@ package garray
import (
"bytes"
"encoding/json"
"fmt"
"github.com/gogf/gf/text/gstr"
"math"
"sort"
@ -45,6 +46,21 @@ func NewArraySize(size int, cap int, safe ...bool) *Array {
}
}
// NewArrayRange creates and returns a array by a range from <start> to <end>
// with step value <step>.
func NewArrayRange(start, end, step int, safe ...bool) *Array {
if step == 0 {
panic(fmt.Sprintf(`invalid step value: %d`, step))
}
slice := make([]interface{}, (end-start+1)/step)
index := 0
for i := start; i <= end; i += step {
slice[index] = i
index++
}
return NewArrayFrom(slice, safe...)
}
// See NewArrayFrom.
func NewFrom(array []interface{}, safe ...bool) *Array {
return NewArrayFrom(array, safe...)

View File

@ -9,6 +9,7 @@ package garray
import (
"bytes"
"encoding/json"
"fmt"
"math"
"sort"
@ -39,6 +40,21 @@ func NewIntArraySize(size int, cap int, safe ...bool) *IntArray {
}
}
// NewIntArrayRange creates and returns a array by a range from <start> to <end>
// with step value <step>.
func NewIntArrayRange(start, end, step int, safe ...bool) *IntArray {
if step == 0 {
panic(fmt.Sprintf(`invalid step value: %d`, step))
}
slice := make([]int, (end-start+1)/step)
index := 0
for i := start; i <= end; i += step {
slice[index] = i
index++
}
return NewIntArrayFrom(slice, safe...)
}
// NewIntArrayFrom creates and returns an array with given slice <array>.
// The parameter <safe> is used to specify whether using array in concurrent-safety,
// which is false in default.

View File

@ -9,6 +9,7 @@ package garray
import (
"bytes"
"encoding/json"
"fmt"
"github.com/gogf/gf/text/gstr"
"github.com/gogf/gf/util/gutil"
"math"
@ -50,6 +51,21 @@ func NewSortedArraySize(cap int, comparator func(a, b interface{}) int, safe ...
}
}
// NewSortedArrayRange creates and returns a array by a range from <start> to <end>
// with step value <step>.
func NewSortedArrayRange(start, end, step int, comparator func(a, b interface{}) int, safe ...bool) *SortedArray {
if step == 0 {
panic(fmt.Sprintf(`invalid step value: %d`, step))
}
slice := make([]interface{}, (end-start+1)/step)
index := 0
for i := start; i <= end; i += step {
slice[index] = i
index++
}
return NewSortedArrayFrom(slice, comparator, safe...)
}
// NewSortedArrayFrom creates and returns an sorted array with given slice <array>.
// The parameter <safe> is used to specify whether using array in concurrent-safety,
// which is false in default.

View File

@ -9,6 +9,7 @@ package garray
import (
"bytes"
"encoding/json"
"fmt"
"math"
"sort"
@ -53,6 +54,21 @@ func NewSortedIntArraySize(cap int, safe ...bool) *SortedIntArray {
}
}
// NewSortedIntArrayRange creates and returns a array by a range from <start> to <end>
// with step value <step>.
func NewSortedIntArrayRange(start, end, step int, safe ...bool) *SortedIntArray {
if step == 0 {
panic(fmt.Sprintf(`invalid step value: %d`, step))
}
slice := make([]int, (end-start+1)/step)
index := 0
for i := start; i <= end; i += step {
slice[index] = i
index++
}
return NewSortedIntArrayFrom(slice, safe...)
}
// NewIntArrayFrom creates and returns an sorted array with given slice <array>.
// The parameter <safe> is used to specify whether using array in concurrent-safety,
// which is false in default.

View File

@ -7,12 +7,14 @@
package glist_test
import (
"container/list"
"fmt"
"github.com/gogf/gf/container/garray"
"github.com/gogf/gf/container/glist"
)
func Example_basic() {
func Example_Basic() {
n := 10
l := glist.New()
for i := 0; i < n; i++ {
@ -35,3 +37,48 @@ func Example_basic() {
//0123456789
//0
}
func Example_Iterate() {
// concurrent-safe list.
l := glist.NewFrom(garray.NewArrayRange(1, 10, 1).Slice(), true)
// iterate reading from head.
l.RLockFunc(func(list *list.List) {
length := list.Len()
if length > 0 {
for i, e := 0, list.Front(); i < length; i, e = i+1, e.Next() {
fmt.Print(e.Value)
}
}
})
fmt.Println()
// iterate reading from tail.
l.RLockFunc(func(list *list.List) {
length := list.Len()
if length > 0 {
for i, e := 0, list.Back(); i < length; i, e = i+1, e.Prev() {
fmt.Print(e.Value)
}
}
})
fmt.Println()
// iterate writing from head.
l.LockFunc(func(list *list.List) {
length := list.Len()
if length > 0 {
for i, e := 0, list.Front(); i < length; i, e = i+1, e.Next() {
if e.Value == 6 {
e.Value = "M"
break
}
}
}
})
fmt.Println(l)
//output:
//12345678910
//10987654321
//[1,2,3,4,5,"M",7,8,9,10]
}

View File

@ -73,6 +73,7 @@ type ServerConfig struct {
PProfPattern string // PProf: PProf service pattern for router.
FormParsingMemory int64 // Other: Max memory in bytes which can be used for parsing multimedia form.
NameToUriType int // Other: Type for converting struct method name to URI when registering routes.
RouteOverWrite bool // Other: Allow overwrite the route if duplicated.
DumpRouterMap bool // Other: Whether automatically dump router map when server starts.
Graceful bool // Other: Enable graceful reload feature for all servers of the process.
}

View File

@ -15,3 +15,7 @@ func (s *Server) SetRewriteMap(rewrites map[string]string) {
s.config.Rewrites[k] = v
}
}
func (s *Server) SetRouteOverWrite(enabled bool) {
s.config.RouteOverWrite = enabled
}

View File

@ -72,11 +72,13 @@ func (s *Server) setHandler(pattern string, handler *handlerItem) {
}
// 注册地址记录及重复注册判断
regKey := s.handlerKey(handler.hookName, method, uri, domain)
switch handler.itemType {
case gHANDLER_TYPE_HANDLER, gHANDLER_TYPE_OBJECT, gHANDLER_TYPE_CONTROLLER:
if item, ok := s.routesMap[regKey]; ok {
glog.Fatalf(`duplicated route registry "%s", already registered at %s`, pattern, item[0].file)
return
if !s.config.RouteOverWrite {
switch handler.itemType {
case gHANDLER_TYPE_HANDLER, gHANDLER_TYPE_OBJECT, gHANDLER_TYPE_CONTROLLER:
if item, ok := s.routesMap[regKey]; ok {
glog.Fatalf(`duplicated route registry "%s", already registered at %s`, pattern, item[0].file)
return
}
}
}
// 注册的路由信息对象
@ -263,8 +265,8 @@ func (s *Server) compareRouterPriority(newItem *handlerItem, oldItem *handlerIte
return true
}
// 最后新的规则比旧的规则优先级
return false
// 最后新的规则比旧的规则优先级高(路由覆盖)
return true
}
// 将pattern不带method和domain解析成正则表达式匹配以及对应的query字符串

View File

@ -53,7 +53,7 @@ func (s *Server) doBindController(pattern string, controller Controller, method
// 当pattern中的method为all时去掉该method以便于后续方法判断
domain, method, path, err := s.parsePattern(pattern)
if err != nil {
glog.Error(err)
glog.Fatal(err)
return
}
if strings.EqualFold(method, gDEFAULT_METHOD) {
@ -63,15 +63,15 @@ func (s *Server) doBindController(pattern string, controller Controller, method
m := make(handlerMap)
v := reflect.ValueOf(controller)
t := v.Type()
sname := t.Elem().Name()
pkgPath := t.Elem().PkgPath()
pkgName := gfile.Basename(pkgPath)
structName := t.Elem().Name()
for i := 0; i < v.NumMethod(); i++ {
mname := t.Method(i).Name
if methodMap != nil && !methodMap[mname] {
methodName := t.Method(i).Name
if methodMap != nil && !methodMap[methodName] {
continue
}
if mname == "Init" || mname == "Shut" || mname == "Exit" {
if methodName == "Init" || methodName == "Shut" || methodName == "Exit" {
continue
}
ctlName := gstr.Replace(t.String(), fmt.Sprintf(`%s.`, pkgName), "")
@ -82,20 +82,20 @@ func (s *Server) doBindController(pattern string, controller Controller, method
if len(methodMap) > 0 {
// 指定的方法名称注册,那么需要使用错误提示
glog.Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func()" is required for controller registry`,
pkgPath, ctlName, mname, v.Method(i).Type().String())
pkgPath, ctlName, methodName, v.Method(i).Type().String())
} else {
// 否则只是Debug提示
glog.Debugf(`ignore route method: %s.%s.%s defined as "%s", no match "func()"`,
pkgPath, ctlName, mname, v.Method(i).Type().String())
pkgPath, ctlName, methodName, v.Method(i).Type().String())
}
continue
}
key := s.mergeBuildInNameToPattern(pattern, sname, mname, true)
key := s.mergeBuildInNameToPattern(pattern, structName, methodName, true)
m[key] = &handlerItem{
itemName: fmt.Sprintf(`%s.%s.%s`, pkgPath, ctlName, mname),
itemName: fmt.Sprintf(`%s.%s.%s`, pkgPath, ctlName, methodName),
itemType: gHANDLER_TYPE_CONTROLLER,
ctrlInfo: &handlerController{
name: mname,
name: methodName,
reflect: v.Elem().Type(),
},
middleware: middleware,
@ -104,17 +104,17 @@ func (s *Server) doBindController(pattern string, controller Controller, method
// 例如: pattern为/user, 那么会同时注册/user及/user/index
// 这里处理新增/user路由绑定。
// 注意当pattern带有内置变量时不会自动加该路由。
if strings.EqualFold(mname, "Index") && !gregex.IsMatchString(`\{\.\w+\}`, pattern) {
if strings.EqualFold(methodName, "Index") && !gregex.IsMatchString(`\{\.\w+\}`, pattern) {
p := gstr.PosRI(key, "/index")
k := key[0:p] + key[p+6:]
if len(k) == 0 || k[0] == '@' {
k = "/" + k
}
m[k] = &handlerItem{
itemName: fmt.Sprintf(`%s.%s.%s`, pkgPath, ctlName, mname),
itemName: fmt.Sprintf(`%s.%s.%s`, pkgPath, ctlName, methodName),
itemType: gHANDLER_TYPE_CONTROLLER,
ctrlInfo: &handlerController{
name: mname,
name: methodName,
reflect: v.Elem().Type(),
},
middleware: middleware,
@ -128,11 +128,11 @@ func (s *Server) doBindControllerMethod(pattern string, controller Controller, m
m := make(handlerMap)
v := reflect.ValueOf(controller)
t := v.Type()
sname := t.Elem().Name()
mname := strings.TrimSpace(method)
fval := v.MethodByName(mname)
if !fval.IsValid() {
glog.Error("invalid method name:" + mname)
structName := t.Elem().Name()
methodName := strings.TrimSpace(method)
methodValue := v.MethodByName(methodName)
if !methodValue.IsValid() {
glog.Fatal("invalid method name: " + methodName)
return
}
pkgPath := t.Elem().PkgPath()
@ -141,17 +141,17 @@ func (s *Server) doBindControllerMethod(pattern string, controller Controller, m
if ctlName[0] == '*' {
ctlName = fmt.Sprintf(`(%s)`, ctlName)
}
if _, ok := fval.Interface().(func()); !ok {
if _, ok := methodValue.Interface().(func()); !ok {
glog.Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func()" is required for controller registry`,
pkgPath, ctlName, mname, fval.Type().String())
pkgPath, ctlName, methodName, methodValue.Type().String())
return
}
key := s.mergeBuildInNameToPattern(pattern, sname, mname, false)
key := s.mergeBuildInNameToPattern(pattern, structName, methodName, false)
m[key] = &handlerItem{
itemName: fmt.Sprintf(`%s.%s.%s`, pkgPath, ctlName, mname),
itemName: fmt.Sprintf(`%s.%s.%s`, pkgPath, ctlName, methodName),
itemType: gHANDLER_TYPE_CONTROLLER,
ctrlInfo: &handlerController{
name: mname,
name: methodName,
reflect: v.Elem().Type(),
},
middleware: middleware,
@ -164,13 +164,12 @@ func (s *Server) doBindControllerRest(pattern string, controller Controller, mid
m := make(handlerMap)
v := reflect.ValueOf(controller)
t := v.Type()
sname := t.Elem().Name()
pkgPath := t.Elem().PkgPath()
structName := t.Elem().Name()
// 如果存在与HttpMethod对应名字的方法那么绑定这些方法
for i := 0; i < v.NumMethod(); i++ {
mname := t.Method(i).Name
method := strings.ToUpper(mname)
if _, ok := methodsMap[method]; !ok {
methodName := t.Method(i).Name
if _, ok := methodsMap[strings.ToUpper(methodName)]; !ok {
continue
}
pkgName := gfile.Basename(pkgPath)
@ -180,15 +179,15 @@ func (s *Server) doBindControllerRest(pattern string, controller Controller, mid
}
if _, ok := v.Method(i).Interface().(func()); !ok {
glog.Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func()" is required for controller registry`,
pkgPath, ctlName, mname, v.Method(i).Type().String())
pkgPath, ctlName, methodName, v.Method(i).Type().String())
return
}
key := s.mergeBuildInNameToPattern(mname+":"+pattern, sname, mname, false)
key := s.mergeBuildInNameToPattern(methodName+":"+pattern, structName, methodName, false)
m[key] = &handlerItem{
itemName: fmt.Sprintf(`%s.%s.%s`, pkgPath, ctlName, mname),
itemName: fmt.Sprintf(`%s.%s.%s`, pkgPath, ctlName, methodName),
itemType: gHANDLER_TYPE_CONTROLLER,
ctrlInfo: &handlerController{
name: mname,
name: methodName,
reflect: v.Elem().Type(),
},
middleware: middleware,

View File

@ -51,19 +51,18 @@ func (s *Server) doBindObject(pattern string, object interface{}, method string,
// 当pattern中的method为all时去掉该method以便于后续方法判断
domain, method, path, err := s.parsePattern(pattern)
if err != nil {
glog.Error(err)
glog.Fatal(err)
return
}
if strings.EqualFold(method, gDEFAULT_METHOD) {
pattern = s.serveHandlerKey("", path, domain)
}
m := make(handlerMap)
v := reflect.ValueOf(object)
t := v.Type()
sname := t.Elem().Name()
initFunc := (func(*Request))(nil)
shutFunc := (func(*Request))(nil)
structName := t.Elem().Name()
if v.MethodByName("Init").IsValid() {
initFunc = v.MethodByName("Init").Interface().(func(*Request))
}
@ -73,11 +72,11 @@ func (s *Server) doBindObject(pattern string, object interface{}, method string,
pkgPath := t.Elem().PkgPath()
pkgName := gfile.Basename(pkgPath)
for i := 0; i < v.NumMethod(); i++ {
mname := t.Method(i).Name
if methodMap != nil && !methodMap[mname] {
methodName := t.Method(i).Name
if methodMap != nil && !methodMap[methodName] {
continue
}
if mname == "Init" || mname == "Shut" {
if methodName == "Init" || methodName == "Shut" {
continue
}
objName := gstr.Replace(t.String(), fmt.Sprintf(`%s.`, pkgName), "")
@ -89,17 +88,17 @@ func (s *Server) doBindObject(pattern string, object interface{}, method string,
if len(methodMap) > 0 {
// 指定的方法名称注册,那么需要使用错误提示
glog.Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" is required for object registry`,
pkgPath, objName, mname, v.Method(i).Type().String())
pkgPath, objName, methodName, v.Method(i).Type().String())
} else {
// 否则只是Debug提示
glog.Debugf(`ignore route method: %s.%s.%s defined as "%s", no match "func(*ghttp.Request)"`,
pkgPath, objName, mname, v.Method(i).Type().String())
pkgPath, objName, methodName, v.Method(i).Type().String())
}
continue
}
key := s.mergeBuildInNameToPattern(pattern, sname, mname, true)
key := s.mergeBuildInNameToPattern(pattern, structName, methodName, true)
m[key] = &handlerItem{
itemName: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, mname),
itemName: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, methodName),
itemType: gHANDLER_TYPE_OBJECT,
itemFunc: itemFunc,
initFunc: initFunc,
@ -108,14 +107,14 @@ func (s *Server) doBindObject(pattern string, object interface{}, method string,
}
// 如果方法中带有Index方法那么额外自动增加一个路由规则匹配主URI。
// 注意当pattern带有内置变量时不会自动加该路由。
if strings.EqualFold(mname, "Index") && !gregex.IsMatchString(`\{\.\w+\}`, pattern) {
if strings.EqualFold(methodName, "Index") && !gregex.IsMatchString(`\{\.\w+\}`, pattern) {
p := gstr.PosRI(key, "/index")
k := key[0:p] + key[p+6:]
if len(k) == 0 || k[0] == '@' {
k = "/" + k
}
m[k] = &handlerItem{
itemName: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, mname),
itemName: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, methodName),
itemType: gHANDLER_TYPE_OBJECT,
itemFunc: itemFunc,
initFunc: initFunc,
@ -133,11 +132,11 @@ func (s *Server) doBindObjectMethod(pattern string, object interface{}, method s
m := make(handlerMap)
v := reflect.ValueOf(object)
t := v.Type()
sname := t.Elem().Name()
mname := strings.TrimSpace(method)
fval := v.MethodByName(mname)
if !fval.IsValid() {
glog.Error("invalid method name:" + mname)
structName := t.Elem().Name()
methodName := strings.TrimSpace(method)
methodValue := v.MethodByName(methodName)
if !methodValue.IsValid() {
glog.Fatal("invalid method name: " + methodName)
return
}
initFunc := (func(*Request))(nil)
@ -154,15 +153,15 @@ func (s *Server) doBindObjectMethod(pattern string, object interface{}, method s
if objName[0] == '*' {
objName = fmt.Sprintf(`(%s)`, objName)
}
itemFunc, ok := fval.Interface().(func(*Request))
itemFunc, ok := methodValue.Interface().(func(*Request))
if !ok {
glog.Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" is required for object registry`,
pkgPath, objName, mname, fval.Type().String())
pkgPath, objName, methodName, methodValue.Type().String())
return
}
key := s.mergeBuildInNameToPattern(pattern, sname, mname, false)
key := s.mergeBuildInNameToPattern(pattern, structName, methodName, false)
m[key] = &handlerItem{
itemName: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, mname),
itemName: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, methodName),
itemType: gHANDLER_TYPE_OBJECT,
itemFunc: itemFunc,
initFunc: initFunc,
@ -177,9 +176,9 @@ func (s *Server) doBindObjectRest(pattern string, object interface{}, middleware
m := make(handlerMap)
v := reflect.ValueOf(object)
t := v.Type()
sname := t.Elem().Name()
initFunc := (func(*Request))(nil)
shutFunc := (func(*Request))(nil)
structName := t.Elem().Name()
if v.MethodByName("Init").IsValid() {
initFunc = v.MethodByName("Init").Interface().(func(*Request))
}
@ -188,9 +187,8 @@ func (s *Server) doBindObjectRest(pattern string, object interface{}, middleware
}
pkgPath := t.Elem().PkgPath()
for i := 0; i < v.NumMethod(); i++ {
mname := t.Method(i).Name
method := strings.ToUpper(mname)
if _, ok := methodsMap[method]; !ok {
methodName := t.Method(i).Name
if _, ok := methodsMap[strings.ToUpper(methodName)]; !ok {
continue
}
pkgName := gfile.Basename(pkgPath)
@ -201,12 +199,12 @@ func (s *Server) doBindObjectRest(pattern string, object interface{}, middleware
itemFunc, ok := v.Method(i).Interface().(func(*Request))
if !ok {
glog.Errorf(`invalid route method: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" is required for object registry`,
pkgPath, objName, mname, v.Method(i).Type().String())
pkgPath, objName, methodName, v.Method(i).Type().String())
continue
}
key := s.mergeBuildInNameToPattern(mname+":"+pattern, sname, mname, false)
key := s.mergeBuildInNameToPattern(methodName+":"+pattern, structName, methodName, false)
m[key] = &handlerItem{
itemName: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, mname),
itemName: fmt.Sprintf(`%s.%s.%s`, pkgPath, objName, methodName),
itemType: gHANDLER_TYPE_OBJECT,
itemFunc: itemFunc,
initFunc: initFunc,