mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
fix(container): remove unnecessary nil check design
This commit is contained in:
@ -17,14 +17,10 @@ import (
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
// NilChecker is a function that checks whether the given value is nil.
|
||||
type NilChecker[V any] func(V) bool
|
||||
|
||||
// KVMap wraps map type `map[K]V` and provides more map features.
|
||||
type KVMap[K comparable, V any] struct {
|
||||
mu rwmutex.RWMutex
|
||||
data map[K]V
|
||||
nilChecker NilChecker[V]
|
||||
mu rwmutex.RWMutex
|
||||
data map[K]V
|
||||
}
|
||||
|
||||
// NewKVMap creates and returns an empty hash map.
|
||||
@ -33,13 +29,6 @@ func NewKVMap[K comparable, V any](safe ...bool) *KVMap[K, V] {
|
||||
return NewKVMapFrom(make(map[K]V), safe...)
|
||||
}
|
||||
|
||||
// NewKVMapWithChecker creates and returns an empty hash map with a custom nil checker.
|
||||
// The parameter `checker` is a function used to determine if a value is nil.
|
||||
// The parameter `safe` is used to specify whether to use the map in concurrent-safety mode, which is false by default.
|
||||
func NewKVMapWithChecker[K comparable, V any](checker NilChecker[V], safe ...bool) *KVMap[K, V] {
|
||||
return NewKVMapWithCheckerFrom(make(map[K]V), checker, safe...)
|
||||
}
|
||||
|
||||
// NewKVMapFrom creates and returns a hash map from given map `data`.
|
||||
// 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.
|
||||
@ -51,38 +40,6 @@ func NewKVMapFrom[K comparable, V any](data map[K]V, safe ...bool) *KVMap[K, V]
|
||||
return m
|
||||
}
|
||||
|
||||
// NewKVMapWithCheckerFrom creates and returns a hash map from given map `data` with a custom nil checker.
|
||||
// Note that, the param `data` map will be set as the underlying data map (no deep copy),
|
||||
// and there might be some concurrent-safe issues when changing the map outside.
|
||||
// The parameter `checker` is a function used to determine if a value is nil.
|
||||
// The parameter `safe` is used to specify whether to use the map in concurrent-safety mode, which is false by default.
|
||||
func NewKVMapWithCheckerFrom[K comparable, V any](data map[K]V, checker NilChecker[V], safe ...bool) *KVMap[K, V] {
|
||||
m := NewKVMapFrom[K, V](data, safe...)
|
||||
m.RegisterNilChecker(checker)
|
||||
return m
|
||||
}
|
||||
|
||||
// RegisterNilChecker registers a custom nil checker function for the map values.
|
||||
// This function is used to determine if a value should be considered as nil.
|
||||
// The nil checker function takes a value of type V and returns a boolean indicating
|
||||
// whether the value should be treated as nil.
|
||||
func (m *KVMap[K, V]) RegisterNilChecker(nilChecker NilChecker[V]) *KVMap[K, V] {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
m.nilChecker = nilChecker
|
||||
return m
|
||||
}
|
||||
|
||||
// isNil checks whether the given value is nil.
|
||||
// It first checks if a custom nil checker function is registered and uses it if available,
|
||||
// otherwise it performs a standard nil check using any(v) == nil.
|
||||
func (m *KVMap[K, V]) isNil(v V) bool {
|
||||
if m.nilChecker != nil {
|
||||
return m.nilChecker(v)
|
||||
}
|
||||
return any(v) == nil
|
||||
}
|
||||
|
||||
// Iterator iterates the hash map readonly with custom callback function `f`.
|
||||
// If `f` returns true, then it continues iterating; or false to stop.
|
||||
func (m *KVMap[K, V]) Iterator(f func(k K, v V) bool) {
|
||||
@ -259,9 +216,7 @@ func (m *KVMap[K, V]) doSetWithLockCheck(key K, value V) (val V, ok bool) {
|
||||
if v, ok := m.data[key]; ok {
|
||||
return v, true
|
||||
}
|
||||
if !m.isNil(value) {
|
||||
m.data[key] = value
|
||||
}
|
||||
m.data[key] = value
|
||||
return value, false
|
||||
}
|
||||
|
||||
@ -296,9 +251,7 @@ func (m *KVMap[K, V]) GetOrSetFuncLock(key K, f func() V) V {
|
||||
return v
|
||||
}
|
||||
value := f()
|
||||
if !m.isNil(value) {
|
||||
m.data[key] = value
|
||||
}
|
||||
m.data[key] = value
|
||||
return value
|
||||
}
|
||||
|
||||
|
||||
@ -27,10 +27,9 @@ import (
|
||||
//
|
||||
// Reference: http://en.wikipedia.org/wiki/Associative_array
|
||||
type ListKVMap[K comparable, V any] struct {
|
||||
mu rwmutex.RWMutex
|
||||
data map[K]*glist.TElement[*gListKVMapNode[K, V]]
|
||||
list *glist.TList[*gListKVMapNode[K, V]]
|
||||
nilChecker NilChecker[V]
|
||||
mu rwmutex.RWMutex
|
||||
data map[K]*glist.TElement[*gListKVMapNode[K, V]]
|
||||
list *glist.TList[*gListKVMapNode[K, V]]
|
||||
}
|
||||
|
||||
type gListKVMapNode[K comparable, V any] struct {
|
||||
@ -50,16 +49,6 @@ func NewListKVMap[K comparable, V any](safe ...bool) *ListKVMap[K, V] {
|
||||
}
|
||||
}
|
||||
|
||||
// NewListKVMapWithChecker creates and returns a new ListKVMap instance with a custom nil checker.
|
||||
// The parameter `checker` is a function used to determine if a value is nil.
|
||||
// The parameter `safe` is used to specify whether using map in concurrent-safety,
|
||||
// which is false by default.
|
||||
func NewListKVMapWithChecker[K comparable, V any](checker NilChecker[V], safe ...bool) *ListKVMap[K, V] {
|
||||
m := NewListKVMap[K, V](safe...)
|
||||
m.RegisterNilChecker(checker)
|
||||
return m
|
||||
}
|
||||
|
||||
// NewListKVMapFrom returns a link map from given map `data`.
|
||||
// Note that, the param `data` map will be copied to the underlying data structure,
|
||||
// so changes to the original map will not affect the link map.
|
||||
@ -69,39 +58,6 @@ func NewListKVMapFrom[K comparable, V any](data map[K]V, safe ...bool) *ListKVMa
|
||||
return m
|
||||
}
|
||||
|
||||
// NewListKVMapWithCheckerFrom returns a link map from given map `data` with a custom nil checker.
|
||||
// Note that, the param `data` map will be copied to the underlying data structure,
|
||||
// so changes to the original map will not affect the link map.
|
||||
// The parameter `checker` is a function used to determine if a value is nil.
|
||||
// The parameter `safe` is used to specify whether using map in concurrent-safety,
|
||||
// which is false by default.
|
||||
func NewListKVMapWithCheckerFrom[K comparable, V any](data map[K]V, nilChecker NilChecker[V], safe ...bool) *ListKVMap[K, V] {
|
||||
m := NewListKVMapWithChecker[K, V](nilChecker, safe...)
|
||||
m.Sets(data)
|
||||
return m
|
||||
}
|
||||
|
||||
// RegisterNilChecker registers a custom nil checker function for the map values.
|
||||
// This function is used to determine if a value should be considered as nil.
|
||||
// The nil checker function takes a value of type V and returns a boolean indicating
|
||||
// whether the value should be treated as nil.
|
||||
func (m *ListKVMap[K, V]) RegisterNilChecker(nilChecker NilChecker[V]) *ListKVMap[K, V] {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
m.nilChecker = nilChecker
|
||||
return m
|
||||
}
|
||||
|
||||
// isNil checks whether the given value is nil.
|
||||
// It first checks if a custom nil checker function is registered and uses it if available,
|
||||
// otherwise it performs a standard nil check using any(v) == nil.
|
||||
func (m *ListKVMap[K, V]) isNil(v V) bool {
|
||||
if m.nilChecker != nil {
|
||||
return m.nilChecker(v)
|
||||
}
|
||||
return any(v) == nil
|
||||
}
|
||||
|
||||
// Iterator is alias of IteratorAsc.
|
||||
func (m *ListKVMap[K, V]) Iterator(f func(key K, value V) bool) {
|
||||
m.IteratorAsc(f)
|
||||
@ -326,9 +282,7 @@ func (m *ListKVMap[K, V]) doSetWithLockCheckWithoutLock(key K, value V) V {
|
||||
if e, ok := m.data[key]; ok {
|
||||
return e.Value.value
|
||||
}
|
||||
if !m.isNil(value) {
|
||||
m.data[key] = m.list.PushBack(&gListKVMapNode[K, V]{key, value})
|
||||
}
|
||||
m.data[key] = m.list.PushBack(&gListKVMapNode[K, V]{key, value})
|
||||
return value
|
||||
}
|
||||
|
||||
@ -371,9 +325,7 @@ func (m *ListKVMap[K, V]) GetOrSetFuncLock(key K, f func() V) V {
|
||||
return e.Value.value
|
||||
}
|
||||
value := f()
|
||||
if !m.isNil(value) {
|
||||
m.data[key] = m.list.PushBack(&gListKVMapNode[K, V]{key, value})
|
||||
}
|
||||
m.data[key] = m.list.PushBack(&gListKVMapNode[K, V]{key, value})
|
||||
return value
|
||||
}
|
||||
|
||||
@ -414,9 +366,7 @@ func (m *ListKVMap[K, V]) SetIfNotExist(key K, value V) bool {
|
||||
if _, ok := m.data[key]; ok {
|
||||
return false
|
||||
}
|
||||
if !m.isNil(value) {
|
||||
m.data[key] = m.list.PushBack(&gListKVMapNode[K, V]{key, value})
|
||||
}
|
||||
m.data[key] = m.list.PushBack(&gListKVMapNode[K, V]{key, value})
|
||||
return true
|
||||
}
|
||||
|
||||
@ -434,9 +384,7 @@ func (m *ListKVMap[K, V]) SetIfNotExistFunc(key K, f func() V) bool {
|
||||
return false
|
||||
}
|
||||
value := f()
|
||||
if !m.isNil(value) {
|
||||
m.data[key] = m.list.PushBack(&gListKVMapNode[K, V]{key, value})
|
||||
}
|
||||
m.data[key] = m.list.PushBack(&gListKVMapNode[K, V]{key, value})
|
||||
return true
|
||||
}
|
||||
|
||||
@ -457,9 +405,7 @@ func (m *ListKVMap[K, V]) SetIfNotExistFuncLock(key K, f func() V) bool {
|
||||
return false
|
||||
}
|
||||
value := f()
|
||||
if !m.isNil(value) {
|
||||
m.data[key] = m.list.PushBack(&gListKVMapNode[K, V]{key, value})
|
||||
}
|
||||
m.data[key] = m.list.PushBack(&gListKVMapNode[K, V]{key, value})
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@ -774,6 +774,13 @@ func Test_KVMap_MarshalJSON(t *testing.T) {
|
||||
t.Assert(data["a"], 1)
|
||||
t.Assert(data["b"], 2)
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var m gmap.KVMap[int, int]
|
||||
m.Set(1, 10)
|
||||
b, err := json.Marshal(m)
|
||||
t.AssertNil(err)
|
||||
t.Assert(string(b), `{"1":10}`)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_KVMap_UnmarshalJSON(t *testing.T) {
|
||||
@ -891,7 +898,7 @@ func Test_KVMap_GetOrSet_NilValue(t *testing.T) {
|
||||
v := m.GetOrSet("a", nil)
|
||||
t.Assert(v, nil)
|
||||
// nil interface value should not be stored
|
||||
t.Assert(m.Contains("a"), false)
|
||||
t.Assert(m.Contains("a"), true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -903,7 +910,7 @@ func Test_KVMap_GetOrSetFunc_NilValue(t *testing.T) {
|
||||
v := m.GetOrSetFunc("a", func() any { return nil })
|
||||
t.Assert(v, nil)
|
||||
// nil interface value should not be stored
|
||||
t.Assert(m.Contains("a"), false)
|
||||
t.Assert(m.Contains("a"), true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -922,7 +929,7 @@ func Test_KVMap_GetOrSetFuncLock_NilData(t *testing.T) {
|
||||
v := m.GetOrSetFuncLock("a", func() any { return nil })
|
||||
t.Assert(v, nil)
|
||||
// nil interface value should not be stored
|
||||
t.Assert(m.Contains("a"), false)
|
||||
t.Assert(m.Contains("a"), true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -1630,67 +1637,3 @@ func Test_KVMap_Flip_String(t *testing.T) {
|
||||
t.Assert(m.Get("val2"), "key2")
|
||||
})
|
||||
}
|
||||
|
||||
// Test TypedNil with custom nil checker for pointers
|
||||
func Test_KVMap_TypedNil(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type Student struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
m1 := gmap.NewKVMap[int, *Student](true)
|
||||
for i := 0; i < 10; i++ {
|
||||
m1.GetOrSetFuncLock(i, func() *Student {
|
||||
if i%2 == 0 {
|
||||
return &Student{}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
t.Assert(m1.Size(), 10)
|
||||
m2 := gmap.NewKVMap[int, *Student](true)
|
||||
m2.RegisterNilChecker(func(student *Student) bool {
|
||||
return student == nil
|
||||
})
|
||||
for i := 0; i < 10; i++ {
|
||||
m2.GetOrSetFuncLock(i, func() *Student {
|
||||
if i%2 == 0 {
|
||||
return &Student{}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
t.Assert(m2.Size(), 5)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_NewKVMapWithChecker_TypedNil(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type Student struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
m1 := gmap.NewKVMap[int, *Student](true)
|
||||
for i := 0; i < 10; i++ {
|
||||
m1.GetOrSetFuncLock(i, func() *Student {
|
||||
if i%2 == 0 {
|
||||
return &Student{}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
t.Assert(m1.Size(), 10)
|
||||
m2 := gmap.NewKVMapWithChecker[int, *Student](func(student *Student) bool {
|
||||
return student == nil
|
||||
}, true)
|
||||
for i := 0; i < 10; i++ {
|
||||
m2.GetOrSetFuncLock(i, func() *Student {
|
||||
if i%2 == 0 {
|
||||
return &Student{}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
t.Assert(m2.Size(), 5)
|
||||
})
|
||||
}
|
||||
|
||||
@ -817,7 +817,7 @@ func Test_ListKVMap_GetOrSet_NilValue(t *testing.T) {
|
||||
v := m.GetOrSet("a", nil)
|
||||
t.Assert(v, nil)
|
||||
// nil interface value should not be stored
|
||||
t.Assert(m.Contains("a"), false)
|
||||
t.Assert(m.Contains("a"), true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -1292,7 +1292,7 @@ func Test_ListKVMap_GetOrSetFuncLock_NilData(t *testing.T) {
|
||||
v := m.GetOrSetFuncLock("a", func() any { return nil })
|
||||
t.Assert(v, nil)
|
||||
// nil interface value should not be stored
|
||||
t.Assert(m.Contains("a"), false)
|
||||
t.Assert(m.Contains("a"), true)
|
||||
})
|
||||
}
|
||||
|
||||
@ -1341,67 +1341,3 @@ func Test_ListKVMap_UnmarshalValue_NilData(t *testing.T) {
|
||||
t.Assert(m.Get("b"), "2")
|
||||
})
|
||||
}
|
||||
|
||||
// Test typed nil values
|
||||
func Test_ListKVMap_TypedNil(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type Student struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
m1 := gmap.NewListKVMap[int, *Student](true)
|
||||
for i := 0; i < 10; i++ {
|
||||
m1.GetOrSetFuncLock(i, func() *Student {
|
||||
if i%2 == 0 {
|
||||
return &Student{}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
t.Assert(m1.Size(), 10)
|
||||
m2 := gmap.NewListKVMap[int, *Student](true)
|
||||
m2.RegisterNilChecker(func(student *Student) bool {
|
||||
return student == nil
|
||||
})
|
||||
for i := 0; i < 10; i++ {
|
||||
m2.GetOrSetFuncLock(i, func() *Student {
|
||||
if i%2 == 0 {
|
||||
return &Student{}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
t.Assert(m2.Size(), 5)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_NewListKVMapWithChecker_TypedNil(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type Student struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
m1 := gmap.NewListKVMap[int, *Student](true)
|
||||
for i := 0; i < 10; i++ {
|
||||
m1.GetOrSetFuncLock(i, func() *Student {
|
||||
if i%2 == 0 {
|
||||
return &Student{}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
t.Assert(m1.Size(), 10)
|
||||
m2 := gmap.NewListKVMapWithChecker[int, *Student](func(student *Student) bool {
|
||||
return student == nil
|
||||
}, true)
|
||||
for i := 0; i < 10; i++ {
|
||||
m2.GetOrSetFuncLock(i, func() *Student {
|
||||
if i%2 == 0 {
|
||||
return &Student{}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
t.Assert(m2.Size(), 5)
|
||||
})
|
||||
}
|
||||
|
||||
@ -86,7 +86,7 @@ func (set *Set) AddIfNotExistFunc(item any, f func() bool) bool {
|
||||
}
|
||||
|
||||
// AddIfNotExistFuncLock checks whether item exists in the set,
|
||||
// it adds the item to set and returns true if it does not exists in the set and
|
||||
// it adds the item to set and returns true if it does not exist in the set and
|
||||
// function `f` returns true, or else it does nothing and returns false.
|
||||
//
|
||||
// Note that, if `item` is nil, it does nothing and returns false. The function `f`
|
||||
|
||||
@ -15,14 +15,10 @@ import (
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
// NilChecker is a function that checks whether the given value is nil.
|
||||
type NilChecker[T any] func(T) bool
|
||||
|
||||
// TSet[T] is consisted of any items.
|
||||
// TSet is a generic set implementation that holds unique items of type T.
|
||||
type TSet[T comparable] struct {
|
||||
mu rwmutex.RWMutex
|
||||
data map[T]struct{}
|
||||
nilChecker NilChecker[T]
|
||||
mu rwmutex.RWMutex
|
||||
data map[T]struct{}
|
||||
}
|
||||
|
||||
// NewTSet creates and returns a new set, which contains un-repeated items.
|
||||
@ -34,15 +30,6 @@ func NewTSet[T comparable](safe ...bool) *TSet[T] {
|
||||
}
|
||||
}
|
||||
|
||||
// NewTSetWithChecker creates and returns a new set with a custom nil checker.
|
||||
// The parameter `nilChecker` is a function used to determine if a value is nil.
|
||||
// The parameter `safe` is used to specify whether using set in concurrent-safety mode.
|
||||
func NewTSetWithChecker[T comparable](checker NilChecker[T], safe ...bool) *TSet[T] {
|
||||
s := NewTSet[T](safe...)
|
||||
s.RegisterNilChecker(checker)
|
||||
return s
|
||||
}
|
||||
|
||||
// NewTSetFrom returns a new set from `items`.
|
||||
// `items` - A slice of type T.
|
||||
func NewTSetFrom[T comparable](items []T, safe ...bool) *TSet[T] {
|
||||
@ -56,37 +43,6 @@ func NewTSetFrom[T comparable](items []T, safe ...bool) *TSet[T] {
|
||||
}
|
||||
}
|
||||
|
||||
// NewTSetWithCheckerFrom returns a new set from `items` with a custom nil checker.
|
||||
// The parameter `items` is a slice of elements to be added to the set.
|
||||
// The parameter `checker` is a function used to determine if a value is nil.
|
||||
// The parameter `safe` is used to specify whether using set in concurrent-safety mode.
|
||||
func NewTSetWithCheckerFrom[T comparable](items []T, checker NilChecker[T], safe ...bool) *TSet[T] {
|
||||
set := NewTSetWithChecker[T](checker, safe...)
|
||||
set.Add(items...)
|
||||
return set
|
||||
}
|
||||
|
||||
// RegisterNilChecker registers a custom nil checker function for the set elements.
|
||||
// This function is used to determine if an element should be considered as nil.
|
||||
// The nil checker function takes an element of type T and returns a boolean indicating
|
||||
// whether the element should be treated as nil.
|
||||
func (set *TSet[T]) RegisterNilChecker(nilChecker NilChecker[T]) *TSet[T] {
|
||||
set.mu.Lock()
|
||||
defer set.mu.Unlock()
|
||||
set.nilChecker = nilChecker
|
||||
return set
|
||||
}
|
||||
|
||||
// isNil checks whether the given value is nil.
|
||||
// It first checks if a custom nil checker function is registered and uses it if available,
|
||||
// otherwise it performs a standard nil check using any(v) == nil.
|
||||
func (set *TSet[T]) isNil(v T) bool {
|
||||
if set.nilChecker != nil {
|
||||
return set.nilChecker(v)
|
||||
}
|
||||
return any(v) == nil
|
||||
}
|
||||
|
||||
// Iterator iterates the set readonly with given callback function `f`,
|
||||
// if `f` returns true then continue iterating; or false to stop.
|
||||
func (set *TSet[T]) Iterator(f func(v T) bool) {
|
||||
@ -115,9 +71,6 @@ func (set *TSet[T]) Add(items ...T) {
|
||||
//
|
||||
// Note that, if `item` is nil, it does nothing and returns false.
|
||||
func (set *TSet[T]) AddIfNotExist(item T) bool {
|
||||
if set.isNil(item) {
|
||||
return false
|
||||
}
|
||||
if !set.Contains(item) {
|
||||
set.mu.Lock()
|
||||
defer set.mu.Unlock()
|
||||
@ -139,9 +92,6 @@ func (set *TSet[T]) AddIfNotExist(item T) bool {
|
||||
// Note that, if `item` is nil, it does nothing and returns false. The function `f`
|
||||
// is executed without writing lock.
|
||||
func (set *TSet[T]) AddIfNotExistFunc(item T, f func() bool) bool {
|
||||
if set.isNil(item) {
|
||||
return false
|
||||
}
|
||||
if !set.Contains(item) {
|
||||
if f() {
|
||||
set.mu.Lock()
|
||||
@ -159,15 +109,12 @@ func (set *TSet[T]) AddIfNotExistFunc(item T, f func() bool) bool {
|
||||
}
|
||||
|
||||
// AddIfNotExistFuncLock checks whether item exists in the set,
|
||||
// it adds the item to set and returns true if it does not exists in the set and
|
||||
// it adds the item to set and returns true if it does not exist in the set and
|
||||
// function `f` returns true, or else it does nothing and returns false.
|
||||
//
|
||||
// Note that, if `item` is nil, it does nothing and returns false. The function `f`
|
||||
// is executed within writing lock.
|
||||
func (set *TSet[T]) AddIfNotExistFuncLock(item T, f func() bool) bool {
|
||||
if set.isNil(item) {
|
||||
return false
|
||||
}
|
||||
if !set.Contains(item) {
|
||||
set.mu.Lock()
|
||||
defer set.mu.Unlock()
|
||||
|
||||
@ -419,6 +419,7 @@ func TestSet_AddIfNotExist(t *testing.T) {
|
||||
t.Assert(s.AddIfNotExist(2), true)
|
||||
t.Assert(s.Contains(2), true)
|
||||
t.Assert(s.AddIfNotExist(2), false)
|
||||
t.Assert(s.AddIfNotExist(nil), true)
|
||||
t.Assert(s.AddIfNotExist(nil), false)
|
||||
t.Assert(s.Contains(2), true)
|
||||
})
|
||||
@ -497,7 +498,18 @@ func TestSet_AddIfNotExistFuncLock(t *testing.T) {
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
s := gset.New(true)
|
||||
t.Assert(s.AddIfNotExistFuncLock(nil, func() bool { return true }), false)
|
||||
t.Assert(
|
||||
s.AddIfNotExistFuncLock(nil, func() bool {
|
||||
return true
|
||||
}),
|
||||
true,
|
||||
)
|
||||
t.Assert(
|
||||
s.AddIfNotExistFuncLock(nil, func() bool {
|
||||
return true
|
||||
}),
|
||||
false,
|
||||
)
|
||||
s1 := gset.Set{}
|
||||
t.Assert(s1.AddIfNotExistFuncLock(1, func() bool { return true }), true)
|
||||
})
|
||||
|
||||
@ -591,42 +591,3 @@ func TestTSet_RLockFunc(t *testing.T) {
|
||||
t.Assert(sum, 6)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_TSet_TypedNil(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type Student struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
set := gset.NewTSet[*Student](true)
|
||||
var s *Student = nil
|
||||
exist := set.AddIfNotExist(s)
|
||||
t.Assert(exist, true)
|
||||
|
||||
set2 := gset.NewTSet[*Student](true)
|
||||
set2.RegisterNilChecker(func(student *Student) bool {
|
||||
return student == nil
|
||||
})
|
||||
exist2 := set2.AddIfNotExist(s)
|
||||
t.Assert(exist2, false)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_NewTSetWithChecker_TypedNil(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type Student struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
set := gset.NewTSet[*Student](true)
|
||||
var s *Student = nil
|
||||
exist := set.AddIfNotExist(s)
|
||||
t.Assert(exist, true)
|
||||
|
||||
set2 := gset.NewTSetWithChecker[*Student](func(student *Student) bool {
|
||||
return student == nil
|
||||
}, true)
|
||||
exist2 := set2.AddIfNotExist(s)
|
||||
t.Assert(exist2, false)
|
||||
})
|
||||
}
|
||||
|
||||
@ -18,15 +18,11 @@ import (
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
// NilChecker is a function that checks whether the given value is nil.
|
||||
type NilChecker[V any] func(V) bool
|
||||
|
||||
// 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]
|
||||
nilChecker NilChecker[V]
|
||||
}
|
||||
|
||||
// AVLKVTreeNode is a single element within the tree.
|
||||
@ -47,15 +43,6 @@ func NewAVLKVTree[K comparable, V any](comparator func(v1, v2 K) int, safe ...bo
|
||||
}
|
||||
}
|
||||
|
||||
// NewAVLKVTreeWithChecker instantiates an AVL tree with the custom key comparator and nil checker.
|
||||
// The parameter `safe` is used to specify whether using tree in concurrent-safety, which is false in default.
|
||||
// The parameter `checker` is used to specify whether the given value is nil.
|
||||
func NewAVLKVTreeWithChecker[K comparable, V any](comparator func(v1, v2 K) int, checker NilChecker[V], safe ...bool) *AVLKVTree[K, V] {
|
||||
t := NewAVLKVTree[K, V](comparator, safe...)
|
||||
t.RegisterNilChecker(checker)
|
||||
return t
|
||||
}
|
||||
|
||||
// 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.
|
||||
@ -67,38 +54,6 @@ func NewAVLKVTreeFrom[K comparable, V any](comparator func(v1, v2 K) int, data m
|
||||
return tree
|
||||
}
|
||||
|
||||
// NewAVLKVTreeWithCheckerFrom instantiates an AVL tree with the custom key comparator, nil checker and data map.
|
||||
// The parameter `safe` is used to specify whether using tree in concurrent-safety, which is false in default.
|
||||
// The parameter `checker` is used to specify whether the given value is nil.
|
||||
func NewAVLKVTreeWithCheckerFrom[K comparable, V any](comparator func(v1, v2 K) int, data map[K]V, checker NilChecker[V], safe ...bool) *AVLKVTree[K, V] {
|
||||
tree := NewAVLKVTreeWithChecker[K, V](comparator, checker, safe...)
|
||||
for k, v := range data {
|
||||
tree.doSet(k, v)
|
||||
}
|
||||
return tree
|
||||
}
|
||||
|
||||
// RegisterNilChecker registers a custom nil checker function for the map values.
|
||||
// This function is used to determine if a value should be considered as nil.
|
||||
// The nil checker function takes a value of type V and returns a boolean indicating
|
||||
// whether the value should be treated as nil.
|
||||
func (tree *AVLKVTree[K, V]) RegisterNilChecker(nilChecker NilChecker[V]) *AVLKVTree[K, V] {
|
||||
tree.mu.Lock()
|
||||
defer tree.mu.Unlock()
|
||||
tree.nilChecker = nilChecker
|
||||
return tree
|
||||
}
|
||||
|
||||
// isNil checks whether the given value is nil.
|
||||
// It first checks if a custom nil checker function is registered and uses it if available,
|
||||
// otherwise it performs a standard nil check using any(v) == nil.
|
||||
func (tree *AVLKVTree[K, V]) isNil(value V) bool {
|
||||
if tree.nilChecker != nil {
|
||||
return tree.nilChecker(value)
|
||||
}
|
||||
return any(value) == nil
|
||||
}
|
||||
|
||||
// Clone clones and returns a new tree from current tree.
|
||||
func (tree *AVLKVTree[K, V]) Clone() *AVLKVTree[K, V] {
|
||||
if tree == nil {
|
||||
@ -563,9 +518,6 @@ func (tree *AVLKVTree[K, V]) Flip(comparator ...func(v1, v2 K) int) {
|
||||
//
|
||||
// It returns value with given `key`.
|
||||
func (tree *AVLKVTree[K, V]) doSet(key K, value V) V {
|
||||
if tree.isNil(value) {
|
||||
return value
|
||||
}
|
||||
tree.tree.Put(key, value)
|
||||
return value
|
||||
}
|
||||
|
||||
@ -24,7 +24,6 @@ type BKVTree[K comparable, V any] struct {
|
||||
comparator func(v1, v2 K) int
|
||||
m int // order (maximum number of children)
|
||||
tree *btree.Tree[K, V]
|
||||
nilChecker NilChecker[V]
|
||||
}
|
||||
|
||||
// BKVTreeEntry represents the key-value pair contained within nodes.
|
||||
@ -46,15 +45,6 @@ func NewBKVTree[K comparable, V any](m int, comparator func(v1, v2 K) int, safe
|
||||
}
|
||||
}
|
||||
|
||||
// NewBKVTreeWithChecker instantiates a B-tree with `m` (maximum number of children), a custom key comparator and nil checker.
|
||||
// The parameter `safe` is used to specify whether using tree in concurrent-safety, which is false in default.
|
||||
// The parameter `checker` is used to specify whether the given value is nil.
|
||||
func NewBKVTreeWithChecker[K comparable, V any](m int, comparator func(v1, v2 K) int, checker NilChecker[V], safe ...bool) *BKVTree[K, V] {
|
||||
t := NewBKVTree[K, V](m, comparator, safe...)
|
||||
t.RegisterNilChecker(checker)
|
||||
return t
|
||||
}
|
||||
|
||||
// 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.
|
||||
@ -66,38 +56,6 @@ func NewBKVTreeFrom[K comparable, V any](m int, comparator func(v1, v2 K) int, d
|
||||
return tree
|
||||
}
|
||||
|
||||
// NewBKVTreeWithCheckerFrom instantiates a B-tree with `m` (maximum number of children), a custom key comparator, nil checker and data map.
|
||||
// The parameter `safe` is used to specify whether using tree in concurrent-safety, which is false in default.
|
||||
// The parameter `checker` is used to specify whether the given value is nil.
|
||||
func NewBKVTreeWithCheckerFrom[K comparable, V any](m int, comparator func(v1, v2 K) int, data map[K]V, checker NilChecker[V], safe ...bool) *BKVTree[K, V] {
|
||||
tree := NewBKVTreeWithChecker[K, V](m, comparator, checker, safe...)
|
||||
for k, v := range data {
|
||||
tree.doSet(k, v)
|
||||
}
|
||||
return tree
|
||||
}
|
||||
|
||||
// RegisterNilChecker registers a custom nil checker function for the map values.
|
||||
// This function is used to determine if a value should be considered as nil.
|
||||
// The nil checker function takes a value of type V and returns a boolean indicating
|
||||
// whether the value should be treated as nil.
|
||||
func (tree *BKVTree[K, V]) RegisterNilChecker(nilChecker NilChecker[V]) *BKVTree[K, V] {
|
||||
tree.mu.Lock()
|
||||
defer tree.mu.Unlock()
|
||||
tree.nilChecker = nilChecker
|
||||
return tree
|
||||
}
|
||||
|
||||
// isNil checks whether the given value is nil.
|
||||
// It first checks if a custom nil checker function is registered and uses it if available,
|
||||
// otherwise it performs a standard nil check using any(v) == nil.
|
||||
func (tree *BKVTree[K, V]) isNil(value V) bool {
|
||||
if tree.nilChecker != nil {
|
||||
return tree.nilChecker(value)
|
||||
}
|
||||
return any(value) == nil
|
||||
}
|
||||
|
||||
// Clone clones and returns a new tree from current tree.
|
||||
func (tree *BKVTree[K, V]) Clone() *BKVTree[K, V] {
|
||||
if tree == nil {
|
||||
@ -495,9 +453,6 @@ func (tree *BKVTree[K, V]) Right() *BKVTreeEntry[K, V] {
|
||||
//
|
||||
// It returns value with given `key`.
|
||||
func (tree *BKVTree[K, V]) doSet(key K, value V) V {
|
||||
if tree.isNil(value) {
|
||||
return value
|
||||
}
|
||||
tree.tree.Put(key, value)
|
||||
return value
|
||||
}
|
||||
|
||||
@ -24,7 +24,6 @@ type RedBlackKVTree[K comparable, V any] struct {
|
||||
mu rwmutex.RWMutex
|
||||
comparator func(v1, v2 K) int
|
||||
tree *redblacktree.Tree[K, V]
|
||||
nilChecker NilChecker[V]
|
||||
}
|
||||
|
||||
// RedBlackKVTreeNode is a single element within the tree.
|
||||
@ -42,15 +41,6 @@ func NewRedBlackKVTree[K comparable, V any](comparator func(v1, v2 K) int, safe
|
||||
return &tree
|
||||
}
|
||||
|
||||
// NewRedBlackKVTreeWithChecker instantiates a red-black tree with the custom key comparator and `nilChecker`.
|
||||
// The parameter `safe` is used to specify whether using tree in concurrent-safety, which is false in default.
|
||||
// The parameter `checker` is used to specify whether the given value is nil.
|
||||
func NewRedBlackKVTreeWithChecker[K comparable, V any](comparator func(v1, v2 K) int, checker NilChecker[V], safe ...bool) *RedBlackKVTree[K, V] {
|
||||
t := NewRedBlackKVTree[K, V](comparator, safe...)
|
||||
t.RegisterNilChecker(checker)
|
||||
return t
|
||||
}
|
||||
|
||||
// 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.
|
||||
@ -60,17 +50,6 @@ func NewRedBlackKVTreeFrom[K comparable, V any](comparator func(v1, v2 K) int, d
|
||||
return &tree
|
||||
}
|
||||
|
||||
// NewRedBlackKVTreeWithCheckerFrom instantiates a red-black tree with the custom key comparator, `data` map and `nilChecker`.
|
||||
// The parameter `safe` is used to specify whether using tree in concurrent-safety, which is false in default.
|
||||
// The parameter `checker` is used to specify whether the given value is nil.
|
||||
func NewRedBlackKVTreeWithCheckerFrom[K comparable, V any](comparator func(v1, v2 K) int, data map[K]V, checker NilChecker[V], safe ...bool) *RedBlackKVTree[K, V] {
|
||||
t := NewRedBlackKVTreeWithChecker[K, V](comparator, checker, safe...)
|
||||
for k, v := range data {
|
||||
t.doSet(k, v)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// 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.
|
||||
@ -96,27 +75,6 @@ func RedBlackKVTreeInitFrom[K comparable, V any](tree *RedBlackKVTree[K, V], com
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterNilChecker registers a custom nil checker function for the map values.
|
||||
// This function is used to determine if a value should be considered as nil.
|
||||
// The nil checker function takes a value of type V and returns a boolean indicating
|
||||
// whether the value should be treated as nil.
|
||||
func (tree *RedBlackKVTree[K, V]) RegisterNilChecker(nilChecker NilChecker[V]) *RedBlackKVTree[K, V] {
|
||||
tree.mu.Lock()
|
||||
defer tree.mu.Unlock()
|
||||
tree.nilChecker = nilChecker
|
||||
return tree
|
||||
}
|
||||
|
||||
// isNil checks whether the given value is nil.
|
||||
// It first checks if a custom nil checker function is registered and uses it if available,
|
||||
// otherwise it performs a standard nil check using any(v) == nil.
|
||||
func (tree *RedBlackKVTree[K, V]) isNil(value V) bool {
|
||||
if tree.nilChecker != nil {
|
||||
return tree.nilChecker(value)
|
||||
}
|
||||
return any(value) == nil
|
||||
}
|
||||
|
||||
// SetComparator sets/changes the comparator for sorting.
|
||||
func (tree *RedBlackKVTree[K, V]) SetComparator(comparator func(a, b K) int) {
|
||||
tree.comparator = comparator
|
||||
@ -634,9 +592,6 @@ func (tree *RedBlackKVTree[K, V]) UnmarshalValue(value any) (err error) {
|
||||
//
|
||||
// It returns value with given `key`.
|
||||
func (tree *RedBlackKVTree[K, V]) doSet(key K, value V) (ret V) {
|
||||
if tree.isNil(value) {
|
||||
return
|
||||
}
|
||||
tree.tree.Put(key, value)
|
||||
return value
|
||||
}
|
||||
|
||||
@ -1,210 +0,0 @@
|
||||
// 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_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/v2/container/gtree"
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
"github.com/gogf/gf/v2/util/gutil"
|
||||
)
|
||||
|
||||
func Test_KVAVLTree_TypedNil(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type Student struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
avlTree := gtree.NewAVLKVTree[int, *Student](gutil.ComparatorTStr[int], true)
|
||||
for i := 0; i < 10; i++ {
|
||||
if i%2 == 0 {
|
||||
avlTree.Set(i, &Student{})
|
||||
} else {
|
||||
var s *Student = nil
|
||||
avlTree.Set(i, s)
|
||||
}
|
||||
}
|
||||
t.Assert(avlTree.Size(), 10)
|
||||
avlTree2 := gtree.NewAVLKVTree[int, *Student](gutil.ComparatorTStr[int], true)
|
||||
avlTree2.RegisterNilChecker(func(student *Student) bool {
|
||||
return student == nil
|
||||
})
|
||||
for i := 0; i < 10; i++ {
|
||||
if i%2 == 0 {
|
||||
avlTree2.Set(i, &Student{})
|
||||
} else {
|
||||
var s *Student = nil
|
||||
avlTree2.Set(i, s)
|
||||
}
|
||||
}
|
||||
t.Assert(avlTree2.Size(), 5)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func Test_KVBTree_TypedNil(t *testing.T) {
|
||||
type Student struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
btree := gtree.NewBKVTree[int, *Student](100, gutil.ComparatorTStr[int], true)
|
||||
for i := 0; i < 10; i++ {
|
||||
if i%2 == 0 {
|
||||
btree.Set(i, &Student{})
|
||||
} else {
|
||||
var s *Student = nil
|
||||
btree.Set(i, s)
|
||||
}
|
||||
}
|
||||
t.Assert(btree.Size(), 10)
|
||||
btree2 := gtree.NewBKVTree[int, *Student](100, gutil.ComparatorTStr[int], true)
|
||||
btree2.RegisterNilChecker(func(student *Student) bool {
|
||||
return student == nil
|
||||
})
|
||||
for i := 0; i < 10; i++ {
|
||||
if i%2 == 0 {
|
||||
btree2.Set(i, &Student{})
|
||||
} else {
|
||||
var s *Student = nil
|
||||
btree2.Set(i, s)
|
||||
}
|
||||
}
|
||||
t.Assert(btree2.Size(), 5)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func Test_KVRedBlackTree_TypedNil(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type Student struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
redBlackTree := gtree.NewRedBlackKVTree[int, *Student](gutil.ComparatorTStr[int], true)
|
||||
for i := 0; i < 10; i++ {
|
||||
if i%2 == 0 {
|
||||
redBlackTree.Set(i, &Student{})
|
||||
} else {
|
||||
var s *Student = nil
|
||||
redBlackTree.Set(i, s)
|
||||
}
|
||||
}
|
||||
t.Assert(redBlackTree.Size(), 10)
|
||||
redBlackTree2 := gtree.NewRedBlackKVTree[int, *Student](gutil.ComparatorTStr[int], true)
|
||||
|
||||
redBlackTree2.RegisterNilChecker(func(student *Student) bool {
|
||||
return student == nil
|
||||
})
|
||||
for i := 0; i < 10; i++ {
|
||||
if i%2 == 0 {
|
||||
redBlackTree2.Set(i, &Student{})
|
||||
} else {
|
||||
var s *Student = nil
|
||||
redBlackTree2.Set(i, s)
|
||||
}
|
||||
}
|
||||
t.Assert(redBlackTree2.Size(), 5)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_NewKVAVLTreeWithChecker_TypedNil(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type Student struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
avlTree := gtree.NewAVLKVTree[int, *Student](gutil.ComparatorTStr[int], true)
|
||||
for i := 0; i < 10; i++ {
|
||||
if i%2 == 0 {
|
||||
avlTree.Set(i, &Student{})
|
||||
} else {
|
||||
var s *Student = nil
|
||||
avlTree.Set(i, s)
|
||||
}
|
||||
}
|
||||
t.Assert(avlTree.Size(), 10)
|
||||
avlTree2 := gtree.NewAVLKVTreeWithChecker[int, *Student](gutil.ComparatorTStr[int], func(student *Student) bool {
|
||||
return student == nil
|
||||
}, true)
|
||||
for i := 0; i < 10; i++ {
|
||||
if i%2 == 0 {
|
||||
avlTree2.Set(i, &Student{})
|
||||
} else {
|
||||
var s *Student = nil
|
||||
avlTree2.Set(i, s)
|
||||
}
|
||||
}
|
||||
t.Assert(avlTree2.Size(), 5)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func Test_NewKVBTreeWithChecker_TypedNil(t *testing.T) {
|
||||
type Student struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
btree := gtree.NewBKVTree[int, *Student](100, gutil.ComparatorTStr[int], true)
|
||||
for i := 0; i < 10; i++ {
|
||||
if i%2 == 0 {
|
||||
btree.Set(i, &Student{})
|
||||
} else {
|
||||
var s *Student = nil
|
||||
btree.Set(i, s)
|
||||
}
|
||||
}
|
||||
t.Assert(btree.Size(), 10)
|
||||
btree2 := gtree.NewBKVTreeWithChecker[int, *Student](100, gutil.ComparatorTStr[int], func(student *Student) bool {
|
||||
return student == nil
|
||||
}, true)
|
||||
for i := 0; i < 10; i++ {
|
||||
if i%2 == 0 {
|
||||
btree2.Set(i, &Student{})
|
||||
} else {
|
||||
var s *Student = nil
|
||||
btree2.Set(i, s)
|
||||
}
|
||||
}
|
||||
t.Assert(btree2.Size(), 5)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func Test_NewRedBlackKVTreeWithChecker_TypedNil(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type Student struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
redBlackTree := gtree.NewRedBlackKVTree[int, *Student](gutil.ComparatorTStr[int], true)
|
||||
for i := 0; i < 10; i++ {
|
||||
if i%2 == 0 {
|
||||
redBlackTree.Set(i, &Student{})
|
||||
} else {
|
||||
var s *Student = nil
|
||||
redBlackTree.Set(i, s)
|
||||
}
|
||||
}
|
||||
t.Assert(redBlackTree.Size(), 10)
|
||||
redBlackTree2 := gtree.NewRedBlackKVTreeWithChecker[int, *Student](gutil.ComparatorTStr[int], func(student *Student) bool {
|
||||
return student == nil
|
||||
}, true)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
if i%2 == 0 {
|
||||
redBlackTree2.Set(i, &Student{})
|
||||
} else {
|
||||
var s *Student = nil
|
||||
redBlackTree2.Set(i, s)
|
||||
}
|
||||
}
|
||||
t.Assert(redBlackTree2.Size(), 5)
|
||||
})
|
||||
}
|
||||
@ -867,10 +867,8 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
// checker is the checker function for instances map.
|
||||
checker = func(v DB) bool { return v == nil }
|
||||
// instances is the management map for instances.
|
||||
instances = gmap.NewKVMapWithChecker[string, DB](checker, true)
|
||||
instances = gmap.NewKVMap[string, DB](true)
|
||||
|
||||
// driverMap manages all custom registered driver.
|
||||
driverMap = map[string]Driver{}
|
||||
@ -944,9 +942,6 @@ func NewByGroup(group ...string) (db DB, err error) {
|
||||
)
|
||||
}
|
||||
|
||||
// linksChecker is the checker function for links map.
|
||||
var linksChecker = func(v *sql.DB) bool { return v == nil }
|
||||
|
||||
// newDBByConfigNode creates and returns an ORM object with given configuration node and group name.
|
||||
//
|
||||
// Very Note:
|
||||
@ -963,7 +958,7 @@ func newDBByConfigNode(node *ConfigNode, group string) (db DB, err error) {
|
||||
group: group,
|
||||
debug: gtype.NewBool(),
|
||||
cache: gcache.New(),
|
||||
links: gmap.NewKVMapWithChecker[ConfigNode, *sql.DB](linksChecker, true),
|
||||
links: gmap.NewKVMap[ConfigNode, *sql.DB](true),
|
||||
logger: glog.New(),
|
||||
config: node,
|
||||
localTypeMap: gmap.NewStrAnyMap(true),
|
||||
|
||||
@ -50,10 +50,8 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
// configChecker checks whether the *Config is nil.
|
||||
configChecker = func(v *Config) bool { return v == nil }
|
||||
// Configuration groups.
|
||||
localConfigMap = gmap.NewKVMapWithChecker[string, *Config](configChecker, true)
|
||||
localConfigMap = gmap.NewKVMap[string, *Config](true)
|
||||
)
|
||||
|
||||
// SetConfig sets the global configuration for specified group.
|
||||
|
||||
@ -14,9 +14,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
// checker is the checker function for instances map.
|
||||
checker = func(v *Redis) bool { return v == nil }
|
||||
localInstances = gmap.NewKVMapWithChecker[string, *Redis](checker, true)
|
||||
localInstances = gmap.NewKVMap[string, *Redis](true)
|
||||
)
|
||||
|
||||
// Instance returns an instance of redis client with specified group.
|
||||
|
||||
1
go.sum
1
go.sum
@ -4,6 +4,7 @@ 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/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=
|
||||
|
||||
@ -14,11 +14,9 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
// checker is used for checking whether the value is nil.
|
||||
checker = func(v *Manager) bool { return v == nil }
|
||||
// instances is the instances map for management
|
||||
// for multiple i18n instance by name.
|
||||
instances = gmap.NewKVMapWithChecker[string, *Manager](checker, true)
|
||||
instances = gmap.NewKVMap[string, *Manager](true)
|
||||
)
|
||||
|
||||
// Instance returns an instance of Resource.
|
||||
|
||||
@ -176,12 +176,9 @@ var (
|
||||
// It is used for quick HTTP method searching using map.
|
||||
methodsMap = make(map[string]struct{})
|
||||
|
||||
// checker is used for checking whether the value is nil.
|
||||
checker = func(v *Server) bool { return v == nil }
|
||||
|
||||
// serverMapping stores more than one server instances for current processes.
|
||||
// The key is the name of the server, and the value is its instance.
|
||||
serverMapping = gmap.NewKVMapWithChecker[string, *Server](checker, true)
|
||||
serverMapping = gmap.NewKVMap[string, *Server](true)
|
||||
|
||||
// serverRunning marks the running server counts.
|
||||
// If there is no successful server running or all servers' shutdown, this value is 0.
|
||||
|
||||
@ -30,9 +30,8 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
poolChecker = func(v *gpool.Pool) bool { return v == nil }
|
||||
// addressPoolMap is a mapping for address to its pool object.
|
||||
addressPoolMap = gmap.NewKVMapWithChecker[string, *gpool.Pool](poolChecker, true)
|
||||
addressPoolMap = gmap.NewKVMap[string, *gpool.Pool](true)
|
||||
)
|
||||
|
||||
// NewPoolConn creates and returns a connection with pool feature.
|
||||
|
||||
@ -39,10 +39,8 @@ type Server struct {
|
||||
|
||||
// Map for name to server, for singleton purpose.
|
||||
var (
|
||||
// checker is used for checking whether the value is nil.
|
||||
checker = func(v *Server) bool { return v == nil }
|
||||
// serverMapping is the map for name to server.
|
||||
serverMapping = gmap.NewKVMapWithChecker[any, *Server](checker, true)
|
||||
serverMapping = gmap.NewKVMap[any, *Server](true)
|
||||
)
|
||||
|
||||
// GetServer returns the TCP server with specified `name`,
|
||||
|
||||
@ -47,10 +47,8 @@ type Server struct {
|
||||
type ServerHandler func(conn *ServerConn)
|
||||
|
||||
var (
|
||||
// checker is used for checking whether the value is nil.
|
||||
checker = func(v *Server) bool { return v == nil }
|
||||
// serverMapping is used for instance name to its UDP server mappings.
|
||||
serverMapping = gmap.NewKVMapWithChecker[string, *Server](checker, true)
|
||||
serverMapping = gmap.NewKVMap[string, *Server](true)
|
||||
)
|
||||
|
||||
// GetServer creates and returns an udp server instance with given name.
|
||||
|
||||
@ -13,9 +13,6 @@ import (
|
||||
"github.com/gogf/gf/v2/container/gmap"
|
||||
)
|
||||
|
||||
// checker is used to check if the value is nil.
|
||||
var checker = func(v *glist.Element) bool { return v == nil }
|
||||
|
||||
// memoryLru holds LRU info.
|
||||
// It uses list.List from stdlib for its underlying doubly linked list.
|
||||
type memoryLru struct {
|
||||
@ -29,7 +26,7 @@ type memoryLru struct {
|
||||
func newMemoryLru(cap int) *memoryLru {
|
||||
lru := &memoryLru{
|
||||
cap: cap,
|
||||
data: gmap.NewKVMapWithChecker[any, *glist.Element](checker, false),
|
||||
data: gmap.NewKVMap[any, *glist.Element](false),
|
||||
list: glist.New(false),
|
||||
}
|
||||
return lru
|
||||
|
||||
@ -46,9 +46,8 @@ const (
|
||||
|
||||
var (
|
||||
supportedFileTypes = []string{"toml", "yaml", "yml", "json", "ini", "xml", "properties"} // All supported file types suffixes.
|
||||
checker = func(v *Config) bool { return v == nil }
|
||||
localInstances = gmap.NewKVMapWithChecker[string, *Config](checker, true) // Instances map containing configuration instances.
|
||||
customConfigContentMap = gmap.NewStrStrMap(true) // Customized configuration content.
|
||||
localInstances = gmap.NewKVMap[string, *Config](true) // Instances map containing configuration instances.
|
||||
customConfigContentMap = gmap.NewStrStrMap(true) // Customized configuration content.
|
||||
|
||||
// Prefix array for trying searching in resource manager.
|
||||
resourceTryFolders = []string{
|
||||
@ -58,9 +57,6 @@ var (
|
||||
|
||||
// Prefix array for trying searching in the local system.
|
||||
localSystemTryFolders = []string{"", "config/", "manifest/config"}
|
||||
|
||||
// jsonMapChecker is the checker for JSON map.
|
||||
jsonMapChecker = func(v *gjson.Json) bool { return v == nil }
|
||||
)
|
||||
|
||||
// NewAdapterFile returns a new configuration management object.
|
||||
@ -81,7 +77,7 @@ func NewAdapterFile(fileNameOrPath ...string) (*AdapterFile, error) {
|
||||
config := &AdapterFile{
|
||||
defaultFileNameOrPath: gtype.NewString(usedFileNameOrPath),
|
||||
searchPaths: garray.NewStrArray(true),
|
||||
jsonMap: gmap.NewKVMapWithChecker[string, *gjson.Json](jsonMapChecker, true),
|
||||
jsonMap: gmap.NewKVMap[string, *gjson.Json](true),
|
||||
watchers: NewWatcherRegistry(),
|
||||
}
|
||||
// Customized dir path from env/cmd.
|
||||
|
||||
@ -36,8 +36,6 @@ type File struct {
|
||||
}
|
||||
|
||||
var (
|
||||
// checker is used for checking whether the value is nil.
|
||||
checker = func(v *Pool) bool { return v == nil }
|
||||
// Global file pointer pool.
|
||||
pools = gmap.NewKVMapWithChecker[string, *Pool](checker, true)
|
||||
pools = gmap.NewKVMap[string, *Pool](true)
|
||||
)
|
||||
|
||||
@ -82,12 +82,10 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
callBacksChecker = func(v *glist.TList[*Callback]) bool { return v == nil } // callBacksChecker checks whether the value is nil.
|
||||
callbackIdMapChecker = func(v *Callback) bool { return v == nil } // callbackIdMapChecker checks whether the value is nil.
|
||||
mu sync.Mutex // Mutex for concurrent safety of defaultWatcher.
|
||||
defaultWatcher *Watcher // Default watcher.
|
||||
callbackIdMap = gmap.NewKVMapWithChecker[int, *Callback](callbackIdMapChecker, true) // Global callback id to callback function mapping.
|
||||
callbackIdGenerator = gtype.NewInt() // Atomic id generator for callback.
|
||||
mu sync.Mutex // Mutex for concurrent safety of defaultWatcher.
|
||||
defaultWatcher *Watcher // Default watcher.
|
||||
callbackIdMap = gmap.NewKVMap[int, *Callback](true) // Global callback id to callback function mapping.
|
||||
callbackIdGenerator = gtype.NewInt() // Atomic id generator for callback.
|
||||
)
|
||||
|
||||
// New creates and returns a new watcher.
|
||||
@ -101,7 +99,7 @@ func New() (*Watcher, error) {
|
||||
events: gqueue.NewTQueue[*Event](),
|
||||
nameSet: gset.NewStrSet(true),
|
||||
closeChan: make(chan struct{}),
|
||||
callbacks: gmap.NewKVMapWithChecker[string, *glist.TList[*Callback]](callBacksChecker, true),
|
||||
callbacks: gmap.NewKVMap[string, *glist.TList[*Callback]](true),
|
||||
}
|
||||
if watcher, err := fsnotify.NewWatcher(); err == nil {
|
||||
w.watcher = watcher
|
||||
|
||||
@ -14,10 +14,8 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
// Checker function for instances map.
|
||||
checker = func(v *Logger) bool { return v == nil }
|
||||
// Instances map.
|
||||
instances = gmap.NewKVMapWithChecker[string, *Logger](checker, true)
|
||||
instances = gmap.NewKVMap[string, *Logger](true)
|
||||
)
|
||||
|
||||
// Instance returns an instance of Logger with default settings.
|
||||
|
||||
@ -12,8 +12,6 @@ import (
|
||||
"github.com/gogf/gf/v2/container/gmap"
|
||||
)
|
||||
|
||||
var checker = func(v *sync.RWMutex) bool { return v == nil }
|
||||
|
||||
// Locker is a memory based locker.
|
||||
// Note that there's no cache expire mechanism for mutex in locker.
|
||||
// You need remove certain mutex manually when you do not want use it anymore.
|
||||
@ -25,7 +23,7 @@ type Locker struct {
|
||||
// A memory locker can lock/unlock with dynamic string key.
|
||||
func New() *Locker {
|
||||
return &Locker{
|
||||
m: gmap.NewKVMapWithChecker[string, *sync.RWMutex](checker, true),
|
||||
m: gmap.NewKVMap[string, *sync.RWMutex](true),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -43,11 +43,9 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
// checker is used for checking whether the value is nil.
|
||||
checker = func(v *gqueue.TQueue[*MsgRequest]) bool { return v == nil }
|
||||
// commReceiveQueues is the group name to queue map for storing received data.
|
||||
// The value of the map is type of *gqueue.TQueue[*MsgRequest].
|
||||
commReceiveQueues = gmap.NewKVMapWithChecker[string, *gqueue.TQueue[*MsgRequest]](checker, true)
|
||||
commReceiveQueues = gmap.NewKVMap[string, *gqueue.TQueue[*MsgRequest]](true)
|
||||
|
||||
// commPidFolderPath specifies the folder path storing pid to port mapping files.
|
||||
commPidFolderPath string
|
||||
|
||||
@ -14,10 +14,8 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
// checker checks whether the value is nil.
|
||||
checker = func(v *Resource) bool { return v == nil }
|
||||
// Instances map.
|
||||
instances = gmap.NewKVMapWithChecker[string, *Resource](checker, true)
|
||||
instances = gmap.NewKVMap[string, *Resource](true)
|
||||
)
|
||||
|
||||
// Instance returns an instance of Resource.
|
||||
|
||||
@ -39,10 +39,8 @@ type SPathCacheItem struct {
|
||||
}
|
||||
|
||||
var (
|
||||
// checker is the checking function for checking the value is nil or not.
|
||||
checker = func(v *SPath) bool { return v == nil }
|
||||
// Path to searching object mapping, used for instance management.
|
||||
pathsMap = gmap.NewKVMapWithChecker[string, *SPath](checker, true)
|
||||
pathsMap = gmap.NewKVMap[string, *SPath](true)
|
||||
)
|
||||
|
||||
// New creates and returns a new path searching manager.
|
||||
|
||||
@ -41,8 +41,7 @@ const (
|
||||
|
||||
var (
|
||||
// Default view object.
|
||||
defaultViewObj *View
|
||||
fileCacheItemChecker = func(v *fileCacheItem) bool { return v == nil }
|
||||
defaultViewObj *View
|
||||
)
|
||||
|
||||
// checkAndInitDefaultView checks and initializes the default view object.
|
||||
@ -70,7 +69,7 @@ func New(path ...string) *View {
|
||||
searchPaths: garray.NewStrArray(),
|
||||
data: make(map[string]any),
|
||||
funcMap: make(map[string]any),
|
||||
fileCacheMap: gmap.NewKVMapWithChecker[string, *fileCacheItem](fileCacheItemChecker, true),
|
||||
fileCacheMap: gmap.NewKVMap[string, *fileCacheItem](true),
|
||||
config: DefaultConfig(),
|
||||
}
|
||||
if len(path) > 0 && len(path[0]) > 0 {
|
||||
|
||||
@ -14,9 +14,8 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
checker = func(v *View) bool { return v == nil }
|
||||
// Instances map.
|
||||
instances = gmap.NewKVMapWithChecker[string, *View](checker, true)
|
||||
instances = gmap.NewKVMap[string, *View](true)
|
||||
)
|
||||
|
||||
// Instance returns an instance of View with default settings.
|
||||
|
||||
Reference in New Issue
Block a user