diff --git a/README_ZH.MD b/README_ZH.MD index 6a59bbc54..dffab1c07 100644 --- a/README_ZH.MD +++ b/README_ZH.MD @@ -11,7 +11,7 @@ -`GF(Go Frame)`是一款模块化、松耦合、生产级Go应用开发框架。提供了常用的核心开发组件,如:缓存、日志、文件、时间、队列、数组、集合、字符串、定时器、命令行、文件锁、内存锁、对象池、连接池、数据校验、数据编码、文件监控、定时任务、数据库ORM、TCP/UDP组件、进程管理/通信、 +`GF(Go Frame)`是一款模块化、高性能、生产级Go应用开发框架。提供了常用的核心开发组件,如:缓存、日志、文件、时间、队列、数组、集合、字符串、定时器、命令行、文件锁、内存锁、对象池、连接池、数据校验、数据编码、文件监控、定时任务、数据库ORM、TCP/UDP组件、进程管理/通信、 并发安全容器等等。并提供了Web服务开发的系列核心组件,如:Router、Cookie、Session、服务注册、配置管理、模板引擎等等,支持热重启、热更新、多域名、多端口、多服务、HTTPS、Rewrite等特性。 diff --git a/g/container/glist/glist.go b/g/container/glist/glist.go index cef9b7c01..fa0361702 100644 --- a/g/container/glist/glist.go +++ b/g/container/glist/glist.go @@ -209,7 +209,7 @@ func (l *List) Len() (length int) { return } -// Alias of Len. +// Size is alias of Len. func (l *List) Size() int { return l.Len() } diff --git a/g/container/gqueue/gqueue.go b/g/container/gqueue/gqueue.go index 9ec7b12c7..eb4b2a340 100644 --- a/g/container/gqueue/gqueue.go +++ b/g/container/gqueue/gqueue.go @@ -110,9 +110,16 @@ func (q *Queue) Close() { close(q.closed) } -// Size returns the length of the queue. -func (q *Queue) Size() int { - return len(q.C) + q.list.Len() +// Len returns the length of the queue. +func (q *Queue) Len() (length int) { + if q.list != nil { + length += q.list.Len() + } + length += len(q.C) + return } - +// Size is alias of Len. +func (q *Queue) Size() int { + return q.Len() +} diff --git a/g/container/gtree/gtree_avltree.go b/g/container/gtree/gtree_avltree.go index 7c67bc25f..23ba935f1 100644 --- a/g/container/gtree/gtree_avltree.go +++ b/g/container/gtree/gtree_avltree.go @@ -29,7 +29,7 @@ type AVLTreeNode struct { b int8 } -// NewAVLTree instantiates an AVL tree with the custom comparator. +// NewAVLTree instantiates an AVL tree with the custom key comparator. // The parameter used to specify whether using tree in un-concurrent-safety, // which is false in default. func NewAVLTree(comparator func(v1, v2 interface{}) int, unsafe...bool) *AVLTree { @@ -39,7 +39,7 @@ func NewAVLTree(comparator func(v1, v2 interface{}) int, unsafe...bool) *AVLTree } } -// NewAVLTreeFrom instantiates an AVL tree with the custom comparator and data map. +// NewAVLTreeFrom instantiates an AVL tree with the custom key comparator and data map. // The parameter used to specify whether using tree in un-concurrent-safety, // which is false in default. func NewAVLTreeFrom(comparator func(v1, v2 interface{}) int, data map[interface{}]interface{}, unsafe...bool) *AVLTree { @@ -222,7 +222,7 @@ func (tree *AVLTree) Contains(key interface{}) bool { return ok } -// Remove remove the node from the tree by key. +// Remove removes the node from the tree by key. // Key should adhere to the comparator's type assertion, otherwise method panics. func (tree *AVLTree) Remove(key interface{}) (value interface{}) { tree.mu.Lock() @@ -306,7 +306,7 @@ func (tree *AVLTree) Right() *AVLTreeNode { return node } -// Floor Finds floor node of the input key, return the floor node or nil if no ceiling is found. +// Floor Finds floor node of the input key, return the floor node or nil if no floor node is found. // Second return parameter is true if floor was found, otherwise false. // // Floor node is defined as the largest node that is smaller than or equal to the given node. @@ -317,16 +317,15 @@ func (tree *AVLTree) Right() *AVLTreeNode { func (tree *AVLTree) Floor(key interface{}) (floor *AVLTreeNode, found bool) { tree.mu.RLock() defer tree.mu.RUnlock() - found = false n := tree.root for n != nil { c := tree.comparator(key, n.Key) switch { - case c == 0: return n, true - case c < 0: n = n.children[0] - case c > 0: - floor, found = n, true - n = n.children[1] + case c == 0: return n, true + case c < 0: n = n.children[0] + case c > 0: + floor, found = n, true + n = n.children[1] } } if found { @@ -335,7 +334,7 @@ func (tree *AVLTree) Floor(key interface{}) (floor *AVLTreeNode, found bool) { return nil, false } -// Ceiling finds ceiling node of the input key, return the ceiling node or nil if no ceiling is found. +// Ceiling finds ceiling node of the input key, return the ceiling node or nil if no ceiling node is found. // Second return parameter is true if ceiling was found, otherwise false. // // Ceiling node is defined as the smallest node that is larger than or equal to the given node. @@ -343,10 +342,9 @@ func (tree *AVLTree) Floor(key interface{}) (floor *AVLTreeNode, found bool) { // all nodes in the tree is smaller than the given node. // // Key should adhere to the comparator's type assertion, otherwise method panics. -func (tree *AVLTree) Ceiling(key interface{}) (floor *AVLTreeNode, found bool) { +func (tree *AVLTree) Ceiling(key interface{}) (ceiling *AVLTreeNode, found bool) { tree.mu.RLock() defer tree.mu.RUnlock() - found = false n := tree.root for n != nil { c := tree.comparator(key, n.Key) @@ -354,7 +352,7 @@ func (tree *AVLTree) Ceiling(key interface{}) (floor *AVLTreeNode, found bool) { case c == 0: return n, true case c > 0: n = n.children[1] case c < 0: - floor, found = n, true + ceiling, found = n, true n = n.children[0] } } @@ -514,7 +512,7 @@ func (tree *AVLTree) remove(key interface{}, qp **AVLTreeNode) (value interface{ if fix { return value, removeFix(int8(-c), qp) } - return nil, false + return value, false } func removeMin(qp **AVLTreeNode, minKey *interface{}, minVal *interface{}) bool { diff --git a/g/container/gtree/gtree_btree.go b/g/container/gtree/gtree_btree.go index de4546cca..34f375257 100644 --- a/g/container/gtree/gtree_btree.go +++ b/g/container/gtree/gtree_btree.go @@ -503,9 +503,9 @@ func (tree *BTree) isLeaf(node *BTreeNode) bool { return len(node.Children) == 0 } -func (tree *BTree) isFull(node *BTreeNode) bool { - return len(node.Entries) == tree.maxEntries() -} +//func (tree *BTree) isFull(node *BTreeNode) bool { +// return len(node.Entries) == tree.maxEntries() +//} func (tree *BTree) shouldSplit(node *BTreeNode) bool { return len(node.Entries) > tree.maxEntries() diff --git a/g/container/gtree/gtree_redblacktree.go b/g/container/gtree/gtree_redblacktree.go index 064b1ac63..cc4cdd82a 100644 --- a/g/container/gtree/gtree_redblacktree.go +++ b/g/container/gtree/gtree_redblacktree.go @@ -36,7 +36,7 @@ type RedBlackTreeNode struct { parent *RedBlackTreeNode } -// NewRedBlackTree instantiates a red-black tree with the custom comparator. +// NewRedBlackTree instantiates a red-black tree with the custom key comparator. // The parameter used to specify whether using tree in un-concurrent-safety, // which is false in default. func NewRedBlackTree(comparator func(v1, v2 interface{}) int, unsafe...bool) *RedBlackTree { @@ -46,7 +46,7 @@ func NewRedBlackTree(comparator func(v1, v2 interface{}) int, unsafe...bool) *Re } } -// NewRedBlackTreeFrom instantiates a red-black tree with the custom comparator and map. +// NewRedBlackTreeFrom instantiates a red-black tree with the custom key comparator and map. // The parameter used to specify whether using tree in un-concurrent-safety, // which is false in default. func NewRedBlackTreeFrom(comparator func(v1, v2 interface{}) int, data map[interface{}]interface{}, unsafe...bool) *RedBlackTree { @@ -393,60 +393,56 @@ func (tree *RedBlackTree) rightNode() *RedBlackTreeNode { return p } -// Floor Finds floor node of the input , return the floor node or nil if no floor is found. +// Floor Finds floor node of the input key, return the floor node or nil if no floor node is found. +// Second return parameter is true if floor was found, otherwise false. // // Floor node is defined as the largest node that its key is smaller than or equal to the given . // A floor node may not be found, either because the tree is empty, or because // all nodes in the tree are larger than the given node. -func (tree *RedBlackTree) Floor(key interface{}) (floor *RedBlackTreeNode) { +func (tree *RedBlackTree) Floor(key interface{}) (floor *RedBlackTreeNode, found bool) { tree.mu.RLock() defer tree.mu.RUnlock() - found := false - node := tree.root - for node != nil { - compare := tree.comparator(key, node.Key) + n := tree.root + for n != nil { + compare := tree.comparator(key, n.Key) switch { - case compare == 0: - return node - case compare < 0: - node = node.left - case compare > 0: - floor, found = node, true - node = node.right + case compare == 0: return n, true + case compare < 0: n = n.left + case compare > 0: + floor, found = n, true + n = n.right } } if found { - return floor + return } - return nil + return nil, false } -// Ceiling finds ceiling node of the input , return the ceiling node or nil if no ceiling is found. +// Ceiling finds ceiling node of the input key, return the ceiling node or nil if no ceiling node is found. +// Second return parameter is true if ceiling was found, otherwise false. // // Ceiling node is defined as the smallest node that its key is larger than or equal to the given . // A ceiling node may not be found, either because the tree is empty, or because // all nodes in the tree are smaller than the given node. -func (tree *RedBlackTree) Ceiling(key interface{}) (ceiling *RedBlackTreeNode) { +func (tree *RedBlackTree) Ceiling(key interface{}) (ceiling *RedBlackTreeNode, found bool) { tree.mu.RLock() defer tree.mu.RUnlock() - found := false - node := tree.root - for node != nil { - compare := tree.comparator(key, node.Key) + n := tree.root + for n != nil { + compare := tree.comparator(key, n.Key) switch { - case compare == 0: - return node - case compare < 0: - ceiling, found = node, true - node = node.left - case compare > 0: - node = node.right + case compare == 0: return n, true + case compare > 0: n = n.right + case compare < 0: + ceiling, found = n, true + n = n.left } } if found { - return ceiling + return } - return nil + return nil, false } // Iterator is alias of IteratorAsc. diff --git a/g/container/gtree/gtree_z_avl_tree_test.go b/g/container/gtree/gtree_z_avl_tree_test.go index f20ed2601..8cf58032f 100644 --- a/g/container/gtree/gtree_z_avl_tree_test.go +++ b/g/container/gtree/gtree_z_avl_tree_test.go @@ -7,13 +7,15 @@ package gtree_test import ( + "fmt" + "testing" + "github.com/gogf/gf/g/container/gtree" + "github.com/gogf/gf/g/container/gvar" "github.com/gogf/gf/g/test/gtest" "github.com/gogf/gf/g/util/gutil" - "testing" ) - func Test_AVLTree_Basic(t *testing.T) { gtest.Case(t, func() { m := gtree.NewAVLTree(gutil.ComparatorString) @@ -24,6 +26,7 @@ func Test_AVLTree_Basic(t *testing.T) { gtest.Assert(m.Size(), 1) gtest.Assert(m.IsEmpty(), false) + gtest.Assert(m.GetOrSet("key2", "val2"), "val2") gtest.Assert(m.GetOrSet("key2", "val2"), "val2") gtest.Assert(m.SetIfNotExist("key2", "val2"), false) @@ -37,9 +40,14 @@ func Test_AVLTree_Basic(t *testing.T) { gtest.AssertIN("val3", m.Values()) gtest.AssertIN("val1", m.Values()) + m.Sets(map[interface{}]interface{}{"key3": "val3", "key1": "val1"}) + m.Flip() gtest.Assert(m.Map(), map[interface{}]interface{}{"val3": "key3", "val1": "key1"}) + m.Flip(gutil.ComparatorString) + gtest.Assert(m.Map(), map[interface{}]interface{}{"key3": "val3", "key1": "val1"}) + m.Clear() gtest.Assert(m.Size(), 0) gtest.Assert(m.IsEmpty(), true) @@ -49,14 +57,45 @@ func Test_AVLTree_Basic(t *testing.T) { }) } func Test_AVLTree_Set_Fun(t *testing.T) { - m := gtree.NewAVLTree(gutil.ComparatorString) - m.GetOrSetFunc("fun", getValue) - m.GetOrSetFuncLock("funlock", getValue) - gtest.Assert(m.Get("funlock"), 3) - gtest.Assert(m.Get("fun"), 3) - m.GetOrSetFunc("fun", getValue) - gtest.Assert(m.SetIfNotExistFunc("fun", getValue), false) - gtest.Assert(m.SetIfNotExistFuncLock("funlock", getValue), false) + //GetOrSetFunc lock or unlock + gtest.Case(t, func() { + m := gtree.NewAVLTree(gutil.ComparatorString) + gtest.Assert(m.GetOrSetFunc("fun", getValue), 3) + gtest.Assert(m.GetOrSetFunc("fun", getValue), 3) + gtest.Assert(m.GetOrSetFuncLock("funlock", getValue), 3) + gtest.Assert(m.GetOrSetFuncLock("funlock", getValue), 3) + gtest.Assert(m.Get("funlock"), 3) + gtest.Assert(m.Get("fun"), 3) + }) + //SetIfNotExistFunc lock or unlock + gtest.Case(t, func() { + m := gtree.NewAVLTree(gutil.ComparatorString) + gtest.Assert(m.SetIfNotExistFunc("fun", getValue), true) + gtest.Assert(m.SetIfNotExistFunc("fun", getValue), false) + gtest.Assert(m.SetIfNotExistFuncLock("funlock", getValue), true) + gtest.Assert(m.SetIfNotExistFuncLock("funlock", getValue), false) + gtest.Assert(m.Get("funlock"), 3) + gtest.Assert(m.Get("fun"), 3) + }) + +} + +func Test_AVLTree_Get_Set_Var(t *testing.T) { + gtest.Case(t, func() { + m := gtree.NewAVLTree(gutil.ComparatorString) + gtest.AssertEQ(m.SetIfNotExist("key1", "val1"), true) + gtest.AssertEQ(m.SetIfNotExist("key1", "val1"), false) + gtest.AssertEQ(m.GetVarOrSet("key1", "val1"), gvar.New("val1", true)) + gtest.AssertEQ(m.GetVar("key1"), gvar.New("val1", true)) + }) + + gtest.Case(t, func() { + m := gtree.NewAVLTree(gutil.ComparatorString) + gtest.AssertEQ(m.GetVarOrSetFunc("fun", getValue), gvar.New(3, true)) + gtest.AssertEQ(m.GetVarOrSetFunc("fun", getValue), gvar.New(3, true)) + gtest.AssertEQ(m.GetVarOrSetFuncLock("funlock", getValue), gvar.New(3, true)) + gtest.AssertEQ(m.GetVarOrSetFuncLock("funlock", getValue), gvar.New(3, true)) + }) } func Test_AVLTree_Batch(t *testing.T) { @@ -66,27 +105,61 @@ func Test_AVLTree_Batch(t *testing.T) { m.Removes([]interface{}{"key1", 1}) gtest.Assert(m.Map(), map[interface{}]interface{}{"key2": "val2", "key3": "val3"}) } -func Test_AVLTree_Iterator(t *testing.T){ - expect := map[interface{}]interface{}{1: 1, "key1": "val1"} + +func Test_AVLTree_Iterator(t *testing.T) { + keys := []string{"1", "key1", "key2", "key3", "key4"} + keyLen := len(keys) + index := 0 + + expect := map[interface{}]interface{}{"key4": "val4", 1: 1, "key1": "val1", "key2": "val2", "key3": "val3"} m := gtree.NewAVLTreeFrom(gutil.ComparatorString, expect) m.Iterator(func(k interface{}, v interface{}) bool { + gtest.Assert(k, keys[index]) + index++ gtest.Assert(expect[k], v) return true }) - // 断言返回值对遍历控制 - i := 0 - j := 0 - m.Iterator(func(k interface{}, v interface{}) bool { - i++ + + m.IteratorDesc(func(k interface{}, v interface{}) bool { + index-- + gtest.Assert(k, keys[index]) + gtest.Assert(expect[k], v) return true }) - m.Iterator(func(k interface{}, v interface{}) bool { - j++ - return false + + m.Print() + // 断言返回值对遍历控制 + gtest.Case(t, func() { + 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, keyLen) + gtest.Assert(j, 1) }) - gtest.Assert(i, 2) - gtest.Assert(j, 1) + + gtest.Case(t, func() { + i := 0 + j := 0 + m.IteratorDesc(func(k interface{}, v interface{}) bool { + i++ + return true + }) + m.IteratorDesc(func(k interface{}, v interface{}) bool { + j++ + return false + }) + gtest.Assert(i, keyLen) + gtest.Assert(j, 1) + }) + } func Test_AVLTree_Clone(t *testing.T) { @@ -100,4 +173,78 @@ func Test_AVLTree_Clone(t *testing.T) { m_clone.Remove("key1") //修改clone map,原 map 不影响 gtest.AssertIN("key1", m.Keys()) -} \ No newline at end of file +} + +func Test_AVLTree_LRNode(t *testing.T) { + expect := map[interface{}]interface{}{"key4": "val4", "key1": "val1", "key2": "val2", "key3": "val3"} + //safe + gtest.Case(t, func() { + m := gtree.NewAVLTreeFrom(gutil.ComparatorString, expect) + gtest.Assert(m.Left().Key, "key1") + gtest.Assert(m.Right().Key, "key4") + }) + //unsafe + gtest.Case(t, func() { + m := gtree.NewAVLTreeFrom(gutil.ComparatorString, expect, true) + gtest.Assert(m.Left().Key, "key1") + gtest.Assert(m.Right().Key, "key4") + }) +} + +func Test_AVLTree_CeilingFloor(t *testing.T) { + expect := map[interface{}]interface{}{ + 20: "val20", + 6: "val6", + 10: "val10", + 12: "val12", + 1: "val1", + 15: "val15", + 19: "val19", + 8: "val8", + 4: "val4"} + //found and eq + gtest.Case(t, func() { + m := gtree.NewAVLTreeFrom(gutil.ComparatorInt, expect) + c, cf := m.Ceiling(8) + gtest.Assert(cf, true) + gtest.Assert(c.Value, "val8") + f, ff := m.Floor(20) + gtest.Assert(ff, true) + gtest.Assert(f.Value, "val20") + }) + //found and neq + gtest.Case(t, func() { + m := gtree.NewAVLTreeFrom(gutil.ComparatorInt, expect) + c, cf := m.Ceiling(9) + gtest.Assert(cf, true) + gtest.Assert(c.Value, "val10") + f, ff := m.Floor(5) + gtest.Assert(ff, true) + gtest.Assert(f.Value, "val4") + }) + //nofound + gtest.Case(t, func() { + m := gtree.NewAVLTreeFrom(gutil.ComparatorInt, expect) + c, cf := m.Ceiling(21) + gtest.Assert(cf, false) + gtest.Assert(c, nil) + f, ff := m.Floor(-1) + gtest.Assert(ff, false) + gtest.Assert(f, nil) + }) +} + +func Test_AVLTree_Remove(t *testing.T) { + m := gtree.NewAVLTree(gutil.ComparatorInt) + for i := 1; i <= 50; i++ { + m.Set(i, fmt.Sprintf("val%d", i)) + } + expect := m.Map() + gtest.Case(t, func() { + for k, v := range expect { + m1 := m.Clone() + gtest.Assert(m1.Remove(k), v) + gtest.Assert(m1.Remove(k), nil) + } + }) +} diff --git a/g/container/gtree/gtree_z_b_tree_test.go b/g/container/gtree/gtree_z_b_tree_test.go index 1596bd175..8659b5366 100644 --- a/g/container/gtree/gtree_z_b_tree_test.go +++ b/g/container/gtree/gtree_z_b_tree_test.go @@ -7,16 +7,22 @@ package gtree_test import ( + "fmt" + "testing" + "github.com/gogf/gf/g/container/gtree" + "github.com/gogf/gf/g/container/gvar" "github.com/gogf/gf/g/test/gtest" "github.com/gogf/gf/g/util/gutil" - "testing" ) func Test_BTree_Basic(t *testing.T) { gtest.Case(t, func() { m := gtree.NewBTree(3, gutil.ComparatorString) m.Set("key1", "val1") + + gtest.Assert(m.Height(), 1) + gtest.Assert(m.Keys(), []interface{}{"key1"}) gtest.Assert(m.Get("key1"), "val1") @@ -44,15 +50,47 @@ func Test_BTree_Basic(t *testing.T) { gtest.Assert(m2.Map(), map[interface{}]interface{}{1: 1, "key1": "val1"}) }) } + func Test_BTree_Set_Fun(t *testing.T) { - m := gtree.NewBTree(3, gutil.ComparatorString) - m.GetOrSetFunc("fun", getValue) - m.GetOrSetFuncLock("funlock", getValue) - gtest.Assert(m.Get("funlock"), 3) - gtest.Assert(m.Get("fun"), 3) - m.GetOrSetFunc("fun", getValue) - gtest.Assert(m.SetIfNotExistFunc("fun", getValue), false) - gtest.Assert(m.SetIfNotExistFuncLock("funlock", getValue), false) + //GetOrSetFunc lock or unlock + gtest.Case(t, func() { + m := gtree.NewBTree(3, gutil.ComparatorString) + gtest.Assert(m.GetOrSetFunc("fun", getValue), 3) + gtest.Assert(m.GetOrSetFunc("fun", getValue), 3) + gtest.Assert(m.GetOrSetFuncLock("funlock", getValue), 3) + gtest.Assert(m.GetOrSetFuncLock("funlock", getValue), 3) + gtest.Assert(m.Get("funlock"), 3) + gtest.Assert(m.Get("fun"), 3) + }) + //SetIfNotExistFunc lock or unlock + gtest.Case(t, func() { + m := gtree.NewBTree(3, gutil.ComparatorString) + gtest.Assert(m.SetIfNotExistFunc("fun", getValue), true) + gtest.Assert(m.SetIfNotExistFunc("fun", getValue), false) + gtest.Assert(m.SetIfNotExistFuncLock("funlock", getValue), true) + gtest.Assert(m.SetIfNotExistFuncLock("funlock", getValue), false) + gtest.Assert(m.Get("funlock"), 3) + gtest.Assert(m.Get("fun"), 3) + }) + +} + +func Test_BTree_Get_Set_Var(t *testing.T) { + gtest.Case(t, func() { + m := gtree.NewBTree(3, gutil.ComparatorString) + gtest.AssertEQ(m.SetIfNotExist("key1", "val1"), true) + gtest.AssertEQ(m.SetIfNotExist("key1", "val1"), false) + gtest.AssertEQ(m.GetVarOrSet("key1", "val1"), gvar.New("val1", true)) + gtest.AssertEQ(m.GetVar("key1"), gvar.New("val1", true)) + }) + + gtest.Case(t, func() { + m := gtree.NewBTree(3, gutil.ComparatorString) + gtest.AssertEQ(m.GetVarOrSetFunc("fun", getValue), gvar.New(3, true)) + gtest.AssertEQ(m.GetVarOrSetFunc("fun", getValue), gvar.New(3, true)) + gtest.AssertEQ(m.GetVarOrSetFuncLock("funlock", getValue), gvar.New(3, true)) + gtest.AssertEQ(m.GetVarOrSetFuncLock("funlock", getValue), gvar.New(3, true)) + }) } func Test_BTree_Batch(t *testing.T) { @@ -62,27 +100,61 @@ func Test_BTree_Batch(t *testing.T) { m.Removes([]interface{}{"key1", 1}) gtest.Assert(m.Map(), map[interface{}]interface{}{"key2": "val2", "key3": "val3"}) } -func Test_BTree_Iterator(t *testing.T){ - expect := map[interface{}]interface{}{1: 1, "key1": "val1"} + +func Test_BTree_Iterator(t *testing.T) { + keys := []string{"1", "key1", "key2", "key3", "key4"} + keyLen := len(keys) + index := 0 + + expect := map[interface{}]interface{}{"key4": "val4", 1: 1, "key1": "val1", "key2": "val2", "key3": "val3"} m := gtree.NewBTreeFrom(3, gutil.ComparatorString, expect) m.Iterator(func(k interface{}, v interface{}) bool { + gtest.Assert(k, keys[index]) + index++ gtest.Assert(expect[k], v) return true }) - // 断言返回值对遍历控制 - i := 0 - j := 0 - m.Iterator(func(k interface{}, v interface{}) bool { - i++ + + m.IteratorDesc(func(k interface{}, v interface{}) bool { + index-- + gtest.Assert(k, keys[index]) + gtest.Assert(expect[k], v) return true }) - m.Iterator(func(k interface{}, v interface{}) bool { - j++ - return false + + m.Print() + // 断言返回值对遍历控制 + gtest.Case(t, func() { + 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, keyLen) + gtest.Assert(j, 1) }) - gtest.Assert(i, 2) - gtest.Assert(j, 1) + + gtest.Case(t, func() { + i := 0 + j := 0 + m.IteratorDesc(func(k interface{}, v interface{}) bool { + i++ + return true + }) + m.IteratorDesc(func(k interface{}, v interface{}) bool { + j++ + return false + }) + gtest.Assert(i, keyLen) + gtest.Assert(j, 1) + }) + } func Test_BTree_Clone(t *testing.T) { @@ -96,4 +168,35 @@ func Test_BTree_Clone(t *testing.T) { m_clone.Remove("key1") //修改clone map,原 map 不影响 gtest.AssertIN("key1", m.Keys()) -} \ No newline at end of file +} + +func Test_BTree_LRNode(t *testing.T) { + expect := map[interface{}]interface{}{"key4": "val4", "key1": "val1", "key2": "val2", "key3": "val3"} + //safe + gtest.Case(t, func() { + m := gtree.NewBTreeFrom(3, gutil.ComparatorString, expect) + gtest.Assert(m.Left().Key, "key1") + gtest.Assert(m.Right().Key, "key4") + }) + //unsafe + gtest.Case(t, func() { + m := gtree.NewBTreeFrom(3, gutil.ComparatorString, expect, true) + gtest.Assert(m.Left().Key, "key1") + gtest.Assert(m.Right().Key, "key4") + }) +} + +func Test_BTree_Remove(t *testing.T) { + m := gtree.NewBTree(3, gutil.ComparatorInt) + for i := 1; i <= 100; i++ { + m.Set(i, fmt.Sprintf("val%d", i)) + } + expect := m.Map() + gtest.Case(t, func() { + for k, v := range expect { + m1 := m.Clone() + gtest.Assert(m1.Remove(k), v) + gtest.Assert(m1.Remove(k), nil) + } + }) +} diff --git a/g/container/gtree/gtree_z_redblack_tree_test.go b/g/container/gtree/gtree_z_redblack_tree_test.go index 6dbe85c6a..29406bad8 100644 --- a/g/container/gtree/gtree_z_redblack_tree_test.go +++ b/g/container/gtree/gtree_z_redblack_tree_test.go @@ -7,10 +7,13 @@ package gtree_test import ( + "fmt" + "testing" + "github.com/gogf/gf/g/container/gtree" + "github.com/gogf/gf/g/container/gvar" "github.com/gogf/gf/g/test/gtest" "github.com/gogf/gf/g/util/gutil" - "testing" ) func getValue() interface{} { @@ -27,6 +30,7 @@ func Test_RedBlackTree_Basic(t *testing.T) { gtest.Assert(m.Size(), 1) gtest.Assert(m.IsEmpty(), false) + gtest.Assert(m.GetOrSet("key2", "val2"), "val2") gtest.Assert(m.GetOrSet("key2", "val2"), "val2") gtest.Assert(m.SetIfNotExist("key2", "val2"), false) @@ -40,9 +44,14 @@ func Test_RedBlackTree_Basic(t *testing.T) { gtest.AssertIN("val3", m.Values()) gtest.AssertIN("val1", m.Values()) + m.Sets(map[interface{}]interface{}{"key3": "val3", "key1": "val1"}) + m.Flip() gtest.Assert(m.Map(), map[interface{}]interface{}{"val3": "key3", "val1": "key1"}) + m.Flip(gutil.ComparatorString) + gtest.Assert(m.Map(), map[interface{}]interface{}{"key3": "val3", "key1": "val1"}) + m.Clear() gtest.Assert(m.Size(), 0) gtest.Assert(m.IsEmpty(), true) @@ -51,15 +60,47 @@ func Test_RedBlackTree_Basic(t *testing.T) { gtest.Assert(m2.Map(), map[interface{}]interface{}{1: 1, "key1": "val1"}) }) } + func Test_RedBlackTree_Set_Fun(t *testing.T) { - m := gtree.NewRedBlackTree(gutil.ComparatorString) - m.GetOrSetFunc("fun", getValue) - m.GetOrSetFuncLock("funlock", getValue) - gtest.Assert(m.Get("funlock"), 3) - gtest.Assert(m.Get("fun"), 3) - m.GetOrSetFunc("fun", getValue) - gtest.Assert(m.SetIfNotExistFunc("fun", getValue), false) - gtest.Assert(m.SetIfNotExistFuncLock("funlock", getValue), false) + //GetOrSetFunc lock or unlock + gtest.Case(t, func() { + m := gtree.NewRedBlackTree(gutil.ComparatorString) + gtest.Assert(m.GetOrSetFunc("fun", getValue), 3) + gtest.Assert(m.GetOrSetFunc("fun", getValue), 3) + gtest.Assert(m.GetOrSetFuncLock("funlock", getValue), 3) + gtest.Assert(m.GetOrSetFuncLock("funlock", getValue), 3) + gtest.Assert(m.Get("funlock"), 3) + gtest.Assert(m.Get("fun"), 3) + }) + //SetIfNotExistFunc lock or unlock + gtest.Case(t, func() { + m := gtree.NewRedBlackTree(gutil.ComparatorString) + gtest.Assert(m.SetIfNotExistFunc("fun", getValue), true) + gtest.Assert(m.SetIfNotExistFunc("fun", getValue), false) + gtest.Assert(m.SetIfNotExistFuncLock("funlock", getValue), true) + gtest.Assert(m.SetIfNotExistFuncLock("funlock", getValue), false) + gtest.Assert(m.Get("funlock"), 3) + gtest.Assert(m.Get("fun"), 3) + }) + +} + +func Test_RedBlackTree_Get_Set_Var(t *testing.T) { + gtest.Case(t, func() { + m := gtree.NewRedBlackTree(gutil.ComparatorString) + gtest.AssertEQ(m.SetIfNotExist("key1", "val1"), true) + gtest.AssertEQ(m.SetIfNotExist("key1", "val1"), false) + gtest.AssertEQ(m.GetVarOrSet("key1", "val1"), gvar.New("val1", true)) + gtest.AssertEQ(m.GetVar("key1"), gvar.New("val1", true)) + }) + + gtest.Case(t, func() { + m := gtree.NewRedBlackTree(gutil.ComparatorString) + gtest.AssertEQ(m.GetVarOrSetFunc("fun", getValue), gvar.New(3, true)) + gtest.AssertEQ(m.GetVarOrSetFunc("fun", getValue), gvar.New(3, true)) + gtest.AssertEQ(m.GetVarOrSetFuncLock("funlock", getValue), gvar.New(3, true)) + gtest.AssertEQ(m.GetVarOrSetFuncLock("funlock", getValue), gvar.New(3, true)) + }) } func Test_RedBlackTree_Batch(t *testing.T) { @@ -69,27 +110,61 @@ func Test_RedBlackTree_Batch(t *testing.T) { m.Removes([]interface{}{"key1", 1}) gtest.Assert(m.Map(), map[interface{}]interface{}{"key2": "val2", "key3": "val3"}) } -func Test_RedBlackTree_Iterator(t *testing.T){ - expect := map[interface{}]interface{}{1: 1, "key1": "val1"} + +func Test_RedBlackTree_Iterator(t *testing.T) { + keys := []string{"1", "key1", "key2", "key3", "key4"} + keyLen := len(keys) + index := 0 + + expect := map[interface{}]interface{}{"key4": "val4", 1: 1, "key1": "val1", "key2": "val2", "key3": "val3"} m := gtree.NewRedBlackTreeFrom(gutil.ComparatorString, expect) m.Iterator(func(k interface{}, v interface{}) bool { + gtest.Assert(k, keys[index]) + index++ gtest.Assert(expect[k], v) return true }) - // 断言返回值对遍历控制 - i := 0 - j := 0 - m.Iterator(func(k interface{}, v interface{}) bool { - i++ + + m.IteratorDesc(func(k interface{}, v interface{}) bool { + index-- + gtest.Assert(k, keys[index]) + gtest.Assert(expect[k], v) return true }) - m.Iterator(func(k interface{}, v interface{}) bool { - j++ - return false + + m.Print() + // 断言返回值对遍历控制 + gtest.Case(t, func() { + 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, keyLen) + gtest.Assert(j, 1) }) - gtest.Assert(i, 2) - gtest.Assert(j, 1) + + gtest.Case(t, func() { + i := 0 + j := 0 + m.IteratorDesc(func(k interface{}, v interface{}) bool { + i++ + return true + }) + m.IteratorDesc(func(k interface{}, v interface{}) bool { + j++ + return false + }) + gtest.Assert(i, keyLen) + gtest.Assert(j, 1) + }) + } func Test_RedBlackTree_Clone(t *testing.T) { @@ -103,4 +178,78 @@ func Test_RedBlackTree_Clone(t *testing.T) { m_clone.Remove("key1") //修改clone map,原 map 不影响 gtest.AssertIN("key1", m.Keys()) -} \ No newline at end of file +} + +func Test_RedBlackTree_LRNode(t *testing.T) { + expect := map[interface{}]interface{}{"key4": "val4", "key1": "val1", "key2": "val2", "key3": "val3"} + //safe + gtest.Case(t, func() { + m := gtree.NewRedBlackTreeFrom(gutil.ComparatorString, expect) + gtest.Assert(m.Left().Key, "key1") + gtest.Assert(m.Right().Key, "key4") + }) + //unsafe + gtest.Case(t, func() { + m := gtree.NewRedBlackTreeFrom(gutil.ComparatorString, expect, true) + gtest.Assert(m.Left().Key, "key1") + gtest.Assert(m.Right().Key, "key4") + }) +} + +func Test_RedBlackTree_CeilingFloor(t *testing.T) { + expect := map[interface{}]interface{}{ + 20: "val20", + 6: "val6", + 10: "val10", + 12: "val12", + 1: "val1", + 15: "val15", + 19: "val19", + 8: "val8", + 4: "val4"} + //found and eq + gtest.Case(t, func() { + m := gtree.NewRedBlackTreeFrom(gutil.ComparatorInt, expect) + c, cf := m.Ceiling(8) + gtest.Assert(cf, true) + gtest.Assert(c.Value, "val8") + f, ff := m.Floor(20) + gtest.Assert(ff, true) + gtest.Assert(f.Value, "val20") + }) + //found and neq + gtest.Case(t, func() { + m := gtree.NewRedBlackTreeFrom(gutil.ComparatorInt, expect) + c, cf := m.Ceiling(9) + gtest.Assert(cf, true) + gtest.Assert(c.Value, "val10") + f, ff := m.Floor(5) + gtest.Assert(ff, true) + gtest.Assert(f.Value, "val4") + }) + //nofound + gtest.Case(t, func() { + m := gtree.NewRedBlackTreeFrom(gutil.ComparatorInt, expect) + c, cf := m.Ceiling(21) + gtest.Assert(cf, false) + gtest.Assert(c, nil) + f, ff := m.Floor(-1) + gtest.Assert(ff, false) + gtest.Assert(f, nil) + }) +} + +func Test_RedBlackTree_Remove(t *testing.T) { + m := gtree.NewRedBlackTree(gutil.ComparatorInt) + for i := 1; i <= 100; i++ { + m.Set(i, fmt.Sprintf("val%d", i)) + } + expect := m.Map() + gtest.Case(t, func() { + for k, v := range expect { + m1 := m.Clone() + gtest.Assert(m1.Remove(k), v) + gtest.Assert(m1.Remove(k), nil) + } + }) +} diff --git a/geg/other/test.go b/geg/other/test.go index 125e7e362..49c122b37 100644 --- a/geg/other/test.go +++ b/geg/other/test.go @@ -1,24 +1,14 @@ package main import ( -<<<<<<< HEAD - "fmt" + "github.com/gogf/gf/g/container/gqueue" + "github.com/gogf/gf/g/test/gtest" ) func main() { - var i float64 = 0 - for index := 0; index < 10; index++ { - i += 0.1 - fmt.Println(i) - } + q1 := gqueue.New(2) + q1.Push(1) + q1.Push(2) + gtest.Assert(q1.Size(),2) } -======= - "github.com/gogf/gf/g/encoding/gjson" -) -func main() { - j := gjson.New(`[1,2,3]`) - j.Remove("1") - j.Dump() -} ->>>>>>> master