mirror of
https://gitee.com/johng/gf.git
synced 2024-11-30 19:27:46 +08:00
add gtree.RedBlackTree container
This commit is contained in:
parent
b15d8bdd2e
commit
abaef9ba87
@ -103,6 +103,15 @@ func (m *Map) Sets(data map[interface{}]interface{}) {
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
// Search searches the map with given <key>.
|
||||
// Second return parameter <found> is true if key was found, otherwise false.
|
||||
func (m *Map) Search(key interface{}) (value interface{}, found bool) {
|
||||
m.mu.RLock()
|
||||
value, found = m.data[key]
|
||||
m.mu.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns the value by given <key>.
|
||||
func (m *Map) Get(key interface{}) interface{} {
|
||||
m.mu.RLock()
|
||||
@ -136,7 +145,7 @@ func (m *Map) doSetWithLockCheck(key interface{}, value interface{}) interface{}
|
||||
// GetOrSet returns the value by key,
|
||||
// or set value with given <value> if not exist and returns this value.
|
||||
func (m *Map) GetOrSet(key interface{}, value interface{}) interface{} {
|
||||
if v := m.Get(key); v == nil {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, value)
|
||||
} else {
|
||||
return v
|
||||
@ -147,7 +156,7 @@ func (m *Map) GetOrSet(key interface{}, value interface{}) interface{} {
|
||||
// or sets value with return value of callback function <f> if not exist
|
||||
// and returns this value.
|
||||
func (m *Map) GetOrSetFunc(key interface{}, f func() interface{}) interface{} {
|
||||
if v := m.Get(key); v == nil {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, f())
|
||||
} else {
|
||||
return v
|
||||
@ -161,7 +170,7 @@ func (m *Map) GetOrSetFunc(key interface{}, f func() interface{}) interface{} {
|
||||
// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function <f>
|
||||
// with mutex.Lock of the hash map.
|
||||
func (m *Map) GetOrSetFuncLock(key interface{}, f func() interface{}) interface{} {
|
||||
if v := m.Get(key); v == nil {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, f)
|
||||
} else {
|
||||
return v
|
||||
@ -314,13 +323,13 @@ func (m *Map) RLockFunc(f func(m map[interface{}]interface{})) {
|
||||
f(m.data)
|
||||
}
|
||||
|
||||
// Flip exchanges key-value of the map, it will change key-value to value-key.
|
||||
// Flip exchanges key-value of the map to value-key.
|
||||
func (m *Map) Flip() {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
n := make(map[interface{}]interface{}, len(m.data))
|
||||
for i, v := range m.data {
|
||||
n[v] = i
|
||||
for k, v := range m.data {
|
||||
n[v] = k
|
||||
}
|
||||
m.data = n
|
||||
}
|
||||
|
@ -104,6 +104,15 @@ func (m *IntAnyMap) Sets(data map[int]interface{}) {
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
// Search searches the map with given <key>.
|
||||
// Second return parameter <found> is true if key was found, otherwise false.
|
||||
func (m *IntAnyMap) Search(key int) (value interface{}, found bool) {
|
||||
m.mu.RLock()
|
||||
value, found = m.data[key]
|
||||
m.mu.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns the value by given <key>.
|
||||
func (m *IntAnyMap) Get(key int) (interface{}) {
|
||||
m.mu.RLock()
|
||||
@ -140,7 +149,7 @@ func (m *IntAnyMap) doSetWithLockCheck(key int, value interface{}) interface{} {
|
||||
// GetOrSet returns the value by key,
|
||||
// or set value with given <value> if not exist and returns this value.
|
||||
func (m *IntAnyMap) GetOrSet(key int, value interface{}) interface{} {
|
||||
if v := m.Get(key); v == nil {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, value)
|
||||
} else {
|
||||
return v
|
||||
@ -150,7 +159,7 @@ func (m *IntAnyMap) GetOrSet(key int, 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 *IntAnyMap) GetOrSetFunc(key int, f func() interface{}) interface{} {
|
||||
if v := m.Get(key); v == nil {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, f())
|
||||
} else {
|
||||
return v
|
||||
@ -163,7 +172,7 @@ func (m *IntAnyMap) GetOrSetFunc(key int, f func() interface{}) interface{} {
|
||||
// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function <f>
|
||||
// with mutex.Lock of the hash map.
|
||||
func (m *IntAnyMap) GetOrSetFuncLock(key int, f func() interface{}) interface{} {
|
||||
if v := m.Get(key); v == nil {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, f)
|
||||
} else {
|
||||
return v
|
||||
@ -317,7 +326,7 @@ func (m *IntAnyMap) RLockFunc(f func(m map[int]interface{})) {
|
||||
f(m.data)
|
||||
}
|
||||
|
||||
// Flip exchanges key-value of the map, it will change key-value to value-key.
|
||||
// Flip exchanges key-value of the map to value-key.
|
||||
func (m *IntAnyMap) Flip() {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
@ -101,6 +101,15 @@ func (m *IntIntMap) Sets(data map[int]int) {
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
// Search searches the map with given <key>.
|
||||
// Second return parameter <found> is true if key was found, otherwise false.
|
||||
func (m *IntIntMap) Search(key int) (value int, found bool) {
|
||||
m.mu.RLock()
|
||||
value, found = m.data[key]
|
||||
m.mu.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns the value by given <key>.
|
||||
func (m *IntIntMap) Get(key int) (int) {
|
||||
m.mu.RLock()
|
||||
@ -128,10 +137,7 @@ func (m *IntIntMap) doSetWithLockCheck(key int, value int) int {
|
||||
// GetOrSet returns the value by key,
|
||||
// or set value with given <value> if not exist and returns this value.
|
||||
func (m *IntIntMap) GetOrSet(key int, value int) int {
|
||||
m.mu.RLock()
|
||||
v, ok := m.data[key]
|
||||
m.mu.RUnlock()
|
||||
if !ok {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, value)
|
||||
} else {
|
||||
return v
|
||||
@ -141,10 +147,7 @@ func (m *IntIntMap) GetOrSet(key int, value int) int {
|
||||
// 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 *IntIntMap) GetOrSetFunc(key int, f func() int) int {
|
||||
m.mu.RLock()
|
||||
v, ok := m.data[key]
|
||||
m.mu.RUnlock()
|
||||
if !ok {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, f())
|
||||
} else {
|
||||
return v
|
||||
@ -157,20 +160,17 @@ func (m *IntIntMap) GetOrSetFunc(key int, f func() int) int {
|
||||
// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function <f>
|
||||
// with mutex.Lock of the hash map.
|
||||
func (m *IntIntMap) GetOrSetFuncLock(key int, f func() int) int {
|
||||
m.mu.RLock()
|
||||
val, ok := m.data[key]
|
||||
m.mu.RUnlock()
|
||||
if !ok {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
if v, ok := m.data[key]; ok {
|
||||
if v, ok = m.data[key]; ok {
|
||||
return v
|
||||
}
|
||||
val = f()
|
||||
m.data[key] = val
|
||||
return val
|
||||
v = f()
|
||||
m.data[key] = v
|
||||
return v
|
||||
} else {
|
||||
return val
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
@ -300,7 +300,7 @@ func (m *IntIntMap) RLockFunc(f func(m map[int]int)) {
|
||||
f(m.data)
|
||||
}
|
||||
|
||||
// Flip exchanges key-value of the map, it will change key-value to value-key.
|
||||
// Flip exchanges key-value of the map to value-key.
|
||||
func (m *IntIntMap) Flip() {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
@ -102,6 +102,15 @@ func (m *IntStrMap) Sets(data map[int]string) {
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
// Search searches the map with given <key>.
|
||||
// Second return parameter <found> is true if key was found, otherwise false.
|
||||
func (m *IntStrMap) Search(key int) (value string, found bool) {
|
||||
m.mu.RLock()
|
||||
value, found = m.data[key]
|
||||
m.mu.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns the value by given <key>.
|
||||
func (m *IntStrMap) Get(key int) string {
|
||||
m.mu.RLock()
|
||||
@ -129,10 +138,7 @@ func (m *IntStrMap) doSetWithLockCheck(key int, value string) string {
|
||||
// GetOrSet returns the value by key,
|
||||
// or set value with given <value> if not exist and returns this value.
|
||||
func (m *IntStrMap) GetOrSet(key int, value string) string {
|
||||
m.mu.RLock()
|
||||
v, ok := m.data[key]
|
||||
m.mu.RUnlock()
|
||||
if !ok {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, value)
|
||||
} else {
|
||||
return v
|
||||
@ -142,10 +148,7 @@ func (m *IntStrMap) GetOrSet(key int, value string) string {
|
||||
// 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 *IntStrMap) GetOrSetFunc(key int, f func() string) string {
|
||||
m.mu.RLock()
|
||||
v, ok := m.data[key]
|
||||
m.mu.RUnlock()
|
||||
if !ok {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, f())
|
||||
} else {
|
||||
return v
|
||||
@ -158,20 +161,17 @@ func (m *IntStrMap) GetOrSetFunc(key int, f func() string) string {
|
||||
// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function <f>
|
||||
// with mutex.Lock of the hash map.
|
||||
func (m *IntStrMap) GetOrSetFuncLock(key int, f func() string) string {
|
||||
m.mu.RLock()
|
||||
val, ok := m.data[key]
|
||||
m.mu.RUnlock()
|
||||
if !ok {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
if v, ok := m.data[key]; ok {
|
||||
if v, ok = m.data[key]; ok {
|
||||
return v
|
||||
}
|
||||
val = f()
|
||||
m.data[key] = val
|
||||
return val
|
||||
v = f()
|
||||
m.data[key] = v
|
||||
return v
|
||||
} else {
|
||||
return val
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
@ -301,7 +301,7 @@ func (m *IntStrMap) RLockFunc(f func(m map[int]string)) {
|
||||
f(m.data)
|
||||
}
|
||||
|
||||
// Flip exchanges key-value of the map, it will change key-value to value-key.
|
||||
// Flip exchanges key-value of the map to value-key.
|
||||
func (m *IntStrMap) Flip() {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
@ -104,6 +104,15 @@ func (m *StrAnyMap) Sets(data map[string]interface{}) {
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
// Search searches the map with given <key>.
|
||||
// Second return parameter <found> is true if key was found, otherwise false.
|
||||
func (m *StrAnyMap) Search(key string) (value interface{}, found bool) {
|
||||
m.mu.RLock()
|
||||
value, found = m.data[key]
|
||||
m.mu.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns the value by given <key>.
|
||||
func (m *StrAnyMap) Get(key string) interface{} {
|
||||
m.mu.RLock()
|
||||
@ -139,7 +148,7 @@ func (m *StrAnyMap) doSetWithLockCheck(key string, value interface{}) interface{
|
||||
// GetOrSet returns the value by key,
|
||||
// or set value with given <value> if not exist and returns this value.
|
||||
func (m *StrAnyMap) GetOrSet(key string, value interface{}) interface{} {
|
||||
if v := m.Get(key); v == nil {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, value)
|
||||
} else {
|
||||
return v
|
||||
@ -150,7 +159,7 @@ func (m *StrAnyMap) GetOrSet(key string, value interface{}) interface{} {
|
||||
// or sets value with return value of callback function <f> if not exist
|
||||
// and returns this value.
|
||||
func (m *StrAnyMap) GetOrSetFunc(key string, f func() interface{}) interface{} {
|
||||
if v := m.Get(key); v == nil {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, f())
|
||||
} else {
|
||||
return v
|
||||
@ -164,7 +173,7 @@ func (m *StrAnyMap) GetOrSetFunc(key string, f func() interface{}) interface{} {
|
||||
// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function <f>
|
||||
// with mutex.Lock of the hash map.
|
||||
func (m *StrAnyMap) GetOrSetFuncLock(key string, f func() interface{}) interface{} {
|
||||
if v := m.Get(key); v == nil {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, f)
|
||||
} else {
|
||||
return v
|
||||
@ -317,7 +326,7 @@ func (m *StrAnyMap) RLockFunc(f func(m map[string]interface{})) {
|
||||
f(m.data)
|
||||
}
|
||||
|
||||
// Flip exchanges key-value of the map, it will change key-value to value-key.
|
||||
// Flip exchanges key-value of the map to value-key.
|
||||
func (m *StrAnyMap) Flip() {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
@ -103,6 +103,15 @@ func (m *StrIntMap) Sets(data map[string]int) {
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
// Search searches the map with given <key>.
|
||||
// Second return parameter <found> is true if key was found, otherwise false.
|
||||
func (m *StrIntMap) Search(key string) (value int, found bool) {
|
||||
m.mu.RLock()
|
||||
value, found = m.data[key]
|
||||
m.mu.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns the value by given <key>.
|
||||
func (m *StrIntMap) Get(key string) int {
|
||||
m.mu.RLock()
|
||||
@ -130,10 +139,7 @@ func (m *StrIntMap) doSetWithLockCheck(key string, value int) int {
|
||||
// GetOrSet returns the value by key,
|
||||
// or set value with given <value> if not exist and returns this value.
|
||||
func (m *StrIntMap) GetOrSet(key string, value int) int {
|
||||
m.mu.RLock()
|
||||
v, ok := m.data[key]
|
||||
m.mu.RUnlock()
|
||||
if !ok {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, value)
|
||||
} else {
|
||||
return v
|
||||
@ -144,10 +150,7 @@ func (m *StrIntMap) GetOrSet(key string, value int) int {
|
||||
// or sets value with return value of callback function <f> if not exist
|
||||
// and returns this value.
|
||||
func (m *StrIntMap) GetOrSetFunc(key string, f func() int) int {
|
||||
m.mu.RLock()
|
||||
v, ok := m.data[key]
|
||||
m.mu.RUnlock()
|
||||
if !ok {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, f())
|
||||
} else {
|
||||
return v
|
||||
@ -161,20 +164,17 @@ func (m *StrIntMap) GetOrSetFunc(key string, f func() int) int {
|
||||
// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function <f>
|
||||
// with mutex.Lock of the hash map.
|
||||
func (m *StrIntMap) GetOrSetFuncLock(key string, f func() int) int {
|
||||
m.mu.RLock()
|
||||
val, ok := m.data[key]
|
||||
m.mu.RUnlock()
|
||||
if !ok {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
if v, ok := m.data[key]; ok {
|
||||
if v, ok = m.data[key]; ok {
|
||||
return v
|
||||
}
|
||||
val = f()
|
||||
m.data[key] = val
|
||||
return val
|
||||
v = f()
|
||||
m.data[key] = v
|
||||
return v
|
||||
} else {
|
||||
return val
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
@ -304,7 +304,7 @@ func (m *StrIntMap) RLockFunc(f func(m map[string]int)) {
|
||||
f(m.data)
|
||||
}
|
||||
|
||||
// Flip exchanges key-value of the map, it will change key-value to value-key.
|
||||
// Flip exchanges key-value of the map to value-key.
|
||||
func (m *StrIntMap) Flip() {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
@ -102,6 +102,15 @@ func (m *StrStrMap) Sets(data map[string]string) {
|
||||
m.mu.Unlock()
|
||||
}
|
||||
|
||||
// Search searches the map with given <key>.
|
||||
// Second return parameter <found> is true if key was found, otherwise false.
|
||||
func (m *StrStrMap) Search(key string) (value string, found bool) {
|
||||
m.mu.RLock()
|
||||
value, found = m.data[key]
|
||||
m.mu.RUnlock()
|
||||
return
|
||||
}
|
||||
|
||||
// Get returns the value by given <key>.
|
||||
func (m *StrStrMap) Get(key string) string {
|
||||
m.mu.RLock()
|
||||
@ -129,10 +138,7 @@ func (m *StrStrMap) doSetWithLockCheck(key string, value string) string {
|
||||
// GetOrSet returns the value by key,
|
||||
// or set value with given <value> if not exist and returns this value.
|
||||
func (m *StrStrMap) GetOrSet(key string, value string) string {
|
||||
m.mu.RLock()
|
||||
v, ok := m.data[key]
|
||||
m.mu.RUnlock()
|
||||
if !ok {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, value)
|
||||
} else {
|
||||
return v
|
||||
@ -143,10 +149,7 @@ func (m *StrStrMap) GetOrSet(key string, value string) string {
|
||||
// or sets value with return value of callback function <f> if not exist
|
||||
// and returns this value.
|
||||
func (m *StrStrMap) GetOrSetFunc(key string, f func() string) string {
|
||||
m.mu.RLock()
|
||||
v, ok := m.data[key]
|
||||
m.mu.RUnlock()
|
||||
if !ok {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
return m.doSetWithLockCheck(key, f())
|
||||
} else {
|
||||
return v
|
||||
@ -160,20 +163,17 @@ func (m *StrStrMap) GetOrSetFunc(key string, f func() string) string {
|
||||
// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function <f>
|
||||
// with mutex.Lock of the hash map.
|
||||
func (m *StrStrMap) GetOrSetFuncLock(key string, f func() string) string {
|
||||
m.mu.RLock()
|
||||
val, ok := m.data[key]
|
||||
m.mu.RUnlock()
|
||||
if !ok {
|
||||
if v, ok := m.Search(key); !ok {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
if v, ok := m.data[key]; ok {
|
||||
if v, ok = m.data[key]; ok {
|
||||
return v
|
||||
}
|
||||
val = f()
|
||||
m.data[key] = val
|
||||
return val
|
||||
v = f()
|
||||
m.data[key] = v
|
||||
return v
|
||||
} else {
|
||||
return val
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
@ -303,7 +303,7 @@ func (m *StrStrMap) RLockFunc(f func(m map[string]string)) {
|
||||
f(m.data)
|
||||
}
|
||||
|
||||
// Flip exchanges key-value of the map, it will change key-value to value-key.
|
||||
// Flip exchanges key-value of the map to value-key.
|
||||
func (m *StrStrMap) Flip() {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
8
g/container/gtree/gtree.go
Normal file
8
g/container/gtree/gtree.go
Normal file
@ -0,0 +1,8 @@
|
||||
// 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 gtree provides concurrent-safe/unsafe tree containers.
|
||||
package gtree
|
@ -8,6 +8,7 @@ package gtree
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/g/container/gvar"
|
||||
"github.com/gogf/gf/g/internal/rwmutex"
|
||||
)
|
||||
|
||||
@ -27,8 +28,8 @@ type RedBlackTree struct {
|
||||
|
||||
// RedBlackTreeNode is a single element within the tree
|
||||
type RedBlackTreeNode struct {
|
||||
Key interface{}
|
||||
Value interface{}
|
||||
key interface{}
|
||||
value interface{}
|
||||
color color
|
||||
left *RedBlackTreeNode
|
||||
right *RedBlackTreeNode
|
||||
@ -69,27 +70,27 @@ func (tree *RedBlackTree) Sets(data map[interface{}]interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
// doSet inserts key-value item into the tree.
|
||||
// doSet inserts key-value item into the tree without mutex.
|
||||
func (tree *RedBlackTree) doSet(key interface{}, value interface{}) {
|
||||
insertedNode := (*RedBlackTreeNode)(nil)
|
||||
if tree.root == nil {
|
||||
// Assert key is of comparator's type for initial tree
|
||||
tree.comparator(key, key)
|
||||
tree.root = &RedBlackTreeNode{Key: key, Value: value, color: red}
|
||||
tree.root = &RedBlackTreeNode{key: key, value: value, color: red}
|
||||
insertedNode = tree.root
|
||||
} else {
|
||||
node := tree.root
|
||||
loop := true
|
||||
for loop {
|
||||
compare := tree.comparator(key, node.Key)
|
||||
compare := tree.comparator(key, node.key)
|
||||
switch {
|
||||
case compare == 0:
|
||||
node.Key = key
|
||||
node.Value = value
|
||||
//node.key = key
|
||||
node.value = value
|
||||
return
|
||||
case compare < 0:
|
||||
if node.left == nil {
|
||||
node.left = &RedBlackTreeNode{Key: key, Value: value, color: red}
|
||||
node.left = &RedBlackTreeNode{key: key, value: value, color: red}
|
||||
insertedNode = node.left
|
||||
loop = false
|
||||
} else {
|
||||
@ -97,7 +98,7 @@ func (tree *RedBlackTree) doSet(key interface{}, value interface{}) {
|
||||
}
|
||||
case compare > 0:
|
||||
if node.right == nil {
|
||||
node.right = &RedBlackTreeNode{Key: key, Value: value, color: red}
|
||||
node.right = &RedBlackTreeNode{key: key, value: value, color: red}
|
||||
insertedNode = node.right
|
||||
loop = false
|
||||
} else {
|
||||
@ -113,22 +114,132 @@ func (tree *RedBlackTree) doSet(key interface{}, value interface{}) {
|
||||
|
||||
// Get searches the node in the tree by <key> and returns its value or nil if key is not found in tree.
|
||||
func (tree *RedBlackTree) Get(key interface{}) (value interface{}) {
|
||||
node := tree.Search(key)
|
||||
if node != nil {
|
||||
return node.Value
|
||||
value, _ = tree.Search(key)
|
||||
return
|
||||
}
|
||||
|
||||
// doSetWithLockCheck checks whether value of the key exists with mutex.Lock,
|
||||
// if not exists, set value to the map with given <key>,
|
||||
// or else just return the existing value.
|
||||
//
|
||||
// When setting value, if <value> is type of <func() interface {}>,
|
||||
// it will be executed with mutex.Lock of the hash map,
|
||||
// and its return value will be set to the map with <key>.
|
||||
//
|
||||
// It returns value with given <key>.
|
||||
func (tree *RedBlackTree) doSetWithLockCheck(key interface{}, value interface{}) interface{} {
|
||||
tree.mu.Lock()
|
||||
defer tree.mu.Unlock()
|
||||
if node := tree.doSearch(key); node != nil {
|
||||
return node.value
|
||||
}
|
||||
return nil
|
||||
if f, ok := value.(func() interface {}); ok {
|
||||
value = f()
|
||||
}
|
||||
tree.doSet(key, value)
|
||||
return value
|
||||
}
|
||||
|
||||
// GetOrSet returns the value by key,
|
||||
// or set value with given <value> if not exist and returns this value.
|
||||
func (tree *RedBlackTree) GetOrSet(key interface{}, value interface{}) interface{} {
|
||||
if v, ok := tree.Search(key); !ok {
|
||||
return tree.doSetWithLockCheck(key, value)
|
||||
} else {
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
// GetOrSetFunc returns the value by key,
|
||||
// or sets value with return value of callback function <f> if not exist
|
||||
// and returns this value.
|
||||
func (tree *RedBlackTree) GetOrSetFunc(key interface{}, f func() interface{}) interface{} {
|
||||
if v, ok := tree.Search(key); !ok {
|
||||
return tree.doSetWithLockCheck(key, f())
|
||||
} else {
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
// GetOrSetFuncLock returns the value by key,
|
||||
// or sets value with return value of callback function <f> if not exist
|
||||
// and returns this value.
|
||||
//
|
||||
// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function <f>
|
||||
// with mutex.Lock of the hash map.
|
||||
func (tree *RedBlackTree) GetOrSetFuncLock(key interface{}, f func() interface{}) interface{} {
|
||||
if v, ok := tree.Search(key); !ok {
|
||||
return tree.doSetWithLockCheck(key, f)
|
||||
} else {
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
// GetVar returns a gvar.Var with the value by given <key>.
|
||||
// The returned gvar.Var is un-concurrent safe.
|
||||
func (tree *RedBlackTree) GetVar(key interface{}) *gvar.Var {
|
||||
return gvar.New(tree.Get(key), true)
|
||||
}
|
||||
|
||||
// GetVarOrSet returns a gvar.Var with result from GetVarOrSet.
|
||||
// The returned gvar.Var is un-concurrent safe.
|
||||
func (tree *RedBlackTree) GetVarOrSet(key interface{}, value interface{}) *gvar.Var {
|
||||
return gvar.New(tree.GetOrSet(key, value), true)
|
||||
}
|
||||
|
||||
// GetVarOrSetFunc returns a gvar.Var with result from GetOrSetFunc.
|
||||
// The returned gvar.Var is un-concurrent safe.
|
||||
func (tree *RedBlackTree) GetVarOrSetFunc(key interface{}, f func() interface{}) *gvar.Var {
|
||||
return gvar.New(tree.GetOrSetFunc(key, f), true)
|
||||
}
|
||||
|
||||
// GetVarOrSetFuncLock returns a gvar.Var with result from GetOrSetFuncLock.
|
||||
// The returned gvar.Var is un-concurrent safe.
|
||||
func (tree *RedBlackTree) GetVarOrSetFuncLock(key interface{}, f func() interface{}) *gvar.Var {
|
||||
return gvar.New(tree.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 (tree *RedBlackTree) SetIfNotExist(key interface{}, value interface{}) bool {
|
||||
if !tree.Contains(key) {
|
||||
tree.doSetWithLockCheck(key, value)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// 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 (tree *RedBlackTree) SetIfNotExistFunc(key interface{}, f func() interface{}) bool {
|
||||
if !tree.Contains(key) {
|
||||
tree.doSetWithLockCheck(key, f())
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// SetIfNotExistFuncLock sets value with return value of callback function <f>, then return true.
|
||||
// It returns false if <key> exists, and <value> would be ignored.
|
||||
//
|
||||
// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
|
||||
// it executes function <f> with mutex.Lock of the hash map.
|
||||
func (tree *RedBlackTree) SetIfNotExistFuncLock(key interface{}, f func() interface{}) bool {
|
||||
if !tree.Contains(key) {
|
||||
tree.doSetWithLockCheck(key, f)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Contains checks whether <key> exists in the tree.
|
||||
func (tree *RedBlackTree) Contains(key interface{}) bool {
|
||||
return tree.Search(key) != nil
|
||||
_, ok := tree.Search(key)
|
||||
return ok
|
||||
}
|
||||
|
||||
// Remove removes the node from the tree by <key>.
|
||||
func (tree *RedBlackTree) Remove(key interface{}) (value interface{}) {
|
||||
tree.mu.Lock()
|
||||
defer tree.mu.Unlock()
|
||||
// doRemove removes the node from the tree by <key> without mutex.
|
||||
func (tree *RedBlackTree) doRemove(key interface{}) (value interface{}) {
|
||||
child := (*RedBlackTreeNode)(nil)
|
||||
node := tree.doSearch(key)
|
||||
if node == nil {
|
||||
@ -136,8 +247,8 @@ func (tree *RedBlackTree) Remove(key interface{}) (value interface{}) {
|
||||
}
|
||||
if node.left != nil && node.right != nil {
|
||||
p := node.left.maximumNode()
|
||||
node.Key = p.Key
|
||||
node.Value = p.Value
|
||||
node.key = p.key
|
||||
node.value = p.value
|
||||
node = p
|
||||
}
|
||||
if node.left == nil || node.right == nil {
|
||||
@ -156,10 +267,26 @@ func (tree *RedBlackTree) Remove(key interface{}) (value interface{}) {
|
||||
}
|
||||
}
|
||||
tree.size--
|
||||
value = node.Value
|
||||
value = node.value
|
||||
return
|
||||
}
|
||||
|
||||
// Remove removes the node from the tree by <key>.
|
||||
func (tree *RedBlackTree) Remove(key interface{}) (value interface{}) {
|
||||
tree.mu.Lock()
|
||||
defer tree.mu.Unlock()
|
||||
return tree.doRemove(key)
|
||||
}
|
||||
|
||||
// Removes batch deletes values of the tree by <keys>.
|
||||
func (tree *RedBlackTree) Removes(keys []interface{}) {
|
||||
tree.mu.Lock()
|
||||
defer tree.mu.Unlock()
|
||||
for key := range keys {
|
||||
tree.doRemove(key)
|
||||
}
|
||||
}
|
||||
|
||||
// IsEmpty returns true if tree does not contain any nodes.
|
||||
func (tree *RedBlackTree) IsEmpty() bool {
|
||||
return tree.Size() == 0
|
||||
@ -174,9 +301,7 @@ func (tree *RedBlackTree) Size() int {
|
||||
|
||||
// Keys returns all keys in asc order.
|
||||
func (tree *RedBlackTree) Keys() []interface{} {
|
||||
tree.mu.RLock()
|
||||
defer tree.mu.RUnlock()
|
||||
keys := make([]interface{}, tree.size)
|
||||
keys := make([]interface{}, tree.Size())
|
||||
index := 0
|
||||
tree.IteratorAsc(func(key, value interface{}) bool {
|
||||
keys[index] = key
|
||||
@ -188,9 +313,7 @@ func (tree *RedBlackTree) Keys() []interface{} {
|
||||
|
||||
// Values returns all values in asc order based on the key.
|
||||
func (tree *RedBlackTree) Values() []interface{} {
|
||||
tree.mu.RLock()
|
||||
defer tree.mu.RUnlock()
|
||||
values := make([]interface{}, tree.size)
|
||||
values := make([]interface{}, tree.Size())
|
||||
index := 0
|
||||
tree.IteratorAsc(func(key, value interface{}) bool {
|
||||
values[index] = key
|
||||
@ -202,9 +325,7 @@ func (tree *RedBlackTree) Values() []interface{} {
|
||||
|
||||
// Map returns all key-value items as map.
|
||||
func (tree *RedBlackTree) Map() map[interface{}]interface{} {
|
||||
tree.mu.RLock()
|
||||
defer tree.mu.RUnlock()
|
||||
m := make(map[interface{}]interface{}, tree.size)
|
||||
m := make(map[interface{}]interface{}, tree.Size())
|
||||
tree.IteratorAsc(func(key, value interface{}) bool {
|
||||
m[key] = value
|
||||
return true
|
||||
@ -249,7 +370,7 @@ func (tree *RedBlackTree) Floor(key interface{}) (floor *RedBlackTreeNode) {
|
||||
found := false
|
||||
node := tree.root
|
||||
for node != nil {
|
||||
compare := tree.comparator(key, node.Key)
|
||||
compare := tree.comparator(key, node.key)
|
||||
switch {
|
||||
case compare == 0:
|
||||
return node
|
||||
@ -277,7 +398,7 @@ func (tree *RedBlackTree) Ceiling(key interface{}) (ceiling *RedBlackTreeNode) {
|
||||
found := false
|
||||
node := tree.root
|
||||
for node != nil {
|
||||
compare := tree.comparator(key, node.Key)
|
||||
compare := tree.comparator(key, node.key)
|
||||
switch {
|
||||
case compare == 0:
|
||||
return node
|
||||
@ -308,7 +429,7 @@ func (tree *RedBlackTree) IteratorAsc(f func (key, value interface{}) bool) {
|
||||
if node == nil {
|
||||
break
|
||||
}
|
||||
if !f(node.Key, node.Value) {
|
||||
if !f(node.key, node.value) {
|
||||
break
|
||||
}
|
||||
if node.right != nil {
|
||||
@ -322,7 +443,7 @@ func (tree *RedBlackTree) IteratorAsc(f func (key, value interface{}) bool) {
|
||||
old := node
|
||||
for node.parent != nil {
|
||||
node = node.parent
|
||||
if tree.comparator(old.Key, node.Key) <= 0 {
|
||||
if tree.comparator(old.key, node.key) <= 0 {
|
||||
goto loop
|
||||
}
|
||||
}
|
||||
@ -345,7 +466,7 @@ func (tree *RedBlackTree) IteratorDesc(f func (key, value interface{}) bool) {
|
||||
if node == nil {
|
||||
break
|
||||
}
|
||||
if !f(node.Key, node.Value) {
|
||||
if !f(node.key, node.value) {
|
||||
break
|
||||
}
|
||||
if node.left != nil {
|
||||
@ -359,7 +480,7 @@ func (tree *RedBlackTree) IteratorDesc(f func (key, value interface{}) bool) {
|
||||
old := node
|
||||
for node.parent != nil {
|
||||
node = node.parent
|
||||
if tree.comparator(old.Key, node.Key) >= 0 {
|
||||
if tree.comparator(old.key, node.key) >= 0 {
|
||||
goto loop
|
||||
}
|
||||
}
|
||||
@ -393,15 +514,41 @@ func (tree *RedBlackTree) Print() {
|
||||
}
|
||||
|
||||
func (node *RedBlackTreeNode) String() string {
|
||||
return fmt.Sprintf("%v", node.Key)
|
||||
return fmt.Sprintf("%v", node.key)
|
||||
}
|
||||
|
||||
// Search searches the tree with given <key>.
|
||||
// It returns the node if found or otherwise nil.
|
||||
func (tree *RedBlackTree) Search(key interface{}) *RedBlackTreeNode {
|
||||
// Second return parameter <found> is true if key was found, otherwise false.
|
||||
func (tree *RedBlackTree) Search(key interface{}) (value interface{}, found bool) {
|
||||
tree.mu.RLock()
|
||||
defer tree.mu.RUnlock()
|
||||
return tree.doSearch(key)
|
||||
node := tree.doSearch(key)
|
||||
if node != nil {
|
||||
return node.value, true
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// Flip exchanges key-value of the tree to value-key.
|
||||
// Note that you should guarantee the value is the same type as key,
|
||||
// or else the comparator would panic.
|
||||
//
|
||||
// If the type of value is different with key, you pass the new <comparator>.
|
||||
func (tree *RedBlackTree) Flip(comparator...func(v1, v2 interface{}) int) {
|
||||
t := (*RedBlackTree)(nil)
|
||||
if len(comparator) > 0 {
|
||||
t = NewRedBlackTree(comparator[0], !tree.mu.IsSafe())
|
||||
} else {
|
||||
t = NewRedBlackTree(tree.comparator, !tree.mu.IsSafe())
|
||||
}
|
||||
tree.IteratorAsc(func(key, value interface{}) bool {
|
||||
t.doSet(value, key)
|
||||
return true
|
||||
})
|
||||
tree.mu.Lock()
|
||||
tree.root = t.root
|
||||
tree.size = t.size
|
||||
tree.mu.Unlock()
|
||||
}
|
||||
|
||||
func (tree *RedBlackTree) output(node *RedBlackTreeNode, prefix string, isTail bool, str *string) {
|
||||
@ -432,19 +579,16 @@ func (tree *RedBlackTree) output(node *RedBlackTreeNode, prefix string, isTail b
|
||||
}
|
||||
}
|
||||
|
||||
// Search searches the tree with given <key>.
|
||||
// Search searches the tree with given <key> without mutex.
|
||||
// It returns the node if found or otherwise nil.
|
||||
func (tree *RedBlackTree) doSearch(key interface{}) *RedBlackTreeNode {
|
||||
node := tree.root
|
||||
for node != nil {
|
||||
compare := tree.comparator(key, node.Key)
|
||||
compare := tree.comparator(key, node.key)
|
||||
switch {
|
||||
case compare == 0:
|
||||
return node
|
||||
case compare < 0:
|
||||
node = node.left
|
||||
case compare > 0:
|
||||
node = node.right
|
||||
case compare == 0: return node
|
||||
case compare < 0: node = node.left
|
||||
case compare > 0: node = node.right
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2018 gf Author(https://github.com/gogf/gf). All Rights Reserved.
|
||||
// Copyright 2018-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,
|
||||
@ -33,18 +33,6 @@ func New(value interface{}, unsafe...bool) *Var {
|
||||
return v
|
||||
}
|
||||
|
||||
// NewRead returns a read-only interface object with given <value>.
|
||||
// The param <unsafe> used to specify whether using Var in un-concurrent-safety,
|
||||
// which is false in default, means concurrent-safe.
|
||||
func NewRead(value interface{}, unsafe...bool) VarRead {
|
||||
return VarRead(New(value, unsafe...))
|
||||
}
|
||||
|
||||
// ReadOnly returns a read-only interface object of <v>.
|
||||
func (v *Var) ReadOnly() VarRead {
|
||||
return VarRead(v)
|
||||
}
|
||||
|
||||
// Set sets <value> to <v>, and returns the old value.
|
||||
func (v *Var) Set(value interface{}) (old interface{}) {
|
||||
if v.safe {
|
||||
|
@ -1,44 +0,0 @@
|
||||
// Copyright 2018 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 gvar
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/os/gtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Read-only interface.
|
||||
type VarRead interface {
|
||||
Val() interface{}
|
||||
IsNil() bool
|
||||
Bytes() []byte
|
||||
String() string
|
||||
Bool() bool
|
||||
Int() int
|
||||
Int8() int8
|
||||
Int16() int16
|
||||
Int32() int32
|
||||
Int64() int64
|
||||
Uint() uint
|
||||
Uint8() uint8
|
||||
Uint16() uint16
|
||||
Uint32() uint32
|
||||
Uint64() uint64
|
||||
Float32() float32
|
||||
Float64() float64
|
||||
Interface() interface{}
|
||||
|
||||
Ints() []int
|
||||
Floats() []float64
|
||||
Strings() []string
|
||||
Interfaces() []interface{}
|
||||
|
||||
Time(format ...string) time.Time
|
||||
TimeDuration() time.Duration
|
||||
GTime(format...string) *gtime.Time
|
||||
Struct(objPointer interface{}, attrMapping ...map[string]string) error
|
||||
}
|
@ -1,3 +1,9 @@
|
||||
// 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 gvar_test
|
||||
|
||||
import (
|
||||
@ -9,22 +15,6 @@ import (
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
)
|
||||
|
||||
func TestReadOnly(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
obj := gvar.New(nil, true)
|
||||
var result string
|
||||
|
||||
switch obj.ReadOnly().(type) {
|
||||
case gvar.VarRead:
|
||||
result = "yes"
|
||||
default:
|
||||
result = "no"
|
||||
}
|
||||
|
||||
gtest.Assert(result, "yes")
|
||||
})
|
||||
}
|
||||
|
||||
func TestSet(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
objOne := gvar.New("old", true)
|
||||
|
@ -32,7 +32,7 @@ func init() {
|
||||
// 规则:
|
||||
// 1、命令行参数以小写字母格式,使用: gf.包名.变量名 传递;
|
||||
// 2、环境变量参数以大写字母格式,使用: GF_包名_变量名 传递;
|
||||
func Get(key string, def...interface{}) gvar.VarRead {
|
||||
func Get(key string, def...interface{}) *gvar.Var {
|
||||
value := interface{}(nil)
|
||||
if len(def) > 0 {
|
||||
value = def[0]
|
||||
|
@ -76,7 +76,7 @@ func (r *Request) Get(key string, def...interface{}) string {
|
||||
}
|
||||
|
||||
// 建议都用该参数替代参数获取
|
||||
func (r *Request) GetVar(key string, def...interface{}) gvar.VarRead {
|
||||
func (r *Request) GetVar(key string, def...interface{}) *gvar.Var {
|
||||
return r.GetRequestVar(key, def...)
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ func (r *Request) SetParam(key string, value interface{}) {
|
||||
}
|
||||
|
||||
// 获取请求流程共享变量
|
||||
func (r *Request) GetParam(key string, def...interface{}) gvar.VarRead {
|
||||
func (r *Request) GetParam(key string, def...interface{}) *gvar.Var {
|
||||
if r.params != nil {
|
||||
if v, ok := r.params[key]; ok {
|
||||
return gvar.New(v, true)
|
||||
|
@ -26,7 +26,7 @@ func (r *Request) GetRequest(key string, def...interface{}) []string {
|
||||
return v
|
||||
}
|
||||
|
||||
func (r *Request) GetRequestVar(key string, def...interface{}) gvar.VarRead {
|
||||
func (r *Request) GetRequestVar(key string, def...interface{}) *gvar.Var {
|
||||
value := r.GetRequest(key, def...)
|
||||
if value != nil {
|
||||
return gvar.New(value[0], true)
|
||||
|
@ -113,7 +113,7 @@ func (s *Session) Get(key string, def...interface{}) interface{} {
|
||||
}
|
||||
|
||||
// 获取SESSION,建议都用该方法获取参数
|
||||
func (s *Session) GetVar(key string, def...interface{}) gvar.VarRead {
|
||||
func (s *Session) GetVar(key string, def...interface{}) *gvar.Var {
|
||||
return gvar.NewRead(s.Get(key, def...), true)
|
||||
}
|
||||
|
||||
|
@ -296,7 +296,7 @@ func (c *Config) Get(pattern string, def...interface{}) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Config) GetVar(pattern string, def...interface{}) gvar.VarRead {
|
||||
func (c *Config) GetVar(pattern string, def...interface{}) *gvar.Var {
|
||||
if j := c.getJson(); j != nil {
|
||||
return gvar.New(j.Get(pattern, def...), true)
|
||||
}
|
||||
|
@ -25,8 +25,8 @@ func (c *gCmdOption) Get(key string, def...string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetVar returns the option value as gvar.VarRead object specified by <key>,
|
||||
// GetVar returns the option value as *gvar.Var object specified by <key>,
|
||||
// if value does not exist, then returns <def> as its default value.
|
||||
func (c *gCmdOption) GetVar(key string, def...string) gvar.VarRead {
|
||||
func (c *gCmdOption) GetVar(key string, def...string) *gvar.Var {
|
||||
return gvar.NewRead(c.Get(key, def...), true)
|
||||
}
|
||||
|
@ -25,8 +25,8 @@ func (c *gCmdValue) Get(index int, def...string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetVar returns value by index <index> as gvar.VarRead object,
|
||||
// GetVar returns value by index <index> as *gvar.Var object,
|
||||
// if value does not exist, then returns <def> as its default value.
|
||||
func (c *gCmdValue) GetVar(index int, def...string) gvar.VarRead {
|
||||
func (c *gCmdValue) GetVar(index int, def...string) *gvar.Var {
|
||||
return gvar.NewRead(c.Get(index, def...), true)
|
||||
}
|
||||
|
@ -1,25 +1,17 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/g/container/gtree"
|
||||
)
|
||||
|
||||
func main() {
|
||||
tree := gtree.New(func(v1, v2 interface{}) int {
|
||||
tree := gtree.NewRedBlackTree(func(v1, v2 interface{}) int {
|
||||
return v1.(int) - v2.(int)
|
||||
})
|
||||
for i := 0; i < 20; i++ {
|
||||
tree.Set(i, i)
|
||||
tree.Set(i, i*10)
|
||||
}
|
||||
tree.Print()
|
||||
tree.IteratorAsc(func(key, value interface{}) bool {
|
||||
fmt.Println(key)
|
||||
return true
|
||||
})
|
||||
fmt.Println()
|
||||
tree.IteratorDesc(func(key, value interface{}) bool {
|
||||
fmt.Println(key)
|
||||
return true
|
||||
})
|
||||
tree.Flip()
|
||||
tree.Print()
|
||||
}
|
Loading…
Reference in New Issue
Block a user