feat(container/gtree): add generic tree feature (#4522)

add generic tree feature
improve gmap.TreeMap

---------

Co-authored-by: hailaz <739476267@qq.com>
This commit is contained in:
Hunk Zhu
2025-11-29 21:09:43 +08:00
committed by GitHub
parent 5a67aac85d
commit 777d7aabb5
10 changed files with 1976 additions and 780 deletions

View File

@ -0,0 +1,32 @@
// Copyright GoFrame Author(https://goframe.org). 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.
//go:build go1.24
package gmap
import (
"github.com/gogf/gf/v2/container/gtree"
)
// TreeKVMap based on red-black tree, alias of RedBlackKVTree.
type TreeKVMap[K comparable, V any] = gtree.RedBlackKVTree[K, V]
// NewTreeKVMap instantiates a tree map with the custom comparator.
// The parameter `safe` is used to specify whether using tree in concurrent-safety,
// which is false in default.
func NewTreeKVMap[K comparable, V any](comparator func(v1, v2 K) int, safe ...bool) *TreeKVMap[K, V] {
return gtree.NewRedBlackKVTree[K, V](comparator, safe...)
}
// NewTreeKVMapFrom instantiates a tree map with the custom comparator and `data` map.
// 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.
// The parameter `safe` is used to specify whether using tree in concurrent-safety,
// which is false in default.
func NewTreeKVMapFrom[K comparable, V any](comparator func(v1, v2 K) int, data map[K]V, safe ...bool) *TreeKVMap[K, V] {
return gtree.NewRedBlackKVTreeFrom(comparator, data, safe...)
}

View File

@ -162,12 +162,12 @@ type iTree interface {
IteratorDescFrom(key any, match bool, f func(key, value any) bool)
}
// iteratorFromGetIndex returns the index of the key in the keys slice.
// iteratorFromGetIndexT returns the index of the key in the keys slice.
//
// The parameter `match` specifies whether starting iterating only if the `key` is fully matched,
// or else using index searching iterating.
// If `isIterator` is true, iterator is available; or else not.
func iteratorFromGetIndex(key any, keys []any, match bool) (index int, canIterator bool) {
func iteratorFromGetIndexT[T comparable](key T, keys []T, match bool) (index int, canIterator bool) {
if match {
for i, k := range keys {
if k == key {
@ -176,10 +176,19 @@ func iteratorFromGetIndex(key any, keys []any, match bool) (index int, canIterat
}
}
} else {
if i, ok := key.(int); ok {
if i, ok := any(key).(int); ok {
canIterator = true
index = i
}
}
return
}
// iteratorFromGetIndex returns the index of the key in the keys slice.
//
// The parameter `match` specifies whether starting iterating only if the `key` is fully matched,
// or else using index searching iterating.
// If `isIterator` is true, iterator is available; or else not.
func iteratorFromGetIndex(key any, keys []any, match bool) (index int, canIterator bool) {
return iteratorFromGetIndexT(key, keys, match)
}

View File

@ -7,31 +7,22 @@
package gtree
import (
"fmt"
"github.com/emirpasic/gods/trees/avltree"
"sync"
"github.com/gogf/gf/v2/container/gvar"
"github.com/gogf/gf/v2/internal/rwmutex"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/util/gutil"
)
var _ iTree = (*AVLTree)(nil)
// AVLTree holds elements of the AVL tree.
type AVLTree struct {
mu rwmutex.RWMutex
root *AVLTreeNode
comparator func(v1, v2 any) int
tree *avltree.Tree
*AVLKVTree[any, any]
once sync.Once
}
// AVLTreeNode is a single element within the tree.
type AVLTreeNode struct {
Key any
Value any
}
type AVLTreeNode = AVLKVTreeNode[any, any]
// NewAVLTree instantiates an AVL tree with the custom key comparator.
//
@ -39,9 +30,7 @@ type AVLTreeNode struct {
// which is false in default.
func NewAVLTree(comparator func(v1, v2 any) int, safe ...bool) *AVLTree {
return &AVLTree{
mu: rwmutex.Create(safe...),
comparator: comparator,
tree: avltree.NewWith(comparator),
AVLKVTree: NewAVLKVTree[any, any](comparator, safe...),
}
}
@ -49,58 +38,55 @@ func NewAVLTree(comparator func(v1, v2 any) int, safe ...bool) *AVLTree {
//
// The parameter `safe` is used to specify whether using tree in concurrent-safety, which is false in default.
func NewAVLTreeFrom(comparator func(v1, v2 any) int, data map[any]any, safe ...bool) *AVLTree {
tree := NewAVLTree(comparator, safe...)
for k, v := range data {
tree.doSet(k, v)
return &AVLTree{
AVLKVTree: NewAVLKVTreeFrom(comparator, data, safe...),
}
return tree
}
// lazyInit lazily initializes the tree.
func (tree *AVLTree) lazyInit() {
tree.once.Do(func() {
if tree.AVLKVTree == nil {
tree.AVLKVTree = NewAVLKVTree[any, any](gutil.ComparatorTStr, false)
}
})
}
// Clone clones and returns a new tree from current tree.
func (tree *AVLTree) Clone() *AVLTree {
newTree := NewAVLTree(tree.comparator, tree.mu.IsSafe())
newTree.Sets(tree.Map())
return newTree
if tree == nil {
return nil
}
tree.lazyInit()
return &AVLTree{
AVLKVTree: tree.AVLKVTree.Clone(),
}
}
// Set sets key-value pair into the tree.
func (tree *AVLTree) Set(key any, value any) {
tree.mu.Lock()
defer tree.mu.Unlock()
tree.doSet(key, value)
tree.lazyInit()
tree.AVLKVTree.Set(key, value)
}
// Sets batch sets key-values to the tree.
func (tree *AVLTree) Sets(data map[any]any) {
tree.mu.Lock()
defer tree.mu.Unlock()
for key, value := range data {
tree.doSet(key, value)
}
tree.lazyInit()
tree.AVLKVTree.Sets(data)
}
// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.
// It returns false if `key` exists, and such setting key-value pair operation would be ignored.
func (tree *AVLTree) SetIfNotExist(key any, value any) bool {
tree.mu.Lock()
defer tree.mu.Unlock()
if _, ok := tree.doGet(key); !ok {
tree.doSet(key, value)
return true
}
return false
tree.lazyInit()
return tree.AVLKVTree.SetIfNotExist(key, value)
}
// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.
// It returns false if `key` exists, and such setting key-value pair operation would be ignored.
func (tree *AVLTree) SetIfNotExistFunc(key any, f func() any) bool {
tree.mu.Lock()
defer tree.mu.Unlock()
if _, ok := tree.doGet(key); !ok {
tree.doSet(key, f())
return true
}
return false
tree.lazyInit()
return tree.AVLKVTree.SetIfNotExistFunc(key, f)
}
// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.
@ -109,13 +95,8 @@ func (tree *AVLTree) SetIfNotExistFunc(key any, f func() any) bool {
// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
// it executes function `f` within mutex lock.
func (tree *AVLTree) SetIfNotExistFuncLock(key any, f func() any) bool {
tree.mu.Lock()
defer tree.mu.Unlock()
if _, ok := tree.doGet(key); !ok {
tree.doSet(key, f)
return true
}
return false
tree.lazyInit()
return tree.AVLKVTree.SetIfNotExistFuncLock(key, f)
}
// Get searches the `key` in the tree and returns its associated `value` or nil if key is not found in tree.
@ -123,32 +104,22 @@ func (tree *AVLTree) SetIfNotExistFuncLock(key any, f func() any) bool {
// Note that, the `nil` value from Get function cannot be used to determine key existence, please use Contains function
// to do so.
func (tree *AVLTree) Get(key any) (value any) {
value, _ = tree.Search(key)
return
tree.lazyInit()
return tree.AVLKVTree.Get(key)
}
// GetOrSet returns its `value` of `key`, or sets value with given `value` if it does not exist and then returns
// this value.
func (tree *AVLTree) GetOrSet(key any, value any) any {
tree.mu.Lock()
defer tree.mu.Unlock()
if v, ok := tree.doGet(key); !ok {
return tree.doSet(key, value)
} else {
return v
}
tree.lazyInit()
return tree.AVLKVTree.GetOrSet(key, value)
}
// GetOrSetFunc returns its `value` of `key`, or sets value with returned value of callback function `f` if it does not
// exist and then returns this value.
func (tree *AVLTree) GetOrSetFunc(key any, f func() any) any {
tree.mu.Lock()
defer tree.mu.Unlock()
if v, ok := tree.doGet(key); !ok {
return tree.doSet(key, f())
} else {
return v
}
tree.lazyInit()
return tree.AVLKVTree.GetOrSetFunc(key, f)
}
// GetOrSetFuncLock returns its `value` of `key`, or sets value with returned value of callback function `f` if it does
@ -156,13 +127,8 @@ func (tree *AVLTree) GetOrSetFunc(key any, f func() any) any {
//
// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f` within mutex lock.
func (tree *AVLTree) GetOrSetFuncLock(key any, f func() any) any {
tree.mu.Lock()
defer tree.mu.Unlock()
if v, ok := tree.doGet(key); !ok {
return tree.doSet(key, f)
} else {
return v
}
tree.lazyInit()
return tree.AVLKVTree.GetOrSetFuncLock(key, f)
}
// GetVar returns a gvar.Var with the value by given `key`.
@ -170,7 +136,8 @@ func (tree *AVLTree) GetOrSetFuncLock(key any, f func() any) any {
//
// Also see function Get.
func (tree *AVLTree) GetVar(key any) *gvar.Var {
return gvar.New(tree.Get(key))
tree.lazyInit()
return tree.AVLKVTree.GetVar(key)
}
// GetVarOrSet returns a gvar.Var with result from GetVarOrSet.
@ -178,7 +145,8 @@ func (tree *AVLTree) GetVar(key any) *gvar.Var {
//
// Also see function GetOrSet.
func (tree *AVLTree) GetVarOrSet(key any, value any) *gvar.Var {
return gvar.New(tree.GetOrSet(key, value))
tree.lazyInit()
return tree.AVLKVTree.GetVarOrSet(key, value)
}
// GetVarOrSetFunc returns a gvar.Var with result from GetOrSetFunc.
@ -186,7 +154,8 @@ func (tree *AVLTree) GetVarOrSet(key any, value any) *gvar.Var {
//
// Also see function GetOrSetFunc.
func (tree *AVLTree) GetVarOrSetFunc(key any, f func() any) *gvar.Var {
return gvar.New(tree.GetOrSetFunc(key, f))
tree.lazyInit()
return tree.AVLKVTree.GetVarOrSetFunc(key, f)
}
// GetVarOrSetFuncLock returns a gvar.Var with result from GetOrSetFuncLock.
@ -194,127 +163,100 @@ func (tree *AVLTree) GetVarOrSetFunc(key any, f func() any) *gvar.Var {
//
// Also see function GetOrSetFuncLock.
func (tree *AVLTree) GetVarOrSetFuncLock(key any, f func() any) *gvar.Var {
return gvar.New(tree.GetOrSetFuncLock(key, f))
tree.lazyInit()
return tree.AVLKVTree.GetVarOrSetFuncLock(key, f)
}
// Search searches the tree with given `key`.
// Second return parameter `found` is true if key was found, otherwise false.
func (tree *AVLTree) Search(key any) (value any, found bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
if node, found := tree.doGet(key); found {
return node, true
}
return nil, false
tree.lazyInit()
return tree.AVLKVTree.Search(key)
}
// Contains checks and returns whether given `key` exists in the tree.
func (tree *AVLTree) Contains(key any) bool {
tree.mu.RLock()
defer tree.mu.RUnlock()
_, ok := tree.doGet(key)
return ok
tree.lazyInit()
return tree.AVLKVTree.Contains(key)
}
// Size returns number of nodes in the tree.
func (tree *AVLTree) Size() int {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.Size()
tree.lazyInit()
return tree.AVLKVTree.Size()
}
// IsEmpty returns true if the tree does not contain any nodes.
func (tree *AVLTree) IsEmpty() bool {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.Size() == 0
tree.lazyInit()
return tree.AVLKVTree.IsEmpty()
}
// Remove removes the node from the tree by `key`, and returns its associated value of `key`.
// The given `key` should adhere to the comparator's type assertion, otherwise method panics.
func (tree *AVLTree) Remove(key any) (value any) {
tree.mu.Lock()
defer tree.mu.Unlock()
return tree.doRemove(key)
tree.lazyInit()
return tree.AVLKVTree.Remove(key)
}
// Removes batch deletes key-value pairs from the tree by `keys`.
func (tree *AVLTree) Removes(keys []any) {
tree.mu.Lock()
defer tree.mu.Unlock()
for _, key := range keys {
tree.doRemove(key)
}
tree.lazyInit()
tree.AVLKVTree.Removes(keys)
}
// Clear removes all nodes from the tree.
func (tree *AVLTree) Clear() {
tree.mu.Lock()
defer tree.mu.Unlock()
tree.tree.Clear()
tree.lazyInit()
tree.AVLKVTree.Clear()
}
// Keys returns all keys from the tree in order by its comparator.
func (tree *AVLTree) Keys() []any {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.Keys()
tree.lazyInit()
return tree.AVLKVTree.Keys()
}
// Values returns all values from the true in order by its comparator based on the key.
func (tree *AVLTree) Values() []any {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.Values()
tree.lazyInit()
return tree.AVLKVTree.Values()
}
// Replace clears the data of the tree and sets the nodes by given `data`.
func (tree *AVLTree) Replace(data map[any]any) {
tree.mu.Lock()
defer tree.mu.Unlock()
tree.tree.Clear()
for k, v := range data {
tree.doSet(k, v)
}
tree.lazyInit()
tree.AVLKVTree.Replace(data)
}
// Print prints the tree to stdout.
func (tree *AVLTree) Print() {
fmt.Println(tree.String())
tree.lazyInit()
tree.AVLKVTree.Print()
}
// String returns a string representation of container.
func (tree *AVLTree) String() string {
tree.mu.RLock()
defer tree.mu.RUnlock()
return gstr.Replace(tree.tree.String(), "AVLTree\n", "")
tree.lazyInit()
return tree.AVLKVTree.String()
}
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
func (tree *AVLTree) MarshalJSON() (jsonBytes []byte, err error) {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.MarshalJSON()
tree.lazyInit()
return tree.AVLKVTree.MarshalJSON()
}
// Map returns all key-value pairs as map.
func (tree *AVLTree) Map() map[any]any {
m := make(map[any]any, tree.Size())
tree.IteratorAsc(func(key, value any) bool {
m[key] = value
return true
})
return m
tree.lazyInit()
return tree.AVLKVTree.Map()
}
// MapStrAny returns all key-value items as map[string]any.
func (tree *AVLTree) MapStrAny() map[string]any {
m := make(map[string]any, tree.Size())
tree.IteratorAsc(func(key, value any) bool {
m[gconv.String(key)] = value
return true
})
return m
tree.lazyInit()
return tree.AVLKVTree.MapStrAny()
}
// Iterator is alias of IteratorAsc.
@ -334,18 +276,8 @@ func (tree *AVLTree) IteratorFrom(key any, match bool, f func(key, value any) bo
// IteratorAsc iterates the tree readonly in ascending order with given callback function `f`.
// If callback function `f` returns true, then it continues iterating; or false to stop.
func (tree *AVLTree) IteratorAsc(f func(key, value any) bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
var (
ok bool
it = tree.tree.Iterator()
)
for it.Begin(); it.Next(); {
index, value := it.Key(), it.Value()
if ok = f(index, value); !ok {
break
}
}
tree.lazyInit()
tree.AVLKVTree.IteratorAsc(f)
}
// IteratorAscFrom iterates the tree readonly in ascending order with given callback function `f`.
@ -355,34 +287,16 @@ func (tree *AVLTree) IteratorAsc(f func(key, value any) bool) {
// searching iterating.
// If callback function `f` returns true, then it continues iterating; or false to stop.
func (tree *AVLTree) IteratorAscFrom(key any, match bool, f func(key, value any) bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
var keys = tree.tree.Keys()
index, canIterator := iteratorFromGetIndex(key, keys, match)
if !canIterator {
return
}
for ; index < len(keys); index++ {
f(keys[index], tree.Get(keys[index]))
}
tree.lazyInit()
tree.AVLKVTree.IteratorAscFrom(key, match, f)
}
// IteratorDesc iterates the tree readonly in descending order with given callback function `f`.
//
// If callback function `f` returns true, then it continues iterating; or false to stop.
func (tree *AVLTree) IteratorDesc(f func(key, value any) bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
var (
ok bool
it = tree.tree.Iterator()
)
for it.End(); it.Prev(); {
index, value := it.Key(), it.Value()
if ok = f(index, value); !ok {
break
}
}
tree.lazyInit()
tree.AVLKVTree.IteratorDesc(f)
}
// IteratorDescFrom iterates the tree readonly in descending order with given callback function `f`.
@ -392,44 +306,20 @@ func (tree *AVLTree) IteratorDesc(f func(key, value any) bool) {
// searching iterating.
// If callback function `f` returns true, then it continues iterating; or false to stop.
func (tree *AVLTree) IteratorDescFrom(key any, match bool, f func(key, value any) bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
var keys = tree.tree.Keys()
index, canIterator := iteratorFromGetIndex(key, keys, match)
if !canIterator {
return
}
for ; index >= 0; index-- {
f(keys[index], tree.Get(keys[index]))
}
tree.lazyInit()
tree.AVLKVTree.IteratorDescFrom(key, match, f)
}
// Left returns the minimum element corresponding to the comparator of the tree or nil if the tree is empty.
func (tree *AVLTree) Left() *AVLTreeNode {
tree.mu.RLock()
defer tree.mu.RUnlock()
node := tree.tree.Left()
if node == nil {
return nil
}
return &AVLTreeNode{
Key: node.Key,
Value: node.Value,
}
tree.lazyInit()
return tree.AVLKVTree.Left()
}
// Right returns the maximum element corresponding to the comparator of the tree or nil if the tree is empty.
func (tree *AVLTree) Right() *AVLTreeNode {
tree.mu.RLock()
defer tree.mu.RUnlock()
node := tree.tree.Right()
if node == nil {
return nil
}
return &AVLTreeNode{
Key: node.Key,
Value: node.Value,
}
tree.lazyInit()
return tree.AVLKVTree.Right()
}
// Floor Finds floor node of the input key, returns the floor node or nil if no floor node is found.
@ -441,16 +331,8 @@ func (tree *AVLTree) Right() *AVLTreeNode {
//
// Key should adhere to the comparator's type assertion, otherwise method panics.
func (tree *AVLTree) Floor(key any) (floor *AVLTreeNode, found bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
node, ok := tree.tree.Floor(key)
if !ok {
return nil, false
}
return &AVLTreeNode{
Key: node.Key,
Value: node.Value,
}, true
tree.lazyInit()
return tree.AVLKVTree.Floor(key)
}
// Ceiling finds ceiling node of the input key, returns the ceiling node or nil if no ceiling node is found.
@ -462,16 +344,8 @@ func (tree *AVLTree) Floor(key any) (floor *AVLTreeNode, found bool) {
//
// Key should adhere to the comparator's type assertion, otherwise method panics.
func (tree *AVLTree) Ceiling(key any) (ceiling *AVLTreeNode, found bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
node, ok := tree.tree.Ceiling(key)
if !ok {
return nil, false
}
return &AVLTreeNode{
Key: node.Key,
Value: node.Value,
}, true
tree.lazyInit()
return tree.AVLKVTree.Ceiling(key)
}
// Flip exchanges key-value of the tree to value-key.
@ -480,6 +354,8 @@ func (tree *AVLTree) Ceiling(key any) (ceiling *AVLTreeNode, found bool) {
//
// If the type of value is different with key, you pass the new `comparator`.
func (tree *AVLTree) Flip(comparator ...func(v1, v2 any) int) {
tree.lazyInit()
var t = new(AVLTree)
if len(comparator) > 0 {
t = NewAVLTree(comparator[0], tree.mu.IsSafe())
@ -493,32 +369,3 @@ func (tree *AVLTree) Flip(comparator ...func(v1, v2 any) int) {
tree.Clear()
tree.Sets(t.Map())
}
// doSet inserts key-value pair node into the tree without lock.
// If `key` already exists, then its value is updated with the new value.
// If `value` is type of <func() any>, it will be executed and its return value will be set to the map with `key`.
//
// It returns value with given `key`.
func (tree *AVLTree) doSet(key, value any) any {
if f, ok := value.(func() any); ok {
value = f()
}
if value == nil {
return value
}
tree.tree.Put(key, value)
return value
}
// doGet retrieves and returns the value of given key from tree without lock.
func (tree *AVLTree) doGet(key any) (value any, found bool) {
return tree.tree.Get(key)
}
// doRemove removes key from tree and returns its associated value without lock.
// Note that, the given `key` should adhere to the comparator's type assertion, otherwise method panics.
func (tree *AVLTree) doRemove(key any) (value any) {
value, _ = tree.tree.Get(key)
tree.tree.Remove(key)
return
}

View File

@ -7,31 +7,22 @@
package gtree
import (
"fmt"
"github.com/emirpasic/gods/trees/btree"
"sync"
"github.com/gogf/gf/v2/container/gvar"
"github.com/gogf/gf/v2/internal/rwmutex"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/util/gutil"
)
var _ iTree = (*BTree)(nil)
// BTree holds elements of the B-tree.
type BTree struct {
mu rwmutex.RWMutex
comparator func(v1, v2 any) int
m int // order (maximum number of children)
tree *btree.Tree
*BKVTree[any, any]
once sync.Once
}
// BTreeEntry represents the key-value pair contained within nodes.
type BTreeEntry struct {
Key any
Value any
}
type BTreeEntry = BKVTreeEntry[any, any]
// NewBTree instantiates a B-tree with `m` (maximum number of children) and a custom key comparator.
// The parameter `safe` is used to specify whether using tree in concurrent-safety,
@ -39,10 +30,7 @@ type BTreeEntry struct {
// Note that the `m` must be greater or equal than 3, or else it panics.
func NewBTree(m int, comparator func(v1, v2 any) int, safe ...bool) *BTree {
return &BTree{
mu: rwmutex.Create(safe...),
m: m,
comparator: comparator,
tree: btree.NewWith(m, comparator),
BKVTree: NewBKVTree[any, any](m, comparator, safe...),
}
}
@ -50,58 +38,55 @@ func NewBTree(m int, comparator func(v1, v2 any) int, safe ...bool) *BTree {
// The parameter `safe` is used to specify whether using tree in concurrent-safety,
// which is false in default.
func NewBTreeFrom(m int, comparator func(v1, v2 any) int, data map[any]any, safe ...bool) *BTree {
tree := NewBTree(m, comparator, safe...)
for k, v := range data {
tree.doSet(k, v)
return &BTree{
BKVTree: NewBKVTreeFrom(m, comparator, data, safe...),
}
return tree
}
// lazyInit lazily initializes the tree.
func (tree *BTree) lazyInit() {
tree.once.Do(func() {
if tree.BKVTree == nil {
tree.BKVTree = NewBKVTree[any, any](3, gutil.ComparatorTStr, false)
}
})
}
// Clone clones and returns a new tree from current tree.
func (tree *BTree) Clone() *BTree {
newTree := NewBTree(tree.m, tree.comparator, tree.mu.IsSafe())
newTree.Sets(tree.Map())
return newTree
if tree == nil {
return nil
}
tree.lazyInit()
return &BTree{
BKVTree: tree.BKVTree.Clone(),
}
}
// Set sets key-value pair into the tree.
func (tree *BTree) Set(key any, value any) {
tree.mu.Lock()
defer tree.mu.Unlock()
tree.doSet(key, value)
tree.lazyInit()
tree.BKVTree.Set(key, value)
}
// Sets batch sets key-values to the tree.
func (tree *BTree) Sets(data map[any]any) {
tree.mu.Lock()
defer tree.mu.Unlock()
for k, v := range data {
tree.doSet(k, v)
}
tree.lazyInit()
tree.BKVTree.Sets(data)
}
// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.
// It returns false if `key` exists, and such setting key-value pair operation would be ignored.
func (tree *BTree) SetIfNotExist(key any, value any) bool {
tree.mu.Lock()
defer tree.mu.Unlock()
if _, ok := tree.doGet(key); !ok {
tree.doSet(key, value)
return true
}
return false
tree.lazyInit()
return tree.BKVTree.SetIfNotExist(key, value)
}
// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.
// It returns false if `key` exists, and such setting key-value pair operation would be ignored.
func (tree *BTree) SetIfNotExistFunc(key any, f func() any) bool {
tree.mu.Lock()
defer tree.mu.Unlock()
if _, ok := tree.doGet(key); !ok {
tree.doSet(key, f())
return true
}
return false
tree.lazyInit()
return tree.BKVTree.SetIfNotExistFunc(key, f)
}
// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.
@ -110,13 +95,8 @@ func (tree *BTree) SetIfNotExistFunc(key any, f func() any) bool {
// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
// it executes function `f` within mutex lock.
func (tree *BTree) SetIfNotExistFuncLock(key any, f func() any) bool {
tree.mu.Lock()
defer tree.mu.Unlock()
if _, ok := tree.doGet(key); !ok {
tree.doSet(key, f)
return true
}
return false
tree.lazyInit()
return tree.BKVTree.SetIfNotExistFuncLock(key, f)
}
// Get searches the `key` in the tree and returns its associated `value` or nil if key is not found in tree.
@ -124,34 +104,22 @@ func (tree *BTree) SetIfNotExistFuncLock(key any, f func() any) bool {
// Note that, the `nil` value from Get function cannot be used to determine key existence, please use Contains function
// to do so.
func (tree *BTree) Get(key any) (value any) {
tree.mu.Lock()
defer tree.mu.Unlock()
value, _ = tree.doGet(key)
return
tree.lazyInit()
return tree.BKVTree.Get(key)
}
// GetOrSet returns its `value` of `key`, or sets value with given `value` if it does not exist and then returns
// this value.
func (tree *BTree) GetOrSet(key any, value any) any {
tree.mu.Lock()
defer tree.mu.Unlock()
if v, ok := tree.doGet(key); !ok {
return tree.doSet(key, value)
} else {
return v
}
tree.lazyInit()
return tree.BKVTree.GetOrSet(key, value)
}
// GetOrSetFunc returns its `value` of `key`, or sets value with returned value of callback function `f` if it does not
// exist and then returns this value.
func (tree *BTree) GetOrSetFunc(key any, f func() any) any {
tree.mu.Lock()
defer tree.mu.Unlock()
if v, ok := tree.doGet(key); !ok {
return tree.doSet(key, f())
} else {
return v
}
tree.lazyInit()
return tree.BKVTree.GetOrSetFunc(key, f)
}
// GetOrSetFuncLock returns its `value` of `key`, or sets value with returned value of callback function `f` if it does
@ -159,13 +127,8 @@ func (tree *BTree) GetOrSetFunc(key any, f func() any) any {
//
// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f` within mutex lock.
func (tree *BTree) GetOrSetFuncLock(key any, f func() any) any {
tree.mu.Lock()
defer tree.mu.Unlock()
if v, ok := tree.doGet(key); !ok {
return tree.doSet(key, f)
} else {
return v
}
tree.lazyInit()
return tree.BKVTree.GetOrSetFuncLock(key, f)
}
// GetVar returns a gvar.Var with the value by given `key`.
@ -173,7 +136,8 @@ func (tree *BTree) GetOrSetFuncLock(key any, f func() any) any {
//
// Also see function Get.
func (tree *BTree) GetVar(key any) *gvar.Var {
return gvar.New(tree.Get(key))
tree.lazyInit()
return tree.BKVTree.GetVar(key)
}
// GetVarOrSet returns a gvar.Var with result from GetVarOrSet.
@ -181,7 +145,8 @@ func (tree *BTree) GetVar(key any) *gvar.Var {
//
// Also see function GetOrSet.
func (tree *BTree) GetVarOrSet(key any, value any) *gvar.Var {
return gvar.New(tree.GetOrSet(key, value))
tree.lazyInit()
return tree.BKVTree.GetVarOrSet(key, value)
}
// GetVarOrSetFunc returns a gvar.Var with result from GetOrSetFunc.
@ -189,7 +154,8 @@ func (tree *BTree) GetVarOrSet(key any, value any) *gvar.Var {
//
// Also see function GetOrSetFunc.
func (tree *BTree) GetVarOrSetFunc(key any, f func() any) *gvar.Var {
return gvar.New(tree.GetOrSetFunc(key, f))
tree.lazyInit()
return tree.BKVTree.GetVarOrSetFunc(key, f)
}
// GetVarOrSetFuncLock returns a gvar.Var with result from GetOrSetFuncLock.
@ -197,155 +163,123 @@ func (tree *BTree) GetVarOrSetFunc(key any, f func() any) *gvar.Var {
//
// Also see function GetOrSetFuncLock.
func (tree *BTree) GetVarOrSetFuncLock(key any, f func() any) *gvar.Var {
return gvar.New(tree.GetOrSetFuncLock(key, f))
tree.lazyInit()
return tree.BKVTree.GetVarOrSetFuncLock(key, f)
}
// Search searches the tree with given `key`.
// Second return parameter `found` is true if key was found, otherwise false.
func (tree *BTree) Search(key any) (value any, found bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.Get(key)
tree.lazyInit()
return tree.BKVTree.Search(key)
}
// Contains checks and returns whether given `key` exists in the tree.
func (tree *BTree) Contains(key any) bool {
tree.mu.RLock()
defer tree.mu.RUnlock()
_, ok := tree.doGet(key)
return ok
tree.lazyInit()
return tree.BKVTree.Contains(key)
}
// Size returns number of nodes in the tree.
func (tree *BTree) Size() int {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.Size()
tree.lazyInit()
return tree.BKVTree.Size()
}
// IsEmpty returns true if tree does not contain any nodes
func (tree *BTree) IsEmpty() bool {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.Size() == 0
tree.lazyInit()
return tree.BKVTree.IsEmpty()
}
// Remove removes the node from the tree by `key`, and returns its associated value of `key`.
// The given `key` should adhere to the comparator's type assertion, otherwise method panics.
func (tree *BTree) Remove(key any) (value any) {
tree.mu.Lock()
defer tree.mu.Unlock()
return tree.doRemove(key)
tree.lazyInit()
return tree.BKVTree.Remove(key)
}
// Removes batch deletes key-value pairs from the tree by `keys`.
func (tree *BTree) Removes(keys []any) {
tree.mu.Lock()
defer tree.mu.Unlock()
for _, key := range keys {
tree.doRemove(key)
}
tree.lazyInit()
tree.BKVTree.Removes(keys)
}
// Clear removes all nodes from the tree.
func (tree *BTree) Clear() {
tree.mu.Lock()
defer tree.mu.Unlock()
tree.tree.Clear()
tree.lazyInit()
tree.BKVTree.Clear()
}
// Keys returns all keys from the tree in order by its comparator.
func (tree *BTree) Keys() []any {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.Keys()
tree.lazyInit()
return tree.BKVTree.Keys()
}
// Values returns all values from the true in order by its comparator based on the key.
func (tree *BTree) Values() []any {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.Values()
tree.lazyInit()
return tree.BKVTree.Values()
}
// Replace clears the data of the tree and sets the nodes by given `data`.
func (tree *BTree) Replace(data map[any]any) {
tree.mu.Lock()
defer tree.mu.Unlock()
tree.tree.Clear()
for k, v := range data {
tree.doSet(k, v)
}
tree.lazyInit()
tree.BKVTree.Replace(data)
}
// Map returns all key-value pairs as map.
func (tree *BTree) Map() map[any]any {
m := make(map[any]any, tree.Size())
tree.IteratorAsc(func(key, value any) bool {
m[key] = value
return true
})
return m
tree.lazyInit()
return tree.BKVTree.Map()
}
// MapStrAny returns all key-value items as map[string]any.
func (tree *BTree) MapStrAny() map[string]any {
m := make(map[string]any, tree.Size())
tree.IteratorAsc(func(key, value any) bool {
m[gconv.String(key)] = value
return true
})
return m
tree.lazyInit()
return tree.BKVTree.MapStrAny()
}
// Print prints the tree to stdout.
func (tree *BTree) Print() {
fmt.Println(tree.String())
tree.lazyInit()
tree.BKVTree.Print()
}
// String returns a string representation of container (for debugging purposes)
func (tree *BTree) String() string {
tree.mu.RLock()
defer tree.mu.RUnlock()
return gstr.Replace(tree.tree.String(), "BTree\n", "")
tree.lazyInit()
return tree.BKVTree.String()
}
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
func (tree *BTree) MarshalJSON() (jsonBytes []byte, err error) {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.MarshalJSON()
tree.lazyInit()
return tree.BKVTree.MarshalJSON()
}
// Iterator is alias of IteratorAsc.
//
// Also see IteratorAsc.
func (tree *BTree) Iterator(f func(key, value any) bool) {
tree.IteratorAsc(f)
tree.lazyInit()
tree.BKVTree.Iterator(f)
}
// IteratorFrom is alias of IteratorAscFrom.
//
// Also see IteratorAscFrom.
func (tree *BTree) IteratorFrom(key any, match bool, f func(key, value any) bool) {
tree.IteratorAscFrom(key, match, f)
tree.lazyInit()
tree.BKVTree.IteratorFrom(key, match, f)
}
// IteratorAsc iterates the tree readonly in ascending order with given callback function `f`.
// If callback function `f` returns true, then it continues iterating; or false to stop.
func (tree *BTree) IteratorAsc(f func(key, value any) bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
var (
ok bool
it = tree.tree.Iterator()
)
for it.Begin(); it.Next(); {
index, value := it.Key(), it.Value()
if ok = f(index, value); !ok {
break
}
}
tree.lazyInit()
tree.BKVTree.IteratorAsc(f)
}
// IteratorAscFrom iterates the tree readonly in ascending order with given callback function `f`.
@ -355,34 +289,16 @@ func (tree *BTree) IteratorAsc(f func(key, value any) bool) {
// searching iterating.
// If callback function `f` returns true, then it continues iterating; or false to stop.
func (tree *BTree) IteratorAscFrom(key any, match bool, f func(key, value any) bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
var keys = tree.tree.Keys()
index, canIterator := iteratorFromGetIndex(key, keys, match)
if !canIterator {
return
}
for ; index < len(keys); index++ {
f(keys[index], tree.Get(keys[index]))
}
tree.lazyInit()
tree.BKVTree.IteratorAscFrom(key, match, f)
}
// IteratorDesc iterates the tree readonly in descending order with given callback function `f`.
//
// If callback function `f` returns true, then it continues iterating; or false to stop.
func (tree *BTree) IteratorDesc(f func(key, value any) bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
var (
ok bool
it = tree.tree.Iterator()
)
for it.End(); it.Prev(); {
index, value := it.Key(), it.Value()
if ok = f(index, value); !ok {
break
}
}
tree.lazyInit()
tree.BKVTree.IteratorDesc(f)
}
// IteratorDescFrom iterates the tree readonly in descending order with given callback function `f`.
@ -392,78 +308,24 @@ func (tree *BTree) IteratorDesc(f func(key, value any) bool) {
// searching iterating.
// If callback function `f` returns true, then it continues iterating; or false to stop.
func (tree *BTree) IteratorDescFrom(key any, match bool, f func(key, value any) bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
var keys = tree.tree.Keys()
index, canIterator := iteratorFromGetIndex(key, keys, match)
if !canIterator {
return
}
for ; index >= 0; index-- {
f(keys[index], tree.Get(keys[index]))
}
tree.lazyInit()
tree.BKVTree.IteratorDescFrom(key, match, f)
}
// Height returns the height of the tree.
func (tree *BTree) Height() int {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.Height()
tree.lazyInit()
return tree.BKVTree.Height()
}
// Left returns the minimum element corresponding to the comparator of the tree or nil if the tree is empty.
func (tree *BTree) Left() *BTreeEntry {
tree.mu.RLock()
defer tree.mu.RUnlock()
node := tree.tree.Left()
if node == nil || node.Entries == nil || len(node.Entries) == 0 {
return nil
}
return &BTreeEntry{
Key: node.Entries[0].Key,
Value: node.Entries[0].Value,
}
tree.lazyInit()
return tree.BKVTree.Left()
}
// Right returns the maximum element corresponding to the comparator of the tree or nil if the tree is empty.
func (tree *BTree) Right() *BTreeEntry {
tree.mu.RLock()
defer tree.mu.RUnlock()
node := tree.tree.Right()
if node == nil || node.Entries == nil || len(node.Entries) == 0 {
return nil
}
return &BTreeEntry{
Key: node.Entries[len(node.Entries)-1].Key,
Value: node.Entries[len(node.Entries)-1].Value,
}
}
// doSet inserts key-value pair node into the tree without lock.
// If `key` already exists, then its value is updated with the new value.
// If `value` is type of <func() any>, it will be executed and its return value will be set to the map with `key`.
//
// It returns value with given `key`.
func (tree *BTree) doSet(key any, value any) any {
if f, ok := value.(func() any); ok {
value = f()
}
if value == nil {
return value
}
tree.tree.Put(key, value)
return value
}
// doGet get the value from the tree by key without lock.
func (tree *BTree) doGet(key any) (value any, ok bool) {
return tree.tree.Get(key)
}
// doRemove removes key from tree and returns its associated value without lock.
// Note that, the given `key` should adhere to the comparator's type assertion, otherwise method panics.
func (tree *BTree) doRemove(key any) (value any) {
value, _ = tree.tree.Get(key)
tree.tree.Remove(key)
return
tree.lazyInit()
return tree.BKVTree.Right()
}

View File

@ -0,0 +1,539 @@
// Copyright GoFrame Author(https://goframe.org). 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
import (
"fmt"
"github.com/emirpasic/gods/v2/trees/avltree"
"github.com/gogf/gf/v2/container/gvar"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/internal/rwmutex"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
)
// AVLKVTree holds elements of the AVL tree.
type AVLKVTree[K comparable, V any] struct {
mu rwmutex.RWMutex
comparator func(v1, v2 K) int
tree *avltree.Tree[K, V]
}
// AVLKVTreeNode is a single element within the tree.
type AVLKVTreeNode[K comparable, V any] struct {
Key K
Value V
}
// NewAVLKVTree instantiates an AVL tree with the custom key comparator.
//
// The parameter `safe` is used to specify whether using tree in concurrent-safety,
// which is false in default.
func NewAVLKVTree[K comparable, V any](comparator func(v1, v2 K) int, safe ...bool) *AVLKVTree[K, V] {
return &AVLKVTree[K, V]{
mu: rwmutex.Create(safe...),
comparator: comparator,
tree: avltree.NewWith[K, V](comparator),
}
}
// NewAVLKVTreeFrom instantiates an AVL tree with the custom key comparator and data map.
//
// The parameter `safe` is used to specify whether using tree in concurrent-safety, which is false in default.
func NewAVLKVTreeFrom[K comparable, V any](comparator func(v1, v2 K) int, data map[K]V, safe ...bool) *AVLKVTree[K, V] {
tree := NewAVLKVTree[K, V](comparator, safe...)
for k, v := range data {
tree.doSet(k, v)
}
return tree
}
// Clone clones and returns a new tree from current tree.
func (tree *AVLKVTree[K, V]) Clone() *AVLKVTree[K, V] {
if tree == nil {
return nil
}
newTree := NewAVLKVTree[K, V](tree.comparator, tree.mu.IsSafe())
newTree.Sets(tree.Map())
return newTree
}
// Set sets key-value pair into the tree.
func (tree *AVLKVTree[K, V]) Set(key K, value V) {
tree.mu.Lock()
defer tree.mu.Unlock()
tree.doSet(key, value)
}
// Sets batch sets key-values to the tree.
func (tree *AVLKVTree[K, V]) Sets(data map[K]V) {
tree.mu.Lock()
defer tree.mu.Unlock()
for key, value := range data {
tree.doSet(key, value)
}
}
// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.
// It returns false if `key` exists, and such setting key-value pair operation would be ignored.
func (tree *AVLKVTree[K, V]) SetIfNotExist(key K, value V) bool {
tree.mu.Lock()
defer tree.mu.Unlock()
if _, ok := tree.doGet(key); !ok {
tree.doSet(key, value)
return true
}
return false
}
// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.
// It returns false if `key` exists, and such setting key-value pair operation would be ignored.
func (tree *AVLKVTree[K, V]) SetIfNotExistFunc(key K, f func() V) bool {
tree.mu.Lock()
defer tree.mu.Unlock()
if _, ok := tree.doGet(key); !ok {
tree.doSet(key, f())
return true
}
return false
}
// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.
// It returns false if `key` exists, and such setting key-value pair operation would be ignored.
//
// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
// it executes function `f` within mutex lock.
func (tree *AVLKVTree[K, V]) SetIfNotExistFuncLock(key K, f func() V) bool {
tree.mu.Lock()
defer tree.mu.Unlock()
if _, ok := tree.doGet(key); !ok {
tree.doSet(key, f())
return true
}
return false
}
// Get searches the `key` in the tree and returns its associated `value` or nil if key is not found in tree.
//
// Note that, the `nil` value from Get function cannot be used to determine key existence, please use Contains function
// to do so.
func (tree *AVLKVTree[K, V]) Get(key K) (value V) {
value, _ = tree.Search(key)
return
}
// GetOrSet returns its `value` of `key`, or sets value with given `value` if it does not exist and then returns
// this value.
func (tree *AVLKVTree[K, V]) GetOrSet(key K, value V) V {
tree.mu.Lock()
defer tree.mu.Unlock()
if v, ok := tree.doGet(key); !ok {
return tree.doSet(key, value)
} else {
return v
}
}
// GetOrSetFunc returns its `value` of `key`, or sets value with returned value of callback function `f` if it does not
// exist and then returns this value.
func (tree *AVLKVTree[K, V]) GetOrSetFunc(key K, f func() V) V {
tree.mu.Lock()
defer tree.mu.Unlock()
if v, ok := tree.doGet(key); !ok {
return tree.doSet(key, f())
} else {
return v
}
}
// GetOrSetFuncLock returns its `value` of `key`, or sets value with returned value of callback function `f` if it does
// not exist and then returns this value.
//
// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f` within mutex lock.
func (tree *AVLKVTree[K, V]) GetOrSetFuncLock(key K, f func() V) V {
tree.mu.Lock()
defer tree.mu.Unlock()
if v, ok := tree.doGet(key); !ok {
return tree.doSet(key, f())
} else {
return v
}
}
// GetVar returns a gvar.Var with the value by given `key`.
// Note that, the returned gvar.Var is un-concurrent safe.
//
// Also see function Get.
func (tree *AVLKVTree[K, V]) GetVar(key K) *gvar.Var {
return gvar.New(tree.Get(key))
}
// GetVarOrSet returns a gvar.Var with result from GetVarOrSet.
// Note that, the returned gvar.Var is un-concurrent safe.
//
// Also see function GetOrSet.
func (tree *AVLKVTree[K, V]) GetVarOrSet(key K, value V) *gvar.Var {
return gvar.New(tree.GetOrSet(key, value))
}
// GetVarOrSetFunc returns a gvar.Var with result from GetOrSetFunc.
// Note that, the returned gvar.Var is un-concurrent safe.
//
// Also see function GetOrSetFunc.
func (tree *AVLKVTree[K, V]) GetVarOrSetFunc(key K, f func() V) *gvar.Var {
return gvar.New(tree.GetOrSetFunc(key, f))
}
// GetVarOrSetFuncLock returns a gvar.Var with result from GetOrSetFuncLock.
// Note that, the returned gvar.Var is un-concurrent safe.
//
// Also see function GetOrSetFuncLock.
func (tree *AVLKVTree[K, V]) GetVarOrSetFuncLock(key K, f func() V) *gvar.Var {
return gvar.New(tree.GetOrSetFuncLock(key, f))
}
// Search searches the tree with given `key`.
// Second return parameter `found` is true if key was found, otherwise false.
func (tree *AVLKVTree[K, V]) Search(key K) (value V, found bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
if node, found := tree.doGet(key); found {
return node, true
}
found = false
return
}
// Contains checks and returns whether given `key` exists in the tree.
func (tree *AVLKVTree[K, V]) Contains(key K) bool {
tree.mu.RLock()
defer tree.mu.RUnlock()
_, ok := tree.doGet(key)
return ok
}
// Size returns number of nodes in the tree.
func (tree *AVLKVTree[K, V]) Size() int {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.Size()
}
// IsEmpty returns true if the tree does not contain any nodes.
func (tree *AVLKVTree[K, V]) IsEmpty() bool {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.Size() == 0
}
// Remove removes the node from the tree by `key`, and returns its associated value of `key`.
// The given `key` should adhere to the comparator's type assertion, otherwise method panics.
func (tree *AVLKVTree[K, V]) Remove(key K) (value V) {
tree.mu.Lock()
defer tree.mu.Unlock()
return tree.doRemove(key)
}
// Removes batch deletes key-value pairs from the tree by `keys`.
func (tree *AVLKVTree[K, V]) Removes(keys []K) {
tree.mu.Lock()
defer tree.mu.Unlock()
for _, key := range keys {
tree.doRemove(key)
}
}
// Clear removes all nodes from the tree.
func (tree *AVLKVTree[K, V]) Clear() {
tree.mu.Lock()
defer tree.mu.Unlock()
tree.tree.Clear()
}
// Keys returns all keys from the tree in order by its comparator.
func (tree *AVLKVTree[K, V]) Keys() []K {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.Keys()
}
// Values returns all values from the true in order by its comparator based on the key.
func (tree *AVLKVTree[K, V]) Values() []V {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.Values()
}
// Replace clears the data of the tree and sets the nodes by given `data`.
func (tree *AVLKVTree[K, V]) Replace(data map[K]V) {
tree.mu.Lock()
defer tree.mu.Unlock()
tree.tree.Clear()
for k, v := range data {
tree.doSet(k, v)
}
}
// Print prints the tree to stdout.
func (tree *AVLKVTree[K, V]) Print() {
fmt.Println(tree.String())
}
// String returns a string representation of container.
func (tree *AVLKVTree[K, V]) String() string {
tree.mu.RLock()
defer tree.mu.RUnlock()
return gstr.Replace(tree.tree.String(), "AVLTree\n", "")
}
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
func (tree *AVLKVTree[K, V]) MarshalJSON() (jsonBytes []byte, err error) {
tree.mu.RLock()
defer tree.mu.RUnlock()
elements := make(map[string]V)
it := tree.tree.Iterator()
for it.Next() {
elements[gconv.String(it.Key())] = it.Value()
}
return json.Marshal(&elements)
}
// Map returns all key-value pairs as map.
func (tree *AVLKVTree[K, V]) Map() map[K]V {
m := make(map[K]V, tree.Size())
tree.IteratorAsc(func(key K, value V) bool {
m[key] = value
return true
})
return m
}
// MapStrAny returns all key-value items as map[string]any.
func (tree *AVLKVTree[K, V]) MapStrAny() map[string]any {
m := make(map[string]any, tree.Size())
tree.IteratorAsc(func(key K, value V) bool {
m[gconv.String(key)] = value
return true
})
return m
}
// Iterator is alias of IteratorAsc.
//
// Also see IteratorAsc.
func (tree *AVLKVTree[K, V]) Iterator(f func(key K, value V) bool) {
tree.IteratorAsc(f)
}
// IteratorFrom is alias of IteratorAscFrom.
//
// Also see IteratorAscFrom.
func (tree *AVLKVTree[K, V]) IteratorFrom(key K, match bool, f func(key K, value V) bool) {
tree.IteratorAscFrom(key, match, f)
}
// IteratorAsc iterates the tree readonly in ascending order with given callback function `f`.
// If callback function `f` returns true, then it continues iterating; or false to stop.
func (tree *AVLKVTree[K, V]) IteratorAsc(f func(key K, value V) bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
var (
ok bool
it = tree.tree.Iterator()
)
for it.Begin(); it.Next(); {
index, value := it.Key(), it.Value()
if ok = f(index, value); !ok {
break
}
}
}
// IteratorAscFrom iterates the tree readonly in ascending order with given callback function `f`.
//
// The parameter `key` specifies the start entry for iterating.
// The parameter `match` specifies whether starting iterating only if the `key` is fully matched, or else using index
// searching iterating.
// If callback function `f` returns true, then it continues iterating; or false to stop.
func (tree *AVLKVTree[K, V]) IteratorAscFrom(key K, match bool, f func(key K, value V) bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
var keys = tree.tree.Keys()
index, canIterator := iteratorFromGetIndexT(key, keys, match)
if !canIterator {
return
}
for ; index < len(keys); index++ {
f(keys[index], tree.Get(keys[index]))
}
}
// IteratorDesc iterates the tree readonly in descending order with given callback function `f`.
//
// If callback function `f` returns true, then it continues iterating; or false to stop.
func (tree *AVLKVTree[K, V]) IteratorDesc(f func(key K, value V) bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
var (
ok bool
it = tree.tree.Iterator()
)
for it.End(); it.Prev(); {
index, value := it.Key(), it.Value()
if ok = f(index, value); !ok {
break
}
}
}
// IteratorDescFrom iterates the tree readonly in descending order with given callback function `f`.
//
// The parameter `key` specifies the start entry for iterating.
// The parameter `match` specifies whether starting iterating only if the `key` is fully matched, or else using index
// searching iterating.
// If callback function `f` returns true, then it continues iterating; or false to stop.
func (tree *AVLKVTree[K, V]) IteratorDescFrom(key K, match bool, f func(key K, value V) bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
var keys = tree.tree.Keys()
index, canIterator := iteratorFromGetIndexT(key, keys, match)
if !canIterator {
return
}
for ; index >= 0; index-- {
f(keys[index], tree.Get(keys[index]))
}
}
// Left returns the minimum element corresponding to the comparator of the tree or nil if the tree is empty.
func (tree *AVLKVTree[K, V]) Left() *AVLKVTreeNode[K, V] {
tree.mu.RLock()
defer tree.mu.RUnlock()
node := tree.tree.Left()
if node == nil {
return nil
}
return &AVLKVTreeNode[K, V]{
Key: node.Key,
Value: node.Value,
}
}
// Right returns the maximum element corresponding to the comparator of the tree or nil if the tree is empty.
func (tree *AVLKVTree[K, V]) Right() *AVLKVTreeNode[K, V] {
tree.mu.RLock()
defer tree.mu.RUnlock()
node := tree.tree.Right()
if node == nil {
return nil
}
return &AVLKVTreeNode[K, V]{
Key: node.Key,
Value: node.Value,
}
}
// Floor Finds floor node of the input key, returns the floor node or nil if no floor node is found.
// The second returned parameter `found` is true if floor was found, otherwise false.
//
// Floor node is defined as the largest node that is smaller than or equal to the given node.
// A floor node may not be found, either because the tree is empty, or because
// all nodes in the tree is larger than the given node.
//
// Key should adhere to the comparator's type assertion, otherwise method panics.
func (tree *AVLKVTree[K, V]) Floor(key K) (floor *AVLKVTreeNode[K, V], found bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
node, ok := tree.tree.Floor(key)
if !ok {
return nil, false
}
return &AVLKVTreeNode[K, V]{
Key: node.Key,
Value: node.Value,
}, true
}
// Ceiling finds ceiling node of the input key, returns the ceiling node or nil if no ceiling node is found.
// The second return parameter `found` is true if ceiling was found, otherwise false.
//
// Ceiling node is defined as the smallest node that is larger than or equal to the given node.
// A ceiling node may not be found, either because the tree is empty, or because
// all nodes in the tree is smaller than the given node.
//
// Key should adhere to the comparator's type assertion, otherwise method panics.
func (tree *AVLKVTree[K, V]) Ceiling(key K) (ceiling *AVLKVTreeNode[K, V], found bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
node, ok := tree.tree.Ceiling(key)
if !ok {
return nil, false
}
return &AVLKVTreeNode[K, V]{
Key: node.Key,
Value: node.Value,
}, true
}
// 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 *AVLKVTree[K, V]) Flip(comparator ...func(v1, v2 K) int) {
var t = new(AVLKVTree[K, V])
if len(comparator) > 0 {
t = NewAVLKVTree[K, V](comparator[0], tree.mu.IsSafe())
} else {
t = NewAVLKVTree[K, V](tree.comparator, tree.mu.IsSafe())
}
var (
newKey K
newValue V
)
tree.IteratorAsc(func(key K, value V) bool {
if err := gconv.Scan(key, &newValue); err != nil {
panic(err)
}
if err := gconv.Scan(value, &newKey); err != nil {
panic(err)
}
t.doSet(newKey, newValue)
return true
})
tree.Clear()
tree.Sets(t.Map())
}
// doSet inserts key-value pair node into the tree without lock.
// If `key` already exists, then its value is updated with the new value.
// If `value` is type of <func() any>, it will be executed and its return value will be set to the map with `key`.
//
// It returns value with given `key`.
func (tree *AVLKVTree[K, V]) doSet(key K, value V) V {
if any(value) == nil {
return value
}
tree.tree.Put(key, value)
return value
}
// doGet retrieves and returns the value of given key from tree without lock.
func (tree *AVLKVTree[K, V]) doGet(key K) (value V, found bool) {
return tree.tree.Get(key)
}
// doRemove removes key from tree and returns its associated value without lock.
// Note that, the given `key` should adhere to the comparator's type assertion, otherwise method panics.
func (tree *AVLKVTree[K, V]) doRemove(key K) (value V) {
value, _ = tree.tree.Get(key)
tree.tree.Remove(key)
return
}

View File

@ -0,0 +1,474 @@
// Copyright GoFrame Author(https://goframe.org). 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
import (
"fmt"
"github.com/emirpasic/gods/v2/trees/btree"
"github.com/gogf/gf/v2/container/gvar"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/internal/rwmutex"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
)
// BKVTree holds elements of the B-tree.
type BKVTree[K comparable, V any] struct {
mu rwmutex.RWMutex
comparator func(v1, v2 K) int
m int // order (maximum number of children)
tree *btree.Tree[K, V]
}
// BKVTreeEntry represents the key-value pair contained within nodes.
type BKVTreeEntry[K comparable, V any] struct {
Key K
Value V
}
// NewBKVTree instantiates a B-tree with `m` (maximum number of children) and a custom key comparator.
// The parameter `safe` is used to specify whether using tree in concurrent-safety,
// which is false in default.
// Note that the `m` must be greater or equal than 3, or else it panics.
func NewBKVTree[K comparable, V any](m int, comparator func(v1, v2 K) int, safe ...bool) *BKVTree[K, V] {
return &BKVTree[K, V]{
mu: rwmutex.Create(safe...),
m: m,
comparator: comparator,
tree: btree.NewWith[K, V](m, comparator),
}
}
// NewBKVTreeFrom instantiates a B-tree with `m` (maximum number of children), a custom key comparator and data map.
// The parameter `safe` is used to specify whether using tree in concurrent-safety,
// which is false in default.
func NewBKVTreeFrom[K comparable, V any](m int, comparator func(v1, v2 K) int, data map[K]V, safe ...bool) *BKVTree[K, V] {
tree := NewBKVTree[K, V](m, comparator, safe...)
for k, v := range data {
tree.doSet(k, v)
}
return tree
}
// Clone clones and returns a new tree from current tree.
func (tree *BKVTree[K, V]) Clone() *BKVTree[K, V] {
if tree == nil {
return nil
}
newTree := NewBKVTree[K, V](tree.m, tree.comparator, tree.mu.IsSafe())
newTree.Sets(tree.Map())
return newTree
}
// Set sets key-value pair into the tree.
func (tree *BKVTree[K, V]) Set(key K, value V) {
tree.mu.Lock()
defer tree.mu.Unlock()
tree.doSet(key, value)
}
// Sets batch sets key-values to the tree.
func (tree *BKVTree[K, V]) Sets(data map[K]V) {
tree.mu.Lock()
defer tree.mu.Unlock()
for k, v := range data {
tree.doSet(k, v)
}
}
// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.
// It returns false if `key` exists, and such setting key-value pair operation would be ignored.
func (tree *BKVTree[K, V]) SetIfNotExist(key K, value V) bool {
tree.mu.Lock()
defer tree.mu.Unlock()
if _, ok := tree.doGet(key); !ok {
tree.doSet(key, value)
return true
}
return false
}
// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.
// It returns false if `key` exists, and such setting key-value pair operation would be ignored.
func (tree *BKVTree[K, V]) SetIfNotExistFunc(key K, f func() V) bool {
tree.mu.Lock()
defer tree.mu.Unlock()
if _, ok := tree.doGet(key); !ok {
tree.doSet(key, f())
return true
}
return false
}
// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.
// It returns false if `key` exists, and such setting key-value pair operation would be ignored.
//
// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
// it executes function `f` within mutex lock.
func (tree *BKVTree[K, V]) SetIfNotExistFuncLock(key K, f func() V) bool {
tree.mu.Lock()
defer tree.mu.Unlock()
if _, ok := tree.doGet(key); !ok {
tree.doSet(key, f())
return true
}
return false
}
// Get searches the `key` in the tree and returns its associated `value` or nil if key is not found in tree.
//
// Note that, the `nil` value from Get function cannot be used to determine key existence, please use Contains function
// to do so.
func (tree *BKVTree[K, V]) Get(key K) (value V) {
tree.mu.Lock()
defer tree.mu.Unlock()
value, _ = tree.doGet(key)
return
}
// GetOrSet returns its `value` of `key`, or sets value with given `value` if it does not exist and then returns
// this value.
func (tree *BKVTree[K, V]) GetOrSet(key K, value V) V {
tree.mu.Lock()
defer tree.mu.Unlock()
if v, ok := tree.doGet(key); !ok {
return tree.doSet(key, value)
} else {
return v
}
}
// GetOrSetFunc returns its `value` of `key`, or sets value with returned value of callback function `f` if it does not
// exist and then returns this value.
func (tree *BKVTree[K, V]) GetOrSetFunc(key K, f func() V) V {
tree.mu.Lock()
defer tree.mu.Unlock()
if v, ok := tree.doGet(key); !ok {
return tree.doSet(key, f())
} else {
return v
}
}
// GetOrSetFuncLock returns its `value` of `key`, or sets value with returned value of callback function `f` if it does
// not exist and then returns this value.
//
// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f` within mutex lock.
func (tree *BKVTree[K, V]) GetOrSetFuncLock(key K, f func() V) V {
tree.mu.Lock()
defer tree.mu.Unlock()
if v, ok := tree.doGet(key); !ok {
return tree.doSet(key, f())
} else {
return v
}
}
// GetVar returns a gvar.Var with the value by given `key`.
// Note that, the returned gvar.Var is un-concurrent safe.
//
// Also see function Get.
func (tree *BKVTree[K, V]) GetVar(key K) *gvar.Var {
return gvar.New(tree.Get(key))
}
// GetVarOrSet returns a gvar.Var with result from GetVarOrSet.
// Note that, the returned gvar.Var is un-concurrent safe.
//
// Also see function GetOrSet.
func (tree *BKVTree[K, V]) GetVarOrSet(key K, value V) *gvar.Var {
return gvar.New(tree.GetOrSet(key, value))
}
// GetVarOrSetFunc returns a gvar.Var with result from GetOrSetFunc.
// Note that, the returned gvar.Var is un-concurrent safe.
//
// Also see function GetOrSetFunc.
func (tree *BKVTree[K, V]) GetVarOrSetFunc(key K, f func() V) *gvar.Var {
return gvar.New(tree.GetOrSetFunc(key, f))
}
// GetVarOrSetFuncLock returns a gvar.Var with result from GetOrSetFuncLock.
// Note that, the returned gvar.Var is un-concurrent safe.
//
// Also see function GetOrSetFuncLock.
func (tree *BKVTree[K, V]) GetVarOrSetFuncLock(key K, f func() V) *gvar.Var {
return gvar.New(tree.GetOrSetFuncLock(key, f))
}
// Search searches the tree with given `key`.
// Second return parameter `found` is true if key was found, otherwise false.
func (tree *BKVTree[K, V]) Search(key K) (value V, found bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.Get(key)
}
// Contains checks and returns whether given `key` exists in the tree.
func (tree *BKVTree[K, V]) Contains(key K) bool {
tree.mu.RLock()
defer tree.mu.RUnlock()
_, ok := tree.doGet(key)
return ok
}
// Size returns number of nodes in the tree.
func (tree *BKVTree[K, V]) Size() int {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.Size()
}
// IsEmpty returns true if tree does not contain any nodes
func (tree *BKVTree[K, V]) IsEmpty() bool {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.Size() == 0
}
// Remove removes the node from the tree by `key`, and returns its associated value of `key`.
// The given `key` should adhere to the comparator's type assertion, otherwise method panics.
func (tree *BKVTree[K, V]) Remove(key K) (value V) {
tree.mu.Lock()
defer tree.mu.Unlock()
return tree.doRemove(key)
}
// Removes batch deletes key-value pairs from the tree by `keys`.
func (tree *BKVTree[K, V]) Removes(keys []K) {
tree.mu.Lock()
defer tree.mu.Unlock()
for _, key := range keys {
tree.doRemove(key)
}
}
// Clear removes all nodes from the tree.
func (tree *BKVTree[K, V]) Clear() {
tree.mu.Lock()
defer tree.mu.Unlock()
tree.tree.Clear()
}
// Keys returns all keys from the tree in order by its comparator.
func (tree *BKVTree[K, V]) Keys() []K {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.Keys()
}
// Values returns all values from the true in order by its comparator based on the key.
func (tree *BKVTree[K, V]) Values() []V {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.Values()
}
// Replace clears the data of the tree and sets the nodes by given `data`.
func (tree *BKVTree[K, V]) Replace(data map[K]V) {
tree.mu.Lock()
defer tree.mu.Unlock()
tree.tree.Clear()
for k, v := range data {
tree.doSet(k, v)
}
}
// Map returns all key-value pairs as map.
func (tree *BKVTree[K, V]) Map() map[K]V {
m := make(map[K]V, tree.Size())
tree.IteratorAsc(func(key K, value V) bool {
m[key] = value
return true
})
return m
}
// MapStrAny returns all key-value items as map[string]any.
func (tree *BKVTree[K, V]) MapStrAny() map[string]any {
m := make(map[string]any, tree.Size())
tree.IteratorAsc(func(key K, value V) bool {
m[gconv.String(key)] = value
return true
})
return m
}
// Print prints the tree to stdout.
func (tree *BKVTree[K, V]) Print() {
fmt.Println(tree.String())
}
// String returns a string representation of container (for debugging purposes)
func (tree *BKVTree[K, V]) String() string {
tree.mu.RLock()
defer tree.mu.RUnlock()
return gstr.Replace(tree.tree.String(), "BTree\n", "")
}
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
func (tree *BKVTree[K, V]) MarshalJSON() (jsonBytes []byte, err error) {
tree.mu.RLock()
defer tree.mu.RUnlock()
elements := make(map[string]V)
it := tree.tree.Iterator()
for it.Next() {
elements[gconv.String(it.Key())] = it.Value()
}
return json.Marshal(&elements)
}
// Iterator is alias of IteratorAsc.
//
// Also see IteratorAsc.
func (tree *BKVTree[K, V]) Iterator(f func(key K, value V) bool) {
tree.IteratorAsc(f)
}
// IteratorFrom is alias of IteratorAscFrom.
//
// Also see IteratorAscFrom.
func (tree *BKVTree[K, V]) IteratorFrom(key K, match bool, f func(key K, value V) bool) {
tree.IteratorAscFrom(key, match, f)
}
// IteratorAsc iterates the tree readonly in ascending order with given callback function `f`.
// If callback function `f` returns true, then it continues iterating; or false to stop.
func (tree *BKVTree[K, V]) IteratorAsc(f func(key K, value V) bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
var (
ok bool
it = tree.tree.Iterator()
)
for it.Begin(); it.Next(); {
index, value := it.Key(), it.Value()
if ok = f(index, value); !ok {
break
}
}
}
// IteratorAscFrom iterates the tree readonly in ascending order with given callback function `f`.
//
// The parameter `key` specifies the start entry for iterating.
// The parameter `match` specifies whether starting iterating only if the `key` is fully matched, or else using index
// searching iterating.
// If callback function `f` returns true, then it continues iterating; or false to stop.
func (tree *BKVTree[K, V]) IteratorAscFrom(key K, match bool, f func(key K, value V) bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
var keys = tree.tree.Keys()
index, canIterator := iteratorFromGetIndexT(key, keys, match)
if !canIterator {
return
}
for ; index < len(keys); index++ {
f(keys[index], tree.Get(keys[index]))
}
}
// IteratorDesc iterates the tree readonly in descending order with given callback function `f`.
//
// If callback function `f` returns true, then it continues iterating; or false to stop.
func (tree *BKVTree[K, V]) IteratorDesc(f func(key K, value V) bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
var (
ok bool
it = tree.tree.Iterator()
)
for it.End(); it.Prev(); {
index, value := it.Key(), it.Value()
if ok = f(index, value); !ok {
break
}
}
}
// IteratorDescFrom iterates the tree readonly in descending order with given callback function `f`.
//
// The parameter `key` specifies the start entry for iterating.
// The parameter `match` specifies whether starting iterating only if the `key` is fully matched, or else using index
// searching iterating.
// If callback function `f` returns true, then it continues iterating; or false to stop.
func (tree *BKVTree[K, V]) IteratorDescFrom(key K, match bool, f func(key K, value V) bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
var keys = tree.tree.Keys()
index, canIterator := iteratorFromGetIndexT(key, keys, match)
if !canIterator {
return
}
for ; index >= 0; index-- {
f(keys[index], tree.Get(keys[index]))
}
}
// Height returns the height of the tree.
func (tree *BKVTree[K, V]) Height() int {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.Height()
}
// Left returns the minimum element corresponding to the comparator of the tree or nil if the tree is empty.
func (tree *BKVTree[K, V]) Left() *BKVTreeEntry[K, V] {
tree.mu.RLock()
defer tree.mu.RUnlock()
node := tree.tree.Left()
if node == nil || node.Entries == nil || len(node.Entries) == 0 {
return nil
}
return &BKVTreeEntry[K, V]{
Key: node.Entries[0].Key,
Value: node.Entries[0].Value,
}
}
// Right returns the maximum element corresponding to the comparator of the tree or nil if the tree is empty.
func (tree *BKVTree[K, V]) Right() *BKVTreeEntry[K, V] {
tree.mu.RLock()
defer tree.mu.RUnlock()
node := tree.tree.Right()
if node == nil || node.Entries == nil || len(node.Entries) == 0 {
return nil
}
return &BKVTreeEntry[K, V]{
Key: node.Entries[len(node.Entries)-1].Key,
Value: node.Entries[len(node.Entries)-1].Value,
}
}
// doSet inserts key-value pair node into the tree without lock.
// If `key` already exists, then its value is updated with the new value.
// If `value` is type of <func() any>, it will be executed and its return value will be set to the map with `key`.
//
// It returns value with given `key`.
func (tree *BKVTree[K, V]) doSet(key K, value V) V {
if any(value) == nil {
return value
}
tree.tree.Put(key, value)
return value
}
// doGet get the value from the tree by key without lock.
func (tree *BKVTree[K, V]) doGet(key K) (value V, ok bool) {
return tree.tree.Get(key)
}
// doRemove removes key from tree and returns its associated value without lock.
// Note that, the given `key` should adhere to the comparator's type assertion, otherwise method panics.
func (tree *BKVTree[K, V]) doRemove(key K) (value V) {
value, _ = tree.tree.Get(key)
tree.tree.Remove(key)
return
}

View File

@ -0,0 +1,613 @@
// Copyright GoFrame Author(https://goframe.org). 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
import (
"fmt"
"github.com/emirpasic/gods/v2/trees/redblacktree"
"github.com/gogf/gf/v2/container/gvar"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/internal/rwmutex"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/util/gutil"
)
// RedBlackKVTree holds elements of the red-black tree.
type RedBlackKVTree[K comparable, V any] struct {
mu rwmutex.RWMutex
comparator func(v1, v2 K) int
tree *redblacktree.Tree[K, V]
}
// RedBlackKVTreeNode is a single element within the tree.
type RedBlackKVTreeNode[K comparable, V any] struct {
Key K
Value V
}
// NewRedBlackKVTree instantiates a red-black tree with the custom key comparator.
// The parameter `safe` is used to specify whether using tree in concurrent-safety,
// which is false in default.
func NewRedBlackKVTree[K comparable, V any](comparator func(v1, v2 K) int, safe ...bool) *RedBlackKVTree[K, V] {
var tree RedBlackKVTree[K, V]
RedBlackKVTreeInit(&tree, comparator, safe...)
return &tree
}
// NewRedBlackKVTreeFrom instantiates a red-black tree with the custom key comparator and `data` map.
// The parameter `safe` is used to specify whether using tree in concurrent-safety,
// which is false in default.
func NewRedBlackKVTreeFrom[K comparable, V any](comparator func(v1, v2 K) int, data map[K]V, safe ...bool) *RedBlackKVTree[K, V] {
var tree RedBlackKVTree[K, V]
RedBlackKVTreeInitFrom(&tree, comparator, data, safe...)
return &tree
}
// RedBlackKVTreeInit instantiates a red-black tree with the custom key comparator.
// The parameter `safe` is used to specify whether using tree in concurrent-safety,
// which is false in default.
func RedBlackKVTreeInit[K comparable, V any](tree *RedBlackKVTree[K, V], comparator func(v1, v2 K) int, safe ...bool) {
if tree == nil {
return
}
tree.mu = rwmutex.Create(safe...)
tree.comparator = comparator
tree.tree = redblacktree.NewWith[K, V](comparator)
}
// RedBlackKVTreeInitFrom instantiates a red-black tree with the custom key comparator and `data` map.
// The parameter `safe` is used to specify whether using tree in concurrent-safety,
// which is false in default.
func RedBlackKVTreeInitFrom[K comparable, V any](tree *RedBlackKVTree[K, V], comparator func(v1, v2 K) int, data map[K]V, safe ...bool) {
if tree == nil {
return
}
RedBlackKVTreeInit(tree, comparator, safe...)
for k, v := range data {
tree.doSet(k, v)
}
}
// SetComparator sets/changes the comparator for sorting.
func (tree *RedBlackKVTree[K, V]) SetComparator(comparator func(a, b K) int) {
tree.comparator = comparator
if tree.tree == nil {
tree.tree = redblacktree.NewWith[K, V](comparator)
}
size := tree.tree.Size()
if size > 0 {
m := tree.Map()
tree.Sets(m)
}
}
// Clone clones and returns a new tree from current tree.
func (tree *RedBlackKVTree[K, V]) Clone() *RedBlackKVTree[K, V] {
if tree == nil {
return nil
}
newTree := NewRedBlackKVTree[K, V](tree.comparator, tree.mu.IsSafe())
newTree.Sets(tree.Map())
return newTree
}
// Set sets key-value pair into the tree.
func (tree *RedBlackKVTree[K, V]) Set(key K, value V) {
tree.mu.Lock()
defer tree.mu.Unlock()
tree.doSet(key, value)
}
// Sets batch sets key-values to the tree.
func (tree *RedBlackKVTree[K, V]) Sets(data map[K]V) {
tree.mu.Lock()
defer tree.mu.Unlock()
for key, value := range data {
tree.doSet(key, value)
}
}
// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.
// It returns false if `key` exists, and such setting key-value pair operation would be ignored.
func (tree *RedBlackKVTree[K, V]) SetIfNotExist(key K, value V) bool {
tree.mu.Lock()
defer tree.mu.Unlock()
if _, ok := tree.doGet(key); !ok {
tree.doSet(key, value)
return true
}
return false
}
// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.
// It returns false if `key` exists, and such setting key-value pair operation would be ignored.
func (tree *RedBlackKVTree[K, V]) SetIfNotExistFunc(key K, f func() V) bool {
tree.mu.Lock()
defer tree.mu.Unlock()
if _, ok := tree.doGet(key); !ok {
tree.doSet(key, f())
return true
}
return false
}
// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.
// It returns false if `key` exists, and such setting key-value pair operation would be ignored.
//
// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
// it executes function `f` within mutex lock.
func (tree *RedBlackKVTree[K, V]) SetIfNotExistFuncLock(key K, f func() V) bool {
tree.mu.Lock()
defer tree.mu.Unlock()
if _, ok := tree.doGet(key); !ok {
tree.doSet(key, f())
return true
}
return false
}
// Get searches the `key` in the tree and returns its associated `value` or nil if key is not found in tree.
//
// Note that, the `nil` value from Get function cannot be used to determine key existence, please use Contains function
// to do so.
func (tree *RedBlackKVTree[K, V]) Get(key K) (value V) {
value, _ = tree.Search(key)
return
}
// GetOrSet returns its `value` of `key`, or sets value with given `value` if it does not exist and then returns
// this value.
func (tree *RedBlackKVTree[K, V]) GetOrSet(key K, value V) V {
tree.mu.Lock()
defer tree.mu.Unlock()
if v, ok := tree.doGet(key); !ok {
return tree.doSet(key, value)
} else {
return v
}
}
// GetOrSetFunc returns its `value` of `key`, or sets value with returned value of callback function `f` if it does not
// exist and then returns this value.
func (tree *RedBlackKVTree[K, V]) GetOrSetFunc(key K, f func() V) V {
tree.mu.Lock()
defer tree.mu.Unlock()
if v, ok := tree.doGet(key); !ok {
return tree.doSet(key, f())
} else {
return v
}
}
// GetOrSetFuncLock returns its `value` of `key`, or sets value with returned value of callback function `f` if it does
// not exist and then returns this value.
//
// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f`within mutex lock.
func (tree *RedBlackKVTree[K, V]) GetOrSetFuncLock(key K, f func() V) V {
tree.mu.Lock()
defer tree.mu.Unlock()
if v, ok := tree.doGet(key); !ok {
return tree.doSet(key, f())
} else {
return v
}
}
// GetVar returns a gvar.Var with the value by given `key`.
// Note that, the returned gvar.Var is un-concurrent safe.
//
// Also see function Get.
func (tree *RedBlackKVTree[K, V]) GetVar(key K) *gvar.Var {
return gvar.New(tree.Get(key))
}
// GetVarOrSet returns a gvar.Var with result from GetVarOrSet.
// Note that, the returned gvar.Var is un-concurrent safe.
//
// Also see function GetOrSet.
func (tree *RedBlackKVTree[K, V]) GetVarOrSet(key K, value V) *gvar.Var {
return gvar.New(tree.GetOrSet(key, value))
}
// GetVarOrSetFunc returns a gvar.Var with result from GetOrSetFunc.
// Note that, the returned gvar.Var is un-concurrent safe.
//
// Also see function GetOrSetFunc.
func (tree *RedBlackKVTree[K, V]) GetVarOrSetFunc(key K, f func() V) *gvar.Var {
return gvar.New(tree.GetOrSetFunc(key, f))
}
// GetVarOrSetFuncLock returns a gvar.Var with result from GetOrSetFuncLock.
// Note that, the returned gvar.Var is un-concurrent safe.
//
// Also see function GetOrSetFuncLock.
func (tree *RedBlackKVTree[K, V]) GetVarOrSetFuncLock(key K, f func() V) *gvar.Var {
return gvar.New(tree.GetOrSetFuncLock(key, f))
}
// Search searches the tree with given `key`.
// Second return parameter `found` is true if key was found, otherwise false.
func (tree *RedBlackKVTree[K, V]) Search(key K) (value V, found bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
if node, found := tree.doGet(key); found {
return node, true
}
found = false
return
}
// Contains checks and returns whether given `key` exists in the tree.
func (tree *RedBlackKVTree[K, V]) Contains(key K) bool {
tree.mu.RLock()
defer tree.mu.RUnlock()
_, ok := tree.doGet(key)
return ok
}
// Size returns number of nodes in the tree.
func (tree *RedBlackKVTree[K, V]) Size() int {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.Size()
}
// IsEmpty returns true if tree does not contain any nodes.
func (tree *RedBlackKVTree[K, V]) IsEmpty() bool {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.Size() == 0
}
// Remove removes the node from the tree by `key`, and returns its associated value of `key`.
// The given `key` should adhere to the comparator's type assertion, otherwise method panics.
func (tree *RedBlackKVTree[K, V]) Remove(key K) (value V) {
tree.mu.Lock()
defer tree.mu.Unlock()
return tree.doRemove(key)
}
// Removes batch deletes key-value pairs from the tree by `keys`.
func (tree *RedBlackKVTree[K, V]) Removes(keys []K) {
tree.mu.Lock()
defer tree.mu.Unlock()
for _, key := range keys {
tree.doRemove(key)
}
}
// Clear removes all nodes from the tree.
func (tree *RedBlackKVTree[K, V]) Clear() {
tree.mu.Lock()
defer tree.mu.Unlock()
tree.tree.Clear()
}
// Keys returns all keys from the tree in order by its comparator.
func (tree *RedBlackKVTree[K, V]) Keys() []K {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.Keys()
}
// Values returns all values from the true in order by its comparator based on the key.
func (tree *RedBlackKVTree[K, V]) Values() []V {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.Values()
}
// Replace clears the data of the tree and sets the nodes by given `data`.
func (tree *RedBlackKVTree[K, V]) Replace(data map[K]V) {
tree.mu.Lock()
defer tree.mu.Unlock()
tree.tree.Clear()
for k, v := range data {
tree.doSet(k, v)
}
}
// Print prints the tree to stdout.
func (tree *RedBlackKVTree[K, V]) Print() {
fmt.Println(tree.String())
}
// String returns a string representation of container
func (tree *RedBlackKVTree[K, V]) String() string {
tree.mu.RLock()
defer tree.mu.RUnlock()
return gstr.Replace(tree.tree.String(), "RedBlackTree\n", "")
}
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
func (tree RedBlackKVTree[K, V]) MarshalJSON() (jsonBytes []byte, err error) {
tree.mu.RLock()
defer tree.mu.RUnlock()
elements := make(map[string]V)
it := tree.tree.Iterator()
for it.Next() {
elements[gconv.String(it.Key())] = it.Value()
}
return json.Marshal(&elements)
}
// Map returns all key-value pairs as map.
func (tree *RedBlackKVTree[K, V]) Map() map[K]V {
m := make(map[K]V, tree.Size())
tree.IteratorAsc(func(key K, value V) bool {
m[key] = value
return true
})
return m
}
// MapStrAny returns all key-value items as map[string]any.
func (tree *RedBlackKVTree[K, V]) MapStrAny() map[string]any {
m := make(map[string]any, tree.Size())
tree.IteratorAsc(func(key K, value V) bool {
m[gconv.String(key)] = value
return true
})
return m
}
// Iterator is alias of IteratorAsc.
//
// Also see IteratorAsc.
func (tree *RedBlackKVTree[K, V]) Iterator(f func(key K, value V) bool) {
tree.IteratorAsc(f)
}
// IteratorFrom is alias of IteratorAscFrom.
//
// Also see IteratorAscFrom.
func (tree *RedBlackKVTree[K, V]) IteratorFrom(key K, match bool, f func(key K, value V) bool) {
tree.IteratorAscFrom(key, match, f)
}
// IteratorAsc iterates the tree readonly in ascending order with given callback function `f`.
// If callback function `f` returns true, then it continues iterating; or false to stop.
func (tree *RedBlackKVTree[K, V]) IteratorAsc(f func(key K, value V) bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
var (
ok bool
it = tree.tree.Iterator()
)
for it.Begin(); it.Next(); {
index, value := it.Key(), it.Value()
if ok = f(index, value); !ok {
break
}
}
}
// IteratorAscFrom iterates the tree readonly in ascending order with given callback function `f`.
//
// The parameter `key` specifies the start entry for iterating.
// The parameter `match` specifies whether starting iterating only if the `key` is fully matched, or else using index
// searching iterating.
// If callback function `f` returns true, then it continues iterating; or false to stop.
func (tree *RedBlackKVTree[K, V]) IteratorAscFrom(key K, match bool, f func(key K, value V) bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
var keys = tree.tree.Keys()
index, canIterator := iteratorFromGetIndexT(key, keys, match)
if !canIterator {
return
}
for ; index < len(keys); index++ {
f(keys[index], tree.Get(keys[index]))
}
}
// IteratorDesc iterates the tree readonly in descending order with given callback function `f`.
//
// If callback function `f` returns true, then it continues iterating; or false to stop.
func (tree *RedBlackKVTree[K, V]) IteratorDesc(f func(key K, value V) bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
var (
ok bool
it = tree.tree.Iterator()
)
for it.End(); it.Prev(); {
index, value := it.Key(), it.Value()
if ok = f(index, value); !ok {
break
}
}
}
// IteratorDescFrom iterates the tree readonly in descending order with given callback function `f`.
//
// The parameter `key` specifies the start entry for iterating.
// The parameter `match` specifies whether starting iterating only if the `key` is fully matched, or else using index
// searching iterating.
// If callback function `f` returns true, then it continues iterating; or false to stop.
func (tree *RedBlackKVTree[K, V]) IteratorDescFrom(key K, match bool, f func(key K, value V) bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
var keys = tree.tree.Keys()
index, canIterator := iteratorFromGetIndexT(key, keys, match)
if !canIterator {
return
}
for ; index >= 0; index-- {
f(keys[index], tree.Get(keys[index]))
}
}
// Left returns the minimum element corresponding to the comparator of the tree or nil if the tree is empty.
func (tree *RedBlackKVTree[K, V]) Left() *RedBlackKVTreeNode[K, V] {
tree.mu.RLock()
defer tree.mu.RUnlock()
node := tree.tree.Left()
if node == nil {
return nil
}
return &RedBlackKVTreeNode[K, V]{
Key: node.Key,
Value: node.Value,
}
}
// Right returns the maximum element corresponding to the comparator of the tree or nil if the tree is empty.
func (tree *RedBlackKVTree[K, V]) Right() *RedBlackKVTreeNode[K, V] {
tree.mu.RLock()
defer tree.mu.RUnlock()
node := tree.tree.Right()
if node == nil {
return nil
}
return &RedBlackKVTreeNode[K, V]{
Key: node.Key,
Value: node.Value,
}
}
// Floor Finds floor node of the input key, returns the floor node or nil if no floor node is found.
// The second returned parameter `found` is true if floor was found, otherwise false.
//
// Floor node is defined as the largest node that is smaller than or equal to the given node.
// A floor node may not be found, either because the tree is empty, or because
// all nodes in the tree is larger than the given node.
//
// Key should adhere to the comparator's type assertion, otherwise method panics.
func (tree *RedBlackKVTree[K, V]) Floor(key K) (floor *RedBlackKVTreeNode[K, V], found bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
node, found := tree.tree.Floor(key)
if !found {
return nil, false
}
return &RedBlackKVTreeNode[K, V]{
Key: node.Key,
Value: node.Value,
}, true
}
// Ceiling finds ceiling node of the input key, returns the ceiling node or nil if no ceiling node is found.
// The second return parameter `found` is true if ceiling was found, otherwise false.
//
// Ceiling node is defined as the smallest node that is larger than or equal to the given node.
// A ceiling node may not be found, either because the tree is empty, or because
// all nodes in the tree is smaller than the given node.
//
// Key should adhere to the comparator's type assertion, otherwise method panics.
func (tree *RedBlackKVTree[K, V]) Ceiling(key K) (ceiling *RedBlackKVTreeNode[K, V], found bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
node, found := tree.tree.Ceiling(key)
if !found {
return nil, false
}
return &RedBlackKVTreeNode[K, V]{
Key: node.Key,
Value: node.Value,
}, true
}
// 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 *RedBlackKVTree[K, V]) Flip(comparator ...func(v1, v2 K) int) {
var t = new(RedBlackKVTree[K, V])
if len(comparator) > 0 {
t = NewRedBlackKVTree[K, V](comparator[0], tree.mu.IsSafe())
} else {
t = NewRedBlackKVTree[K, V](tree.comparator, tree.mu.IsSafe())
}
var (
newKey K
newValue V
)
tree.IteratorAsc(func(key K, value V) bool {
if err := gconv.Scan(key, &newValue); err != nil {
panic(err)
}
if err := gconv.Scan(value, &newKey); err != nil {
panic(err)
}
t.doSet(newKey, newValue)
return true
})
tree.Clear()
tree.Sets(t.Map())
}
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
func (tree *RedBlackKVTree[K, V]) UnmarshalJSON(b []byte) (err error) {
tree.mu.Lock()
defer tree.mu.Unlock()
if tree.comparator == nil {
tree.comparator = gutil.ComparatorTStr[K]
tree.tree = redblacktree.NewWith[K, V](tree.comparator)
}
var data map[string]any
if err := json.UnmarshalUseNumber(b, &data); err != nil {
return err
}
var m = make(map[K]V)
if err = gconv.Scan(data, &m); err != nil {
return
}
for k, v := range m {
tree.doSet(k, v)
}
return nil
}
// UnmarshalValue is an interface implement which sets any type of value for map.
func (tree *RedBlackKVTree[K, V]) UnmarshalValue(value any) (err error) {
tree.mu.Lock()
defer tree.mu.Unlock()
if tree.comparator == nil {
tree.comparator = gutil.ComparatorTStr[K]
tree.tree = redblacktree.NewWith[K, V](tree.comparator)
}
var m = make(map[K]V)
if err = gconv.Scan(value, &m); err != nil {
return
}
for k, v := range m {
tree.doSet(k, v)
}
return
}
// doSet inserts key-value pair node into the tree without lock.
// If `key` already exists, then its value is updated with the new value.
// If `value` is type of <func() any>, it will be executed and its return value will be set to the map with `key`.
//
// It returns value with given `key`.
func (tree *RedBlackKVTree[K, V]) doSet(key K, value V) (ret V) {
if any(value) == nil {
return
}
tree.tree.Put(key, value)
return value
}
// doGet retrieves and returns the value of given key from tree without lock.
func (tree *RedBlackKVTree[K, V]) doGet(key K) (value V, found bool) {
return tree.tree.Get(key)
}
// doRemove removes key from tree and returns its associated value without lock.
// Note that, the given `key` should adhere to the comparator's type assertion, otherwise method panics.
func (tree *RedBlackKVTree[K, V]) doRemove(key K) (value V) {
value, _ = tree.tree.Get(key)
tree.tree.Remove(key)
return
}

View File

@ -7,15 +7,9 @@
package gtree
import (
"fmt"
"github.com/emirpasic/gods/trees/redblacktree"
"sync"
"github.com/gogf/gf/v2/container/gvar"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/internal/rwmutex"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/util/gutil"
)
@ -23,25 +17,19 @@ var _ iTree = (*RedBlackTree)(nil)
// RedBlackTree holds elements of the red-black tree.
type RedBlackTree struct {
mu rwmutex.RWMutex
comparator func(v1, v2 any) int
tree *redblacktree.Tree
*RedBlackKVTree[any, any]
once sync.Once
}
// RedBlackTreeNode is a single element within the tree.
type RedBlackTreeNode struct {
Key any
Value any
}
type RedBlackTreeNode = RedBlackKVTreeNode[any, any]
// NewRedBlackTree instantiates a red-black tree with the custom key comparator.
// The parameter `safe` is used to specify whether using tree in concurrent-safety,
// which is false in default.
func NewRedBlackTree(comparator func(v1, v2 any) int, safe ...bool) *RedBlackTree {
return &RedBlackTree{
mu: rwmutex.Create(safe...),
comparator: comparator,
tree: redblacktree.NewWith(comparator),
RedBlackKVTree: NewRedBlackKVTree[any, any](comparator, safe...),
}
}
@ -49,71 +37,61 @@ func NewRedBlackTree(comparator func(v1, v2 any) int, safe ...bool) *RedBlackTre
// The parameter `safe` is used to specify whether using tree in concurrent-safety,
// which is false in default.
func NewRedBlackTreeFrom(comparator func(v1, v2 any) int, data map[any]any, safe ...bool) *RedBlackTree {
tree := NewRedBlackTree(comparator, safe...)
for k, v := range data {
tree.doSet(k, v)
return &RedBlackTree{
RedBlackKVTree: NewRedBlackKVTreeFrom(comparator, data, safe...),
}
return tree
}
// lazyInit lazily initializes the tree.
func (tree *RedBlackTree) lazyInit() {
tree.once.Do(func() {
if tree.RedBlackKVTree == nil {
tree.RedBlackKVTree = NewRedBlackKVTree[any, any](gutil.ComparatorTStr, false)
}
})
}
// SetComparator sets/changes the comparator for sorting.
func (tree *RedBlackTree) SetComparator(comparator func(a, b any) int) {
tree.comparator = comparator
if tree.tree == nil {
tree.tree = redblacktree.NewWith(comparator)
}
size := tree.tree.Size()
if size > 0 {
m := tree.Map()
tree.Sets(m)
}
tree.lazyInit()
tree.RedBlackKVTree.SetComparator(comparator)
}
// Clone clones and returns a new tree from current tree.
func (tree *RedBlackTree) Clone() *RedBlackTree {
newTree := NewRedBlackTree(tree.comparator, tree.mu.IsSafe())
newTree.Sets(tree.Map())
return newTree
if tree == nil {
return nil
}
tree.lazyInit()
return &RedBlackTree{
RedBlackKVTree: tree.RedBlackKVTree.Clone(),
}
}
// Set sets key-value pair into the tree.
func (tree *RedBlackTree) Set(key any, value any) {
tree.mu.Lock()
defer tree.mu.Unlock()
tree.doSet(key, value)
tree.lazyInit()
tree.RedBlackKVTree.Set(key, value)
}
// Sets batch sets key-values to the tree.
func (tree *RedBlackTree) Sets(data map[any]any) {
tree.mu.Lock()
defer tree.mu.Unlock()
for key, value := range data {
tree.doSet(key, value)
}
tree.lazyInit()
tree.RedBlackKVTree.Sets(data)
}
// SetIfNotExist sets `value` to the map if the `key` does not exist, and then returns true.
// It returns false if `key` exists, and such setting key-value pair operation would be ignored.
func (tree *RedBlackTree) SetIfNotExist(key any, value any) bool {
tree.mu.Lock()
defer tree.mu.Unlock()
if _, ok := tree.doGet(key); !ok {
tree.doSet(key, value)
return true
}
return false
tree.lazyInit()
return tree.RedBlackKVTree.SetIfNotExist(key, value)
}
// SetIfNotExistFunc sets value with return value of callback function `f`, and then returns true.
// It returns false if `key` exists, and such setting key-value pair operation would be ignored.
func (tree *RedBlackTree) SetIfNotExistFunc(key any, f func() any) bool {
tree.mu.Lock()
defer tree.mu.Unlock()
if _, ok := tree.doGet(key); !ok {
tree.doSet(key, f())
return true
}
return false
tree.lazyInit()
return tree.RedBlackKVTree.SetIfNotExistFunc(key, f)
}
// SetIfNotExistFuncLock sets value with return value of callback function `f`, and then returns true.
@ -122,13 +100,8 @@ func (tree *RedBlackTree) SetIfNotExistFunc(key any, f func() any) bool {
// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
// it executes function `f` within mutex lock.
func (tree *RedBlackTree) SetIfNotExistFuncLock(key any, f func() any) bool {
tree.mu.Lock()
defer tree.mu.Unlock()
if _, ok := tree.doGet(key); !ok {
tree.doSet(key, f)
return true
}
return false
tree.lazyInit()
return tree.RedBlackKVTree.SetIfNotExistFuncLock(key, f)
}
// Get searches the `key` in the tree and returns its associated `value` or nil if key is not found in tree.
@ -136,32 +109,22 @@ func (tree *RedBlackTree) SetIfNotExistFuncLock(key any, f func() any) bool {
// Note that, the `nil` value from Get function cannot be used to determine key existence, please use Contains function
// to do so.
func (tree *RedBlackTree) Get(key any) (value any) {
value, _ = tree.Search(key)
return
tree.lazyInit()
return tree.RedBlackKVTree.Get(key)
}
// GetOrSet returns its `value` of `key`, or sets value with given `value` if it does not exist and then returns
// this value.
func (tree *RedBlackTree) GetOrSet(key any, value any) any {
tree.mu.Lock()
defer tree.mu.Unlock()
if v, ok := tree.doGet(key); !ok {
return tree.doSet(key, value)
} else {
return v
}
tree.lazyInit()
return tree.RedBlackKVTree.GetOrSet(key, value)
}
// GetOrSetFunc returns its `value` of `key`, or sets value with returned value of callback function `f` if it does not
// exist and then returns this value.
func (tree *RedBlackTree) GetOrSetFunc(key any, f func() any) any {
tree.mu.Lock()
defer tree.mu.Unlock()
if v, ok := tree.doGet(key); !ok {
return tree.doSet(key, f())
} else {
return v
}
tree.lazyInit()
return tree.RedBlackKVTree.GetOrSetFunc(key, f)
}
// GetOrSetFuncLock returns its `value` of `key`, or sets value with returned value of callback function `f` if it does
@ -169,13 +132,8 @@ func (tree *RedBlackTree) GetOrSetFunc(key any, f func() any) any {
//
// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f`within mutex lock.
func (tree *RedBlackTree) GetOrSetFuncLock(key any, f func() any) any {
tree.mu.Lock()
defer tree.mu.Unlock()
if v, ok := tree.doGet(key); !ok {
return tree.doSet(key, f)
} else {
return v
}
tree.lazyInit()
return tree.RedBlackKVTree.GetOrSetFuncLock(key, f)
}
// GetVar returns a gvar.Var with the value by given `key`.
@ -183,7 +141,8 @@ func (tree *RedBlackTree) GetOrSetFuncLock(key any, f func() any) any {
//
// Also see function Get.
func (tree *RedBlackTree) GetVar(key any) *gvar.Var {
return gvar.New(tree.Get(key))
tree.lazyInit()
return tree.RedBlackKVTree.GetVar(key)
}
// GetVarOrSet returns a gvar.Var with result from GetVarOrSet.
@ -191,7 +150,8 @@ func (tree *RedBlackTree) GetVar(key any) *gvar.Var {
//
// Also see function GetOrSet.
func (tree *RedBlackTree) GetVarOrSet(key any, value any) *gvar.Var {
return gvar.New(tree.GetOrSet(key, value))
tree.lazyInit()
return tree.RedBlackKVTree.GetVarOrSet(key, value)
}
// GetVarOrSetFunc returns a gvar.Var with result from GetOrSetFunc.
@ -199,7 +159,8 @@ func (tree *RedBlackTree) GetVarOrSet(key any, value any) *gvar.Var {
//
// Also see function GetOrSetFunc.
func (tree *RedBlackTree) GetVarOrSetFunc(key any, f func() any) *gvar.Var {
return gvar.New(tree.GetOrSetFunc(key, f))
tree.lazyInit()
return tree.RedBlackKVTree.GetVarOrSetFunc(key, f)
}
// GetVarOrSetFuncLock returns a gvar.Var with result from GetOrSetFuncLock.
@ -207,158 +168,123 @@ func (tree *RedBlackTree) GetVarOrSetFunc(key any, f func() any) *gvar.Var {
//
// Also see function GetOrSetFuncLock.
func (tree *RedBlackTree) GetVarOrSetFuncLock(key any, f func() any) *gvar.Var {
return gvar.New(tree.GetOrSetFuncLock(key, f))
tree.lazyInit()
return tree.RedBlackKVTree.GetVarOrSetFuncLock(key, f)
}
// Search searches the tree with given `key`.
// Second return parameter `found` is true if key was found, otherwise false.
func (tree *RedBlackTree) Search(key any) (value any, found bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
if node, found := tree.doGet(key); found {
return node, true
}
return nil, false
tree.lazyInit()
return tree.RedBlackKVTree.Search(key)
}
// Contains checks and returns whether given `key` exists in the tree.
func (tree *RedBlackTree) Contains(key any) bool {
tree.mu.RLock()
defer tree.mu.RUnlock()
_, ok := tree.doGet(key)
return ok
tree.lazyInit()
return tree.RedBlackKVTree.Contains(key)
}
// Size returns number of nodes in the tree.
func (tree *RedBlackTree) Size() int {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.Size()
tree.lazyInit()
return tree.RedBlackKVTree.Size()
}
// IsEmpty returns true if tree does not contain any nodes.
func (tree *RedBlackTree) IsEmpty() bool {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.Size() == 0
tree.lazyInit()
return tree.RedBlackKVTree.IsEmpty()
}
// Remove removes the node from the tree by `key`, and returns its associated value of `key`.
// The given `key` should adhere to the comparator's type assertion, otherwise method panics.
func (tree *RedBlackTree) Remove(key any) (value any) {
tree.mu.Lock()
defer tree.mu.Unlock()
return tree.doRemove(key)
tree.lazyInit()
return tree.RedBlackKVTree.Remove(key)
}
// Removes batch deletes key-value pairs from the tree by `keys`.
func (tree *RedBlackTree) Removes(keys []any) {
tree.mu.Lock()
defer tree.mu.Unlock()
for _, key := range keys {
tree.doRemove(key)
}
tree.lazyInit()
tree.RedBlackKVTree.Removes(keys)
}
// Clear removes all nodes from the tree.
func (tree *RedBlackTree) Clear() {
tree.mu.Lock()
defer tree.mu.Unlock()
tree.tree.Clear()
tree.lazyInit()
tree.RedBlackKVTree.Clear()
}
// Keys returns all keys from the tree in order by its comparator.
func (tree *RedBlackTree) Keys() []any {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.Keys()
tree.lazyInit()
return tree.RedBlackKVTree.Keys()
}
// Values returns all values from the true in order by its comparator based on the key.
func (tree *RedBlackTree) Values() []any {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.Values()
tree.lazyInit()
return tree.RedBlackKVTree.Values()
}
// Replace clears the data of the tree and sets the nodes by given `data`.
func (tree *RedBlackTree) Replace(data map[any]any) {
tree.mu.Lock()
defer tree.mu.Unlock()
tree.tree.Clear()
for k, v := range data {
tree.doSet(k, v)
}
tree.lazyInit()
tree.RedBlackKVTree.Replace(data)
}
// Print prints the tree to stdout.
func (tree *RedBlackTree) Print() {
fmt.Println(tree.String())
tree.lazyInit()
tree.RedBlackKVTree.Print()
}
// String returns a string representation of container
func (tree *RedBlackTree) String() string {
tree.mu.RLock()
defer tree.mu.RUnlock()
return gstr.Replace(tree.tree.String(), "RedBlackTree\n", "")
tree.lazyInit()
return tree.RedBlackKVTree.String()
}
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
func (tree *RedBlackTree) MarshalJSON() (jsonBytes []byte, err error) {
tree.mu.RLock()
defer tree.mu.RUnlock()
return tree.tree.MarshalJSON()
func (tree RedBlackTree) MarshalJSON() (jsonBytes []byte, err error) {
tree.lazyInit()
return tree.RedBlackKVTree.MarshalJSON()
}
// Map returns all key-value pairs as map.
func (tree *RedBlackTree) Map() map[any]any {
m := make(map[any]any, tree.Size())
tree.IteratorAsc(func(key, value any) bool {
m[key] = value
return true
})
return m
tree.lazyInit()
return tree.RedBlackKVTree.Map()
}
// MapStrAny returns all key-value items as map[string]any.
func (tree *RedBlackTree) MapStrAny() map[string]any {
m := make(map[string]any, tree.Size())
tree.IteratorAsc(func(key, value any) bool {
m[gconv.String(key)] = value
return true
})
return m
tree.lazyInit()
return tree.RedBlackKVTree.MapStrAny()
}
// Iterator is alias of IteratorAsc.
//
// Also see IteratorAsc.
func (tree *RedBlackTree) Iterator(f func(key, value any) bool) {
tree.IteratorAsc(f)
tree.lazyInit()
tree.RedBlackKVTree.Iterator(f)
}
// IteratorFrom is alias of IteratorAscFrom.
//
// Also see IteratorAscFrom.
func (tree *RedBlackTree) IteratorFrom(key any, match bool, f func(key, value any) bool) {
tree.IteratorAscFrom(key, match, f)
tree.lazyInit()
tree.RedBlackKVTree.IteratorFrom(key, match, f)
}
// IteratorAsc iterates the tree readonly in ascending order with given callback function `f`.
// If callback function `f` returns true, then it continues iterating; or false to stop.
func (tree *RedBlackTree) IteratorAsc(f func(key, value any) bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
var (
ok bool
it = tree.tree.Iterator()
)
for it.Begin(); it.Next(); {
index, value := it.Key(), it.Value()
if ok = f(index, value); !ok {
break
}
}
tree.lazyInit()
tree.RedBlackKVTree.IteratorAsc(f)
}
// IteratorAscFrom iterates the tree readonly in ascending order with given callback function `f`.
@ -368,34 +294,16 @@ func (tree *RedBlackTree) IteratorAsc(f func(key, value any) bool) {
// searching iterating.
// If callback function `f` returns true, then it continues iterating; or false to stop.
func (tree *RedBlackTree) IteratorAscFrom(key any, match bool, f func(key, value any) bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
var keys = tree.tree.Keys()
index, canIterator := iteratorFromGetIndex(key, keys, match)
if !canIterator {
return
}
for ; index < len(keys); index++ {
f(keys[index], tree.Get(keys[index]))
}
tree.lazyInit()
tree.RedBlackKVTree.IteratorAscFrom(key, match, f)
}
// IteratorDesc iterates the tree readonly in descending order with given callback function `f`.
//
// If callback function `f` returns true, then it continues iterating; or false to stop.
func (tree *RedBlackTree) IteratorDesc(f func(key, value any) bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
var (
ok bool
it = tree.tree.Iterator()
)
for it.End(); it.Prev(); {
index, value := it.Key(), it.Value()
if ok = f(index, value); !ok {
break
}
}
tree.lazyInit()
tree.RedBlackKVTree.IteratorDesc(f)
}
// IteratorDescFrom iterates the tree readonly in descending order with given callback function `f`.
@ -405,44 +313,20 @@ func (tree *RedBlackTree) IteratorDesc(f func(key, value any) bool) {
// searching iterating.
// If callback function `f` returns true, then it continues iterating; or false to stop.
func (tree *RedBlackTree) IteratorDescFrom(key any, match bool, f func(key, value any) bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
var keys = tree.tree.Keys()
index, canIterator := iteratorFromGetIndex(key, keys, match)
if !canIterator {
return
}
for ; index >= 0; index-- {
f(keys[index], tree.Get(keys[index]))
}
tree.lazyInit()
tree.RedBlackKVTree.IteratorDescFrom(key, match, f)
}
// Left returns the minimum element corresponding to the comparator of the tree or nil if the tree is empty.
func (tree *RedBlackTree) Left() *RedBlackTreeNode {
tree.mu.RLock()
defer tree.mu.RUnlock()
node := tree.tree.Left()
if node == nil {
return nil
}
return &RedBlackTreeNode{
Key: node.Key,
Value: node.Value,
}
tree.lazyInit()
return tree.RedBlackKVTree.Left()
}
// Right returns the maximum element corresponding to the comparator of the tree or nil if the tree is empty.
func (tree *RedBlackTree) Right() *RedBlackTreeNode {
tree.mu.RLock()
defer tree.mu.RUnlock()
node := tree.tree.Right()
if node == nil {
return nil
}
return &RedBlackTreeNode{
Key: node.Key,
Value: node.Value,
}
tree.lazyInit()
return tree.RedBlackKVTree.Right()
}
// Floor Finds floor node of the input key, returns the floor node or nil if no floor node is found.
@ -454,16 +338,8 @@ func (tree *RedBlackTree) Right() *RedBlackTreeNode {
//
// Key should adhere to the comparator's type assertion, otherwise method panics.
func (tree *RedBlackTree) Floor(key any) (floor *RedBlackTreeNode, found bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
node, found := tree.tree.Floor(key)
if !found {
return nil, false
}
return &RedBlackTreeNode{
Key: node.Key,
Value: node.Value,
}, true
tree.lazyInit()
return tree.RedBlackKVTree.Floor(key)
}
// Ceiling finds ceiling node of the input key, returns the ceiling node or nil if no ceiling node is found.
@ -475,16 +351,8 @@ func (tree *RedBlackTree) Floor(key any) (floor *RedBlackTreeNode, found bool) {
//
// Key should adhere to the comparator's type assertion, otherwise method panics.
func (tree *RedBlackTree) Ceiling(key any) (ceiling *RedBlackTreeNode, found bool) {
tree.mu.RLock()
defer tree.mu.RUnlock()
node, found := tree.tree.Ceiling(key)
if !found {
return nil, false
}
return &RedBlackTreeNode{
Key: node.Key,
Value: node.Value,
}, true
tree.lazyInit()
return tree.RedBlackKVTree.Ceiling(key)
}
// Flip exchanges key-value of the tree to value-key.
@ -493,6 +361,7 @@ func (tree *RedBlackTree) Ceiling(key any) (ceiling *RedBlackTreeNode, found boo
//
// If the type of value is different with key, you pass the new `comparator`.
func (tree *RedBlackTree) Flip(comparator ...func(v1, v2 any) int) {
tree.lazyInit()
var t = new(RedBlackTree)
if len(comparator) > 0 {
t = NewRedBlackTree(comparator[0], tree.mu.IsSafe())
@ -509,61 +378,12 @@ func (tree *RedBlackTree) Flip(comparator ...func(v1, v2 any) int) {
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
func (tree *RedBlackTree) UnmarshalJSON(b []byte) error {
tree.mu.Lock()
defer tree.mu.Unlock()
if tree.comparator == nil {
tree.comparator = gutil.ComparatorString
tree.tree = redblacktree.NewWith(tree.comparator)
}
var data map[string]any
if err := json.UnmarshalUseNumber(b, &data); err != nil {
return err
}
for k, v := range data {
tree.doSet(k, v)
}
return nil
tree.lazyInit()
return tree.RedBlackKVTree.UnmarshalJSON(b)
}
// UnmarshalValue is an interface implement which sets any type of value for map.
func (tree *RedBlackTree) UnmarshalValue(value any) (err error) {
tree.mu.Lock()
defer tree.mu.Unlock()
if tree.comparator == nil {
tree.comparator = gutil.ComparatorString
tree.tree = redblacktree.NewWith(tree.comparator)
}
for k, v := range gconv.Map(value) {
tree.doSet(k, v)
}
return
}
// doSet inserts key-value pair node into the tree without lock.
// If `key` already exists, then its value is updated with the new value.
// If `value` is type of <func() any>, it will be executed and its return value will be set to the map with `key`.
//
// It returns value with given `key`.
func (tree *RedBlackTree) doSet(key, value any) any {
if f, ok := value.(func() any); ok {
value = f()
}
if value == nil {
return value
}
tree.tree.Put(key, value)
return value
}
// doGet retrieves and returns the value of given key from tree without lock.
func (tree *RedBlackTree) doGet(key any) (value any, found bool) {
return tree.tree.Get(key)
}
// doRemove removes key from tree and returns its associated value without lock.
// Note that, the given `key` should adhere to the comparator's type assertion, otherwise method panics.
func (tree *RedBlackTree) doRemove(key any) (value any) {
value, _ = tree.tree.Get(key)
tree.tree.Remove(key)
return
tree.lazyInit()
return tree.RedBlackKVTree.UnmarshalValue(value)
}

2
go.mod
View File

@ -5,7 +5,7 @@ go 1.23.0
require (
github.com/BurntSushi/toml v1.5.0
github.com/clbanning/mxj/v2 v2.7.0
github.com/emirpasic/gods v1.18.1
github.com/emirpasic/gods/v2 v2.0.0-alpha
github.com/fatih/color v1.18.0
github.com/fsnotify/fsnotify v1.9.0
github.com/gorilla/websocket v1.5.3

4
go.sum
View File

@ -4,8 +4,8 @@ github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyM
github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
github.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=
github.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=