add gtree.RedBlackTree container

This commit is contained in:
John 2019-05-10 13:38:06 +08:00
parent b15d8bdd2e
commit abaef9ba87
21 changed files with 334 additions and 229 deletions

View File

@ -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
}

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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()

View 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

View File

@ -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

View File

@ -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 {

View File

@ -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
}

View File

@ -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)

View File

@ -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]

View File

@ -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...)
}

View File

@ -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)

View File

@ -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)

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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()
}