fix(container): remove unnecessary nil check design

This commit is contained in:
John Guo
2026-01-22 20:39:19 +08:00
parent 096c0b2b05
commit 9b5ebbc3d7
32 changed files with 70 additions and 761 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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