diff --git a/container/gmap/gmap_tree_k_v_map.go b/container/gmap/gmap_tree_k_v_map.go new file mode 100644 index 00000000000..d5909513230 --- /dev/null +++ b/container/gmap/gmap_tree_k_v_map.go @@ -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...) +} diff --git a/container/gtree/gtree.go b/container/gtree/gtree.go index 461756c2b66..29287da5637 100644 --- a/container/gtree/gtree.go +++ b/container/gtree/gtree.go @@ -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) +} diff --git a/container/gtree/gtree_avltree.go b/container/gtree/gtree_avltree.go index 0d21c131eaf..5835d6bbde5 100644 --- a/container/gtree/gtree_avltree.go +++ b/container/gtree/gtree_avltree.go @@ -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 , 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 -} diff --git a/container/gtree/gtree_btree.go b/container/gtree/gtree_btree.go index 1ae03a13270..24b8589a91b 100644 --- a/container/gtree/gtree_btree.go +++ b/container/gtree/gtree_btree.go @@ -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 , 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() } diff --git a/container/gtree/gtree_k_v_avltree.go b/container/gtree/gtree_k_v_avltree.go new file mode 100644 index 00000000000..323097039bd --- /dev/null +++ b/container/gtree/gtree_k_v_avltree.go @@ -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 , 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 +} diff --git a/container/gtree/gtree_k_v_btree.go b/container/gtree/gtree_k_v_btree.go new file mode 100644 index 00000000000..e1a4399ecd6 --- /dev/null +++ b/container/gtree/gtree_k_v_btree.go @@ -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 , 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 +} diff --git a/container/gtree/gtree_k_v_redblacktree.go b/container/gtree/gtree_k_v_redblacktree.go new file mode 100644 index 00000000000..5b0be020be0 --- /dev/null +++ b/container/gtree/gtree_k_v_redblacktree.go @@ -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 , 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 +} diff --git a/container/gtree/gtree_redblacktree.go b/container/gtree/gtree_redblacktree.go index a94dc585e9d..25138b2438d 100644 --- a/container/gtree/gtree_redblacktree.go +++ b/container/gtree/gtree_redblacktree.go @@ -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 , 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) } diff --git a/go.mod b/go.mod index 2af383f247c..a8b9e8120fa 100644 --- a/go.mod +++ b/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 diff --git a/go.sum b/go.sum index c73eb0c2ea4..0718fa9fee4 100644 --- a/go.sum +++ b/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=