add gmap.HashMap/TreeMap/AnyAnyMap for gmap; add unit test cases for TreeMap

This commit is contained in:
John
2019-05-11 20:47:25 +08:00
parent 61d64e7ae4
commit 4e2e4e95e0
26 changed files with 647 additions and 550 deletions

View File

@ -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 <unsafe> 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 <data>.
// Notice that, the param map is a type of pointer,
// Note that, the param <data> map will be set as the underlying data map(no deep copy),
// there might be some concurrent-safe issues when changing the map outside.
// The param <unsafe> 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 <keys> is given as the keys of the map,
// and <values> as its corresponding values.
//
// If length of <keys> is greater than that of <values>,
// 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 <unsafe> 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 <f>.
// If <f> 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 <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.
// The param <unsafe> 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 <unsafe> 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 <key>.
// Second return parameter <found> 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 <key>.
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 <key>,
// or else just return the existing value.
//
// When setting value, if <value> is type of <func() interface {}>,
// it will be executed with mutex.Lock of the hash map,
// and its return value will be set to the map with <key>.
//
// It returns value with given <key>.
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 <value> 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 <f> 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 <f> if not exist
// and returns this value.
//
// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function <f>
// 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 <key>.
// 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 <value> to the map if the <key> does not exist, then return true.
// It returns false if <key> exists, and <value> 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 <f>, then return true.
// It returns false if <key> exists, and <value> 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 <f>, then return true.
// It returns false if <key> exists, and <value> would be ignored.
//
// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
// it executes function <f> 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 <key>, 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 <key> 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 <f> 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 <f> 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 <other> map will be merged into the map <m>.
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 <data> map.
// Note that, the param <data> map will be set as the underlying data map(no deep copy),
// there might be some concurrent-safe issues when changing the map outside.
// The param <unsafe> 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...)
}

View File

@ -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 <unsafe> 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 <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.
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 <f>.
// If <f> 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 <key>.
// Second return parameter <found> 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 <key>.
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 <key>,
// or else just return the existing value.
//
// When setting value, if <value> is type of <func() interface {}>,
// it will be executed with mutex.Lock of the hash map,
// and its return value will be set to the map with <key>.
//
// It returns value with given <key>.
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 <value> 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 <f> 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 <f> if not exist
// and returns this value.
//
// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function <f>
// 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 <key>.
// 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 <value> to the map if the <key> does not exist, then return true.
// It returns false if <key> exists, and <value> 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 <f>, then return true.
// It returns false if <key> exists, and <value> 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 <f>, then return true.
// It returns false if <key> exists, and <value> would be ignored.
//
// SetIfNotExistFuncLock differs with SetIfNotExistFunc function is that
// it executes function <f> 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 <key>, 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 <key> 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 <f> 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 <f> 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 <other> map will be merged into the map <m>.
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
}
}

View File

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

View File

@ -28,8 +28,8 @@ func NewIntAnyMap(unsafe...bool) *IntAnyMap {
}
}
// NewIntAnyMapFrom returns an IntAnyMap object from given map <data>.
// Notice that, the param map is a type of pointer,
// NewIntAnyMapFrom 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.
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 <keys> is given as the keys of the map,
// and <values> as its corresponding values.
//
// If length of <keys> is greater than that of <values>,
// 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 <f>.
// If <f> returns true, then it continues iterating; or false to stop.
func (m *IntAnyMap) Iterator(f func (k int, v interface{}) bool) {

View File

@ -25,8 +25,8 @@ func NewIntIntMap(unsafe...bool) *IntIntMap {
}
}
// NewIntIntMapFrom returns an IntIntMap object from given map <data>.
// Notice that, the param map is a type of pointer,
// NewIntIntMapFrom 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.
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 <keys> is given as the keys of the map,
// and <values> as its corresponding values.
//
// If length of <keys> is greater than that of <values>,
// 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 <f>.
// If <f> returns true, then it continues iterating; or false to stop.
func (m *IntIntMap) Iterator(f func (k int, v int) bool) {

View File

@ -26,8 +26,8 @@ func NewIntStrMap(unsafe ...bool) *IntStrMap {
}
}
// NewIntStrMapFrom returns an IntStrMap object from given map <data>.
// Notice that, the param map is a type of pointer,
// NewIntStrMapFrom 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.
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 <keys> is given as the keys of the map,
// and <values> as its corresponding values.
//
// If length of <keys> is greater than that of <values>,
// 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 <f>.
// If <f> returns true, then it continues iterating; or false to stop.
func (m *IntStrMap) Iterator(f func(k int, v string) bool) {

View File

@ -28,8 +28,8 @@ func NewStrAnyMap(unsafe ...bool) *StrAnyMap {
}
}
// NewStrAnyMapFrom returns an StrAnyMap object from given map <data>.
// Notice that, the param map is a type of pointer,
// NewStrAnyMapFrom 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.
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 <keys> is given as the keys of the map,
// and <values> as its corresponding values.
//
// If length of <keys> is greater than that of <values>,
// 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 <f>.
// If <f> returns true, then it continues iterating; or false to stop.
func (m *StrAnyMap) Iterator(f func(k string, v interface{}) bool) {

View File

@ -27,8 +27,8 @@ func NewStrIntMap(unsafe ...bool) *StrIntMap {
}
}
// NewStrIntMapFrom returns an StrIntMap object from given map <data>.
// Notice that, the param map is a type of pointer,
// NewStrIntMapFrom 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.
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 <keys> is given as the keys of the map,
// and <values> as its corresponding values.
//
// If length of <keys> is greater than that of <values>,
// 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 <f>.
// If <f> returns true, then it continues iterating; or false to stop.
func (m *StrIntMap) Iterator(f func(k string, v int) bool) {

View File

@ -26,8 +26,8 @@ func NewStrStrMap(unsafe...bool) *StrStrMap {
}
}
// NewStrStrMapFrom returns an StrStrMap object from given map <data>.
// Notice that, the param map is a type of pointer,
// NewStrStrMapFrom 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.
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 <keys> is given as the keys of the map,
// and <values> as its corresponding values.
//
// If length of <keys> is greater than that of <values>,
// 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 <f>.
// If <f> returns true, then it continues iterating; or false to stop.
func (m *StrStrMap) Iterator(f func (k string, v string) bool) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 <unsafe> 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 <f>.
// If <f> returns true, then it continues iterating; or false to stop.
func (tree *AVLTree) IteratorAsc(f func (key, value interface{}) bool) {

View File

@ -37,6 +37,8 @@ type BTreeEntry struct {
}
// NewBTree instantiates a B-tree with <m> (maximum number of children) and a custom key comparator.
// The param <unsafe> used to specify whether using tree in un-concurrent-safety,
// which is false in default.
// Note that the <m> 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 <m> (maximum number of children), a custom key comparator and data map.
// The param <unsafe> 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 <f>.
// If <f> returns true, then it continues iterating; or false to stop.
func (tree *BTree) IteratorAsc(f func (key, value interface{}) bool) {

View File

@ -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 <data> map.
// The param <unsafe> 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 <f>.
// If <f> 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) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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