diff --git a/g/container/gmap/gmap.go b/g/container/gmap/gmap.go index e749acaad..99cdf3bd6 100644 --- a/g/container/gmap/gmap.go +++ b/g/container/gmap/gmap.go @@ -4,346 +4,65 @@ // If a copy of the MIT was not distributed with gm file, // You can obtain one at https://github.com/gogf/gf. -// Package gmap provides concurrent-safe/unsafe maps. +// Package gmap provides concurrent-safe/unsafe map containers. package gmap import ( - "github.com/gogf/gf/g/container/gvar" - "github.com/gogf/gf/g/internal/rwmutex" + "github.com/gogf/gf/g/container/gtree" ) -type Map struct { - mu *rwmutex.RWMutex - data map[interface{}]interface{} -} +// Map based on hash table, alias of AnyAnyMap. +type Map = AnyAnyMap +type HashMap = AnyAnyMap + +// Map based on red-black tree, alias of RedBlackTree. +type TreeMap = gtree.RedBlackTree + // New returns an empty hash map. // The param used to specify whether using map in un-concurrent-safety, // which is false in default, means concurrent-safe. func New(unsafe ...bool) *Map { - return &Map{ - mu : rwmutex.New(unsafe...), - data : make(map[interface{}]interface{}), - } + return NewAnyAnyMap(unsafe...) } // NewFrom returns a hash map from given map . -// Notice that, the param map is a type of pointer, +// Note that, the param map will be set as the underlying data map(no deep copy), // there might be some concurrent-safe issues when changing the map outside. +// The param used to specify whether using tree in un-concurrent-safety, +// which is false in default. func NewFrom(data map[interface{}]interface{}, unsafe...bool) *Map { - return &Map{ - mu : rwmutex.New(unsafe...), - data : data, - } + return NewAnyAnyMapFrom(data, unsafe...) } -// NewFromArray returns a hash map from given array. -// The param is given as the keys of the map, -// and as its corresponding values. -// -// If length of is greater than that of , -// the corresponding overflow map values will be the default value of its type. -func NewFromArray(keys []interface{}, values []interface{}, unsafe...bool) *Map { - m := make(map[interface{}]interface{}) - l := len(values) - for i, k := range keys { - if i < l { - m[k] = values[i] - } else { - m[k] = interface{}(nil) - } - } - return &Map{ - mu : rwmutex.New(unsafe...), - data : m, - } +// NewHashMap returns an empty hash map. +// The param used to specify whether using map in un-concurrent-safety, +// which is false in default, means concurrent-safe. +func NewHashMap(unsafe ...bool) *Map { + return NewAnyAnyMap(unsafe...) } -// Iterator iterates the hash map with custom callback function . -// If returns true, then it continues iterating; or false to stop. -func (m *Map) Iterator(f func (k interface{}, v interface{}) bool) { - m.mu.RLock() - defer m.mu.RUnlock() - for k, v := range m.data { - if !f(k, v) { - break - } - } +// NewHashMapFrom returns a hash map from given map . +// Note that, the param map will be set as the underlying data map(no deep copy), +// there might be some concurrent-safe issues when changing the map outside. +// The param used to specify whether using tree in un-concurrent-safety, +// which is false in default. +func NewHashMapFrom(data map[interface{}]interface{}, unsafe...bool) *Map { + return NewAnyAnyMapFrom(data, unsafe...) } -// Clone returns a new hash map with copy of current map data. -func (m *Map) Clone(unsafe ...bool) *Map { - return NewFrom(m.Map(), unsafe ...) +// NewTreeMap instantiates a tree map with the custom comparator. +// The param used to specify whether using tree in un-concurrent-safety, +// which is false in default. +func NewTreeMap(comparator func(v1, v2 interface{}) int, unsafe...bool) *TreeMap { + return gtree.NewRedBlackTree(comparator, unsafe...) } -// Map returns a copy of the data of the hash map. -func (m *Map) Map() map[interface{}]interface{} { - data := make(map[interface{}]interface{}) - m.mu.RLock() - for k, v := range m.data { - data[k] = v - } - m.mu.RUnlock() - return data -} - -// Set sets key-value to the hash map. -func (m *Map) Set(key interface{}, val interface{}) { - m.mu.Lock() - m.data[key] = val - m.mu.Unlock() -} - -// Sets batch sets key-values to the hash map. -func (m *Map) Sets(data map[interface{}]interface{}) { - m.mu.Lock() - for k, v := range data { - m.data[k] = v - } - m.mu.Unlock() -} - -// Search searches the map with given . -// Second return parameter is true if key was found, otherwise false. -func (m *Map) Search(key interface{}) (value interface{}, found bool) { - m.mu.RLock() - value, found = m.data[key] - m.mu.RUnlock() - return -} - -// Get returns the value by given . -func (m *Map) Get(key interface{}) interface{} { - m.mu.RLock() - val, _ := m.data[key] - m.mu.RUnlock() - return val -} - -// doSetWithLockCheck checks whether value of the key exists with mutex.Lock, -// if not exists, set value to the map with given , -// or else just return the existing value. -// -// When setting value, if is type of , -// it will be executed with mutex.Lock of the hash map, -// and its return value will be set to the map with . -// -// It returns value with given . -func (m *Map) doSetWithLockCheck(key interface{}, value interface{}) interface{} { - m.mu.Lock() - defer m.mu.Unlock() - if v, ok := m.data[key]; ok { - return v - } - if f, ok := value.(func() interface {}); ok { - value = f() - } - m.data[key] = value - return value -} - -// GetOrSet returns the value by key, -// or set value with given if not exist and returns this value. -func (m *Map) GetOrSet(key interface{}, value interface{}) interface{} { - if v, ok := m.Search(key); !ok { - return m.doSetWithLockCheck(key, value) - } else { - return v - } -} - -// GetOrSetFunc returns the value by key, -// or sets value with return value of callback function if not exist -// and returns this value. -func (m *Map) GetOrSetFunc(key interface{}, f func() interface{}) interface{} { - if v, ok := m.Search(key); !ok { - return m.doSetWithLockCheck(key, f()) - } else { - return v - } -} - -// GetOrSetFuncLock returns the value by key, -// or sets value with return value of callback function if not exist -// and returns this value. -// -// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function -// with mutex.Lock of the hash map. -func (m *Map) GetOrSetFuncLock(key interface{}, f func() interface{}) interface{} { - if v, ok := m.Search(key); !ok { - return m.doSetWithLockCheck(key, f) - } else { - return v - } -} - -// GetVar returns a gvar.Var with the value by given . -// The returned gvar.Var is un-concurrent safe. -func (m *Map) GetVar(key interface{}) *gvar.Var { - return gvar.New(m.Get(key), true) -} - -// GetVarOrSet returns a gvar.Var with result from GetVarOrSet. -// The returned gvar.Var is un-concurrent safe. -func (m *Map) GetVarOrSet(key interface{}, value interface{}) *gvar.Var { - return gvar.New(m.GetOrSet(key, value), true) -} - -// GetVarOrSetFunc returns a gvar.Var with result from GetOrSetFunc. -// The returned gvar.Var is un-concurrent safe. -func (m *Map) GetVarOrSetFunc(key interface{}, f func() interface{}) *gvar.Var { - return gvar.New(m.GetOrSetFunc(key, f), true) -} - -// GetVarOrSetFuncLock returns a gvar.Var with result from GetOrSetFuncLock. -// The returned gvar.Var is un-concurrent safe. -func (m *Map) GetVarOrSetFuncLock(key interface{}, f func() interface{}) *gvar.Var { - return gvar.New(m.GetOrSetFuncLock(key, f), true) -} - -// SetIfNotExist sets to the map if the does not exist, then return true. -// It returns false if exists, and would be ignored. -func (m *Map) SetIfNotExist(key interface{}, value interface{}) bool { - if !m.Contains(key) { - m.doSetWithLockCheck(key, value) - return true - } - return false -} - -// SetIfNotExistFunc sets value with return value of callback function , then return true. -// It returns false if exists, and would be ignored. -func (m *Map) SetIfNotExistFunc(key interface{}, f func() interface{}) bool { - if !m.Contains(key) { - m.doSetWithLockCheck(key, f()) - return true - } - return false -} - -// SetIfNotExistFuncLock sets value with return value of callback function , then return true. -// It returns false if exists, and would be ignored. -// -// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that -// it executes function with mutex.Lock of the hash map. -func (m *Map) SetIfNotExistFuncLock(key interface{}, f func() interface{}) bool { - if !m.Contains(key) { - m.doSetWithLockCheck(key, f) - return true - } - return false -} - -// Remove deletes value from map by given , and return this deleted value. -func (m *Map) Remove(key interface{}) interface{} { - m.mu.Lock() - val, exists := m.data[key] - if exists { - delete(m.data, key) - } - m.mu.Unlock() - return val -} - -// Removes batch deletes values of the map by keys. -func (m *Map) Removes(keys []interface{}) { - m.mu.Lock() - for _, key := range keys { - delete(m.data, key) - } - m.mu.Unlock() -} - -// Keys returns all keys of the map as a slice. -func (m *Map) Keys() []interface{} { - m.mu.RLock() - keys := make([]interface{}, 0) - for key := range m.data { - keys = append(keys, key) - } - m.mu.RUnlock() - return keys -} - -// Values returns all values of the map as a slice. -func (m *Map) Values() []interface{} { - m.mu.RLock() - values := make([]interface{}, 0) - for _, value := range m.data { - values = append(values, value) - } - m.mu.RUnlock() - return values -} - -// Contains checks whether a key exists. -// It returns true if the exists, or else false. -func (m *Map) Contains(key interface{}) bool { - m.mu.RLock() - _, exists := m.data[key] - m.mu.RUnlock() - return exists -} - -// Size returns the size of the map. -func (m *Map) Size() int { - m.mu.RLock() - length := len(m.data) - m.mu.RUnlock() - return length -} - -// IsEmpty checks whether the map is empty. -// It returns true if map is empty, or else false. -func (m *Map) IsEmpty() bool { - m.mu.RLock() - empty := len(m.data) == 0 - m.mu.RUnlock() - return empty -} - -// Clear deletes all data of the map, it will remake a new underlying data map. -func (m *Map) Clear() { - m.mu.Lock() - m.data = make(map[interface{}]interface{}) - m.mu.Unlock() -} - -// LockFunc locks writing with given callback function within RWMutex.Lock. -func (m *Map) LockFunc(f func(m map[interface{}]interface{})) { - m.mu.Lock() - defer m.mu.Unlock() - f(m.data) -} - -// RLockFunc locks reading with given callback function within RWMutex.RLock. -func (m *Map) RLockFunc(f func(m map[interface{}]interface{})) { - m.mu.RLock() - defer m.mu.RUnlock() - f(m.data) -} - -// Flip exchanges key-value of the map to value-key. -func (m *Map) Flip() { - m.mu.Lock() - defer m.mu.Unlock() - n := make(map[interface{}]interface{}, len(m.data)) - for k, v := range m.data { - n[v] = k - } - m.data = n -} - -// Merge merges two hash maps. -// The map will be merged into the map . -func (m *Map) Merge(other *Map) { - m.mu.Lock() - defer m.mu.Unlock() - if other != m { - other.mu.RLock() - defer other.mu.RUnlock() - } - for k, v := range other.data { - m.data[k] = v - } +// NewTreeMapFrom instantiates a tree map with the custom comparator and map. +// Note that, the param map will be set as the underlying data map(no deep copy), +// there might be some concurrent-safe issues when changing the map outside. +// The param used to specify whether using tree in un-concurrent-safety, +// which is false in default. +func NewTreeMapFrom(comparator func(v1, v2 interface{}) int, data map[interface{}]interface{}, unsafe...bool) *TreeMap { + return gtree.NewRedBlackTreeFrom(comparator, data, unsafe...) } \ No newline at end of file diff --git a/g/container/gmap/gmap_any_any_map.go b/g/container/gmap/gmap_any_any_map.go new file mode 100644 index 000000000..31b428d0d --- /dev/null +++ b/g/container/gmap/gmap_any_any_map.go @@ -0,0 +1,326 @@ +// Copyright 2017 gf Author(https://github.com/gogf/gf). 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 gm file, +// You can obtain one at https://github.com/gogf/gf. + +package gmap + +import ( + "github.com/gogf/gf/g/container/gvar" + "github.com/gogf/gf/g/internal/rwmutex" +) + +type AnyAnyMap struct { + mu *rwmutex.RWMutex + data map[interface{}]interface{} +} + +// NewAnyAnyMap returns an empty hash map. +// The param used to specify whether using map in un-concurrent-safety, +// which is false in default, means concurrent-safe. +func NewAnyAnyMap(unsafe ...bool) *AnyAnyMap { + return &AnyAnyMap{ + mu : rwmutex.New(unsafe...), + data : make(map[interface{}]interface{}), + } +} + +// NewAnyAnyMapFrom returns a hash map from given map . +// Note that, the param map will be set as the underlying data map(no deep copy), +// there might be some concurrent-safe issues when changing the map outside. +func NewAnyAnyMapFrom(data map[interface{}]interface{}, unsafe...bool) *AnyAnyMap { + return &AnyAnyMap{ + mu : rwmutex.New(unsafe...), + data : data, + } +} + +// Iterator iterates the hash map with custom callback function . +// If returns true, then it continues iterating; or false to stop. +func (m *AnyAnyMap) Iterator(f func (k interface{}, v interface{}) bool) { + m.mu.RLock() + defer m.mu.RUnlock() + for k, v := range m.data { + if !f(k, v) { + break + } + } +} + +// Clone returns a new hash map with copy of current map data. +func (m *AnyAnyMap) Clone(unsafe ...bool) *AnyAnyMap { + return NewFrom(m.Map(), unsafe ...) +} + +// Map returns a copy of the data of the hash map. +func (m *AnyAnyMap) Map() map[interface{}]interface{} { + data := make(map[interface{}]interface{}) + m.mu.RLock() + for k, v := range m.data { + data[k] = v + } + m.mu.RUnlock() + return data +} + +// Set sets key-value to the hash map. +func (m *AnyAnyMap) Set(key interface{}, val interface{}) { + m.mu.Lock() + m.data[key] = val + m.mu.Unlock() +} + +// Sets batch sets key-values to the hash map. +func (m *AnyAnyMap) Sets(data map[interface{}]interface{}) { + m.mu.Lock() + for k, v := range data { + m.data[k] = v + } + m.mu.Unlock() +} + +// Search searches the map with given . +// Second return parameter is true if key was found, otherwise false. +func (m *AnyAnyMap) Search(key interface{}) (value interface{}, found bool) { + m.mu.RLock() + value, found = m.data[key] + m.mu.RUnlock() + return +} + +// Get returns the value by given . +func (m *AnyAnyMap) Get(key interface{}) interface{} { + m.mu.RLock() + val, _ := m.data[key] + m.mu.RUnlock() + return val +} + +// doSetWithLockCheck checks whether value of the key exists with mutex.Lock, +// if not exists, set value to the map with given , +// or else just return the existing value. +// +// When setting value, if is type of , +// it will be executed with mutex.Lock of the hash map, +// and its return value will be set to the map with . +// +// It returns value with given . +func (m *AnyAnyMap) doSetWithLockCheck(key interface{}, value interface{}) interface{} { + m.mu.Lock() + defer m.mu.Unlock() + if v, ok := m.data[key]; ok { + return v + } + if f, ok := value.(func() interface {}); ok { + value = f() + } + m.data[key] = value + return value +} + +// GetOrSet returns the value by key, +// or set value with given if not exist and returns this value. +func (m *AnyAnyMap) GetOrSet(key interface{}, value interface{}) interface{} { + if v, ok := m.Search(key); !ok { + return m.doSetWithLockCheck(key, value) + } else { + return v + } +} + +// GetOrSetFunc returns the value by key, +// or sets value with return value of callback function if not exist +// and returns this value. +func (m *AnyAnyMap) GetOrSetFunc(key interface{}, f func() interface{}) interface{} { + if v, ok := m.Search(key); !ok { + return m.doSetWithLockCheck(key, f()) + } else { + return v + } +} + +// GetOrSetFuncLock returns the value by key, +// or sets value with return value of callback function if not exist +// and returns this value. +// +// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function +// with mutex.Lock of the hash map. +func (m *AnyAnyMap) GetOrSetFuncLock(key interface{}, f func() interface{}) interface{} { + if v, ok := m.Search(key); !ok { + return m.doSetWithLockCheck(key, f) + } else { + return v + } +} + +// GetVar returns a gvar.Var with the value by given . +// The returned gvar.Var is un-concurrent safe. +func (m *AnyAnyMap) GetVar(key interface{}) *gvar.Var { + return gvar.New(m.Get(key), true) +} + +// GetVarOrSet returns a gvar.Var with result from GetVarOrSet. +// The returned gvar.Var is un-concurrent safe. +func (m *AnyAnyMap) GetVarOrSet(key interface{}, value interface{}) *gvar.Var { + return gvar.New(m.GetOrSet(key, value), true) +} + +// GetVarOrSetFunc returns a gvar.Var with result from GetOrSetFunc. +// The returned gvar.Var is un-concurrent safe. +func (m *AnyAnyMap) GetVarOrSetFunc(key interface{}, f func() interface{}) *gvar.Var { + return gvar.New(m.GetOrSetFunc(key, f), true) +} + +// GetVarOrSetFuncLock returns a gvar.Var with result from GetOrSetFuncLock. +// The returned gvar.Var is un-concurrent safe. +func (m *AnyAnyMap) GetVarOrSetFuncLock(key interface{}, f func() interface{}) *gvar.Var { + return gvar.New(m.GetOrSetFuncLock(key, f), true) +} + +// SetIfNotExist sets to the map if the does not exist, then return true. +// It returns false if exists, and would be ignored. +func (m *AnyAnyMap) SetIfNotExist(key interface{}, value interface{}) bool { + if !m.Contains(key) { + m.doSetWithLockCheck(key, value) + return true + } + return false +} + +// SetIfNotExistFunc sets value with return value of callback function , then return true. +// It returns false if exists, and would be ignored. +func (m *AnyAnyMap) SetIfNotExistFunc(key interface{}, f func() interface{}) bool { + if !m.Contains(key) { + m.doSetWithLockCheck(key, f()) + return true + } + return false +} + +// SetIfNotExistFuncLock sets value with return value of callback function , then return true. +// It returns false if exists, and would be ignored. +// +// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that +// it executes function with mutex.Lock of the hash map. +func (m *AnyAnyMap) SetIfNotExistFuncLock(key interface{}, f func() interface{}) bool { + if !m.Contains(key) { + m.doSetWithLockCheck(key, f) + return true + } + return false +} + +// Remove deletes value from map by given , and return this deleted value. +func (m *AnyAnyMap) Remove(key interface{}) interface{} { + m.mu.Lock() + val, exists := m.data[key] + if exists { + delete(m.data, key) + } + m.mu.Unlock() + return val +} + +// Removes batch deletes values of the map by keys. +func (m *AnyAnyMap) Removes(keys []interface{}) { + m.mu.Lock() + for _, key := range keys { + delete(m.data, key) + } + m.mu.Unlock() +} + +// Keys returns all keys of the map as a slice. +func (m *AnyAnyMap) Keys() []interface{} { + m.mu.RLock() + keys := make([]interface{}, 0) + for key := range m.data { + keys = append(keys, key) + } + m.mu.RUnlock() + return keys +} + +// Values returns all values of the map as a slice. +func (m *AnyAnyMap) Values() []interface{} { + m.mu.RLock() + values := make([]interface{}, 0) + for _, value := range m.data { + values = append(values, value) + } + m.mu.RUnlock() + return values +} + +// Contains checks whether a key exists. +// It returns true if the exists, or else false. +func (m *AnyAnyMap) Contains(key interface{}) bool { + m.mu.RLock() + _, exists := m.data[key] + m.mu.RUnlock() + return exists +} + +// Size returns the size of the map. +func (m *AnyAnyMap) Size() int { + m.mu.RLock() + length := len(m.data) + m.mu.RUnlock() + return length +} + +// IsEmpty checks whether the map is empty. +// It returns true if map is empty, or else false. +func (m *AnyAnyMap) IsEmpty() bool { + m.mu.RLock() + empty := len(m.data) == 0 + m.mu.RUnlock() + return empty +} + +// Clear deletes all data of the map, it will remake a new underlying data map. +func (m *AnyAnyMap) Clear() { + m.mu.Lock() + m.data = make(map[interface{}]interface{}) + m.mu.Unlock() +} + +// LockFunc locks writing with given callback function within RWMutex.Lock. +func (m *AnyAnyMap) LockFunc(f func(m map[interface{}]interface{})) { + m.mu.Lock() + defer m.mu.Unlock() + f(m.data) +} + +// RLockFunc locks reading with given callback function within RWMutex.RLock. +func (m *AnyAnyMap) RLockFunc(f func(m map[interface{}]interface{})) { + m.mu.RLock() + defer m.mu.RUnlock() + f(m.data) +} + +// Flip exchanges key-value of the map to value-key. +func (m *AnyAnyMap) Flip() { + m.mu.Lock() + defer m.mu.Unlock() + n := make(map[interface{}]interface{}, len(m.data)) + for k, v := range m.data { + n[v] = k + } + m.data = n +} + +// Merge merges two hash maps. +// The map will be merged into the map . +func (m *AnyAnyMap) Merge(other *AnyAnyMap) { + m.mu.Lock() + defer m.mu.Unlock() + if other != m { + other.mu.RLock() + defer other.mu.RUnlock() + } + for k, v := range other.data { + m.data[k] = v + } +} \ No newline at end of file diff --git a/g/container/gmap/gmap_func.go b/g/container/gmap/gmap_func.go deleted file mode 100644 index 8a6eea0db..000000000 --- a/g/container/gmap/gmap_func.go +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2019 gf Author(https://github.com/gogf/gf). 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 gm file, -// You can obtain one at https://github.com/gogf/gf. - -package gmap - diff --git a/g/container/gmap/gmap_int_any_map.go b/g/container/gmap/gmap_int_any_map.go index e3da3b9bd..c043a4d5f 100644 --- a/g/container/gmap/gmap_int_any_map.go +++ b/g/container/gmap/gmap_int_any_map.go @@ -28,8 +28,8 @@ func NewIntAnyMap(unsafe...bool) *IntAnyMap { } } -// NewIntAnyMapFrom returns an IntAnyMap object from given map . -// Notice that, the param map is a type of pointer, +// NewIntAnyMapFrom returns a hash map from given map . +// Note that, the param map will be set as the underlying data map(no deep copy), // there might be some concurrent-safe issues when changing the map outside. func NewIntAnyMapFrom(data map[int]interface{}, unsafe...bool) *IntAnyMap { return &IntAnyMap{ @@ -38,28 +38,6 @@ func NewIntAnyMapFrom(data map[int]interface{}, unsafe...bool) *IntAnyMap { } } -// NewIntAnyMapFromArray returns a hash map from given array. -// The param is given as the keys of the map, -// and as its corresponding values. -// -// If length of is greater than that of , -// the corresponding overflow map values will be the default value of its type. -func NewIntAnyMapFromArray(keys []int, values []interface{}, unsafe...bool) *IntAnyMap { - m := make(map[int]interface{}) - l := len(values) - for i, k := range keys { - if i < l { - m[k] = values[i] - } else { - m[k] = interface{}(nil) - } - } - return &IntAnyMap{ - mu : rwmutex.New(unsafe...), - data : m, - } -} - // Iterator iterates the hash map with custom callback function . // If returns true, then it continues iterating; or false to stop. func (m *IntAnyMap) Iterator(f func (k int, v interface{}) bool) { diff --git a/g/container/gmap/gmap_int_int_map.go b/g/container/gmap/gmap_int_int_map.go index 798931742..8032f60bb 100644 --- a/g/container/gmap/gmap_int_int_map.go +++ b/g/container/gmap/gmap_int_int_map.go @@ -25,8 +25,8 @@ func NewIntIntMap(unsafe...bool) *IntIntMap { } } -// NewIntIntMapFrom returns an IntIntMap object from given map . -// Notice that, the param map is a type of pointer, +// NewIntIntMapFrom returns a hash map from given map . +// Note that, the param map will be set as the underlying data map(no deep copy), // there might be some concurrent-safe issues when changing the map outside. func NewIntIntMapFrom(data map[int]int, unsafe...bool) *IntIntMap { return &IntIntMap{ @@ -35,28 +35,6 @@ func NewIntIntMapFrom(data map[int]int, unsafe...bool) *IntIntMap { } } -// NewIntIntMapFromArray returns an IntIntMap object from given array. -// The param is given as the keys of the map, -// and as its corresponding values. -// -// If length of is greater than that of , -// the corresponding overflow map values will be the default value of its type. -func NewIntIntMapFromArray(keys []int, values []int, unsafe...bool) *IntIntMap { - m := make(map[int]int) - l := len(values) - for i, k := range keys { - if i < l { - m[k] = values[i] - } else { - m[k] = 0 - } - } - return &IntIntMap{ - mu : rwmutex.New(unsafe...), - data : m, - } -} - // Iterator iterates the hash map with custom callback function . // If returns true, then it continues iterating; or false to stop. func (m *IntIntMap) Iterator(f func (k int, v int) bool) { diff --git a/g/container/gmap/gmap_int_str_map.go b/g/container/gmap/gmap_int_str_map.go index d9e2d0c49..ae5422cba 100644 --- a/g/container/gmap/gmap_int_str_map.go +++ b/g/container/gmap/gmap_int_str_map.go @@ -26,8 +26,8 @@ func NewIntStrMap(unsafe ...bool) *IntStrMap { } } -// NewIntStrMapFrom returns an IntStrMap object from given map . -// Notice that, the param map is a type of pointer, +// NewIntStrMapFrom returns a hash map from given map . +// Note that, the param map will be set as the underlying data map(no deep copy), // there might be some concurrent-safe issues when changing the map outside. func NewIntStrMapFrom(data map[int]string, unsafe ...bool) *IntStrMap { return &IntStrMap{ @@ -36,28 +36,6 @@ func NewIntStrMapFrom(data map[int]string, unsafe ...bool) *IntStrMap { } } -// NewIntStrMapFromArray returns an IntStrMap object from given array. -// The param is given as the keys of the map, -// and as its corresponding values. -// -// If length of is greater than that of , -// the corresponding overflow map values will be the default value of its type. -func NewIntStrMapFromArray(keys []int, values []string, unsafe ...bool) *IntStrMap { - m := make(map[int]string) - l := len(values) - for i, k := range keys { - if i < l { - m[k] = values[i] - } else { - m[k] = "" - } - } - return &IntStrMap{ - mu : rwmutex.New(unsafe...), - data : m, - } -} - // Iterator iterates the hash map with custom callback function . // If returns true, then it continues iterating; or false to stop. func (m *IntStrMap) Iterator(f func(k int, v string) bool) { diff --git a/g/container/gmap/gmap_str_any_map.go b/g/container/gmap/gmap_str_any_map.go index d076c2bdd..ccf607c24 100644 --- a/g/container/gmap/gmap_str_any_map.go +++ b/g/container/gmap/gmap_str_any_map.go @@ -28,8 +28,8 @@ func NewStrAnyMap(unsafe ...bool) *StrAnyMap { } } -// NewStrAnyMapFrom returns an StrAnyMap object from given map . -// Notice that, the param map is a type of pointer, +// NewStrAnyMapFrom returns a hash map from given map . +// Note that, the param map will be set as the underlying data map(no deep copy), // there might be some concurrent-safe issues when changing the map outside. func NewStrAnyMapFrom(data map[string]interface{}, unsafe ...bool) *StrAnyMap { return &StrAnyMap{ @@ -38,28 +38,6 @@ func NewStrAnyMapFrom(data map[string]interface{}, unsafe ...bool) *StrAnyMap { } } -// NewStrAnyMapFromArray returns an StrAnyMap object from given array. -// The param is given as the keys of the map, -// and as its corresponding values. -// -// If length of is greater than that of , -// the corresponding overflow map values will be the default value of its type. -func NewStrAnyMapFromArray(keys []string, values []interface{}, unsafe ...bool) *StrAnyMap { - m := make(map[string]interface{}) - l := len(values) - for i, k := range keys { - if i < l { - m[k] = values[i] - } else { - m[k] = interface{}(nil) - } - } - return &StrAnyMap{ - mu : rwmutex.New(unsafe...), - data : m, - } -} - // Iterator iterates the hash map with custom callback function . // If returns true, then it continues iterating; or false to stop. func (m *StrAnyMap) Iterator(f func(k string, v interface{}) bool) { diff --git a/g/container/gmap/gmap_str_int_map.go b/g/container/gmap/gmap_str_int_map.go index 998247242..5f765ad7a 100644 --- a/g/container/gmap/gmap_str_int_map.go +++ b/g/container/gmap/gmap_str_int_map.go @@ -27,8 +27,8 @@ func NewStrIntMap(unsafe ...bool) *StrIntMap { } } -// NewStrIntMapFrom returns an StrIntMap object from given map . -// Notice that, the param map is a type of pointer, +// NewStrIntMapFrom returns a hash map from given map . +// Note that, the param map will be set as the underlying data map(no deep copy), // there might be some concurrent-safe issues when changing the map outside. func NewStrIntMapFrom(data map[string]int, unsafe ...bool) *StrIntMap { return &StrIntMap{ @@ -37,28 +37,6 @@ func NewStrIntMapFrom(data map[string]int, unsafe ...bool) *StrIntMap { } } -// NewStrIntMapFromArray returns an StrIntMap object from given array. -// The param is given as the keys of the map, -// and as its corresponding values. -// -// If length of is greater than that of , -// the corresponding overflow map values will be the default value of its type. -func NewStrIntMapFromArray(keys []string, values []int, unsafe ...bool) *StrIntMap { - m := make(map[string]int) - l := len(values) - for i, k := range keys { - if i < l { - m[k] = values[i] - } else { - m[k] = 0 - } - } - return &StrIntMap{ - mu : rwmutex.New(unsafe...), - data : m, - } -} - // Iterator iterates the hash map with custom callback function . // If returns true, then it continues iterating; or false to stop. func (m *StrIntMap) Iterator(f func(k string, v int) bool) { diff --git a/g/container/gmap/gmap_str_str_map.go b/g/container/gmap/gmap_str_str_map.go index ac445887a..b232886cd 100644 --- a/g/container/gmap/gmap_str_str_map.go +++ b/g/container/gmap/gmap_str_str_map.go @@ -26,8 +26,8 @@ func NewStrStrMap(unsafe...bool) *StrStrMap { } } -// NewStrStrMapFrom returns an StrStrMap object from given map . -// Notice that, the param map is a type of pointer, +// NewStrStrMapFrom returns a hash map from given map . +// Note that, the param map will be set as the underlying data map(no deep copy), // there might be some concurrent-safe issues when changing the map outside. func NewStrStrMapFrom(data map[string]string, unsafe...bool) *StrStrMap { return &StrStrMap{ @@ -36,28 +36,6 @@ func NewStrStrMapFrom(data map[string]string, unsafe...bool) *StrStrMap { } } -// NewStrStrMapFromArray returns an StrStrMap object from given array. -// The param is given as the keys of the map, -// and as its corresponding values. -// -// If length of is greater than that of , -// the corresponding overflow map values will be the default value of its type. -func NewStrStrMapFromArray(keys []string, values []string, unsafe...bool) *StrStrMap { - m := make(map[string]string) - l := len(values) - for i, k := range keys { - if i < l { - m[k] = values[i] - } else { - m[k] = "" - } - } - return &StrStrMap{ - mu : rwmutex.New(unsafe...), - data : m, - } -} - // Iterator iterates the hash map with custom callback function . // If returns true, then it continues iterating; or false to stop. func (m *StrStrMap) Iterator(f func (k string, v string) bool) { diff --git a/g/container/gmap/gmap_z_basic_test.go b/g/container/gmap/gmap_z_basic_test.go index 065ce1af5..e32cd9586 100644 --- a/g/container/gmap/gmap_z_basic_test.go +++ b/g/container/gmap/gmap_z_basic_test.go @@ -15,9 +15,6 @@ import ( func getValue() interface{} { return 3 } -func callBack(k interface{}, v interface{}) bool { - return true -} func Test_Map_Basic(t *testing.T) { gtest.Case(t, func() { @@ -51,9 +48,6 @@ func Test_Map_Basic(t *testing.T) { m2 := gmap.NewFrom(map[interface{}]interface{}{1: 1, "key1": "val1"}) gtest.Assert(m2.Map(), map[interface{}]interface{}{1: 1, "key1": "val1"}) - m3 := gmap.NewFromArray([]interface{}{1, "key1"}, []interface{}{1, "val1"}) - gtest.Assert(m3.Map(), map[interface{}]interface{}{1: 1, "key1": "val1"}) - }) } func Test_Map_Set_Fun(t *testing.T) { diff --git a/g/container/gmap/gmap_z_int_any_test.go b/g/container/gmap/gmap_z_int_any_test.go index 228c6f712..b42f26b49 100644 --- a/g/container/gmap/gmap_z_int_any_test.go +++ b/g/container/gmap/gmap_z_int_any_test.go @@ -48,9 +48,6 @@ func Test_IntAnyMap_Basic(t *testing.T) { m2 := gmap.NewIntAnyMapFrom(map[int]interface{}{1: 1, 2: "2"}) gtest.Assert(m2.Map(), map[int]interface{}{1: 1, 2: "2"}) - m3 := gmap.NewIntAnyMapFromArray([]int{1, 2}, []interface{}{1, "2"}) - gtest.Assert(m3.Map(), map[int]interface{}{1: 1, 2: "2"}) - }) } func Test_IntAnyMap_Set_Fun(t *testing.T) { diff --git a/g/container/gmap/gmap_z_int_int_test.go b/g/container/gmap/gmap_z_int_int_test.go index 23615f0b9..fee32c642 100644 --- a/g/container/gmap/gmap_z_int_int_test.go +++ b/g/container/gmap/gmap_z_int_int_test.go @@ -48,9 +48,6 @@ func Test_IntIntMap_Basic(t *testing.T) { m2 := gmap.NewIntIntMapFrom(map[int]int{1: 1, 2: 2}) gtest.Assert(m2.Map(), map[int]int{1: 1, 2: 2}) - m3 := gmap.NewIntIntMapFromArray([]int{1, 2}, []int{1, 2}) - gtest.Assert(m3.Map(), map[int]int{1: 1, 2: 2}) - }) } func Test_IntIntMap_Set_Fun(t *testing.T) { diff --git a/g/container/gmap/gmap_z_int_str_test.go b/g/container/gmap/gmap_z_int_str_test.go index 02c278748..45c446cab 100644 --- a/g/container/gmap/gmap_z_int_str_test.go +++ b/g/container/gmap/gmap_z_int_str_test.go @@ -53,9 +53,6 @@ func Test_IntStrMap_Basic(t *testing.T) { m2 := gmap.NewIntStrMapFrom(map[int]string{1: "a", 2: "b"}) gtest.Assert(m2.Map(), map[int]string{1: "a", 2: "b"}) - m3 := gmap.NewIntStrMapFromArray([]int{1, 2}, []string{"a", "b"}) - gtest.Assert(m3.Map(), map[int]string{1: "a", 2: "b"}) - }) } func Test_IntStrMap_Set_Fun(t *testing.T) { diff --git a/g/container/gmap/gmap_z_str_any_test.go b/g/container/gmap/gmap_z_str_any_test.go index eb4508eb1..29567bc77 100644 --- a/g/container/gmap/gmap_z_str_any_test.go +++ b/g/container/gmap/gmap_z_str_any_test.go @@ -46,9 +46,6 @@ func Test_StrAnyMap_Basic(t *testing.T) { m2 := gmap.NewStrAnyMapFrom(map[string]interface{}{"a": 1, "b": "2"}) gtest.Assert(m2.Map(), map[string]interface{}{"a": 1, "b": "2"}) - m3 := gmap.NewStrAnyMapFromArray([]string{"a", "b"}, []interface{}{1, "2"}) - gtest.Assert(m3.Map(), map[string]interface{}{"a": 1, "b": "2"}) - }) } func Test_StrAnyMap_Set_Fun(t *testing.T) { diff --git a/g/container/gmap/gmap_z_str_int_test.go b/g/container/gmap/gmap_z_str_int_test.go index fed3f539f..4bc4a6c89 100644 --- a/g/container/gmap/gmap_z_str_int_test.go +++ b/g/container/gmap/gmap_z_str_int_test.go @@ -48,9 +48,6 @@ func Test_StrIntMap_Basic(t *testing.T) { m2 := gmap.NewStrIntMapFrom(map[string]int{"a": 1, "b": 2}) gtest.Assert(m2.Map(), map[string]int{"a": 1, "b": 2}) - m3 := gmap.NewStrIntMapFromArray([]string{"a", "b"}, []int{1, 2}) - gtest.Assert(m3.Map(), map[string]int{"a": 1, "b": 2}) - }) } func Test_StrIntMap_Set_Fun(t *testing.T) { diff --git a/g/container/gmap/gmap_z_str_str_test.go b/g/container/gmap/gmap_z_str_str_test.go index d29cc340b..6d700729d 100644 --- a/g/container/gmap/gmap_z_str_str_test.go +++ b/g/container/gmap/gmap_z_str_str_test.go @@ -47,9 +47,6 @@ func Test_StrStrMap_Basic(t *testing.T) { m2 := gmap.NewStrStrMapFrom(map[string]string{"a": "a", "b": "b"}) gtest.Assert(m2.Map(), map[string]string{"a": "a", "b": "b"}) - m3 := gmap.NewStrStrMapFromArray([]string{"a", "b"}, []string{"a", "b"}) - gtest.Assert(m3.Map(), map[string]string{"a": "a", "b": "b"}) - }) } func Test_StrStrMap_Set_Fun(t *testing.T) { diff --git a/g/container/gmap/gmap_z_tree_map_test.go b/g/container/gmap/gmap_z_tree_map_test.go new file mode 100644 index 000000000..d7322e7cb --- /dev/null +++ b/g/container/gmap/gmap_z_tree_map_test.go @@ -0,0 +1,103 @@ +// Copyright 2017-2019 gf Author(https://github.com/gogf/gf). 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 gm file, +// You can obtain one at https://github.com/gogf/gf. + +package gmap_test + +import ( + "github.com/gogf/gf/g/container/gmap" + "github.com/gogf/gf/g/test/gtest" + "github.com/gogf/gf/g/util/gutil" + "testing" +) + + +func Test_Tree_Map_Basic(t *testing.T) { + gtest.Case(t, func() { + m := gmap.NewTreeMap(gutil.ComparatorString) + m.Set("key1", "val1") + gtest.Assert(m.Keys(), []interface{}{"key1"}) + + gtest.Assert(m.Get("key1"), "val1") + gtest.Assert(m.Size(), 1) + gtest.Assert(m.IsEmpty(), false) + + gtest.Assert(m.GetOrSet("key2", "val2"), "val2") + gtest.Assert(m.SetIfNotExist("key2", "val2"), false) + + gtest.Assert(m.SetIfNotExist("key3", "val3"), true) + + gtest.Assert(m.Remove("key2"), "val2") + gtest.Assert(m.Contains("key2"), false) + + gtest.AssertIN("key3", m.Keys()) + gtest.AssertIN("key1", m.Keys()) + gtest.AssertIN("val3", m.Values()) + gtest.AssertIN("val1", m.Values()) + + m.Flip() + gtest.Assert(m.Map(), map[interface{}]interface{}{"val3": "key3", "val1": "key1"}) + + m.Clear() + gtest.Assert(m.Size(), 0) + gtest.Assert(m.IsEmpty(), true) + + m2 := gmap.NewTreeMapFrom(gutil.ComparatorString, map[interface{}]interface{}{1: 1, "key1": "val1"}) + gtest.Assert(m2.Map(), map[interface{}]interface{}{1: 1, "key1": "val1"}) + }) +} +func Test_Tree_Map_Set_Fun(t *testing.T) { + m := gmap.NewTreeMap(gutil.ComparatorString) + m.GetOrSetFunc("fun", getValue) + m.GetOrSetFuncLock("funlock", getValue) + gtest.Assert(m.Get("funlock"), 3) + gtest.Assert(m.Get("fun"), 3) + m.GetOrSetFunc("fun", getValue) + gtest.Assert(m.SetIfNotExistFunc("fun", getValue), false) + gtest.Assert(m.SetIfNotExistFuncLock("funlock", getValue), false) +} + +func Test_Tree_Map_Batch(t *testing.T) { + m := gmap.NewTreeMap(gutil.ComparatorString) + m.Sets(map[interface{}]interface{}{1: 1, "key1": "val1", "key2": "val2", "key3": "val3"}) + gtest.Assert(m.Map(), map[interface{}]interface{}{1: 1, "key1": "val1", "key2": "val2", "key3": "val3"}) + m.Removes([]interface{}{"key1", 1}) + gtest.Assert(m.Map(), map[interface{}]interface{}{"key2": "val2", "key3": "val3"}) +} +func Test_Tree_Map_Iterator(t *testing.T){ + expect := map[interface{}]interface{}{1: 1, "key1": "val1"} + + m := gmap.NewTreeMapFrom(gutil.ComparatorString, expect) + m.Iterator(func(k interface{}, v interface{}) bool { + gtest.Assert(expect[k], v) + return true + }) + // 断言返回值对遍历控制 + i := 0 + j := 0 + m.Iterator(func(k interface{}, v interface{}) bool { + i++ + return true + }) + m.Iterator(func(k interface{}, v interface{}) bool { + j++ + return false + }) + gtest.Assert(i, 2) + gtest.Assert(j, 1) +} + +func Test_Tree_Map_Clone(t *testing.T) { + //clone 方法是深克隆 + m := gmap.NewTreeMapFrom(gutil.ComparatorString, map[interface{}]interface{}{1: 1, "key1": "val1"}) + m_clone := m.Clone() + m.Remove(1) + //修改原 map,clone 后的 map 不影响 + gtest.AssertIN(1, m_clone.Keys()) + + m_clone.Remove("key1") + //修改clone map,原 map 不影响 + gtest.AssertIN("key1", m.Keys()) +} \ No newline at end of file diff --git a/g/container/gtree/gtree_avltree.go b/g/container/gtree/gtree_avltree.go index af1416213..87a19e397 100644 --- a/g/container/gtree/gtree_avltree.go +++ b/g/container/gtree/gtree_avltree.go @@ -39,6 +39,17 @@ func NewAVLTree(comparator func(v1, v2 interface{}) int, unsafe...bool) *AVLTree } } +// NewAVLTreeFrom instantiates an AVL tree with the custom comparator and data map. +// The param used to specify whether using tree in un-concurrent-safety, +// which is false in default. +func NewAVLTreeFrom(comparator func(v1, v2 interface{}) int, data map[interface{}]interface{}, unsafe...bool) *AVLTree { + tree := NewAVLTree(comparator, unsafe...) + for k, v := range data { + tree.put(k, v, nil, &tree.root) + } + return tree +} + // Clone returns a new tree with a copy of current tree. func (tree *AVLTree) Clone(unsafe ...bool) *AVLTree { newTree := NewAVLTree(tree.comparator, !tree.mu.IsSafe()) @@ -223,7 +234,7 @@ func (tree *AVLTree) Remove(key interface{}) { func (tree *AVLTree) Removes(keys []interface{}) { tree.mu.Lock() defer tree.mu.Unlock() - for key := range keys { + for _, key := range keys { tree.remove(key, &tree.root) } } @@ -257,7 +268,7 @@ func (tree *AVLTree) Values() []interface{} { values := make([]interface{}, tree.Size()) index := 0 tree.IteratorAsc(func(key, value interface{}) bool { - values[index] = key + values[index] = value index++ return true }) @@ -412,6 +423,11 @@ func (tree *AVLTree) Flip(comparator...func(v1, v2 interface{}) int) { tree.mu.Unlock() } +// Iterator is alias of IteratorAsc. +func (tree *AVLTree) Iterator(f func (key, value interface{}) bool) { + tree.IteratorAsc(f) +} + // IteratorAsc iterates the tree in ascending order with given callback function . // If returns true, then it continues iterating; or false to stop. func (tree *AVLTree) IteratorAsc(f func (key, value interface{}) bool) { diff --git a/g/container/gtree/gtree_btree.go b/g/container/gtree/gtree_btree.go index 230a6a340..9f44221a3 100644 --- a/g/container/gtree/gtree_btree.go +++ b/g/container/gtree/gtree_btree.go @@ -37,6 +37,8 @@ type BTreeEntry struct { } // NewBTree instantiates a B-tree with (maximum number of children) and a custom key comparator. +// The param used to specify whether using tree in un-concurrent-safety, +// which is false in default. // Note that the must be greater or equal than 3, or else it panics. func NewBTree(m int, comparator func(v1, v2 interface{}) int, unsafe...bool) *BTree { if m < 3 { @@ -49,6 +51,17 @@ func NewBTree(m int, comparator func(v1, v2 interface{}) int, unsafe...bool) *BT } } +// NewBTreeFrom instantiates a B-tree with (maximum number of children), a custom key comparator and data map. +// The param used to specify whether using tree in un-concurrent-safety, +// which is false in default. +func NewBTreeFrom(m int, comparator func(v1, v2 interface{}) int, data map[interface{}]interface{}, unsafe...bool) *BTree { + tree := NewBTree(m, comparator, unsafe...) + for k, v := range data { + tree.doSet(k, v) + } + return tree +} + // Clone returns a new tree with a copy of current tree. func (tree *BTree) Clone(unsafe ...bool) *BTree { newTree := NewBTree(tree.m, tree.comparator, !tree.mu.IsSafe()) @@ -236,7 +249,7 @@ func (tree *BTree) Remove(key interface{}) (value interface{}) { func (tree *BTree) Removes(keys []interface{}) { tree.mu.Lock() defer tree.mu.Unlock() - for key := range keys { + for _, key := range keys { tree.doRemove(key) } } @@ -270,7 +283,7 @@ func (tree *BTree) Values() []interface{} { values := make([]interface{}, tree.Size()) index := 0 tree.IteratorAsc(func(key, value interface{}) bool { - values[index] = key + values[index] = value index++ return true }) @@ -362,6 +375,11 @@ func (entry *BTreeEntry) String() string { return fmt.Sprintf("%v", entry.Key) } +// Iterator is alias of IteratorAsc. +func (tree *BTree) Iterator(f func (key, value interface{}) bool) { + tree.IteratorAsc(f) +} + // IteratorAsc iterates the tree in ascending order with given callback function . // If returns true, then it continues iterating; or false to stop. func (tree *BTree) IteratorAsc(f func (key, value interface{}) bool) { diff --git a/g/container/gtree/gtree_redblacktree.go b/g/container/gtree/gtree_redblacktree.go index 4b88a4019..81e314454 100644 --- a/g/container/gtree/gtree_redblacktree.go +++ b/g/container/gtree/gtree_redblacktree.go @@ -46,6 +46,17 @@ func NewRedBlackTree(comparator func(v1, v2 interface{}) int, unsafe...bool) *Re } } +// NewRedBlackTreeFrom instantiates a red-black tree with the custom comparator and map. +// The param used to specify whether using tree in un-concurrent-safety, +// which is false in default. +func NewRedBlackTreeFrom(comparator func(v1, v2 interface{}) int, data map[interface{}]interface{}, unsafe...bool) *RedBlackTree { + tree := NewRedBlackTree(comparator, unsafe...) + for k, v := range data { + tree.doSet(k, v) + } + return tree +} + // Clone returns a new tree with a copy of current tree. func (tree *RedBlackTree) Clone(unsafe ...bool) *RedBlackTree { newTree := NewRedBlackTree(tree.comparator, !tree.mu.IsSafe()) @@ -244,6 +255,7 @@ func (tree *RedBlackTree) doRemove(key interface{}) (value interface{}) { if node == nil { return } + value = node.Value if node.left != nil && node.right != nil { p := node.left.maximumNode() node.Key = p.Key @@ -266,7 +278,6 @@ func (tree *RedBlackTree) doRemove(key interface{}) (value interface{}) { } } tree.size-- - value = node.Value return } @@ -281,7 +292,7 @@ func (tree *RedBlackTree) Remove(key interface{}) (value interface{}) { func (tree *RedBlackTree) Removes(keys []interface{}) { tree.mu.Lock() defer tree.mu.Unlock() - for key := range keys { + for _, key := range keys { tree.doRemove(key) } } @@ -315,7 +326,7 @@ func (tree *RedBlackTree) Values() []interface{} { values := make([]interface{}, tree.Size()) index := 0 tree.IteratorAsc(func(key, value interface{}) bool { - values[index] = key + values[index] = value index++ return true }) @@ -438,6 +449,11 @@ func (tree *RedBlackTree) Ceiling(key interface{}) (ceiling *RedBlackTreeNode) { return nil } +// Iterator is alias of IteratorAsc. +func (tree *RedBlackTree) Iterator(f func (key, value interface{}) bool) { + tree.IteratorAsc(f) +} + // IteratorAsc iterates the tree in ascending order with given callback function . // If returns true, then it continues iterating; or false to stop. func (tree *RedBlackTree) IteratorAsc(f func (key, value interface{}) bool) { @@ -642,7 +658,7 @@ func (tree *RedBlackTree) rotateLeft(node *RedBlackTreeNode) { if right.left != nil { right.left.parent = node } - right.left = node + right.left = node node.parent = right } @@ -653,7 +669,7 @@ func (tree *RedBlackTree) rotateRight(node *RedBlackTreeNode) { if left.right != nil { left.right.parent = node } - left.right = node + left.right = node node.parent = left } @@ -729,7 +745,7 @@ func (node *RedBlackTreeNode) maximumNode() *RedBlackTreeNode { for node.right != nil { return node.right } - return nil + return node } func (tree *RedBlackTree) deleteCase1(node *RedBlackTreeNode) { diff --git a/g/util/gutil/gutil_comparator.go b/g/util/gutil/gutil_comparator.go index a9a627d2d..f571ba4db 100644 --- a/g/util/gutil/gutil_comparator.go +++ b/g/util/gutil/gutil_comparator.go @@ -13,83 +13,83 @@ import ( // positive , if a > b type Comparator func(a, b interface{}) int -// StringComparator provides a fast comparison on strings. -func StringComparator(a, b interface{}) int { +// ComparatorString provides a fast comparison on strings. +func ComparatorString(a, b interface{}) int { return strings.Compare(gconv.String(a), gconv.String(b)) } -// IntComparator provides a basic comparison on int. -func IntComparator(a, b interface{}) int { +// ComparatorInt provides a basic comparison on int. +func ComparatorInt(a, b interface{}) int { return gconv.Int(a) - gconv.Int(b) } -// Int8Comparator provides a basic comparison on int8. -func Int8Comparator(a, b interface{}) int { +// ComparatorInt8 provides a basic comparison on int8. +func ComparatorInt8(a, b interface{}) int { return int(gconv.Int8(a) - gconv.Int8(b)) } -// Int16Comparator provides a basic comparison on int16. -func Int16Comparator(a, b interface{}) int { +// ComparatorInt16 provides a basic comparison on int16. +func ComparatorInt16(a, b interface{}) int { return int(gconv.Int16(a) - gconv.Int16(b)) } -// Int32Comparator provides a basic comparison on int32. -func Int32Comparator(a, b interface{}) int { +// ComparatorInt32 provides a basic comparison on int32. +func ComparatorInt32(a, b interface{}) int { return int(gconv.Int32(a) - gconv.Int32(b)) } -// Int64Comparator provides a basic comparison on int64. -func Int64Comparator(a, b interface{}) int { +// ComparatorInt64 provides a basic comparison on int64. +func ComparatorInt64(a, b interface{}) int { return int(gconv.Int64(a) - gconv.Int64(b)) } -// UintComparator provides a basic comparison on uint. -func UintComparator(a, b interface{}) int { +// ComparatorUint provides a basic comparison on uint. +func ComparatorUint(a, b interface{}) int { return int(gconv.Uint(a) - gconv.Uint(b)) } -// Uint8Comparator provides a basic comparison on uint8. -func Uint8Comparator(a, b interface{}) int { +// ComparatorUint8 provides a basic comparison on uint8. +func ComparatorUint8(a, b interface{}) int { return int(gconv.Uint8(a) - gconv.Uint8(b)) } -// Uint16Comparator provides a basic comparison on uint16. -func Uint16Comparator(a, b interface{}) int { +// ComparatorUint16 provides a basic comparison on uint16. +func ComparatorUint16(a, b interface{}) int { return int(gconv.Uint16(a) - gconv.Uint16(b)) } -// Uint32Comparator provides a basic comparison on uint32. -func Uint32Comparator(a, b interface{}) int { +// ComparatorUint32 provides a basic comparison on uint32. +func ComparatorUint32(a, b interface{}) int { return int(gconv.Uint32(a) - gconv.Uint32(b)) } -// Uint64Comparator provides a basic comparison on uint64. -func Uint64Comparator(a, b interface{}) int { +// ComparatorUint64 provides a basic comparison on uint64. +func ComparatorUint64(a, b interface{}) int { return int(gconv.Uint64(a) - gconv.Uint64(b)) } -// Float32Comparator provides a basic comparison on float32. -func Float32Comparator(a, b interface{}) int { +// ComparatorFloat32 provides a basic comparison on float32. +func ComparatorFloat32(a, b interface{}) int { return int(gconv.Float32(a) - gconv.Float32(b)) } -// Float64Comparator provides a basic comparison on float64. -func Float64Comparator(a, b interface{}) int { +// ComparatorFloat64 provides a basic comparison on float64. +func ComparatorFloat64(a, b interface{}) int { return int(gconv.Float64(a) - gconv.Float64(b)) } -// ByteComparator provides a basic comparison on byte. -func ByteComparator(a, b interface{}) int { +// ComparatorByte provides a basic comparison on byte. +func ComparatorByte(a, b interface{}) int { return int(gconv.Byte(a) - gconv.Byte(b)) } -// RuneComparator provides a basic comparison on rune. -func RuneComparator(a, b interface{}) int { +// ComparatorRune provides a basic comparison on rune. +func ComparatorRune(a, b interface{}) int { return int(gconv.Rune(a) - gconv.Rune(b)) } -// TimeComparator provides a basic comparison on time.Time. -func TimeComparator(a, b interface{}) int { +// ComparatorTime provides a basic comparison on time.Time. +func ComparatorTime(a, b interface{}) int { aTime := gconv.Time(a) bTime := gconv.Time(b) switch { diff --git a/geg/container/gmap/gmap.go b/geg/container/gmap/gmap.go index ad8a9baf0..1f86e5c5e 100644 --- a/geg/container/gmap/gmap.go +++ b/geg/container/gmap/gmap.go @@ -18,7 +18,7 @@ func main() { // 查询大小 fmt.Println(m.Size()) // 批量设置键值对(不同的数据类型对象参数不同) - m.BatchSet(map[interface{}]interface{}{ + m.Sets(map[interface{}]interface{}{ 10: 10, 11: 11, }) @@ -35,7 +35,7 @@ func main() { fmt.Println(m.Size()) // 批量删除 - m.BatchRemove([]interface{}{10, 11}) + m.Removes([]interface{}{10, 11}) fmt.Println(m.Size()) // 当前键名列表(随机排序) @@ -44,10 +44,10 @@ func main() { fmt.Println(m.Values()) // 查询键名,当键值不存在时,写入给定的默认值 - fmt.Println(m.GetWithDefault(100, 100)) + fmt.Println(m.GetOrSet(100, 100)) // 删除键值对,并返回对应的键值 - fmt.Println(m.GetAndRemove(100)) + fmt.Println(m.Remove(100)) // 遍历map m.Iterator(func(k interface{}, v interface{}) bool { diff --git a/geg/container/gmap/gmap_map_safe.go b/geg/container/gmap/gmap_map_safe.go index f225d5473..63b8f2bf7 100644 --- a/geg/container/gmap/gmap_map_safe.go +++ b/geg/container/gmap/gmap_map_safe.go @@ -9,7 +9,7 @@ func main() { m := gmap.New() m.Set("1", "1") - m1 := m.Clone() + m1 := m.Map() m1["2"] = "2" g.Dump(m.Clone()) diff --git a/geg/container/gmap/gmap_treemap.go b/geg/container/gmap/gmap_treemap.go new file mode 100644 index 000000000..f66a8006d --- /dev/null +++ b/geg/container/gmap/gmap_treemap.go @@ -0,0 +1,62 @@ +package main + +import ( + "fmt" + "github.com/gogf/gf/g/container/gmap" + "github.com/gogf/gf/g/util/gutil" +) + +func main() { + m := gmap.NewTreeMap(gutil.ComparatorInt) + + // 设置键值对 + for i := 0; i < 10; i++ { + m.Set(i, i) + } + // 查询大小 + fmt.Println(m.Size()) + // 批量设置键值对(不同的数据类型对象参数不同) + m.Sets(map[interface{}]interface{}{ + 10: 10, + 11: 11, + }) + fmt.Println(m.Size()) + + // 查询是否存在 + fmt.Println(m.Contains(1)) + + // 查询键值 + fmt.Println(m.Get(1)) + + // 删除数据项 + m.Remove(9) + fmt.Println(m.Size()) + + // 批量删除 + m.Removes([]interface{}{10, 11}) + fmt.Println(m.Size()) + + // 当前键名列表(随机排序) + fmt.Println(m.Keys()) + // 当前键值列表(随机排序) + fmt.Println(m.Values()) + + // 查询键名,当键值不存在时,写入给定的默认值 + fmt.Println(m.GetOrSet(100, 100)) + + // 删除键值对,并返回对应的键值 + fmt.Println(m.Remove(100)) + + // 遍历map + m.IteratorAsc(func(k interface{}, v interface{}) bool { + fmt.Printf("%v:%v ", k, v) + return true + }) + fmt.Println() + + // 清空map + m.Clear() + + // 判断map是否为空 + fmt.Println(m.IsEmpty()) +} diff --git a/geg/container/gtree/gtree_avltree.go b/geg/container/gtree/gtree_avltree.go index f26d5c674..231fe53b4 100644 --- a/geg/container/gtree/gtree_avltree.go +++ b/geg/container/gtree/gtree_avltree.go @@ -9,11 +9,11 @@ func main() { tree := gtree.NewAVLTree(func(v1, v2 interface{}) int { return v1.(int) - v2.(int) }) - for i := 0; i < 20; i++ { + for i := 0; i < 10; i++ { tree.Set(i, i*10) } fmt.Println(tree.String()) - + tree.Remove(1) tree.IteratorDesc(func(key, value interface{}) bool { fmt.Println(key, value) return true diff --git a/geg/other/test.go b/geg/other/test.go index fa60feef7..7e80fb035 100644 --- a/geg/other/test.go +++ b/geg/other/test.go @@ -1,8 +1,8 @@ package main import ( + "encoding/json" "fmt" - "github.com/gogf/gf/g/encoding/gparser" "time" ) @@ -27,12 +27,13 @@ func main() { for { m := make(map[string]interface{}) m["facet_is_special_price"] = []string{"1"} - m["score_outlet"] = "0" - m["skus"] = []string{"DI139BE71WDWDFMX", "DI139BE71WDWDFMX-519406"} + m["score_outlet"] = "0" + m["skus"] = []string{"DI139BE71WDWDFMX", "DI139BE71WDWDFMX-519406"} m["facet_novelty_two_days"] = []string{"0"} - m["facet_brand"] = []string{"139"} - m["sku"] = []string{"DI139BE71WDWDFMX"} - fmt.Println(gparser.VarToJsonString(m)) + m["facet_brand"] = []string{"139"} + m["sku"] = []string{"DI139BE71WDWDFMX"} + b, _ := json.Marshal(m) + fmt.Println(string(b)) time.Sleep(100*time.Millisecond) }