mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
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:
32
container/gmap/gmap_tree_k_v_map.go
Normal file
32
container/gmap/gmap_tree_k_v_map.go
Normal 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...)
|
||||
}
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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()
|
||||
}
|
||||
|
||||
539
container/gtree/gtree_k_v_avltree.go
Normal file
539
container/gtree/gtree_k_v_avltree.go
Normal 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
|
||||
}
|
||||
474
container/gtree/gtree_k_v_btree.go
Normal file
474
container/gtree/gtree_k_v_btree.go
Normal 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
|
||||
}
|
||||
613
container/gtree/gtree_k_v_redblacktree.go
Normal file
613
container/gtree/gtree_k_v_redblacktree.go
Normal 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
|
||||
}
|
||||
@ -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
2
go.mod
@ -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
4
go.sum
@ -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=
|
||||
|
||||
Reference in New Issue
Block a user