Compare commits

...

9 Commits

Author SHA1 Message Date
75725db6fb remove gmlock for print of glog; add time.Time support for gdb 2019-05-15 23:53:48 +08:00
5cd8475143 add time.Time support for convertParam function of gdb 2019-05-15 16:47:39 +08:00
5629f37939 version updates 2019-05-14 22:38:03 +08:00
08ec04d8b6 fix issue in unit test case of gredis 2019-05-14 22:37:13 +08:00
c0b46f364a version updates 2019-05-14 22:02:09 +08:00
8c5f74e8bb add DoVar/ReceiveVar function for gredis 2019-05-14 21:34:38 +08:00
94832262e3 version updates 2019-05-13 22:37:31 +08:00
aefbfd52e9 add more example for gtree 2019-05-13 22:37:05 +08:00
f3f0689bd4 rename LinkMap to ListMap for gmap 2019-05-13 22:26:39 +08:00
27 changed files with 448 additions and 187 deletions

View File

@ -12,74 +12,74 @@ import (
"github.com/gogf/gf/g/internal/rwmutex"
)
type LinkMap struct {
type ListMap struct {
mu *rwmutex.RWMutex
data map[interface{}]*glist.Element
list *glist.List
}
type gLinkMapNode struct {
type gListMapNode struct {
key interface{}
value interface{}
}
// NewLinkMap returns an empty link map.
// LinkMap is backed by a hash table to store values and doubly-linked list to store ordering.
// NewListMap returns an empty link map.
// ListMap is backed by a hash table to store values and doubly-linked list to store ordering.
// The param <unsafe> used to specify whether using map in un-concurrent-safety,
// which is false in default, means concurrent-safe.
func NewLinkMap(unsafe ...bool) *LinkMap {
return &LinkMap{
func NewListMap(unsafe ...bool) *ListMap {
return &ListMap{
mu : rwmutex.New(unsafe...),
data : make(map[interface{}]*glist.Element),
list : glist.New(true),
}
}
// NewLinkMapFrom returns a link map from given map <data>.
// NewListMapFrom returns a link map from given map <data>.
// Note that, the param <data> map will be set as the underlying data map(no deep copy),
// there might be some concurrent-safe issues when changing the map outside.
func NewLinkMapFrom(data map[interface{}]interface{}, unsafe...bool) *LinkMap {
m := NewLinkMap(unsafe...)
func NewListMapFrom(data map[interface{}]interface{}, unsafe...bool) *ListMap {
m := NewListMap(unsafe...)
m.Sets(data)
return m
}
// Iterator is alias of IteratorAsc.
func (m *LinkMap) Iterator(f func (key, value interface{}) bool) {
func (m *ListMap) Iterator(f func (key, value interface{}) bool) {
m.IteratorAsc(f)
}
// IteratorAsc iterates the map in ascending order with given callback function <f>.
// If <f> returns true, then it continues iterating; or false to stop.
func (m *LinkMap) IteratorAsc(f func (key interface{}, value interface{}) bool) {
func (m *ListMap) IteratorAsc(f func (key interface{}, value interface{}) bool) {
m.mu.RLock()
defer m.mu.RUnlock()
node := (*gLinkMapNode)(nil)
node := (*gListMapNode)(nil)
m.list.IteratorAsc(func(e *glist.Element) bool {
node = e.Value.(*gLinkMapNode)
node = e.Value.(*gListMapNode)
return f(node.key, node.value)
})
}
// IteratorDesc iterates the map in descending order with given callback function <f>.
// If <f> returns true, then it continues iterating; or false to stop.
func (m *LinkMap) IteratorDesc(f func (key interface{}, value interface{}) bool) {
func (m *ListMap) IteratorDesc(f func (key interface{}, value interface{}) bool) {
m.mu.RLock()
defer m.mu.RUnlock()
node := (*gLinkMapNode)(nil)
node := (*gListMapNode)(nil)
m.list.IteratorDesc(func(e *glist.Element) bool {
node = e.Value.(*gLinkMapNode)
node = e.Value.(*gListMapNode)
return f(node.key, node.value)
})
}
// Clone returns a new link map with copy of current map data.
func (m *LinkMap) Clone(unsafe ...bool) *LinkMap {
return NewLinkMapFrom(m.Map(), unsafe ...)
func (m *ListMap) Clone(unsafe ...bool) *ListMap {
return NewListMapFrom(m.Map(), unsafe ...)
}
// Clear deletes all data of the map, it will remake a new underlying data map.
func (m *LinkMap) Clear() {
func (m *ListMap) Clear() {
m.mu.Lock()
m.data = make(map[interface{}]*glist.Element)
m.list = glist.New(true)
@ -87,12 +87,12 @@ func (m *LinkMap) Clear() {
}
// Map returns a copy of the data of the map.
func (m *LinkMap) Map() map[interface{}]interface{} {
func (m *ListMap) Map() map[interface{}]interface{} {
m.mu.RLock()
node := (*gLinkMapNode)(nil)
node := (*gListMapNode)(nil)
data := make(map[interface{}]interface{}, len(m.data))
m.list.IteratorAsc(func(e *glist.Element) bool {
node = e.Value.(*gLinkMapNode)
node = e.Value.(*gListMapNode)
data[node.key] = node.value
return true
})
@ -101,24 +101,24 @@ func (m *LinkMap) Map() map[interface{}]interface{} {
}
// Set sets key-value to the map.
func (m *LinkMap) Set(key interface{}, value interface{}) {
func (m *ListMap) Set(key interface{}, value interface{}) {
m.mu.Lock()
if e, ok := m.data[key]; !ok {
m.data[key] = m.list.PushBack(&gLinkMapNode{key, value})
m.data[key] = m.list.PushBack(&gListMapNode{key, value})
} else {
e.Value = &gLinkMapNode{key, value}
e.Value = &gListMapNode{key, value}
}
m.mu.Unlock()
}
// Sets batch sets key-values to the map.
func (m *LinkMap) Sets(data map[interface{}]interface{}) {
func (m *ListMap) Sets(data map[interface{}]interface{}) {
m.mu.Lock()
for key, value := range data {
if e, ok := m.data[key]; !ok {
m.data[key] = m.list.PushBack(&gLinkMapNode{key, value})
m.data[key] = m.list.PushBack(&gListMapNode{key, value})
} else {
e.Value = &gLinkMapNode{key, value}
e.Value = &gListMapNode{key, value}
}
}
m.mu.Unlock()
@ -126,10 +126,10 @@ func (m *LinkMap) Sets(data map[interface{}]interface{}) {
// Search searches the map with given <key>.
// Second return parameter <found> is true if key was found, otherwise false.
func (m *LinkMap) Search(key interface{}) (value interface{}, found bool) {
func (m *ListMap) Search(key interface{}) (value interface{}, found bool) {
m.mu.RLock()
if e, ok := m.data[key]; ok {
value = e.Value.(*gLinkMapNode).value
value = e.Value.(*gListMapNode).value
found = ok
}
m.mu.RUnlock()
@ -137,10 +137,10 @@ func (m *LinkMap) Search(key interface{}) (value interface{}, found bool) {
}
// Get returns the value by given <key>.
func (m *LinkMap) Get(key interface{}) (value interface{}) {
func (m *ListMap) Get(key interface{}) (value interface{}) {
m.mu.RLock()
if e, ok := m.data[key]; ok {
value = e.Value.(*gLinkMapNode).value
value = e.Value.(*gListMapNode).value
}
m.mu.RUnlock()
return
@ -155,22 +155,22 @@ func (m *LinkMap) Get(key interface{}) (value interface{}) {
// and its return value will be set to the map with <key>.
//
// It returns value with given <key>.
func (m *LinkMap) doSetWithLockCheck(key interface{}, value interface{}) interface{} {
func (m *ListMap) doSetWithLockCheck(key interface{}, value interface{}) interface{} {
m.mu.Lock()
defer m.mu.Unlock()
if e, ok := m.data[key]; ok {
return e.Value.(*gLinkMapNode).value
return e.Value.(*gListMapNode).value
}
if f, ok := value.(func() interface {}); ok {
value = f()
}
m.data[key] = m.list.PushBack(&gLinkMapNode{key, value})
m.data[key] = m.list.PushBack(&gListMapNode{key, value})
return value
}
// GetOrSet returns the value by key,
// or set value with given <value> if not exist and returns this value.
func (m *LinkMap) GetOrSet(key interface{}, value interface{}) interface{} {
func (m *ListMap) GetOrSet(key interface{}, value interface{}) interface{} {
if v, ok := m.Search(key); !ok {
return m.doSetWithLockCheck(key, value)
} else {
@ -181,7 +181,7 @@ func (m *LinkMap) GetOrSet(key interface{}, value interface{}) interface{} {
// GetOrSetFunc returns the value by key,
// or sets value with return value of callback function <f> if not exist
// and returns this value.
func (m *LinkMap) GetOrSetFunc(key interface{}, f func() interface{}) interface{} {
func (m *ListMap) GetOrSetFunc(key interface{}, f func() interface{}) interface{} {
if v, ok := m.Search(key); !ok {
return m.doSetWithLockCheck(key, f())
} else {
@ -195,7 +195,7 @@ func (m *LinkMap) GetOrSetFunc(key interface{}, f func() interface{}) interface{
//
// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function <f>
// with mutex.Lock of the map.
func (m *LinkMap) GetOrSetFuncLock(key interface{}, f func() interface{}) interface{} {
func (m *ListMap) GetOrSetFuncLock(key interface{}, f func() interface{}) interface{} {
if v, ok := m.Search(key); !ok {
return m.doSetWithLockCheck(key, f)
} else {
@ -205,31 +205,31 @@ func (m *LinkMap) GetOrSetFuncLock(key interface{}, f func() interface{}) interf
// GetVar returns a gvar.Var with the value by given <key>.
// The returned gvar.Var is un-concurrent safe.
func (m *LinkMap) GetVar(key interface{}) *gvar.Var {
func (m *ListMap) GetVar(key interface{}) *gvar.Var {
return gvar.New(m.Get(key), true)
}
// GetVarOrSet returns a gvar.Var with result from GetVarOrSet.
// The returned gvar.Var is un-concurrent safe.
func (m *LinkMap) GetVarOrSet(key interface{}, value interface{}) *gvar.Var {
func (m *ListMap) GetVarOrSet(key interface{}, value interface{}) *gvar.Var {
return gvar.New(m.GetOrSet(key, value), true)
}
// GetVarOrSetFunc returns a gvar.Var with result from GetOrSetFunc.
// The returned gvar.Var is un-concurrent safe.
func (m *LinkMap) GetVarOrSetFunc(key interface{}, f func() interface{}) *gvar.Var {
func (m *ListMap) GetVarOrSetFunc(key interface{}, f func() interface{}) *gvar.Var {
return gvar.New(m.GetOrSetFunc(key, f), true)
}
// GetVarOrSetFuncLock returns a gvar.Var with result from GetOrSetFuncLock.
// The returned gvar.Var is un-concurrent safe.
func (m *LinkMap) GetVarOrSetFuncLock(key interface{}, f func() interface{}) *gvar.Var {
func (m *ListMap) GetVarOrSetFuncLock(key interface{}, f func() interface{}) *gvar.Var {
return gvar.New(m.GetOrSetFuncLock(key, f), true)
}
// SetIfNotExist sets <value> to the map if the <key> does not exist, then return true.
// It returns false if <key> exists, and <value> would be ignored.
func (m *LinkMap) SetIfNotExist(key interface{}, value interface{}) bool {
func (m *ListMap) SetIfNotExist(key interface{}, value interface{}) bool {
if !m.Contains(key) {
m.doSetWithLockCheck(key, value)
return true
@ -239,7 +239,7 @@ func (m *LinkMap) SetIfNotExist(key interface{}, value interface{}) bool {
// SetIfNotExistFunc sets value with return value of callback function <f>, then return true.
// It returns false if <key> exists, and <value> would be ignored.
func (m *LinkMap) SetIfNotExistFunc(key interface{}, f func() interface{}) bool {
func (m *ListMap) SetIfNotExistFunc(key interface{}, f func() interface{}) bool {
if !m.Contains(key) {
m.doSetWithLockCheck(key, f())
return true
@ -252,7 +252,7 @@ func (m *LinkMap) SetIfNotExistFunc(key interface{}, f func() interface{}) bool
//
// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
// it executes function <f> with mutex.Lock of the map.
func (m *LinkMap) SetIfNotExistFuncLock(key interface{}, f func() interface{}) bool {
func (m *ListMap) SetIfNotExistFuncLock(key interface{}, f func() interface{}) bool {
if !m.Contains(key) {
m.doSetWithLockCheck(key, f)
return true
@ -261,10 +261,10 @@ func (m *LinkMap) SetIfNotExistFuncLock(key interface{}, f func() interface{}) b
}
// Remove deletes value from map by given <key>, and return this deleted value.
func (m *LinkMap) Remove(key interface{}) (value interface{}) {
func (m *ListMap) Remove(key interface{}) (value interface{}) {
m.mu.Lock()
if e, ok := m.data[key]; ok {
value = e.Value.(*gLinkMapNode).value
value = e.Value.(*gListMapNode).value
delete(m.data, key)
m.list.Remove(e)
}
@ -273,7 +273,7 @@ func (m *LinkMap) Remove(key interface{}) (value interface{}) {
}
// Removes batch deletes values of the map by keys.
func (m *LinkMap) Removes(keys []interface{}) {
func (m *ListMap) Removes(keys []interface{}) {
m.mu.Lock()
for _, key := range keys {
if e, ok := m.data[key]; ok {
@ -285,12 +285,12 @@ func (m *LinkMap) Removes(keys []interface{}) {
}
// Keys returns all keys of the map as a slice in ascending order.
func (m *LinkMap) Keys() []interface{} {
func (m *ListMap) Keys() []interface{} {
m.mu.RLock()
keys := make([]interface{}, m.list.Len())
index := 0
m.list.IteratorAsc(func(e *glist.Element) bool {
keys[index] = e.Value.(*gLinkMapNode).key
keys[index] = e.Value.(*gListMapNode).key
index++
return true
})
@ -299,12 +299,12 @@ func (m *LinkMap) Keys() []interface{} {
}
// Values returns all values of the map as a slice.
func (m *LinkMap) Values() []interface{} {
func (m *ListMap) Values() []interface{} {
m.mu.RLock()
values := make([]interface{}, m.list.Len())
index := 0
m.list.IteratorAsc(func(e *glist.Element) bool {
values[index] = e.Value.(*gLinkMapNode).value
values[index] = e.Value.(*gListMapNode).value
index++
return true
})
@ -314,7 +314,7 @@ func (m *LinkMap) Values() []interface{} {
// Contains checks whether a key exists.
// It returns true if the <key> exists, or else false.
func (m *LinkMap) Contains(key interface{}) (ok bool) {
func (m *ListMap) Contains(key interface{}) (ok bool) {
m.mu.RLock()
_, ok = m.data[key]
m.mu.RUnlock()
@ -322,7 +322,7 @@ func (m *LinkMap) Contains(key interface{}) (ok bool) {
}
// Size returns the size of the map.
func (m *LinkMap) Size() (size int) {
func (m *ListMap) Size() (size int) {
m.mu.RLock()
size = len(m.data)
m.mu.RUnlock()
@ -331,12 +331,12 @@ func (m *LinkMap) Size() (size int) {
// IsEmpty checks whether the map is empty.
// It returns true if map is empty, or else false.
func (m *LinkMap) IsEmpty() bool {
func (m *ListMap) IsEmpty() bool {
return m.Size() == 0
}
// Flip exchanges key-value of the map to value-key.
func (m *LinkMap) Flip() {
func (m *ListMap) Flip() {
data := m.Map()
m.Clear()
for key, value := range data {
@ -346,20 +346,20 @@ func (m *LinkMap) Flip() {
// Merge merges two link maps.
// The <other> map will be merged into the map <m>.
func (m *LinkMap) Merge(other *LinkMap) {
func (m *ListMap) Merge(other *ListMap) {
m.mu.Lock()
defer m.mu.Unlock()
if other != m {
other.mu.RLock()
defer other.mu.RUnlock()
}
node := (*gLinkMapNode)(nil)
node := (*gListMapNode)(nil)
other.list.IteratorAsc(func(e *glist.Element) bool {
node = e.Value.(*gLinkMapNode)
node = e.Value.(*gListMapNode)
if e, ok := m.data[node.key]; !ok {
m.data[node.key] = m.list.PushBack(&gLinkMapNode{node.key, node.value})
m.data[node.key] = m.list.PushBack(&gListMapNode{node.key, node.value})
} else {
e.Value = &gLinkMapNode{node.key, node.value}
e.Value = &gListMapNode{node.key, node.value}
}
return true
})

View File

@ -0,0 +1,55 @@
// Copyright 2017 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with gm file,
// You can obtain one at https://github.com/gogf/gf.
// go test *.go -bench=".*" -benchmem
package gmap_test
import (
"github.com/gogf/gf/g/container/gmap"
"github.com/gogf/gf/g/util/gutil"
"testing"
)
var hashMap = gmap.New()
var listMap = gmap.NewListMap()
var treeMap = gmap.NewTreeMap(gutil.ComparatorInt)
func Benchmark_HashMap_Set(b *testing.B) {
for i := 0; i < b.N; i++ {
hashMap.Set(i, i)
}
}
func Benchmark_ListMap_Set(b *testing.B) {
for i := 0; i < b.N; i++ {
listMap.Set(i, i)
}
}
func Benchmark_TreeMap_Set(b *testing.B) {
for i := 0; i < b.N; i++ {
treeMap.Set(i, i)
}
}
func Benchmark_HashMap_Get(b *testing.B) {
for i := 0; i < b.N; i++ {
hashMap.Get(i)
}
}
func Benchmark_ListMap_Get(b *testing.B) {
for i := 0; i < b.N; i++ {
listMap.Get(i)
}
}
func Benchmark_TreeMap_Get(b *testing.B) {
for i := 0; i < b.N; i++ {
treeMap.Get(i)
}
}

View File

@ -6,21 +6,21 @@
// go test *.go -bench=".*" -benchmem
package gmap
package gmap_test
import (
"testing"
"github.com/gogf/gf/g/container/gmap"
"testing"
"strconv"
)
var iim = NewIntIntMap()
var iifm = NewIntAnyMap()
var ism = NewIntStrMap()
var ififm = New()
var sim = NewStrIntMap()
var sifm = NewStrAnyMap()
var ssm = NewStrStrMap()
var ififm = gmap.New()
var iim = gmap.NewIntIntMap()
var iifm = gmap.NewIntAnyMap()
var ism = gmap.NewIntStrMap()
var sim = gmap.NewStrIntMap()
var sifm = gmap.NewStrAnyMap()
var ssm = gmap.NewStrStrMap()
func Benchmark_IntIntMap_Set(b *testing.B) {
for i := 0; i < b.N; i++ {

View File

@ -6,21 +6,21 @@
// go test *.go -bench=".*" -benchmem
package gmap
package gmap_test
import (
"testing"
"github.com/gogf/gf/g/container/gmap"
"testing"
"strconv"
)
var iimUnsafe = NewIntIntMap(true)
var iifmUnsafe = NewIntAnyMap(true)
var ismUnsafe = NewIntStrMap(true)
var ififmUnsafe = New(true)
var simUnsafe = NewStrIntMap(true)
var sifmUnsafe = NewStrAnyMap(true)
var ssmUnsafe = NewStrStrMap(true)
var ififmUnsafe = gmap.New(true)
var iimUnsafe = gmap.NewIntIntMap(true)
var iifmUnsafe = gmap.NewIntAnyMap(true)
var ismUnsafe = gmap.NewIntStrMap(true)
var simUnsafe = gmap.NewStrIntMap(true)
var sifmUnsafe = gmap.NewStrAnyMap(true)
var ssmUnsafe = gmap.NewStrStrMap(true)
// 写入性能测试

View File

@ -13,9 +13,9 @@ import (
"testing"
)
func Test_Link_Map_Basic(t *testing.T) {
func Test_List_Map_Basic(t *testing.T) {
gtest.Case(t, func() {
m := gmap.NewLinkMap()
m := gmap.NewListMap()
m.Set("key1", "val1")
gtest.Assert(m.Keys(), []interface{}{"key1"})
@ -43,12 +43,12 @@ func Test_Link_Map_Basic(t *testing.T) {
gtest.Assert(m.Size(), 0)
gtest.Assert(m.IsEmpty(), true)
m2 := gmap.NewLinkMapFrom(map[interface{}]interface{}{1: 1, "key1": "val1"})
m2 := gmap.NewListMapFrom(map[interface{}]interface{}{1: 1, "key1": "val1"})
gtest.Assert(m2.Map(), map[interface{}]interface{}{1: 1, "key1": "val1"})
})
}
func Test_Link_Map_Set_Fun(t *testing.T) {
m := gmap.NewLinkMap()
func Test_List_Map_Set_Fun(t *testing.T) {
m := gmap.NewListMap()
m.GetOrSetFunc("fun", getValue)
m.GetOrSetFuncLock("funlock", getValue)
gtest.Assert(m.Get("funlock"), 3)
@ -58,17 +58,17 @@ func Test_Link_Map_Set_Fun(t *testing.T) {
gtest.Assert(m.SetIfNotExistFuncLock("funlock", getValue), false)
}
func Test_Link_Map_Batch(t *testing.T) {
m := gmap.NewLinkMap()
func Test_List_Map_Batch(t *testing.T) {
m := gmap.NewListMap()
m.Sets(map[interface{}]interface{}{1: 1, "key1": "val1", "key2": "val2", "key3": "val3"})
gtest.Assert(m.Map(), map[interface{}]interface{}{1: 1, "key1": "val1", "key2": "val2", "key3": "val3"})
m.Removes([]interface{}{"key1", 1})
gtest.Assert(m.Map(), map[interface{}]interface{}{"key2": "val2", "key3": "val3"})
}
func Test_Link_Map_Iterator(t *testing.T){
func Test_List_Map_Iterator(t *testing.T){
expect :=map[interface{}]interface{}{1: 1, "key1": "val1"}
m := gmap.NewLinkMapFrom(expect)
m := gmap.NewListMapFrom(expect)
m.Iterator(func(k interface{}, v interface{}) bool {
gtest.Assert(expect[k], v)
return true
@ -88,9 +88,9 @@ func Test_Link_Map_Iterator(t *testing.T){
gtest.Assert(j, 1)
}
func Test_Link_Map_Clone(t *testing.T) {
func Test_List_Map_Clone(t *testing.T) {
//clone 方法是深克隆
m := gmap.NewLinkMapFrom(map[interface{}]interface{}{1: 1, "key1": "val1"})
m := gmap.NewListMapFrom(map[interface{}]interface{}{1: 1, "key1": "val1"})
m_clone := m.Clone()
m.Remove(1)
//修改原 map,clone 后的 map 不影响
@ -101,17 +101,17 @@ func Test_Link_Map_Clone(t *testing.T) {
gtest.AssertIN("key1", m.Keys())
}
func Test_Link_Map_Basic_Merge(t *testing.T) {
m1 := gmap.NewLinkMap()
m2 := gmap.NewLinkMap()
func Test_List_Map_Basic_Merge(t *testing.T) {
m1 := gmap.NewListMap()
m2 := gmap.NewListMap()
m1.Set("key1", "val1")
m2.Set("key2", "val2")
m1.Merge(m2)
gtest.Assert(m1.Map(), map[interface{}]interface{}{"key1": "val1", "key2": "val2"})
}
func Test_Link_Map_Order(t *testing.T) {
m := gmap.NewLinkMap()
func Test_List_Map_Order(t *testing.T) {
m := gmap.NewListMap()
m.Set("k1", "v1")
m.Set("k2", "v2")
m.Set("k3", "v3")

View File

@ -388,10 +388,6 @@ func (tree *AVLTree) Print() {
fmt.Println(tree.String())
}
func (node *AVLTreeNode) String() string {
return fmt.Sprintf("%v", node.Key)
}
// Map returns all key-value items as map.
func (tree *AVLTree) Map() map[interface{}]interface{} {
m := make(map[interface{}]interface{}, tree.Size())
@ -692,7 +688,7 @@ func output(node *AVLTreeNode, prefix string, isTail bool, str *string) {
} else {
*str += "┌── "
}
*str += node.String() + "\n"
*str += fmt.Sprintf("%v\n", node.Key)
if node.children[0] != nil {
newPrefix := prefix
if isTail {

View File

@ -371,10 +371,6 @@ func (tree *BTree) Print() {
fmt.Println(tree.String())
}
func (entry *BTreeEntry) String() string {
return fmt.Sprintf("%v", entry.Key)
}
// Iterator is alias of IteratorAsc.
func (tree *BTree) Iterator(f func (key, value interface{}) bool) {
tree.IteratorAsc(f)

View File

@ -546,10 +546,6 @@ func (tree *RedBlackTree) Print() {
fmt.Println(tree.String())
}
func (node *RedBlackTreeNode) String() string {
return fmt.Sprintf("%v", node.Key)
}
// Search searches the tree with given <key>.
// Second return parameter <found> is true if key was found, otherwise false.
func (tree *RedBlackTree) Search(key interface{}) (value interface{}, found bool) {
@ -600,7 +596,7 @@ func (tree *RedBlackTree) output(node *RedBlackTreeNode, prefix string, isTail b
} else {
*str += "┌── "
}
*str += node.String() + "\n"
*str += fmt.Sprintf("%v\n", node.Key)
if node.left != nil {
newPrefix := prefix
if isTail {

View File

@ -17,6 +17,7 @@ import (
"github.com/gogf/gf/g/util/gconv"
"reflect"
"strings"
"time"
)
// 格式化SQL查询条件
@ -136,6 +137,10 @@ func convertParam(value interface{}) interface{} {
}
switch kind {
case reflect.Struct:
// 底层数据库引擎支持 time.Time 类型
if _, ok := value.(time.Time); ok {
return value
}
return gconv.String(value)
}
return value

View File

@ -7,14 +7,17 @@
// Package gredis provides convenient client for redis server.
//
// Redis Client.
//
// Redis Commands Official: https://redis.io/commands
//
// Redis Chinese Documentation: http://redisdoc.com/
package gredis
import (
"fmt"
"github.com/gogf/gf/g/container/gmap"
"github.com/gogf/gf/third/github.com/gomodule/redigo/redis"
"github.com/gogf/gf/g/container/gvar"
"github.com/gogf/gf/third/github.com/gomodule/redigo/redis"
"time"
)
@ -31,7 +34,9 @@ type Redis struct {
}
// Redis connection.
type Conn redis.Conn
type Conn struct {
redis.Conn
}
// Redis configuration.
type Config struct {
@ -134,16 +139,17 @@ func (r *Redis) Close() error {
return r.pool.Close()
}
// Alias of GetConn, see GetConn.
func (r *Redis) Conn() Conn {
return r.GetConn()
}
// GetConn returns a raw underlying connection object,
// Conn returns a raw underlying connection object,
// which expose more methods to communicate with server.
// **You should call Close function manually if you do not use this connection any further.**
func (r *Redis) GetConn() Conn {
return r.pool.Get().(Conn)
func (r *Redis) Conn() *Conn {
return &Conn{ r.pool.Get() }
}
// Alias of Conn, see Conn.
func (r *Redis) GetConn() *Conn {
return r.Conn()
}
// SetMaxIdle sets the MaxIdle attribute of the connection pool.
@ -175,15 +181,21 @@ func (r *Redis) Stats() *PoolStats {
// Do automatically get a connection from pool, and close it when reply received.
// It does not really "close" the connection, but drop it back to the connection pool.
func (r *Redis) Do(command string, args ...interface{}) (interface{}, error) {
conn := r.pool.Get()
conn := &Conn{ r.pool.Get() }
defer conn.Close()
return conn.Do(command, args...)
}
// DoVar returns value from Do as gvar.Var.
func (r *Redis) DoVar(command string, args ...interface{}) (*gvar.Var, error) {
v, err := r.Do(command, args...)
return gvar.New(v, true), err
}
// Deprecated.
// Send writes the command to the client's output buffer.
func (r *Redis) Send(command string, args ...interface{}) error {
conn := r.pool.Get()
conn := &Conn{ r.pool.Get() }
defer conn.Close()
return conn.Send(command, args...)
}

View File

@ -0,0 +1,21 @@
// Copyright 2019 gf Author(https://github.com/gogf/gf). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package gredis
import "github.com/gogf/gf/g/container/gvar"
// DoVar returns value from Do as gvar.Var.
func (c *Conn) DoVar(command string, args ...interface{}) (*gvar.Var, error) {
v, err := c.Do(command, args...)
return gvar.New(v, true), err
}
// ReceiveVar receives a single reply as gvar.Var from the Redis server.
func (c *Conn) ReceiveVar() (*gvar.Var, error) {
v, err := c.Receive()
return gvar.New(v, true), err
}

View File

@ -71,7 +71,7 @@ func Test_Stats(t *testing.T) {
redis.SetIdleTimeout(500*time.Millisecond)
redis.SetMaxConnLifetime(500*time.Millisecond)
array := make([]gredis.Conn, 0)
array := make([]*gredis.Conn, 0)
for i := 0; i < 10; i++ {
array = append(array, redis.Conn())
}

View File

@ -9,20 +9,19 @@
package glog
import (
"errors"
"fmt"
"github.com/gogf/gf/g/container/gtype"
"github.com/gogf/gf/g/os/gfile"
"github.com/gogf/gf/g/os/gfpool"
"github.com/gogf/gf/g/os/gmlock"
"github.com/gogf/gf/g/os/gtime"
"github.com/gogf/gf/g/text/gregex"
"io"
"os"
"runtime"
"strings"
"sync"
"time"
"errors"
"fmt"
"github.com/gogf/gf/g/container/gtype"
"github.com/gogf/gf/g/os/gfile"
"github.com/gogf/gf/g/os/gfpool"
"github.com/gogf/gf/g/os/gtime"
"github.com/gogf/gf/g/text/gregex"
"io"
"os"
"runtime"
"strings"
"sync"
"time"
)
type Logger struct {
@ -216,11 +215,7 @@ func (l *Logger) print(std io.Writer, s string) {
if _, ok := writer.(*Writer); ok {
if f := l.getFilePointer(); f != nil {
defer f.Close()
key := l.path.Val()
gmlock.Lock(key)
_, err := io.WriteString(f, s)
gmlock.Unlock(key)
if err != nil {
if _, err := io.WriteString(f, s); err != nil {
fmt.Fprintln(os.Stderr, err.Error())
}
}

View File

@ -7,10 +7,10 @@
package gconv_test
import (
"github.com/gogf/gf/g"
"github.com/gogf/gf/g/test/gtest"
"github.com/gogf/gf/g/util/gconv"
"testing"
"github.com/gogf/gf/g"
"github.com/gogf/gf/g/test/gtest"
"github.com/gogf/gf/g/util/gconv"
"testing"
)
@ -113,7 +113,6 @@ func Test_Map_StructWithJsonTag(t *testing.T) {
})
}
// 私有属性不会进行转换
func Test_Map_PrivateAttribute(t *testing.T) {
type User struct {
Id int
@ -123,4 +122,24 @@ func Test_Map_PrivateAttribute(t *testing.T) {
user := &User{1, "john"}
gtest.Assert(gconv.Map(user), g.Map{"Id" : 1})
})
}
}
//
//func Test_Map_StructInherit(t *testing.T) {
// type Base struct {
// Id int
// }
// type User struct {
// Base
// Name string
// }
// gtest.Case(t, func() {
// user := &User{
// Base : Base {
// Id : 100,
// },
// Name : "john",
// }
// fmt.Println(gconv.Map(user))
// //gtest.Assert(gconv.Map(user), g.Map{"Id" : 1})
// })
//}

View File

@ -0,0 +1,30 @@
package main
import (
"fmt"
"github.com/gogf/gf/g"
"github.com/gogf/gf/g/container/gmap"
"github.com/gogf/gf/g/util/gutil"
)
func main() {
array := g.Slice{2, 3, 1, 5, 4, 6, 8, 7, 9}
hashMap := gmap.New(true)
linkMap := gmap.NewLinkMap(true)
treeMap := gmap.NewTreeMap(gutil.ComparatorInt, true)
for _, v := range array {
hashMap.Set(v, v)
}
for _, v := range array {
linkMap.Set(v, v)
}
for _, v := range array {
treeMap.Set(v, v)
}
fmt.Println("HashMap Keys:", hashMap.Keys())
fmt.Println("HashMap Values:", hashMap.Values())
fmt.Println("LinkMap Keys:", linkMap.Keys())
fmt.Println("LinkMap Values:", linkMap.Values())
fmt.Println("TreeMap Keys:", treeMap.Keys())
fmt.Println("TreeMap Values:", treeMap.Values())
}

View File

@ -3,17 +3,24 @@ package main
import (
"fmt"
"github.com/gogf/gf/g/container/gtree"
"github.com/gogf/gf/g/util/gutil"
)
func main() {
tree := gtree.NewAVLTree(func(v1, v2 interface{}) int {
return v1.(int) - v2.(int)
})
tree := gtree.NewAVLTree(gutil.ComparatorInt)
for i := 0; i < 10; i++ {
tree.Set(i, i*10)
}
fmt.Println(tree.String())
tree.Remove(1)
// 打印树形
tree.Print()
// 前序遍历
fmt.Println("ASC:")
tree.IteratorAsc(func(key, value interface{}) bool {
fmt.Println(key, value)
return true
})
// 后续遍历
fmt.Println("DESC:")
tree.IteratorDesc(func(key, value interface{}) bool {
fmt.Println(key, value)
return true

View File

@ -0,0 +1,62 @@
package main
import (
"fmt"
"github.com/gogf/gf/g/container/gtree"
"github.com/gogf/gf/g/util/gutil"
)
func main() {
m := gtree.NewRedBlackTree(gutil.ComparatorInt)
// 设置键值对
for i := 0; i < 10; i++ {
m.Set(i, i*10)
}
// 查询大小
fmt.Println(m.Size())
// 批量设置键值对(不同的数据类型对象参数不同)
m.Sets(map[interface{}]interface{}{
10: 10,
11: 11,
})
fmt.Println(m.Size())
// 查询是否存在
fmt.Println(m.Contains(1))
// 查询键值
fmt.Println(m.Get(1))
// 删除数据项
m.Remove(9)
fmt.Println(m.Size())
// 批量删除
m.Removes([]interface{}{10, 11})
fmt.Println(m.Size())
// 当前键名列表(随机排序)
fmt.Println(m.Keys())
// 当前键值列表(随机排序)
fmt.Println(m.Values())
// 查询键名,当键值不存在时,写入给定的默认值
fmt.Println(m.GetOrSet(100, 100))
// 删除键值对,并返回对应的键值
fmt.Println(m.Remove(100))
// 遍历map
m.IteratorAsc(func(k interface{}, v interface{}) bool {
fmt.Printf("%v:%v ", k, v)
return true
})
fmt.Println()
// 清空map
m.Clear()
// 判断map是否为空
fmt.Println(m.IsEmpty())
}

View File

@ -8,8 +8,8 @@ func main() {
tree := gtree.NewRedBlackTree(func(v1, v2 interface{}) int {
return v1.(int) - v2.(int)
})
for i := 0; i < 20; i++ {
tree.Set(i, i*10)
for i := 0; i < 10; i++ {
tree.Set(i, i)
}
tree.Print()
tree.Flip()

View File

@ -0,0 +1,26 @@
package main
import (
"fmt"
"github.com/gogf/gf/g"
"time"
)
func main() {
db := g.DB()
// 开启调试模式以便于记录所有执行的SQL
db.SetDebug(true)
r, e := db.Table("user").Data(g.Map{
"passport" : "1",
"password" : "1",
"nickname" : "1",
"create_time" : time.Now(),
}).Insert()
if e != nil {
panic(e)
}
if r != nil {
fmt.Println(r.LastInsertId())
}
}

View File

@ -0,0 +1,16 @@
package main
import (
"fmt"
"github.com/gogf/gf/g"
)
func main() {
conn := g.Redis().Conn()
defer conn.Close()
if _, err := conn.Do("SET", "k", "v"); err != nil {
panic(err)
}
v, _ := conn.DoVar("GET", "k")
fmt.Println(v.String())
}

View File

@ -0,0 +1,19 @@
package main
import (
"fmt"
"github.com/gogf/gf/g"
)
func main() {
conn := g.Redis().Conn()
defer conn.Close()
conn.Send("SET", "foo", "bar")
conn.Send("GET", "foo")
conn.Flush()
// reply from SET
conn.Receive()
// reply from GET
v, _ := conn.ReceiveVar()
fmt.Println(v.String())
}

View File

@ -0,0 +1,22 @@
package main
import (
"fmt"
"github.com/gogf/gf/g"
)
func main() {
conn := g.Redis().Conn()
defer conn.Close()
_, err := conn.Do("SUBSCRIBE", "channel")
if err != nil {
panic(err)
}
for {
reply, err := conn.ReceiveVar()
if err != nil {
panic(err)
}
fmt.Println(reply.Strings())
}
}

View File

@ -1,40 +1,24 @@
package main
import (
"encoding/json"
"fmt"
"time"
"github.com/gogf/gf/g"
"github.com/gogf/gf/g/util/gconv"
)
func main() {
//b, e := gjson.MarshalOrdered(g.Map{
// "a" : 1,
// "b" : 2,
// "c" : 3,
//})
//fmt.Println(e)
//fmt.Println(string(b))
//m := map[string]interface{}{
// "facet_is_special_price":[]string{"1"},
// "score_outlet":"0",
// "skus":[]string{"DI139BE71WDWDFMX", "DI139BE71WDWDFMX-519406"},
// "facet_novelty_two_days":[]string{"0"},
// "facet_brand":[]string{"139"},
// "sku":[]string{"DI139BE71WDWDFMX"},
//}
for {
m := make(map[string]interface{})
m["facet_is_special_price"] = []string{"1"}
m["score_outlet"] = "0"
m["skus"] = []string{"DI139BE71WDWDFMX", "DI139BE71WDWDFMX-519406"}
m["facet_novelty_two_days"] = []string{"0"}
m["facet_brand"] = []string{"139"}
m["sku"] = []string{"DI139BE71WDWDFMX"}
b, _ := json.Marshal(m)
fmt.Println(string(b))
time.Sleep(100*time.Millisecond)
type Person struct{
Name string
}
type Staff struct{
Person
StaffId int
}
staff := &Staff{}
params := g.Map{
"Name" : "john",
"StaffId" : "10000",
}
gconv.Struct(params, staff)
fmt.Println(staff)
}

View File

@ -1,4 +1,4 @@
package gf
const VERSION = "v1.6.10"
const VERSION = "v1.6.13"
const AUTHORS = "john<john@goframe.org>"