diff --git a/.example/container/glist/basic.go b/.example/container/glist/basic.go new file mode 100644 index 000000000..7eafce3a8 --- /dev/null +++ b/.example/container/glist/basic.go @@ -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) +} diff --git a/.example/container/glist/json_marshal.go b/.example/container/glist/json_marshal.go new file mode 100644 index 000000000..f6daafa06 --- /dev/null +++ b/.example/container/glist/json_marshal.go @@ -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)) +} diff --git a/.example/container/glist/json_unmarshal.go b/.example/container/glist/json_unmarshal.go new file mode 100644 index 000000000..313dfe570 --- /dev/null +++ b/.example/container/glist/json_unmarshal.go @@ -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) +} diff --git a/container/glist/glist.go b/container/glist/glist.go index 9e24d85c1..082c6db73 100644 --- a/container/glist/glist.go +++ b/container/glist/glist.go @@ -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 . +// The parameter 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 with value at the front of list and returns . 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 with value immediately after

and returns . // If

is not an element of , the list is not modified. // The

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 with value immediately before

and returns . // If

is not an element of , the list is not modified. // The

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,6 +390,34 @@ func (l *List) IteratorDesc(f func(e *Element) bool) { l.mu.RUnlock() } +// Join joins list elements with a string . +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()) diff --git a/container/glist/glist_z_unit_test.go b/container/glist/glist_z_unit_test.go index 5ffbabb45..c1fe8b56d 100644 --- a/container/glist/glist_z_unit_test.go +++ b/container/glist/glist_z_unit_test.go @@ -9,7 +9,6 @@ package glist import ( "container/list" "encoding/json" - "github.com/gogf/gf/test/gtest" "github.com/gogf/gf/util/gconv" @@ -121,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) @@ -265,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) } @@ -348,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}) } @@ -358,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}) } @@ -585,6 +584,21 @@ func TestList_Iterator(t *testing.T) { 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() { diff --git a/internal/utilstr/utilstr.go b/internal/utilstr/utilstr.go index 0809d16fe..8c80c08b6 100644 --- a/internal/utilstr/utilstr.go +++ b/internal/utilstr/utilstr.go @@ -33,6 +33,9 @@ func IsNumeric(s string) bool { return false } for i := 0; i < len(s); i++ { + if s[i] == '-' && i == 0 { + continue + } if s[i] == '.' { if i > 0 && i < len(s)-1 { continue diff --git a/net/ghttp/ghttp_server_router.go b/net/ghttp/ghttp_server_router.go index 023c5566a..bbc95c0cc 100644 --- a/net/ghttp/ghttp_server_router.go +++ b/net/ghttp/ghttp_server_router.go @@ -143,7 +143,7 @@ func (s *Server) setHandler(pattern string, handler *handlerItem) { item = e.Value.(*handlerItem) // 判断优先级,决定当前注册项的插入顺序 if s.compareRouterPriority(handler, item) { - l.InsertBefore(handler, e) + l.InsertBefore(e, handler) pushed = true goto end } diff --git a/net/ghttp/ghttp_server_router_serve.go b/net/ghttp/ghttp_server_router_serve.go index 6b80dec0b..2b9eb318a 100644 --- a/net/ghttp/ghttp_server_router_serve.go +++ b/net/ghttp/ghttp_server_router_serve.go @@ -140,7 +140,7 @@ func (s *Server) searchHandlers(method, path, domain string) (parsedItems []*han if lastMiddlewareElem == nil { lastMiddlewareElem = parsedItemList.PushFront(parsedItem) } else { - lastMiddlewareElem = parsedItemList.InsertAfter(parsedItem, lastMiddlewareElem) + lastMiddlewareElem = parsedItemList.InsertAfter(lastMiddlewareElem, parsedItem) } // 钩子函数存在性判断