mirror of
https://gitee.com/johng/gf.git
synced 2024-12-02 20:28:17 +08:00
commit
8300885ab6
@ -66,12 +66,14 @@ func main() {
|
||||
|
||||
# Contributors
|
||||
|
||||
- [aloncn](https://github.com/aloncn)
|
||||
- [chenyang351](https://github.com/chenyang351)
|
||||
- [garfieldkwong](https://gitee.com/garfieldkwong)
|
||||
- [hailaz](https://gitee.com/hailaz)
|
||||
- [johng](https://gitee.com/johng)
|
||||
- [pibigstar](https://github.com/pibigstar)
|
||||
- [qq1054000800](https://gitee.com/qq1054000800)
|
||||
- [qq976739120](https://github.com/qq976739120)
|
||||
- [wenzi1](https://gitee.com/wenzi1)
|
||||
- [wxkj001](https://github.com/wxkj001)
|
||||
- [ymrjqyy](https://gitee.com/ymrjqyy)
|
||||
|
@ -86,12 +86,14 @@ func main() {
|
||||
|
||||
# 贡献者
|
||||
|
||||
- [aloncn](https://github.com/aloncn)
|
||||
- [chenyang351](https://github.com/chenyang351)
|
||||
- [garfieldkwong](https://gitee.com/garfieldkwong)
|
||||
- [hailaz](https://gitee.com/hailaz)
|
||||
- [johng](https://gitee.com/johng)
|
||||
- [pibigstar](https://github.com/pibigstar)
|
||||
- [qq1054000800](https://gitee.com/qq1054000800)
|
||||
- [qq976739120](https://github.com/qq976739120)
|
||||
- [wenzi1](https://gitee.com/wenzi1)
|
||||
- [wxkj001](https://github.com/wxkj001)
|
||||
- [ymrjqyy](https://gitee.com/ymrjqyy)
|
||||
|
2
TODO.MD
2
TODO.MD
@ -43,7 +43,7 @@
|
||||
1. 添加Save/Replace/BatchSave/BatchReplace方法对sqlite数据库的支持;
|
||||
1. 添加sqlite数据库的单元测试用例;
|
||||
1. gredis增加cluster支持;
|
||||
|
||||
1. gset.Add/Remove/Contains方法增加批量操作支持;
|
||||
|
||||
# DONE
|
||||
1. gconv完善针对不同类型的判断,例如:尽量减少sprintf("%v", xxx)来执行string类型的转换;
|
||||
|
@ -4,12 +4,11 @@
|
||||
// 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/internal/rwmutex"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
"github.com/gogf/gf/g/internal/rwmutex"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
)
|
||||
|
||||
type IntStringMap struct {
|
||||
@ -20,21 +19,21 @@ type IntStringMap struct {
|
||||
// NewIntStringMap returns an empty IntStringMap object.
|
||||
// The param <unsafe> used to specify whether using map with un-concurrent-safety,
|
||||
// which is false in default, means concurrent-safe.
|
||||
func NewIntStringMap(unsafe...bool) *IntStringMap {
|
||||
func NewIntStringMap(unsafe ...bool) *IntStringMap {
|
||||
return &IntStringMap{
|
||||
m : make(map[int]string),
|
||||
mu : rwmutex.New(unsafe...),
|
||||
}
|
||||
m: make(map[int]string),
|
||||
mu: rwmutex.New(unsafe...),
|
||||
}
|
||||
}
|
||||
|
||||
// NewIntStringMapFrom returns an IntStringMap object from given map <m>.
|
||||
// Notice that, the param map is a type of pointer,
|
||||
// there might be some concurrent-safe issues when changing the map outside.
|
||||
func NewIntStringMapFrom(m map[int]string, unsafe...bool) *IntStringMap {
|
||||
return &IntStringMap{
|
||||
m : m,
|
||||
mu : rwmutex.New(unsafe...),
|
||||
}
|
||||
func NewIntStringMapFrom(m map[int]string, unsafe ...bool) *IntStringMap {
|
||||
return &IntStringMap{
|
||||
m: m,
|
||||
mu: rwmutex.New(unsafe...),
|
||||
}
|
||||
}
|
||||
|
||||
// NewIntStringMapFromArray returns an IntStringMap object from given array.
|
||||
@ -43,37 +42,37 @@ func NewIntStringMapFrom(m map[int]string, unsafe...bool) *IntStringMap {
|
||||
//
|
||||
// If length of <keys> is greater than that of <values>,
|
||||
// the corresponding overflow map values will be the default value of its type.
|
||||
func NewIntStringMapFromArray(keys []int, values []string, unsafe...bool) *IntStringMap {
|
||||
m := make(map[int]string)
|
||||
l := len(values)
|
||||
for i, k := range keys {
|
||||
if i < l {
|
||||
m[k] = values[i]
|
||||
} else {
|
||||
m[k] = ""
|
||||
}
|
||||
}
|
||||
return &IntStringMap{
|
||||
m : m,
|
||||
mu : rwmutex.New(unsafe...),
|
||||
}
|
||||
func NewIntStringMapFromArray(keys []int, values []string, unsafe ...bool) *IntStringMap {
|
||||
m := make(map[int]string)
|
||||
l := len(values)
|
||||
for i, k := range keys {
|
||||
if i < l {
|
||||
m[k] = values[i]
|
||||
} else {
|
||||
m[k] = ""
|
||||
}
|
||||
}
|
||||
return &IntStringMap{
|
||||
m: m,
|
||||
mu: rwmutex.New(unsafe...),
|
||||
}
|
||||
}
|
||||
|
||||
// Iterator iterates the hash map with custom callback function <f>.
|
||||
// If f returns true, then continue iterating; or false to stop.
|
||||
func (gm *IntStringMap) Iterator(f func (k int, v string) bool) {
|
||||
gm.mu.RLock()
|
||||
defer gm.mu.RUnlock()
|
||||
for k, v := range gm.m {
|
||||
if !f(k, v) {
|
||||
break
|
||||
}
|
||||
}
|
||||
func (gm *IntStringMap) Iterator(f func(k int, v string) bool) {
|
||||
gm.mu.RLock()
|
||||
defer gm.mu.RUnlock()
|
||||
for k, v := range gm.m {
|
||||
if !f(k, v) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clone returns a new hash map with copy of current map data.
|
||||
func (gm *IntStringMap) Clone() *IntStringMap {
|
||||
return NewIntStringMapFrom(gm.Map(), !gm.mu.IsSafe())
|
||||
return NewIntStringMapFrom(gm.Map(), !gm.mu.IsSafe())
|
||||
}
|
||||
|
||||
// Map returns a copy of the data of the hash map.
|
||||
@ -83,7 +82,7 @@ func (gm *IntStringMap) Map() map[int]string {
|
||||
for k, v := range gm.m {
|
||||
m[k] = v
|
||||
}
|
||||
gm.mu.RUnlock()
|
||||
gm.mu.RUnlock()
|
||||
return m
|
||||
}
|
||||
|
||||
@ -117,40 +116,40 @@ func (gm *IntStringMap) Get(key int) string {
|
||||
//
|
||||
// It returns value with given <key>.
|
||||
func (gm *IntStringMap) doSetWithLockCheck(key int, value string) string {
|
||||
gm.mu.Lock()
|
||||
if v, ok := gm.m[key]; ok {
|
||||
gm.mu.Unlock()
|
||||
return v
|
||||
}
|
||||
gm.m[key] = value
|
||||
gm.mu.Unlock()
|
||||
return value
|
||||
gm.mu.Lock()
|
||||
if v, ok := gm.m[key]; ok {
|
||||
gm.mu.Unlock()
|
||||
return v
|
||||
}
|
||||
gm.m[key] = value
|
||||
gm.mu.Unlock()
|
||||
return value
|
||||
}
|
||||
|
||||
// GetOrSet returns the value by key,
|
||||
// or set value with given <value> if not exist and returns this value.
|
||||
func (gm *IntStringMap) GetOrSet(key int, value string) string {
|
||||
gm.mu.RLock()
|
||||
v, ok := gm.m[key]
|
||||
gm.mu.RUnlock()
|
||||
if !ok {
|
||||
return gm.doSetWithLockCheck(key, value)
|
||||
} else {
|
||||
return v
|
||||
}
|
||||
gm.mu.RLock()
|
||||
v, ok := gm.m[key]
|
||||
gm.mu.RUnlock()
|
||||
if !ok {
|
||||
return gm.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 (gm *IntStringMap) GetOrSetFunc(key int, f func() string) string {
|
||||
gm.mu.RLock()
|
||||
v, ok := gm.m[key]
|
||||
gm.mu.RUnlock()
|
||||
if !ok {
|
||||
return gm.doSetWithLockCheck(key, f())
|
||||
} else {
|
||||
return v
|
||||
}
|
||||
gm.mu.RLock()
|
||||
v, ok := gm.m[key]
|
||||
gm.mu.RUnlock()
|
||||
if !ok {
|
||||
return gm.doSetWithLockCheck(key, f())
|
||||
} else {
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
// GetOrSetFuncLock returns the value by key,
|
||||
@ -159,31 +158,31 @@ func (gm *IntStringMap) GetOrSetFunc(key int, f func() string) string {
|
||||
// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function <f>
|
||||
// with mutex.Lock of the hash map.
|
||||
func (gm *IntStringMap) GetOrSetFuncLock(key int, f func() string) string {
|
||||
gm.mu.RLock()
|
||||
val, ok := gm.m[key]
|
||||
gm.mu.RUnlock()
|
||||
if !ok {
|
||||
gm.mu.Lock()
|
||||
defer gm.mu.Unlock()
|
||||
if v, ok := gm.m[key]; ok {
|
||||
return v
|
||||
}
|
||||
val = f()
|
||||
gm.m[key] = val
|
||||
return val
|
||||
} else {
|
||||
return val
|
||||
}
|
||||
gm.mu.RLock()
|
||||
val, ok := gm.m[key]
|
||||
gm.mu.RUnlock()
|
||||
if !ok {
|
||||
gm.mu.Lock()
|
||||
defer gm.mu.Unlock()
|
||||
if v, ok := gm.m[key]; ok {
|
||||
return v
|
||||
}
|
||||
val = f()
|
||||
gm.m[key] = val
|
||||
return val
|
||||
} else {
|
||||
return val
|
||||
}
|
||||
}
|
||||
|
||||
// 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 (gm *IntStringMap) SetIfNotExist(key int, value string) bool {
|
||||
if !gm.Contains(key) {
|
||||
gm.doSetWithLockCheck(key, value)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
if !gm.Contains(key) {
|
||||
gm.doSetWithLockCheck(key, value)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// SetIfNotExistFunc sets value with return value of callback function <f>, then return true.
|
||||
@ -213,117 +212,116 @@ func (gm *IntStringMap) SetIfNotExistFuncLock(key int, f func() string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
// BatchRemove batch deletes values of the map by keys.
|
||||
func (gm *IntStringMap) BatchRemove(keys []int) {
|
||||
gm.mu.Lock()
|
||||
for _, key := range keys {
|
||||
delete(gm.m, key)
|
||||
}
|
||||
gm.mu.Unlock()
|
||||
gm.mu.Lock()
|
||||
for _, key := range keys {
|
||||
delete(gm.m, key)
|
||||
}
|
||||
gm.mu.Unlock()
|
||||
}
|
||||
|
||||
// Remove deletes value from map by given <key>, and return this deleted value.
|
||||
func (gm *IntStringMap) Remove(key int) string {
|
||||
gm.mu.Lock()
|
||||
val, exists := gm.m[key]
|
||||
if exists {
|
||||
delete(gm.m, key)
|
||||
}
|
||||
gm.mu.Unlock()
|
||||
return val
|
||||
gm.mu.Lock()
|
||||
val, exists := gm.m[key]
|
||||
if exists {
|
||||
delete(gm.m, key)
|
||||
}
|
||||
gm.mu.Unlock()
|
||||
return val
|
||||
}
|
||||
|
||||
// Keys returns all keys of the map as a slice.
|
||||
func (gm *IntStringMap) Keys() []int {
|
||||
gm.mu.RLock()
|
||||
keys := make([]int, 0)
|
||||
for key, _ := range gm.m {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
gm.mu.RUnlock()
|
||||
return keys
|
||||
gm.mu.RLock()
|
||||
keys := make([]int, 0)
|
||||
for key, _ := range gm.m {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
gm.mu.RUnlock()
|
||||
return keys
|
||||
}
|
||||
|
||||
// Values returns all values of the map as a slice.
|
||||
func (gm *IntStringMap) Values() []string {
|
||||
gm.mu.RLock()
|
||||
vals := make([]string, 0)
|
||||
for _, val := range gm.m {
|
||||
vals = append(vals, val)
|
||||
}
|
||||
gm.mu.RUnlock()
|
||||
return vals
|
||||
gm.mu.RLock()
|
||||
vals := make([]string, 0)
|
||||
for _, val := range gm.m {
|
||||
vals = append(vals, val)
|
||||
}
|
||||
gm.mu.RUnlock()
|
||||
return vals
|
||||
}
|
||||
|
||||
// Contains checks whether a key exists.
|
||||
// It returns true if the <key> exists, or else false.
|
||||
func (gm *IntStringMap) Contains(key int) bool {
|
||||
gm.mu.RLock()
|
||||
_, exists := gm.m[key]
|
||||
gm.mu.RUnlock()
|
||||
return exists
|
||||
gm.mu.RLock()
|
||||
_, exists := gm.m[key]
|
||||
gm.mu.RUnlock()
|
||||
return exists
|
||||
}
|
||||
|
||||
// Size returns the size of the map.
|
||||
func (gm *IntStringMap) Size() int {
|
||||
gm.mu.RLock()
|
||||
length := len(gm.m)
|
||||
gm.mu.RUnlock()
|
||||
return length
|
||||
gm.mu.RLock()
|
||||
length := len(gm.m)
|
||||
gm.mu.RUnlock()
|
||||
return length
|
||||
}
|
||||
|
||||
// IsEmpty checks whether the map is empty.
|
||||
// It returns true if map is empty, or else false.
|
||||
func (gm *IntStringMap) IsEmpty() bool {
|
||||
gm.mu.RLock()
|
||||
empty := len(gm.m) == 0
|
||||
gm.mu.RUnlock()
|
||||
return empty
|
||||
gm.mu.RLock()
|
||||
empty := len(gm.m) == 0
|
||||
gm.mu.RUnlock()
|
||||
return empty
|
||||
}
|
||||
|
||||
// Clear deletes all data of the map, it will remake a new underlying map data map.
|
||||
func (gm *IntStringMap) Clear() {
|
||||
gm.mu.Lock()
|
||||
gm.m = make(map[int]string)
|
||||
gm.mu.Unlock()
|
||||
gm.mu.Lock()
|
||||
gm.m = make(map[int]string)
|
||||
gm.mu.Unlock()
|
||||
}
|
||||
|
||||
// LockFunc locks writing with given callback function <f> and mutex.Lock.
|
||||
func (gm *IntStringMap) LockFunc(f func(m map[int]string)) {
|
||||
gm.mu.Lock()
|
||||
defer gm.mu.Unlock()
|
||||
f(gm.m)
|
||||
gm.mu.Lock()
|
||||
defer gm.mu.Unlock()
|
||||
f(gm.m)
|
||||
}
|
||||
|
||||
// RLockFunc locks reading with given callback function <f> and mutex.RLock.
|
||||
func (gm *IntStringMap) RLockFunc(f func(m map[int]string)) {
|
||||
gm.mu.RLock()
|
||||
defer gm.mu.RUnlock()
|
||||
f(gm.m)
|
||||
gm.mu.RLock()
|
||||
defer gm.mu.RUnlock()
|
||||
f(gm.m)
|
||||
}
|
||||
|
||||
// Flip exchanges key-value of the map, it will change key-value to value-key.
|
||||
func (gm *IntStringMap) Flip() {
|
||||
gm.mu.Lock()
|
||||
defer gm.mu.Unlock()
|
||||
n := make(map[int]string, len(gm.m))
|
||||
for k, v := range gm.m {
|
||||
n[gconv.Int(v)] = gconv.String(k)
|
||||
}
|
||||
gm.m = n
|
||||
gm.mu.Lock()
|
||||
defer gm.mu.Unlock()
|
||||
n := make(map[int]string, len(gm.m))
|
||||
for k, v := range gm.m {
|
||||
n[gconv.Int(v)] = gconv.String(k)
|
||||
}
|
||||
gm.m = n
|
||||
}
|
||||
|
||||
// Merge merges two hash maps.
|
||||
// The <other> map will be merged into the map <gm>.
|
||||
func (gm *IntStringMap) Merge(other *IntStringMap) {
|
||||
gm.mu.Lock()
|
||||
defer gm.mu.Unlock()
|
||||
if other != gm {
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
}
|
||||
for k, v := range other.m {
|
||||
gm.m[k] = v
|
||||
}
|
||||
}
|
||||
gm.mu.Lock()
|
||||
defer gm.mu.Unlock()
|
||||
if other != gm {
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
}
|
||||
for k, v := range other.m {
|
||||
gm.m[k] = v
|
||||
}
|
||||
}
|
||||
|
@ -8,8 +8,8 @@
|
||||
package gmap
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/internal/rwmutex"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
"github.com/gogf/gf/g/internal/rwmutex"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
)
|
||||
|
||||
type StringIntMap struct {
|
||||
@ -20,21 +20,21 @@ type StringIntMap struct {
|
||||
// NewStringIntMap returns an empty StringIntMap object.
|
||||
// The param <unsafe> used to specify whether using map with un-concurrent-safety,
|
||||
// which is false in default, means concurrent-safe.
|
||||
func NewStringIntMap(unsafe...bool) *StringIntMap {
|
||||
func NewStringIntMap(unsafe ...bool) *StringIntMap {
|
||||
return &StringIntMap{
|
||||
m : make(map[string]int),
|
||||
mu : rwmutex.New(unsafe...),
|
||||
}
|
||||
m: make(map[string]int),
|
||||
mu: rwmutex.New(unsafe...),
|
||||
}
|
||||
}
|
||||
|
||||
// NewStringIntMapFrom returns an StringIntMap object from given map <m>.
|
||||
// Notice that, the param map is a type of pointer,
|
||||
// there might be some concurrent-safe issues when changing the map outside.
|
||||
func NewStringIntMapFrom(m map[string]int, unsafe...bool) *StringIntMap {
|
||||
return &StringIntMap{
|
||||
m : m,
|
||||
mu : rwmutex.New(unsafe...),
|
||||
}
|
||||
func NewStringIntMapFrom(m map[string]int, unsafe ...bool) *StringIntMap {
|
||||
return &StringIntMap{
|
||||
m: m,
|
||||
mu: rwmutex.New(unsafe...),
|
||||
}
|
||||
}
|
||||
|
||||
// NewStringIntMapFromArray returns an StringIntMap object from given array.
|
||||
@ -43,48 +43,48 @@ func NewStringIntMapFrom(m map[string]int, unsafe...bool) *StringIntMap {
|
||||
//
|
||||
// If length of <keys> is greater than that of <values>,
|
||||
// the corresponding overflow map values will be the default value of its type.
|
||||
func NewStringIntMapFromArray(keys []string, values []int, unsafe...bool) *StringIntMap {
|
||||
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 &StringIntMap{
|
||||
m : m,
|
||||
mu : rwmutex.New(unsafe...),
|
||||
}
|
||||
func NewStringIntMapFromArray(keys []string, values []int, unsafe ...bool) *StringIntMap {
|
||||
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 &StringIntMap{
|
||||
m: m,
|
||||
mu: rwmutex.New(unsafe...),
|
||||
}
|
||||
}
|
||||
|
||||
// Iterator iterates the hash map with custom callback function <f>.
|
||||
// If f returns true, then continue iterating; or false to stop.
|
||||
func (gm *StringIntMap) Iterator(f func (k string, v int) bool) {
|
||||
gm.mu.RLock()
|
||||
defer gm.mu.RUnlock()
|
||||
for k, v := range gm.m {
|
||||
if !f(k, v) {
|
||||
break
|
||||
}
|
||||
}
|
||||
func (gm *StringIntMap) Iterator(f func(k string, v int) bool) {
|
||||
gm.mu.RLock()
|
||||
defer gm.mu.RUnlock()
|
||||
for k, v := range gm.m {
|
||||
if !f(k, v) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clone returns a new hash map with copy of current map data.
|
||||
func (gm *StringIntMap) Clone() *StringIntMap {
|
||||
return NewStringIntMapFrom(gm.Map(), !gm.mu.IsSafe())
|
||||
return NewStringIntMapFrom(gm.Map(), !gm.mu.IsSafe())
|
||||
}
|
||||
|
||||
// Map returns a copy of the data of the hash map.
|
||||
func (gm *StringIntMap) Map() map[string]int {
|
||||
m := make(map[string]int)
|
||||
gm.mu.RLock()
|
||||
for k, v := range gm.m {
|
||||
m[k] = v
|
||||
}
|
||||
gm.mu.RUnlock()
|
||||
return m
|
||||
m := make(map[string]int)
|
||||
gm.mu.RLock()
|
||||
for k, v := range gm.m {
|
||||
m[k] = v
|
||||
}
|
||||
gm.mu.RUnlock()
|
||||
return m
|
||||
}
|
||||
|
||||
// Set sets key-value to the hash map.
|
||||
@ -107,7 +107,7 @@ func (gm *StringIntMap) BatchSet(m map[string]int) {
|
||||
func (gm *StringIntMap) Get(key string) int {
|
||||
gm.mu.RLock()
|
||||
val, _ := gm.m[key]
|
||||
gm.mu.RUnlock()
|
||||
gm.mu.RUnlock()
|
||||
return val
|
||||
}
|
||||
|
||||
@ -117,41 +117,41 @@ func (gm *StringIntMap) Get(key string) int {
|
||||
//
|
||||
// It returns value with given <key>.
|
||||
func (gm *StringIntMap) doSetWithLockCheck(key string, value int) int {
|
||||
gm.mu.Lock()
|
||||
if v, ok := gm.m[key]; ok {
|
||||
gm.mu.Unlock()
|
||||
return v
|
||||
}
|
||||
gm.m[key] = value
|
||||
gm.mu.Unlock()
|
||||
return value
|
||||
gm.mu.Lock()
|
||||
if v, ok := gm.m[key]; ok {
|
||||
gm.mu.Unlock()
|
||||
return v
|
||||
}
|
||||
gm.m[key] = value
|
||||
gm.mu.Unlock()
|
||||
return value
|
||||
}
|
||||
|
||||
// GetOrSet returns the value by key,
|
||||
// or set value with given <value> if not exist and returns this value.
|
||||
func (gm *StringIntMap) GetOrSet(key string, value int) int {
|
||||
gm.mu.RLock()
|
||||
v, ok := gm.m[key]
|
||||
gm.mu.RUnlock()
|
||||
if !ok {
|
||||
return gm.doSetWithLockCheck(key, value)
|
||||
} else {
|
||||
return v
|
||||
}
|
||||
gm.mu.RLock()
|
||||
v, ok := gm.m[key]
|
||||
gm.mu.RUnlock()
|
||||
if !ok {
|
||||
return gm.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 (gm *StringIntMap) GetOrSetFunc(key string, f func() int) int {
|
||||
gm.mu.RLock()
|
||||
v, ok := gm.m[key]
|
||||
gm.mu.RUnlock()
|
||||
if !ok {
|
||||
return gm.doSetWithLockCheck(key, f())
|
||||
} else {
|
||||
return v
|
||||
}
|
||||
gm.mu.RLock()
|
||||
v, ok := gm.m[key]
|
||||
gm.mu.RUnlock()
|
||||
if !ok {
|
||||
return gm.doSetWithLockCheck(key, f())
|
||||
} else {
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
// GetOrSetFuncLock returns the value by key,
|
||||
@ -161,31 +161,31 @@ func (gm *StringIntMap) GetOrSetFunc(key string, f func() int) int {
|
||||
// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function <f>
|
||||
// with mutex.Lock of the hash map.
|
||||
func (gm *StringIntMap) GetOrSetFuncLock(key string, f func() int) int {
|
||||
gm.mu.RLock()
|
||||
val, ok := gm.m[key]
|
||||
gm.mu.RUnlock()
|
||||
if !ok {
|
||||
gm.mu.Lock()
|
||||
defer gm.mu.Unlock()
|
||||
if v, ok := gm.m[key]; ok {
|
||||
return v
|
||||
}
|
||||
val = f()
|
||||
gm.m[key] = val
|
||||
return val
|
||||
} else {
|
||||
return val
|
||||
}
|
||||
gm.mu.RLock()
|
||||
val, ok := gm.m[key]
|
||||
gm.mu.RUnlock()
|
||||
if !ok {
|
||||
gm.mu.Lock()
|
||||
defer gm.mu.Unlock()
|
||||
if v, ok := gm.m[key]; ok {
|
||||
return v
|
||||
}
|
||||
val = f()
|
||||
gm.m[key] = val
|
||||
return val
|
||||
} else {
|
||||
return val
|
||||
}
|
||||
}
|
||||
|
||||
// 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 (gm *StringIntMap) SetIfNotExist(key string, value int) bool {
|
||||
if !gm.Contains(key) {
|
||||
gm.doSetWithLockCheck(key, value)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
if !gm.Contains(key) {
|
||||
gm.doSetWithLockCheck(key, value)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// SetIfNotExistFunc sets value with return value of callback function <f>, then return true.
|
||||
@ -217,114 +217,114 @@ func (gm *StringIntMap) SetIfNotExistFuncLock(key string, f func() int) bool {
|
||||
|
||||
// BatchRemove batch deletes values of the map by keys.
|
||||
func (gm *StringIntMap) BatchRemove(keys []string) {
|
||||
gm.mu.Lock()
|
||||
for _, key := range keys {
|
||||
delete(gm.m, key)
|
||||
}
|
||||
gm.mu.Unlock()
|
||||
gm.mu.Lock()
|
||||
for _, key := range keys {
|
||||
delete(gm.m, key)
|
||||
}
|
||||
gm.mu.Unlock()
|
||||
}
|
||||
|
||||
// Remove deletes value from map by given <key>, and return this deleted value.
|
||||
func (gm *StringIntMap) Remove(key string) int {
|
||||
gm.mu.Lock()
|
||||
val, exists := gm.m[key]
|
||||
if exists {
|
||||
delete(gm.m, key)
|
||||
}
|
||||
gm.mu.Unlock()
|
||||
return val
|
||||
gm.mu.Lock()
|
||||
val, exists := gm.m[key]
|
||||
if exists {
|
||||
delete(gm.m, key)
|
||||
}
|
||||
gm.mu.Unlock()
|
||||
return val
|
||||
}
|
||||
|
||||
// Keys returns all keys of the map as a slice.
|
||||
func (gm *StringIntMap) Keys() []string {
|
||||
gm.mu.RLock()
|
||||
keys := make([]string, 0)
|
||||
for key, _ := range gm.m {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
gm.mu.RUnlock()
|
||||
return keys
|
||||
gm.mu.RLock()
|
||||
keys := make([]string, 0)
|
||||
for key, _ := range gm.m {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
gm.mu.RUnlock()
|
||||
return keys
|
||||
}
|
||||
|
||||
// Values returns all values of the map as a slice.
|
||||
func (gm *StringIntMap) Values() []int {
|
||||
gm.mu.RLock()
|
||||
vals := make([]int, 0)
|
||||
for _, val := range gm.m {
|
||||
vals = append(vals, val)
|
||||
}
|
||||
gm.mu.RUnlock()
|
||||
return vals
|
||||
gm.mu.RLock()
|
||||
vals := make([]int, 0)
|
||||
for _, val := range gm.m {
|
||||
vals = append(vals, val)
|
||||
}
|
||||
gm.mu.RUnlock()
|
||||
return vals
|
||||
}
|
||||
|
||||
// Contains checks whether a key exists.
|
||||
// It returns true if the <key> exists, or else false.
|
||||
func (gm *StringIntMap) Contains(key string) bool {
|
||||
gm.mu.RLock()
|
||||
_, exists := gm.m[key]
|
||||
gm.mu.RUnlock()
|
||||
return exists
|
||||
gm.mu.RLock()
|
||||
_, exists := gm.m[key]
|
||||
gm.mu.RUnlock()
|
||||
return exists
|
||||
}
|
||||
|
||||
// Size returns the size of the map.
|
||||
func (gm *StringIntMap) Size() int {
|
||||
gm.mu.RLock()
|
||||
length := len(gm.m)
|
||||
gm.mu.RUnlock()
|
||||
return length
|
||||
gm.mu.RLock()
|
||||
length := len(gm.m)
|
||||
gm.mu.RUnlock()
|
||||
return length
|
||||
}
|
||||
|
||||
// IsEmpty checks whether the map is empty.
|
||||
// It returns true if map is empty, or else false.
|
||||
func (gm *StringIntMap) IsEmpty() bool {
|
||||
gm.mu.RLock()
|
||||
empty := len(gm.m) == 0
|
||||
gm.mu.RUnlock()
|
||||
return empty
|
||||
gm.mu.RLock()
|
||||
empty := len(gm.m) == 0
|
||||
gm.mu.RUnlock()
|
||||
return empty
|
||||
}
|
||||
|
||||
// Clear deletes all data of the map, it will remake a new underlying map data map.
|
||||
func (gm *StringIntMap) Clear() {
|
||||
gm.mu.Lock()
|
||||
gm.m = make(map[string]int)
|
||||
gm.mu.Unlock()
|
||||
gm.mu.Lock()
|
||||
gm.m = make(map[string]int)
|
||||
gm.mu.Unlock()
|
||||
}
|
||||
|
||||
// LockFunc locks writing with given callback function <f> and mutex.Lock.
|
||||
func (gm *StringIntMap) LockFunc(f func(m map[string]int)) {
|
||||
gm.mu.Lock()
|
||||
defer gm.mu.Unlock()
|
||||
f(gm.m)
|
||||
gm.mu.Lock()
|
||||
defer gm.mu.Unlock()
|
||||
f(gm.m)
|
||||
}
|
||||
|
||||
// RLockFunc locks reading with given callback function <f> and mutex.RLock.
|
||||
func (gm *StringIntMap) RLockFunc(f func(m map[string]int)) {
|
||||
gm.mu.RLock()
|
||||
defer gm.mu.RUnlock()
|
||||
f(gm.m)
|
||||
gm.mu.RLock()
|
||||
defer gm.mu.RUnlock()
|
||||
f(gm.m)
|
||||
}
|
||||
|
||||
// Flip exchanges key-value of the map, it will change key-value to value-key.
|
||||
func (gm *StringIntMap) Flip() {
|
||||
gm.mu.Lock()
|
||||
defer gm.mu.Unlock()
|
||||
n := make(map[string]int, len(gm.m))
|
||||
for k, v := range gm.m {
|
||||
n[gconv.String(v)] = gconv.Int(k)
|
||||
}
|
||||
gm.m = n
|
||||
gm.mu.Lock()
|
||||
defer gm.mu.Unlock()
|
||||
n := make(map[string]int, len(gm.m))
|
||||
for k, v := range gm.m {
|
||||
n[gconv.String(v)] = gconv.Int(k)
|
||||
}
|
||||
gm.m = n
|
||||
}
|
||||
|
||||
// Merge merges two hash maps.
|
||||
// The <other> map will be merged into the map <gm>.
|
||||
func (gm *StringIntMap) Merge(other *StringIntMap) {
|
||||
gm.mu.Lock()
|
||||
defer gm.mu.Unlock()
|
||||
if other != gm {
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
}
|
||||
for k, v := range other.m {
|
||||
gm.m[k] = v
|
||||
}
|
||||
}
|
||||
gm.mu.Lock()
|
||||
defer gm.mu.Unlock()
|
||||
if other != gm {
|
||||
other.mu.RLock()
|
||||
defer other.mu.RUnlock()
|
||||
}
|
||||
for k, v := range other.m {
|
||||
gm.m[k] = v
|
||||
}
|
||||
}
|
||||
|
@ -20,21 +20,21 @@ type StringInterfaceMap struct {
|
||||
// NewStringInterfaceMap returns an empty StringInterfaceMap object.
|
||||
// The param <unsafe> used to specify whether using map with un-concurrent-safety,
|
||||
// which is false in default, means concurrent-safe.
|
||||
func NewStringInterfaceMap(unsafe...bool) *StringInterfaceMap {
|
||||
func NewStringInterfaceMap(unsafe ...bool) *StringInterfaceMap {
|
||||
return &StringInterfaceMap{
|
||||
m : make(map[string]interface{}),
|
||||
mu : rwmutex.New(unsafe...),
|
||||
m: make(map[string]interface{}),
|
||||
mu: rwmutex.New(unsafe...),
|
||||
}
|
||||
}
|
||||
|
||||
// NewStringInterfaceMapFrom returns an StringInterfaceMap object from given map <m>.
|
||||
// Notice that, the param map is a type of pointer,
|
||||
// there might be some concurrent-safe issues when changing the map outside.
|
||||
func NewStringInterfaceMapFrom(m map[string]interface{}, unsafe...bool) *StringInterfaceMap {
|
||||
return &StringInterfaceMap{
|
||||
m : m,
|
||||
mu : rwmutex.New(unsafe...),
|
||||
}
|
||||
func NewStringInterfaceMapFrom(m map[string]interface{}, unsafe ...bool) *StringInterfaceMap {
|
||||
return &StringInterfaceMap{
|
||||
m: m,
|
||||
mu: rwmutex.New(unsafe...),
|
||||
}
|
||||
}
|
||||
|
||||
// NewStringInterfaceMapFromArray returns an StringInterfaceMap object from given array.
|
||||
@ -43,25 +43,25 @@ func NewStringInterfaceMapFrom(m map[string]interface{}, unsafe...bool) *StringI
|
||||
//
|
||||
// If length of <keys> is greater than that of <values>,
|
||||
// the corresponding overflow map values will be the default value of its type.
|
||||
func NewStringInterfaceMapFromArray(keys []string, values []interface{}, unsafe...bool) *StringInterfaceMap {
|
||||
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 &StringInterfaceMap{
|
||||
m : m,
|
||||
mu : rwmutex.New(unsafe...),
|
||||
}
|
||||
func NewStringInterfaceMapFromArray(keys []string, values []interface{}, unsafe ...bool) *StringInterfaceMap {
|
||||
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 &StringInterfaceMap{
|
||||
m: m,
|
||||
mu: rwmutex.New(unsafe...),
|
||||
}
|
||||
}
|
||||
|
||||
// Iterator iterates the hash map with custom callback function <f>.
|
||||
// If f returns true, then continue iterating; or false to stop.
|
||||
func (gm *StringInterfaceMap) Iterator(f func (k string, v interface{}) bool) {
|
||||
func (gm *StringInterfaceMap) Iterator(f func(k string, v interface{}) bool) {
|
||||
gm.mu.RLock()
|
||||
defer gm.mu.RUnlock()
|
||||
for k, v := range gm.m {
|
||||
@ -73,18 +73,18 @@ func (gm *StringInterfaceMap) Iterator(f func (k string, v interface{}) bool) {
|
||||
|
||||
// Clone returns a new hash map with copy of current map data.
|
||||
func (gm *StringInterfaceMap) Clone() *StringInterfaceMap {
|
||||
return NewStringInterfaceMapFrom(gm.Map(), !gm.mu.IsSafe())
|
||||
return NewStringInterfaceMapFrom(gm.Map(), !gm.mu.IsSafe())
|
||||
}
|
||||
|
||||
// Map returns a copy of the data of the hash map.
|
||||
func (gm *StringInterfaceMap) Map() map[string]interface{} {
|
||||
m := make(map[string]interface{})
|
||||
gm.mu.RLock()
|
||||
for k, v := range gm.m {
|
||||
m[k] = v
|
||||
}
|
||||
gm.mu.RUnlock()
|
||||
return m
|
||||
m := make(map[string]interface{})
|
||||
gm.mu.RLock()
|
||||
for k, v := range gm.m {
|
||||
m[k] = v
|
||||
}
|
||||
gm.mu.RUnlock()
|
||||
return m
|
||||
}
|
||||
|
||||
// Set sets key-value to the hash map.
|
||||
@ -96,11 +96,11 @@ func (gm *StringInterfaceMap) Set(key string, val interface{}) {
|
||||
|
||||
// BatchSet batch sets key-values to the hash map.
|
||||
func (gm *StringInterfaceMap) BatchSet(m map[string]interface{}) {
|
||||
gm.mu.Lock()
|
||||
for k, v := range m {
|
||||
gm.m[k] = v
|
||||
}
|
||||
gm.mu.Unlock()
|
||||
gm.mu.Lock()
|
||||
for k, v := range m {
|
||||
gm.m[k] = v
|
||||
}
|
||||
gm.mu.Unlock()
|
||||
}
|
||||
|
||||
// Get returns the value by given <key>.
|
||||
@ -123,37 +123,37 @@ func (gm *StringInterfaceMap) Get(key string) interface{} {
|
||||
func (gm *StringInterfaceMap) doSetWithLockCheck(key string, value interface{}) interface{} {
|
||||
gm.mu.Lock()
|
||||
defer gm.mu.Unlock()
|
||||
if v, ok := gm.m[key]; ok {
|
||||
return v
|
||||
}
|
||||
if f, ok := value.(func() interface {}); ok {
|
||||
value = f()
|
||||
}
|
||||
if value != nil {
|
||||
gm.m[key] = value
|
||||
}
|
||||
return value
|
||||
if v, ok := gm.m[key]; ok {
|
||||
return v
|
||||
}
|
||||
if f, ok := value.(func() interface{}); ok {
|
||||
value = f()
|
||||
}
|
||||
if value != nil {
|
||||
gm.m[key] = value
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// GetOrSet returns the value by key,
|
||||
// or set value with given <value> if not exist and returns this value.
|
||||
func (gm *StringInterfaceMap) GetOrSet(key string, value interface{}) interface{} {
|
||||
if v := gm.Get(key); v == nil {
|
||||
return gm.doSetWithLockCheck(key, value)
|
||||
} else {
|
||||
return v
|
||||
}
|
||||
if v := gm.Get(key); v == nil {
|
||||
return gm.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 (gm *StringInterfaceMap) GetOrSetFunc(key string, f func() interface{}) interface{} {
|
||||
if v := gm.Get(key); v == nil {
|
||||
return gm.doSetWithLockCheck(key, f())
|
||||
} else {
|
||||
return v
|
||||
}
|
||||
if v := gm.Get(key); v == nil {
|
||||
return gm.doSetWithLockCheck(key, f())
|
||||
} else {
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
// GetOrSetFuncLock returns the value by key,
|
||||
@ -163,21 +163,21 @@ func (gm *StringInterfaceMap) GetOrSetFunc(key string, f func() interface{}) int
|
||||
// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function <f>
|
||||
// with mutex.Lock of the hash map.
|
||||
func (gm *StringInterfaceMap) GetOrSetFuncLock(key string, f func() interface{}) interface{} {
|
||||
if v := gm.Get(key); v == nil {
|
||||
return gm.doSetWithLockCheck(key, f)
|
||||
} else {
|
||||
return v
|
||||
}
|
||||
if v := gm.Get(key); v == nil {
|
||||
return gm.doSetWithLockCheck(key, f)
|
||||
} else {
|
||||
return v
|
||||
}
|
||||
}
|
||||
|
||||
// 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 (gm *StringInterfaceMap) SetIfNotExist(key string, value interface{}) bool {
|
||||
if !gm.Contains(key) {
|
||||
gm.doSetWithLockCheck(key, value)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
if !gm.Contains(key) {
|
||||
gm.doSetWithLockCheck(key, value)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// SetIfNotExistFunc sets value with return value of callback function <f>, then return true.
|
||||
@ -205,11 +205,11 @@ func (gm *StringInterfaceMap) SetIfNotExistFuncLock(key string, f func() interfa
|
||||
|
||||
// BatchRemove batch deletes values of the map by keys.
|
||||
func (gm *StringInterfaceMap) BatchRemove(keys []string) {
|
||||
gm.mu.Lock()
|
||||
for _, key := range keys {
|
||||
delete(gm.m, key)
|
||||
}
|
||||
gm.mu.Unlock()
|
||||
gm.mu.Lock()
|
||||
for _, key := range keys {
|
||||
delete(gm.m, key)
|
||||
}
|
||||
gm.mu.Unlock()
|
||||
}
|
||||
|
||||
// Remove deletes value from map by given <key>, and return this deleted value.
|
||||
@ -230,7 +230,7 @@ func (gm *StringInterfaceMap) Keys() []string {
|
||||
for key, _ := range gm.m {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
gm.mu.RUnlock()
|
||||
gm.mu.RUnlock()
|
||||
return keys
|
||||
}
|
||||
|
||||
@ -273,9 +273,9 @@ func (gm *StringInterfaceMap) IsEmpty() bool {
|
||||
|
||||
// Clear deletes all data of the map, it will remake a new underlying map data map.
|
||||
func (gm *StringInterfaceMap) Clear() {
|
||||
gm.mu.Lock()
|
||||
gm.m = make(map[string]interface{})
|
||||
gm.mu.Unlock()
|
||||
gm.mu.Lock()
|
||||
gm.m = make(map[string]interface{})
|
||||
gm.mu.Unlock()
|
||||
}
|
||||
|
||||
// LockFunc locks writing with given callback function <f> and mutex.Lock.
|
||||
@ -315,4 +315,4 @@ func (gm *StringInterfaceMap) Merge(other *StringInterfaceMap) {
|
||||
for k, v := range other.m {
|
||||
gm.m[k] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
|
87
g/container/gmap/gmap_z_int_bool_test.go
Normal file
87
g/container/gmap/gmap_z_int_bool_test.go
Normal file
@ -0,0 +1,87 @@
|
||||
package gmap_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/container/gmap"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func getBool() bool {
|
||||
return true
|
||||
}
|
||||
func intBoolCallBack(int, bool) bool {
|
||||
return true
|
||||
}
|
||||
func Test_IntBoolMap_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
m := gmap.NewIntBoolMap()
|
||||
m.Set(1, true)
|
||||
|
||||
gtest.Assert(m.Get(1), true)
|
||||
gtest.Assert(m.Size(), 1)
|
||||
gtest.Assert(m.IsEmpty(), false)
|
||||
|
||||
gtest.Assert(m.GetOrSet(2, false), false)
|
||||
gtest.Assert(m.SetIfNotExist(2, false), false)
|
||||
|
||||
gtest.Assert(m.SetIfNotExist(3, false), true)
|
||||
|
||||
gtest.Assert(m.Remove(2), false)
|
||||
gtest.Assert(m.Contains(2), false)
|
||||
|
||||
gtest.AssertIN(3, m.Keys())
|
||||
gtest.AssertIN(1, m.Keys())
|
||||
|
||||
m.Clear()
|
||||
gtest.Assert(m.Size(), 0)
|
||||
gtest.Assert(m.IsEmpty(), true)
|
||||
|
||||
m2 := gmap.NewIntBoolMapFrom(map[int]bool{1: true, 2: false})
|
||||
gtest.Assert(m2.Map(), map[int]bool{1: true, 2: false})
|
||||
m3 := gmap.NewIntBoolMapFromArray([]int{1, 2}, []bool{true, false})
|
||||
gtest.Assert(m3.Map(), map[int]bool{1: true, 2: false})
|
||||
|
||||
})
|
||||
}
|
||||
func Test_IntBoolMap_Set_Fun(t *testing.T) {
|
||||
m := gmap.NewIntBoolMap()
|
||||
|
||||
m.GetOrSetFunc(1, getBool)
|
||||
m.GetOrSetFuncLock(2, getBool)
|
||||
gtest.Assert(m.Get(1), true)
|
||||
gtest.Assert(m.Get(2), true)
|
||||
gtest.Assert(m.SetIfNotExistFunc(1, getBool), false)
|
||||
gtest.Assert(m.SetIfNotExistFuncLock(2, getBool), false)
|
||||
}
|
||||
|
||||
func Test_IntBoolMap_Batch(t *testing.T) {
|
||||
m := gmap.NewIntBoolMap()
|
||||
|
||||
m.BatchSet(map[int]bool{1: true, 2: false, 3: true})
|
||||
m.Iterator(intBoolCallBack)
|
||||
gtest.Assert(m.Map(), map[int]bool{1: true, 2: false, 3: true})
|
||||
m.BatchRemove([]int{1, 2})
|
||||
gtest.Assert(m.Map(), map[int]bool{3: true})
|
||||
}
|
||||
|
||||
func Test_IntBoolMap_Clone(t *testing.T) {
|
||||
//clone 方法是深克隆
|
||||
m := gmap.NewIntBoolMapFrom(map[int]bool{1: true, 2: false})
|
||||
|
||||
m_clone := m.Clone()
|
||||
m.Remove(1)
|
||||
//修改原 map,clone 后的 map 不影响
|
||||
gtest.AssertIN(1, m_clone.Keys())
|
||||
|
||||
m_clone.Remove(2)
|
||||
//修改clone map,原 map 不影响
|
||||
gtest.AssertIN(2, m.Keys())
|
||||
}
|
||||
func Test_IntBoolMap_Merge(t *testing.T) {
|
||||
m1 := gmap.NewIntBoolMap()
|
||||
m2 := gmap.NewIntBoolMap()
|
||||
m1.Set(1, true)
|
||||
m2.Set(2, false)
|
||||
m1.Merge(m2)
|
||||
gtest.Assert(m1.Map(), map[int]bool{1: true, 2: false})
|
||||
}
|
91
g/container/gmap/gmap_z_int_int_test.go
Normal file
91
g/container/gmap/gmap_z_int_int_test.go
Normal file
@ -0,0 +1,91 @@
|
||||
package gmap_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/container/gmap"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func getInt() int {
|
||||
return 123
|
||||
}
|
||||
func intIntCallBack(int, int) bool {
|
||||
return true
|
||||
}
|
||||
func Test_IntIntMap_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
m := gmap.NewIntIntMap()
|
||||
m.Set(1, 1)
|
||||
|
||||
gtest.Assert(m.Get(1), 1)
|
||||
gtest.Assert(m.Size(), 1)
|
||||
gtest.Assert(m.IsEmpty(), false)
|
||||
|
||||
gtest.Assert(m.GetOrSet(2, 2), 2)
|
||||
gtest.Assert(m.SetIfNotExist(2, 2), false)
|
||||
|
||||
gtest.Assert(m.SetIfNotExist(3, 3), true)
|
||||
|
||||
gtest.Assert(m.Remove(2), 2)
|
||||
gtest.Assert(m.Contains(2), false)
|
||||
|
||||
gtest.AssertIN(3, m.Keys())
|
||||
gtest.AssertIN(1, m.Keys())
|
||||
gtest.AssertIN(3, m.Values())
|
||||
gtest.AssertIN(1, m.Values())
|
||||
m.Flip()
|
||||
gtest.Assert(m.Map(), map[int]int{1: 1, 3: 3})
|
||||
|
||||
m.Clear()
|
||||
gtest.Assert(m.Size(), 0)
|
||||
gtest.Assert(m.IsEmpty(), true)
|
||||
|
||||
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) {
|
||||
m := gmap.NewIntIntMap()
|
||||
|
||||
m.GetOrSetFunc(1, getInt)
|
||||
m.GetOrSetFuncLock(2, getInt)
|
||||
gtest.Assert(m.Get(1), 123)
|
||||
gtest.Assert(m.Get(2), 123)
|
||||
gtest.Assert(m.SetIfNotExistFunc(1, getInt), false)
|
||||
gtest.Assert(m.SetIfNotExistFuncLock(2, getInt), false)
|
||||
}
|
||||
|
||||
func Test_IntIntMap_Batch(t *testing.T) {
|
||||
m := gmap.NewIntIntMap()
|
||||
|
||||
m.BatchSet(map[int]int{1: 1, 2: 2, 3: 3})
|
||||
m.Iterator(intIntCallBack)
|
||||
gtest.Assert(m.Map(), map[int]int{1: 1, 2: 2, 3: 3})
|
||||
m.BatchRemove([]int{1, 2})
|
||||
gtest.Assert(m.Map(), map[int]int{3: 3})
|
||||
}
|
||||
|
||||
func Test_IntIntMap_Clone(t *testing.T) {
|
||||
//clone 方法是深克隆
|
||||
m := gmap.NewIntIntMapFrom(map[int]int{1: 1, 2: 2})
|
||||
|
||||
m_clone := m.Clone()
|
||||
m.Remove(1)
|
||||
//修改原 map,clone 后的 map 不影响
|
||||
gtest.AssertIN(1, m_clone.Keys())
|
||||
|
||||
m_clone.Remove(2)
|
||||
//修改clone map,原 map 不影响
|
||||
gtest.AssertIN(2, m.Keys())
|
||||
}
|
||||
func Test_IntIntMap_Merge(t *testing.T) {
|
||||
m1 := gmap.NewIntIntMap()
|
||||
m2 := gmap.NewIntIntMap()
|
||||
m1.Set(1, 1)
|
||||
m2.Set(2, 2)
|
||||
m1.Merge(m2)
|
||||
gtest.Assert(m1.Map(), map[int]int{1: 1, 2: 2})
|
||||
}
|
91
g/container/gmap/gmap_z_int_interface_test.go
Normal file
91
g/container/gmap/gmap_z_int_interface_test.go
Normal file
@ -0,0 +1,91 @@
|
||||
package gmap_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/container/gmap"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func getInterface() interface{} {
|
||||
return 123
|
||||
}
|
||||
func intInterfaceCallBack(int, interface{}) bool {
|
||||
return true
|
||||
}
|
||||
func Test_IntInterfaceMap_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
m := gmap.NewIntInterfaceMap()
|
||||
m.Set(1, 1)
|
||||
|
||||
gtest.Assert(m.Get(1), 1)
|
||||
gtest.Assert(m.Size(), 1)
|
||||
gtest.Assert(m.IsEmpty(), false)
|
||||
|
||||
gtest.Assert(m.GetOrSet(2, "2"), "2")
|
||||
gtest.Assert(m.SetIfNotExist(2, "2"), false)
|
||||
|
||||
gtest.Assert(m.SetIfNotExist(3, 3), true)
|
||||
|
||||
gtest.Assert(m.Remove(2), "2")
|
||||
gtest.Assert(m.Contains(2), false)
|
||||
|
||||
gtest.AssertIN(3, m.Keys())
|
||||
gtest.AssertIN(1, m.Keys())
|
||||
gtest.AssertIN(3, m.Values())
|
||||
gtest.AssertIN(1, m.Values())
|
||||
m.Flip()
|
||||
gtest.Assert(m.Map(), map[interface{}]int{1: 1, 3: 3})
|
||||
|
||||
m.Clear()
|
||||
gtest.Assert(m.Size(), 0)
|
||||
gtest.Assert(m.IsEmpty(), true)
|
||||
|
||||
m2 := gmap.NewIntInterfaceMapFrom(map[int]interface{}{1: 1, 2: "2"})
|
||||
gtest.Assert(m2.Map(), map[int]interface{}{1: 1, 2: "2"})
|
||||
m3 := gmap.NewIntInterfaceMapFromArray([]int{1, 2}, []interface{}{1, "2"})
|
||||
gtest.Assert(m3.Map(), map[int]interface{}{1: 1, 2: "2"})
|
||||
|
||||
})
|
||||
}
|
||||
func Test_IntInterfaceMap_Set_Fun(t *testing.T) {
|
||||
m := gmap.NewIntInterfaceMap()
|
||||
|
||||
m.GetOrSetFunc(1, getInterface)
|
||||
m.GetOrSetFuncLock(2, getInterface)
|
||||
gtest.Assert(m.Get(1), 123)
|
||||
gtest.Assert(m.Get(2), 123)
|
||||
gtest.Assert(m.SetIfNotExistFunc(1, getInterface), false)
|
||||
gtest.Assert(m.SetIfNotExistFuncLock(2, getInterface), false)
|
||||
}
|
||||
|
||||
func Test_IntInterfaceMap_Batch(t *testing.T) {
|
||||
m := gmap.NewIntInterfaceMap()
|
||||
|
||||
m.BatchSet(map[int]interface{}{1: 1, 2: "2", 3: 3})
|
||||
m.Iterator(intInterfaceCallBack)
|
||||
gtest.Assert(m.Map(), map[int]interface{}{1: 1, 2: "2", 3: 3})
|
||||
m.BatchRemove([]int{1, 2})
|
||||
gtest.Assert(m.Map(), map[int]interface{}{3: 3})
|
||||
}
|
||||
|
||||
func Test_IntInterfaceMap_Clone(t *testing.T) {
|
||||
//clone 方法是深克隆
|
||||
m := gmap.NewIntInterfaceMapFrom(map[int]interface{}{1: 1, 2: "2"})
|
||||
|
||||
m_clone := m.Clone()
|
||||
m.Remove(1)
|
||||
//修改原 map,clone 后的 map 不影响
|
||||
gtest.AssertIN(1, m_clone.Keys())
|
||||
|
||||
m_clone.Remove(2)
|
||||
//修改clone map,原 map 不影响
|
||||
gtest.AssertIN(2, m.Keys())
|
||||
}
|
||||
func Test_IntInterfaceMap_Merge(t *testing.T) {
|
||||
m1 := gmap.NewIntInterfaceMap()
|
||||
m2 := gmap.NewIntInterfaceMap()
|
||||
m1.Set(1, 1)
|
||||
m2.Set(2, "2")
|
||||
m1.Merge(m2)
|
||||
gtest.Assert(m1.Map(), map[int]interface{}{1: 1, 2: "2"})
|
||||
}
|
96
g/container/gmap/gmap_z_int_string_test.go
Normal file
96
g/container/gmap/gmap_z_int_string_test.go
Normal file
@ -0,0 +1,96 @@
|
||||
package gmap_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/container/gmap"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func getString() string {
|
||||
return "z"
|
||||
}
|
||||
func intStringCallBack(int, string) bool {
|
||||
return true
|
||||
}
|
||||
func Test_IntStringMap_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
m := gmap.NewIntStringMap()
|
||||
m.Set(1, "a")
|
||||
|
||||
gtest.Assert(m.Get(1), "a")
|
||||
gtest.Assert(m.Size(), 1)
|
||||
gtest.Assert(m.IsEmpty(), false)
|
||||
|
||||
gtest.Assert(m.GetOrSet(2, "b"), "b")
|
||||
gtest.Assert(m.SetIfNotExist(2, "b"), false)
|
||||
|
||||
gtest.Assert(m.SetIfNotExist(3, "c"), true)
|
||||
|
||||
gtest.Assert(m.Remove(2), "b")
|
||||
gtest.Assert(m.Contains(2), false)
|
||||
|
||||
gtest.AssertIN(3, m.Keys())
|
||||
gtest.AssertIN(1, m.Keys())
|
||||
gtest.AssertIN("a", m.Values())
|
||||
gtest.AssertIN("c", m.Values())
|
||||
|
||||
//反转之后不成为以下 map,flip 操作只是翻转原 map
|
||||
//gtest.Assert(m.Map(), map[string]int{"a": 1, "c": 3})
|
||||
m_f := gmap.NewIntStringMap()
|
||||
m_f.Set(1, "2")
|
||||
m_f.Flip()
|
||||
gtest.Assert(m_f.Map(), map[int]string{2: "1"})
|
||||
|
||||
m.Clear()
|
||||
gtest.Assert(m.Size(), 0)
|
||||
gtest.Assert(m.IsEmpty(), true)
|
||||
|
||||
m2 := gmap.NewIntStringMapFrom(map[int]string{1: "a", 2: "b"})
|
||||
gtest.Assert(m2.Map(), map[int]string{1: "a", 2: "b"})
|
||||
m3 := gmap.NewIntStringMapFromArray([]int{1, 2}, []string{"a", "b"})
|
||||
gtest.Assert(m3.Map(), map[int]string{1: "a", 2: "b"})
|
||||
|
||||
})
|
||||
}
|
||||
func Test_IntStringMap_Set_Fun(t *testing.T) {
|
||||
m := gmap.NewIntStringMap()
|
||||
|
||||
m.GetOrSetFunc(1, getString)
|
||||
m.GetOrSetFuncLock(2, getString)
|
||||
gtest.Assert(m.Get(1), "z")
|
||||
gtest.Assert(m.Get(2), "z")
|
||||
gtest.Assert(m.SetIfNotExistFunc(1, getString), false)
|
||||
gtest.Assert(m.SetIfNotExistFuncLock(2, getString), false)
|
||||
}
|
||||
|
||||
func Test_IntStringMap_Batch(t *testing.T) {
|
||||
m := gmap.NewIntStringMap()
|
||||
|
||||
m.BatchSet(map[int]string{1: "a", 2: "b", 3: "c"})
|
||||
m.Iterator(intStringCallBack)
|
||||
gtest.Assert(m.Map(), map[int]string{1: "a", 2: "b",3: "c"})
|
||||
m.BatchRemove([]int{1, 2})
|
||||
gtest.Assert(m.Map(), map[int]interface{}{3: "c"})
|
||||
}
|
||||
|
||||
func Test_IntStringMap_Clone(t *testing.T) {
|
||||
//clone 方法是深克隆
|
||||
m := gmap.NewIntStringMapFrom(map[int]string{1: "a", 2: "b", 3: "c"})
|
||||
|
||||
m_clone := m.Clone()
|
||||
m.Remove(1)
|
||||
//修改原 map,clone 后的 map 不影响
|
||||
gtest.AssertIN(1, m_clone.Keys())
|
||||
|
||||
m_clone.Remove(2)
|
||||
//修改clone map,原 map 不影响
|
||||
gtest.AssertIN(2, m.Keys())
|
||||
}
|
||||
func Test_IntStringMap_Merge(t *testing.T) {
|
||||
m1 := gmap.NewIntStringMap()
|
||||
m2 := gmap.NewIntStringMap()
|
||||
m1.Set(1, "a")
|
||||
m2.Set(2, "b")
|
||||
m1.Merge(m2)
|
||||
gtest.Assert(m1.Map(), map[int]string{1: "a", 2: "b"})
|
||||
}
|
91
g/container/gmap/gmap_z_interface_interface_basic_test.go
Normal file
91
g/container/gmap/gmap_z_interface_interface_basic_test.go
Normal file
@ -0,0 +1,91 @@
|
||||
package gmap_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/container/gmap"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
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() {
|
||||
m := gmap.New()
|
||||
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.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) {
|
||||
m := gmap.New()
|
||||
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_Map_Batch(t *testing.T) {
|
||||
m := gmap.New()
|
||||
m.BatchSet(map[interface{}]interface{}{1: 1, "key1": "val1", "key2": "val2", "key3": "val3"})
|
||||
m.Iterator(callBack)
|
||||
gtest.Assert(m.Map(), map[interface{}]interface{}{1: 1, "key1": "val1", "key2": "val2", "key3": "val3"})
|
||||
m.BatchRemove([]interface{}{"key1", 1})
|
||||
gtest.Assert(m.Map(), map[interface{}]interface{}{"key2": "val2", "key3": "val3"})
|
||||
}
|
||||
|
||||
func Test_Map_Clone(t *testing.T) {
|
||||
//clone 方法是深克隆
|
||||
m := gmap.NewFrom(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())
|
||||
}
|
||||
func Test_Map_Basic_Merge(t *testing.T) {
|
||||
m1 := gmap.New()
|
||||
m2 := gmap.New()
|
||||
m1.Set("key1", "val1")
|
||||
m2.Set("key2", "val2")
|
||||
m1.Merge(m2)
|
||||
gtest.Assert(m1.Map(), map[interface{}]interface{}{"key1": "val1", "key2": "val2"})
|
||||
}
|
71
g/container/gmap/gmap_z_normal_example_test.go
Normal file
71
g/container/gmap/gmap_z_normal_example_test.go
Normal file
@ -0,0 +1,71 @@
|
||||
package gmap_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/g/container/gmap"
|
||||
)
|
||||
|
||||
func Example_Normal_Basic() {
|
||||
m := gmap.New()
|
||||
|
||||
//Add data
|
||||
m.Set("key1", "val1")
|
||||
|
||||
//Print size
|
||||
fmt.Println(m.Size())
|
||||
//output 1
|
||||
|
||||
add_map := make(map[interface{}]interface{})
|
||||
add_map["key2"] = "val2"
|
||||
add_map["key3"] = "val3"
|
||||
add_map[1] = 1
|
||||
|
||||
fmt.Println(m.Values())
|
||||
|
||||
//Batch add data
|
||||
m.BatchSet(add_map)
|
||||
|
||||
//Gets the value of the corresponding key
|
||||
key3_val := m.Get("key3")
|
||||
fmt.Println(key3_val)
|
||||
|
||||
//Get the value by key, or set it with given key-value if not exist.
|
||||
get_or_set_val := m.GetOrSet("key4", "val4")
|
||||
fmt.Println(get_or_set_val)
|
||||
|
||||
// Set key-value if the key does not exist, then return true; or else return false.
|
||||
is_set := m.SetIfNotExist("key3", "val3")
|
||||
fmt.Println(is_set)
|
||||
|
||||
//Remove key
|
||||
m.Remove("key2")
|
||||
fmt.Println(m.Keys())
|
||||
|
||||
//Batch remove keys
|
||||
remove_keys := []interface{}{"key1", 1}
|
||||
m.BatchRemove(remove_keys)
|
||||
fmt.Println(m.Keys())
|
||||
|
||||
//Contains checks whether a key exists.
|
||||
is_contain := m.Contains("key3")
|
||||
fmt.Println(is_contain)
|
||||
|
||||
//Flip exchanges key-value of the map, it will change key-value to value-key.
|
||||
m.Flip()
|
||||
fmt.Println(m.Map())
|
||||
|
||||
// Clear deletes all data of the map,
|
||||
m.Clear()
|
||||
|
||||
fmt.Println(m.Size())
|
||||
|
||||
}
|
||||
func Example_Normal_Merge(){
|
||||
m1 := gmap.New()
|
||||
m2 := gmap.New()
|
||||
m1.Set("key1","val1")
|
||||
m2.Set("key2","val2")
|
||||
m1.Merge(m2)
|
||||
fmt.Println(m1.Map())
|
||||
}
|
||||
|
85
g/container/gmap/gmap_z_string_bool_test.go
Normal file
85
g/container/gmap/gmap_z_string_bool_test.go
Normal file
@ -0,0 +1,85 @@
|
||||
package gmap_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/container/gmap"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
||||
func StringBoolCallBack( string, bool) bool {
|
||||
return true
|
||||
}
|
||||
func Test_StringBoolMap_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
m := gmap.NewStringBoolMap()
|
||||
m.Set("a", true)
|
||||
|
||||
gtest.Assert(m.Get("a"), true)
|
||||
gtest.Assert(m.Size(), 1)
|
||||
gtest.Assert(m.IsEmpty(), false)
|
||||
|
||||
gtest.Assert(m.GetOrSet("b", false), false)
|
||||
gtest.Assert(m.SetIfNotExist("b", false), false)
|
||||
|
||||
gtest.Assert(m.SetIfNotExist("c", false), true)
|
||||
|
||||
gtest.Assert(m.Remove("b"), false)
|
||||
gtest.Assert(m.Contains("b"), false)
|
||||
|
||||
gtest.AssertIN("c", m.Keys())
|
||||
gtest.AssertIN("a", m.Keys())
|
||||
|
||||
m.Clear()
|
||||
gtest.Assert(m.Size(), 0)
|
||||
gtest.Assert(m.IsEmpty(), true)
|
||||
|
||||
m2 := gmap.NewStringBoolMapFrom(map[string]bool{"a": true, "b": false})
|
||||
gtest.Assert(m2.Map(), map[string]bool{"a": true, "b": false})
|
||||
m3 := gmap.NewStringBoolMapFromArray([]string{"a", "b"}, []bool{true, false})
|
||||
gtest.Assert(m3.Map(), map[string]bool{"a": true, "b": false})
|
||||
|
||||
})
|
||||
}
|
||||
func Test_StringBoolMap_Set_Fun(t *testing.T) {
|
||||
m := gmap.NewStringBoolMap()
|
||||
|
||||
m.GetOrSetFunc("a", getBool)
|
||||
m.GetOrSetFuncLock("b", getBool)
|
||||
gtest.Assert(m.Get("a"), true)
|
||||
gtest.Assert(m.Get("b"), true)
|
||||
gtest.Assert(m.SetIfNotExistFunc("a", getBool), false)
|
||||
gtest.Assert(m.SetIfNotExistFuncLock("b", getBool), false)
|
||||
}
|
||||
|
||||
func Test_StringBoolMap_Batch(t *testing.T) {
|
||||
m := gmap.NewStringBoolMap()
|
||||
|
||||
m.BatchSet(map[string]bool{"a": true, "b": false, "c": true})
|
||||
m.Iterator(StringBoolCallBack)
|
||||
gtest.Assert(m.Map(), map[string]bool{"a": true, "b": false, "c": true})
|
||||
m.BatchRemove([]string{"a", "b"})
|
||||
gtest.Assert(m.Map(), map[string]bool{"c": true})
|
||||
}
|
||||
|
||||
func Test_StringBoolMap_Clone(t *testing.T) {
|
||||
//clone 方法是深克隆
|
||||
m := gmap.NewStringBoolMapFrom(map[string]bool{"a": true, "b": false})
|
||||
|
||||
m_clone := m.Clone()
|
||||
m.Remove("a")
|
||||
//修改原 map,clone 后的 map 不影响
|
||||
gtest.AssertIN("a", m_clone.Keys())
|
||||
|
||||
m_clone.Remove("b")
|
||||
//修改clone map,原 map 不影响
|
||||
gtest.AssertIN("b", m.Keys())
|
||||
}
|
||||
func Test_StringBoolMap_Merge(t *testing.T) {
|
||||
m1 := gmap.NewStringBoolMap()
|
||||
m2 := gmap.NewStringBoolMap()
|
||||
m1.Set("a", true)
|
||||
m2.Set("b", false)
|
||||
m1.Merge(m2)
|
||||
gtest.Assert(m1.Map(), map[string]bool{"a": true, "b": false})
|
||||
}
|
91
g/container/gmap/gmap_z_string_int_test.go
Normal file
91
g/container/gmap/gmap_z_string_int_test.go
Normal file
@ -0,0 +1,91 @@
|
||||
package gmap_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/container/gmap"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func stringIntCallBack(string, int) bool {
|
||||
return true
|
||||
}
|
||||
func Test_StringIntMap_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
m := gmap.NewStringIntMap()
|
||||
m.Set("a", 1)
|
||||
|
||||
gtest.Assert(m.Get("a"), 1)
|
||||
gtest.Assert(m.Size(), 1)
|
||||
gtest.Assert(m.IsEmpty(), false)
|
||||
|
||||
gtest.Assert(m.GetOrSet("b", 2), 2)
|
||||
gtest.Assert(m.SetIfNotExist("b", 2), false)
|
||||
|
||||
gtest.Assert(m.SetIfNotExist("c", 3), true)
|
||||
|
||||
gtest.Assert(m.Remove("b"), 2)
|
||||
gtest.Assert(m.Contains("b"), false)
|
||||
|
||||
gtest.AssertIN("c", m.Keys())
|
||||
gtest.AssertIN("a", m.Keys())
|
||||
gtest.AssertIN(3, m.Values())
|
||||
gtest.AssertIN(1, m.Values())
|
||||
|
||||
m_f := gmap.NewStringIntMap()
|
||||
m_f.Set("1", 2)
|
||||
m_f.Flip()
|
||||
gtest.Assert(m_f.Map(), map[string]int{"2": 1})
|
||||
|
||||
m.Clear()
|
||||
gtest.Assert(m.Size(), 0)
|
||||
gtest.Assert(m.IsEmpty(), true)
|
||||
|
||||
m2 := gmap.NewStringIntMapFrom(map[string]int{"a": 1, "b": 2})
|
||||
gtest.Assert(m2.Map(), map[string]int{"a": 1, "b": 2})
|
||||
m3 := gmap.NewStringIntMapFromArray([]string{"a", "b"}, []int{1, 2})
|
||||
gtest.Assert(m3.Map(), map[string]int{"a": 1, "b": 2})
|
||||
|
||||
})
|
||||
}
|
||||
func Test_StringIntMap_Set_Fun(t *testing.T) {
|
||||
m := gmap.NewStringIntMap()
|
||||
|
||||
m.GetOrSetFunc("a", getInt)
|
||||
m.GetOrSetFuncLock("b", getInt)
|
||||
gtest.Assert(m.Get("a"), 123)
|
||||
gtest.Assert(m.Get("b"), 123)
|
||||
gtest.Assert(m.SetIfNotExistFunc("a", getInt), false)
|
||||
gtest.Assert(m.SetIfNotExistFuncLock("b", getInt), false)
|
||||
}
|
||||
|
||||
func Test_StringIntMap_Batch(t *testing.T) {
|
||||
m := gmap.NewStringIntMap()
|
||||
|
||||
m.BatchSet(map[string]int{"a": 1, "b": 2, "c": 3})
|
||||
m.Iterator(stringIntCallBack)
|
||||
gtest.Assert(m.Map(), map[string]int{"a": 1, "b": 2, "c": 3})
|
||||
m.BatchRemove([]string{"a", "b"})
|
||||
gtest.Assert(m.Map(), map[string]int{"c": 3})
|
||||
}
|
||||
|
||||
func Test_StringIntMap_Clone(t *testing.T) {
|
||||
//clone 方法是深克隆
|
||||
m := gmap.NewStringIntMapFrom(map[string]int{"a": 1, "b": 2, "c": 3})
|
||||
|
||||
m_clone := m.Clone()
|
||||
m.Remove("a")
|
||||
//修改原 map,clone 后的 map 不影响
|
||||
gtest.AssertIN("a", m_clone.Keys())
|
||||
|
||||
m_clone.Remove("b")
|
||||
//修改clone map,原 map 不影响
|
||||
gtest.AssertIN("b", m.Keys())
|
||||
}
|
||||
func Test_StringIntMap_Merge(t *testing.T) {
|
||||
m1 := gmap.NewStringIntMap()
|
||||
m2 := gmap.NewStringIntMap()
|
||||
m1.Set("a", 1)
|
||||
m2.Set("b", 2)
|
||||
m1.Merge(m2)
|
||||
gtest.Assert(m1.Map(), map[string]int{"a": 1, "b": 2})
|
||||
}
|
89
g/container/gmap/gmap_z_string_interface_test.go
Normal file
89
g/container/gmap/gmap_z_string_interface_test.go
Normal file
@ -0,0 +1,89 @@
|
||||
package gmap_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/container/gmap"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func stringInterfaceCallBack(string, interface{}) bool {
|
||||
return true
|
||||
}
|
||||
func Test_StringInterfaceMap_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
m := gmap.NewStringInterfaceMap()
|
||||
m.Set("a", 1)
|
||||
|
||||
gtest.Assert(m.Get("a"), 1)
|
||||
gtest.Assert(m.Size(), 1)
|
||||
gtest.Assert(m.IsEmpty(), false)
|
||||
|
||||
gtest.Assert(m.GetOrSet("b", "2"), "2")
|
||||
gtest.Assert(m.SetIfNotExist("b", "2"), false)
|
||||
|
||||
gtest.Assert(m.SetIfNotExist("c", 3), true)
|
||||
|
||||
gtest.Assert(m.Remove("b"), "2")
|
||||
gtest.Assert(m.Contains("b"), false)
|
||||
|
||||
gtest.AssertIN("c", m.Keys())
|
||||
gtest.AssertIN("a", m.Keys())
|
||||
gtest.AssertIN(3, m.Values())
|
||||
gtest.AssertIN(1, m.Values())
|
||||
|
||||
m.Flip()
|
||||
gtest.Assert(m.Map(), map[string]interface{}{"1": "a", "3": "c"})
|
||||
|
||||
m.Clear()
|
||||
gtest.Assert(m.Size(), 0)
|
||||
gtest.Assert(m.IsEmpty(), true)
|
||||
|
||||
m2 := gmap.NewStringInterfaceMapFrom(map[string]interface{}{"a": 1, "b": "2"})
|
||||
gtest.Assert(m2.Map(), map[string]interface{}{"a": 1, "b": "2"})
|
||||
m3 := gmap.NewStringInterfaceMapFromArray([]string{"a", "b"}, []interface{}{1, "2"})
|
||||
gtest.Assert(m3.Map(), map[string]interface{}{"a": 1, "b": "2"})
|
||||
|
||||
})
|
||||
}
|
||||
func Test_StringInterfaceMap_Set_Fun(t *testing.T) {
|
||||
m := gmap.NewStringInterfaceMap()
|
||||
|
||||
m.GetOrSetFunc("a", getInterface)
|
||||
m.GetOrSetFuncLock("b", getInterface)
|
||||
gtest.Assert(m.Get("a"), 123)
|
||||
gtest.Assert(m.Get("b"), 123)
|
||||
gtest.Assert(m.SetIfNotExistFunc("a", getInterface), false)
|
||||
gtest.Assert(m.SetIfNotExistFuncLock("b", getInterface), false)
|
||||
}
|
||||
|
||||
func Test_StringInterfaceMap_Batch(t *testing.T) {
|
||||
m := gmap.NewStringInterfaceMap()
|
||||
|
||||
m.BatchSet(map[string]interface{}{"a": 1, "b": "2", "c": 3})
|
||||
m.Iterator(stringInterfaceCallBack)
|
||||
gtest.Assert(m.Map(), map[string]interface{}{"a": 1, "b": "2", "c": 3})
|
||||
m.BatchRemove([]string{"a", "b"})
|
||||
gtest.Assert(m.Map(), map[string]interface{}{"c": 3})
|
||||
}
|
||||
|
||||
func Test_StringInterfaceMap_Clone(t *testing.T) {
|
||||
//clone 方法是深克隆
|
||||
m := gmap.NewStringInterfaceMapFrom(map[string]interface{}{"a": 1, "b": "2"})
|
||||
|
||||
m_clone := m.Clone()
|
||||
m.Remove("a")
|
||||
//修改原 map,clone 后的 map 不影响
|
||||
gtest.AssertIN("a", m_clone.Keys())
|
||||
|
||||
m_clone.Remove("b")
|
||||
//修改clone map,原 map 不影响
|
||||
gtest.AssertIN("b", m.Keys())
|
||||
}
|
||||
func Test_StringInterfaceMap_Merge(t *testing.T) {
|
||||
m1 := gmap.NewStringInterfaceMap()
|
||||
m2 := gmap.NewStringInterfaceMap()
|
||||
m1.Set("a", 1)
|
||||
m2.Set("b", "2")
|
||||
m1.Merge(m2)
|
||||
gtest.Assert(m1.Map(), map[string]interface{}{"a": 1, "b": "2"})
|
||||
}
|
90
g/container/gmap/gmap_z_string_string_test.go
Normal file
90
g/container/gmap/gmap_z_string_string_test.go
Normal file
@ -0,0 +1,90 @@
|
||||
package gmap_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/container/gmap"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func stringStringCallBack(string, string) bool {
|
||||
return true
|
||||
}
|
||||
func Test_StringStringMap_Basic(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
m := gmap.NewStringStringMap()
|
||||
m.Set("a", "a")
|
||||
|
||||
gtest.Assert(m.Get("a"), "a")
|
||||
gtest.Assert(m.Size(), 1)
|
||||
gtest.Assert(m.IsEmpty(), false)
|
||||
|
||||
gtest.Assert(m.GetOrSet("b", "b"), "b")
|
||||
gtest.Assert(m.SetIfNotExist("b", "b"), false)
|
||||
|
||||
gtest.Assert(m.SetIfNotExist("c", "c"), true)
|
||||
|
||||
gtest.Assert(m.Remove("b"), "b")
|
||||
gtest.Assert(m.Contains("b"), false)
|
||||
|
||||
gtest.AssertIN("c", m.Keys())
|
||||
gtest.AssertIN("a", m.Keys())
|
||||
gtest.AssertIN("a", m.Values())
|
||||
gtest.AssertIN("c", m.Values())
|
||||
|
||||
m.Flip()
|
||||
|
||||
gtest.Assert(m.Map(), map[string]string{"a": "a", "c": "c"})
|
||||
|
||||
m.Clear()
|
||||
gtest.Assert(m.Size(), 0)
|
||||
gtest.Assert(m.IsEmpty(), true)
|
||||
|
||||
m2 := gmap.NewStringStringMapFrom(map[string]string{"a": "a", "b": "b"})
|
||||
gtest.Assert(m2.Map(), map[string]string{"a": "a", "b": "b"})
|
||||
m3 := gmap.NewStringStringMapFromArray([]string{"a", "b"}, []string{"a", "b"})
|
||||
gtest.Assert(m3.Map(), map[string]string{"a": "a", "b": "b"})
|
||||
|
||||
})
|
||||
}
|
||||
func Test_StringStringMap_Set_Fun(t *testing.T) {
|
||||
m := gmap.NewStringStringMap()
|
||||
|
||||
m.GetOrSetFunc("a", getString)
|
||||
m.GetOrSetFuncLock("b", getString)
|
||||
gtest.Assert(m.Get("a"), "z")
|
||||
gtest.Assert(m.Get("b"), "z")
|
||||
gtest.Assert(m.SetIfNotExistFunc("a", getString), false)
|
||||
gtest.Assert(m.SetIfNotExistFuncLock("b", getString), false)
|
||||
}
|
||||
|
||||
func Test_StringStringMap_Batch(t *testing.T) {
|
||||
m := gmap.NewStringStringMap()
|
||||
|
||||
m.BatchSet(map[string]string{"a": "a", "b": "b", "c": "c"})
|
||||
m.Iterator(stringStringCallBack)
|
||||
gtest.Assert(m.Map(), map[string]string{"a": "a", "b": "b", "c": "c"})
|
||||
m.BatchRemove([]string{"a", "b"})
|
||||
gtest.Assert(m.Map(), map[string]string{"c": "c"})
|
||||
}
|
||||
|
||||
func Test_StringStringMap_Clone(t *testing.T) {
|
||||
//clone 方法是深克隆
|
||||
m := gmap.NewStringStringMapFrom(map[string]string{"a": "a", "b": "b", "c": "c"})
|
||||
|
||||
m_clone := m.Clone()
|
||||
m.Remove("a")
|
||||
//修改原 map,clone 后的 map 不影响
|
||||
gtest.AssertIN("a", m_clone.Keys())
|
||||
|
||||
m_clone.Remove("b")
|
||||
//修改clone map,原 map 不影响
|
||||
gtest.AssertIN("b", m.Keys())
|
||||
}
|
||||
func Test_StringStringMap_Merge(t *testing.T) {
|
||||
m1 := gmap.NewStringStringMap()
|
||||
m2 := gmap.NewStringStringMap()
|
||||
m1.Set("a", "a")
|
||||
m2.Set("b", "b")
|
||||
m1.Merge(m2)
|
||||
gtest.Assert(m1.Map(), map[string]string{"a": "a", "b": "b"})
|
||||
}
|
229
g/container/gring/gring_unit_test.go
Normal file
229
g/container/gring/gring_unit_test.go
Normal file
@ -0,0 +1,229 @@
|
||||
package gring_test
|
||||
|
||||
import (
|
||||
"container/ring"
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/container/gring"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"testing"
|
||||
)
|
||||
type Student struct {
|
||||
position int
|
||||
name string
|
||||
upgrade bool
|
||||
}
|
||||
|
||||
func TestRing_Val(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
//定义cap 为3的ring类型数据
|
||||
r := gring.New(3, true)
|
||||
//分别给3个元素初始化赋值
|
||||
r.Put(&Student{1,"jimmy", true})
|
||||
r.Put(&Student{2,"tom", true})
|
||||
r.Put(&Student{3,"alon", false})
|
||||
|
||||
//元素取值并判断和预设值是否相等
|
||||
gtest.Assert(r.Val().(*Student).name,"jimmy")
|
||||
//从当前位置往后移两个元素
|
||||
r.Move(2)
|
||||
gtest.Assert(r.Val().(*Student).name,"alon")
|
||||
//更新元素值
|
||||
//测试 value == nil
|
||||
r.Set(nil)
|
||||
gtest.Assert(r.Val(),nil)
|
||||
//测试value != nil
|
||||
r.Set(&Student{3, "jack", true})
|
||||
})
|
||||
}
|
||||
func TestRing_CapLen(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
r := gring.New(10)
|
||||
r.Put("goframe")
|
||||
//cap长度 10
|
||||
gtest.Assert(r.Cap(), 10)
|
||||
//已有数据项 1
|
||||
gtest.Assert(r.Len(), 1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRing_Position(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
r := gring.New(2)
|
||||
r.Put(1)
|
||||
r.Put(2)
|
||||
//往后移动1个元素
|
||||
r.Next()
|
||||
gtest.Assert(r.Val(),2)
|
||||
//往前移动1个元素
|
||||
r.Prev()
|
||||
gtest.Assert(r.Val(),1)
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestRing_Link(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
r := gring.New(3)
|
||||
r.Put(1)
|
||||
r.Put(2)
|
||||
r.Put(3)
|
||||
s := gring.New(2)
|
||||
s.Put("a")
|
||||
s.Put("b")
|
||||
|
||||
rs := r.Link(s)
|
||||
gtest.Assert(rs.Move(2).Val(), "b")
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestRing_Unlink(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
r := gring.New(5)
|
||||
for i := 0; i< 5; i++ {
|
||||
r.Put(i+1)
|
||||
}
|
||||
// 1 2 3 4
|
||||
// 删除当前位置往后的2个数据,返回被删除的数据
|
||||
// 重新计算s len
|
||||
s := r.Unlink(2) // 2 3
|
||||
gtest.Assert(s.Val(), 2)
|
||||
gtest.Assert(s.Len(), 1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestRing_Slice(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
ringLen := 5
|
||||
r := gring.New(ringLen)
|
||||
for i := 0; i< ringLen; i++ {
|
||||
r.Put(i+1)
|
||||
}
|
||||
r.Move(2) // 3
|
||||
array := r.SliceNext() // [3 4 5 1 2]
|
||||
gtest.Assert(array[0], 3)
|
||||
gtest.Assert(len(array), 5)
|
||||
|
||||
//判断array是否等于[3 4 5 1 2]
|
||||
ra := []int{3,4,5,1,2}
|
||||
gtest.Assert(ra, array)
|
||||
|
||||
//第3个元素设为nil
|
||||
r.Set(nil)
|
||||
array2 := r.SliceNext() //[4 5 1 2]
|
||||
//返回当前位置往后不为空的元素数组,长度为4
|
||||
gtest.Assert(array2, g.Slice{4,5,1,2})
|
||||
|
||||
array3 := r.SlicePrev() //[2 1 5 4]
|
||||
gtest.Assert(array3, g.Slice{2,1,5,4})
|
||||
|
||||
s := gring.New(ringLen)
|
||||
for i := 0; i< ringLen; i++ {
|
||||
s.Put(i+1)
|
||||
}
|
||||
array4 := s.SlicePrev() // []
|
||||
gtest.Assert(array4, g.Slice{1,5,4,3,2})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestRing_RLockIterator(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
ringLen := 5
|
||||
r := gring.New(ringLen)
|
||||
|
||||
//ring不存在有值元素
|
||||
r.RLockIteratorNext(func(v interface{}) bool {
|
||||
gtest.Assert(v, nil)
|
||||
return false
|
||||
})
|
||||
r.RLockIteratorNext(func(v interface{}) bool {
|
||||
gtest.Assert(v, nil)
|
||||
return true
|
||||
})
|
||||
|
||||
r.RLockIteratorPrev(func(v interface{}) bool {
|
||||
gtest.Assert(v, nil)
|
||||
return true
|
||||
})
|
||||
|
||||
for i := 0; i< ringLen; i++ {
|
||||
r.Put(i+1)
|
||||
}
|
||||
|
||||
//回调函数返回true,RLockIteratorNext遍历5次,期望值分别是1、2、3、4、5
|
||||
i := 0
|
||||
r.RLockIteratorNext(func(v interface{}) bool {
|
||||
gtest.Assert(v, i+1)
|
||||
i++;
|
||||
return true
|
||||
})
|
||||
|
||||
//RLockIteratorPrev遍历1次返回 false,退出遍历
|
||||
r.RLockIteratorPrev(func(v interface{}) bool {
|
||||
gtest.Assert(v, 1)
|
||||
return false
|
||||
})
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestRing_LockIterator(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
ringLen := 5
|
||||
r := gring.New(ringLen)
|
||||
|
||||
//不存在有值元素
|
||||
r.LockIteratorNext(func(item *ring.Ring) bool {
|
||||
gtest.Assert(item.Value, nil)
|
||||
return false
|
||||
})
|
||||
r.LockIteratorNext(func(item *ring.Ring) bool {
|
||||
gtest.Assert(item.Value, nil)
|
||||
return false
|
||||
})
|
||||
r.LockIteratorNext(func(item *ring.Ring) bool {
|
||||
gtest.Assert(item.Value, nil)
|
||||
return true
|
||||
})
|
||||
|
||||
r.LockIteratorPrev(func(item *ring.Ring) bool {
|
||||
gtest.Assert(item.Value, nil)
|
||||
return false
|
||||
})
|
||||
r.LockIteratorPrev(func(item *ring.Ring) bool {
|
||||
gtest.Assert(item.Value, nil)
|
||||
return true
|
||||
})
|
||||
|
||||
//ring初始化元素值
|
||||
for i := 0; i< ringLen; i++ {
|
||||
r.Put(i+1)
|
||||
}
|
||||
|
||||
//往后遍历组成数据 [1,2,3,4,5]
|
||||
array1 := g.Slice{1,2,3,4,5}
|
||||
ii := 0
|
||||
r.LockIteratorNext(func(item *ring.Ring) bool {
|
||||
//校验每一次遍历取值是否是期望值
|
||||
gtest.Assert(item.Value, array1[ii])
|
||||
ii++;
|
||||
return true
|
||||
})
|
||||
|
||||
//往后取3个元素组成数组
|
||||
//获得 [1,5,4]
|
||||
i := 0
|
||||
a := g.Slice{1,5,4}
|
||||
r.LockIteratorPrev(func(item *ring.Ring) bool {
|
||||
if i > 2 {
|
||||
return false
|
||||
}
|
||||
gtest.Assert(item.Value, a[i])
|
||||
i++;
|
||||
return true
|
||||
})
|
||||
|
||||
|
||||
})
|
||||
}
|
@ -139,9 +139,9 @@ func Test_GetMap(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
j, err := gjson.DecodeToJson(data)
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(j.GetMap("n"), g.Map{})
|
||||
gtest.Assert(j.GetMap("n"), nil)
|
||||
gtest.Assert(j.GetMap("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.GetMap("a"), g.Map{})
|
||||
gtest.Assert(j.GetMap("a"), nil)
|
||||
})
|
||||
}
|
||||
|
||||
@ -189,7 +189,7 @@ func Test_GetStrings(t *testing.T) {
|
||||
gtest.AssertEQ(j.GetStrings("n"), g.SliceStr{"123456789"})
|
||||
gtest.AssertEQ(j.GetStrings("m"), g.SliceStr{`{"k":"v"}`})
|
||||
gtest.AssertEQ(j.GetStrings("a"), g.SliceStr{"1", "2", "3"})
|
||||
gtest.AssertEQ(j.GetStrings("i"), g.SliceStr{})
|
||||
gtest.AssertEQ(j.GetStrings("i"), nil)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -107,9 +107,9 @@ func Test_GetMap(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
j := gparser.New(data)
|
||||
gtest.AssertNE(j, nil)
|
||||
gtest.Assert(j.GetMap("n"), g.Map{})
|
||||
gtest.Assert(j.GetMap("n"), nil)
|
||||
gtest.Assert(j.GetMap("m"), g.Map{"k" : "v"})
|
||||
gtest.Assert(j.GetMap("a"), g.Map{})
|
||||
gtest.Assert(j.GetMap("a"), nil)
|
||||
})
|
||||
}
|
||||
|
||||
@ -144,7 +144,7 @@ func Test_GetStrings(t *testing.T) {
|
||||
gtest.AssertEQ(j.GetStrings("n"), g.SliceStr{"123456789"})
|
||||
gtest.AssertEQ(j.GetStrings("m"), g.SliceStr{`{"k":"v"}`})
|
||||
gtest.AssertEQ(j.GetStrings("a"), g.SliceStr{"1", "2", "3"})
|
||||
gtest.AssertEQ(j.GetStrings("i"), g.SliceStr{})
|
||||
gtest.AssertEQ(j.GetStrings("i"), nil)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -7,12 +7,27 @@
|
||||
package cmdenv
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/container/gvar"
|
||||
"github.com/gogf/gf/g/os/gcmd"
|
||||
"github.com/gogf/gf/g/os/genv"
|
||||
"strings"
|
||||
"github.com/gogf/gf/g/container/gvar"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
// Console options.
|
||||
cmdOptions = make(map[string]string)
|
||||
)
|
||||
|
||||
func init() {
|
||||
reg := regexp.MustCompile(`\-\-{0,1}(.+?)=(.+)`)
|
||||
for i := 0; i < len(os.Args); i++ {
|
||||
result := reg.FindStringSubmatch(os.Args[i])
|
||||
if len(result) > 1 {
|
||||
cmdOptions[result[1]] = result[2]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 获取指定名称的命令行参数,当不存在时获取环境变量参数,皆不存在时,返回给定的默认值。
|
||||
// 规则:
|
||||
// 1、命令行参数以小写字母格式,使用: gf.包名.变量名 传递;
|
||||
@ -22,11 +37,11 @@ func Get(key string, def...interface{}) gvar.VarRead {
|
||||
if len(def) > 0 {
|
||||
value = def[0]
|
||||
}
|
||||
if v := gcmd.Option.Get(key); v != "" {
|
||||
if v, ok := cmdOptions[key]; ok {
|
||||
value = v
|
||||
} else {
|
||||
key = strings.ToUpper(strings.Replace(key, ".", "_", -1))
|
||||
if v := genv.Get(key); v != "" {
|
||||
if v := os.Getenv(key); v != "" {
|
||||
value = v
|
||||
}
|
||||
}
|
||||
|
@ -26,13 +26,13 @@ type GroupItem = []interface{}
|
||||
|
||||
// 获取分组路由对象
|
||||
func (s *Server) Group(prefix...string) *RouterGroup {
|
||||
group := &RouterGroup{
|
||||
server : s,
|
||||
}
|
||||
if len(prefix) > 0 {
|
||||
return &RouterGroup{
|
||||
server : s,
|
||||
prefix : prefix[0],
|
||||
}
|
||||
group.prefix = prefix[0]
|
||||
}
|
||||
return &RouterGroup{}
|
||||
return group
|
||||
}
|
||||
|
||||
// 获取分组路由对象
|
||||
|
@ -6,33 +6,28 @@
|
||||
//
|
||||
|
||||
// Package gcmd provides console operations, like options/values reading and command running.
|
||||
//
|
||||
// 命令行管理.
|
||||
package gcmd
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/os/glog"
|
||||
"os"
|
||||
"errors"
|
||||
"regexp"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
// 命令行参数列表
|
||||
// Console values.
|
||||
type gCmdValue struct {
|
||||
values []string
|
||||
}
|
||||
|
||||
// 命令行选项列表
|
||||
// Console options.
|
||||
type gCmdOption struct {
|
||||
options map[string]string
|
||||
}
|
||||
|
||||
// 终端管理对象(全局)
|
||||
var Value = &gCmdValue{} // 终端参数-命令参数列表
|
||||
var Option = &gCmdOption{} // 终端参数-选项参数列表
|
||||
var cmdFuncMap = make(map[string]func()) // 终端命令及函数地址对应表
|
||||
var Value = &gCmdValue{} // Console values.
|
||||
var Option = &gCmdOption{} // Console options.
|
||||
var cmdFuncMap = make(map[string]func()) // Registered callback functions.
|
||||
|
||||
// 检查并初始化console参数,在包加载的时候触发
|
||||
// 初始化时执行,不影响运行时性能
|
||||
func init() {
|
||||
reg := regexp.MustCompile(`\-\-{0,1}(.+?)=(.+)`)
|
||||
Option.options = make(map[string]string)
|
||||
@ -46,67 +41,34 @@ func init() {
|
||||
}
|
||||
}
|
||||
|
||||
// 返回所有的命令行参数values
|
||||
func (c *gCmdValue) GetAll() []string {
|
||||
return c.values
|
||||
}
|
||||
|
||||
// 返回所有的命令行参数options
|
||||
func (c *gCmdOption) GetAll() map[string]string {
|
||||
return c.options
|
||||
}
|
||||
|
||||
// 获得一条指定索引位置的value参数
|
||||
func (c *gCmdValue) Get(index uint8, def...string) string {
|
||||
if index < uint8(len(c.values)) {
|
||||
return c.values[index]
|
||||
} else if len(def) > 0 {
|
||||
return def[0]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// 获得一条指定索引位置的option参数;
|
||||
func (c *gCmdOption) Get(key string, def...string) string {
|
||||
if option, ok := c.options[key]; ok {
|
||||
return option
|
||||
} else if len(def) > 0 {
|
||||
return def[0]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// 绑定命令行参数及对应的命令函数,注意命令函数参数是函数的内存地址
|
||||
// 如果操作失败返回错误信息
|
||||
func BindHandle (cmd string, f func()) error {
|
||||
// BindHandle registers callback function <f> with <cmd>.
|
||||
func BindHandle (cmd string, f func()) {
|
||||
if _, ok := cmdFuncMap[cmd]; ok {
|
||||
return errors.New("duplicated handle for command:" + cmd)
|
||||
glog.Fatal("duplicated handle for command:" + cmd)
|
||||
} else {
|
||||
cmdFuncMap[cmd] = f
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// 执行命令对应的函数
|
||||
func RunHandle (cmd string) error {
|
||||
// RunHandle executes the callback function registered by <cmd>.
|
||||
func RunHandle (cmd string) {
|
||||
if handle, ok := cmdFuncMap[cmd]; ok {
|
||||
handle()
|
||||
return nil
|
||||
} else {
|
||||
return errors.New("no handle found for command:" + cmd)
|
||||
glog.Fatal("no handle found for command:" + cmd)
|
||||
}
|
||||
}
|
||||
|
||||
// 自动识别命令参数并执行命令参数对应的函数
|
||||
func AutoRun () error {
|
||||
// AutoRun automatically recognizes and executes the callback function
|
||||
// by value of index 0 (the first console parameter).
|
||||
func AutoRun () {
|
||||
if cmd := Value.Get(1); cmd != "" {
|
||||
if handle, ok := cmdFuncMap[cmd]; ok {
|
||||
handle()
|
||||
return nil
|
||||
} else {
|
||||
return errors.New("no handle found for command:" + cmd)
|
||||
glog.Fatal("no handle found for command:" + cmd)
|
||||
}
|
||||
} else {
|
||||
return errors.New("no command found")
|
||||
glog.Fatal("no command found")
|
||||
}
|
||||
}
|
||||
|
32
g/os/gcmd/gcmd_option.go
Normal file
32
g/os/gcmd/gcmd_option.go
Normal file
@ -0,0 +1,32 @@
|
||||
// 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 this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
//
|
||||
|
||||
package gcmd
|
||||
|
||||
import "github.com/gogf/gf/g/container/gvar"
|
||||
|
||||
// GetAll returns all option values as map[string]string.
|
||||
func (c *gCmdOption) GetAll() map[string]string {
|
||||
return c.options
|
||||
}
|
||||
|
||||
// Get returns the option value string specified by <key>,
|
||||
// if value dose not exist, then returns <def>.
|
||||
func (c *gCmdOption) Get(key string, def...string) string {
|
||||
if option, ok := c.options[key]; ok {
|
||||
return option
|
||||
} else if len(def) > 0 {
|
||||
return def[0]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetVar returns the option value as gvar.VarRead object specified by <key>,
|
||||
// if value does not exist, then returns <def> as its default value.
|
||||
func (c *gCmdOption) GetVar(key string, def...string) gvar.VarRead {
|
||||
return gvar.NewRead(c.Get(key, def...), true)
|
||||
}
|
32
g/os/gcmd/gcmd_value.go
Normal file
32
g/os/gcmd/gcmd_value.go
Normal file
@ -0,0 +1,32 @@
|
||||
// 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 this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
//
|
||||
|
||||
package gcmd
|
||||
|
||||
import "github.com/gogf/gf/g/container/gvar"
|
||||
|
||||
// GetAll returns all values as a slice of string.
|
||||
func (c *gCmdValue) GetAll() []string {
|
||||
return c.values
|
||||
}
|
||||
|
||||
// Get returns value by index <index> as string,
|
||||
// if value does not exist, then returns <def>.
|
||||
func (c *gCmdValue) Get(index int, def...string) string {
|
||||
if index < len(c.values) {
|
||||
return c.values[index]
|
||||
} else if len(def) > 0 {
|
||||
return def[0]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// GetVar returns value by index <index> as gvar.VarRead object,
|
||||
// if value does not exist, then returns <def> as its default value.
|
||||
func (c *gCmdValue) GetVar(index int, def...string) gvar.VarRead {
|
||||
return gvar.NewRead(c.Get(index, def...), true)
|
||||
}
|
@ -32,12 +32,9 @@ func Case(t *testing.T, f func()) {
|
||||
|
||||
// Assert checks <value> and <expect> EQUAL.
|
||||
func Assert(value, expect interface{}) {
|
||||
rvValue := reflect.ValueOf(value)
|
||||
rvExpect := reflect.ValueOf(expect)
|
||||
if rvValue.Kind() == reflect.Ptr {
|
||||
if rvValue.IsNil() {
|
||||
value = nil
|
||||
}
|
||||
if isNil(value) {
|
||||
value = nil
|
||||
}
|
||||
if rvExpect.Kind() == reflect.Map {
|
||||
if err := compareMap(value, expect); err != nil {
|
||||
@ -53,13 +50,10 @@ func Assert(value, expect interface{}) {
|
||||
// AssertEQ checks <value> and <expect> EQUAL, including their TYPES.
|
||||
func AssertEQ(value, expect interface{}) {
|
||||
// Value assert.
|
||||
rvValue := reflect.ValueOf(value)
|
||||
rvExpect := reflect.ValueOf(expect)
|
||||
if rvValue.Kind() == reflect.Ptr {
|
||||
if rvValue.IsNil() {
|
||||
value = nil
|
||||
}
|
||||
}
|
||||
if isNil(value) {
|
||||
value = nil
|
||||
}
|
||||
if rvExpect.Kind() == reflect.Map {
|
||||
if err := compareMap(value, expect); err != nil {
|
||||
panic(err)
|
||||
@ -79,13 +73,10 @@ func AssertEQ(value, expect interface{}) {
|
||||
|
||||
// AssertNE checks <value> and <expect> NOT EQUAL.
|
||||
func AssertNE(value, expect interface{}) {
|
||||
rvValue := reflect.ValueOf(value)
|
||||
rvExpect := reflect.ValueOf(expect)
|
||||
if rvValue.Kind() == reflect.Ptr {
|
||||
if rvValue.IsNil() {
|
||||
value = nil
|
||||
}
|
||||
}
|
||||
if isNil(value) {
|
||||
value = nil
|
||||
}
|
||||
if rvExpect.Kind() == reflect.Map {
|
||||
if err := compareMap(value, expect); err == nil {
|
||||
panic(fmt.Sprintf(`[ASSERT] EXPECT %v != %v`, value, expect))
|
||||
@ -259,11 +250,9 @@ func Fatal(message...interface{}) {
|
||||
func compareMap(value, expect interface{}) error {
|
||||
rvValue := reflect.ValueOf(value)
|
||||
rvExpect := reflect.ValueOf(expect)
|
||||
if rvValue.Kind() == reflect.Ptr {
|
||||
if rvValue.IsNil() {
|
||||
value = nil
|
||||
}
|
||||
}
|
||||
if isNil(value) {
|
||||
value = nil
|
||||
}
|
||||
if rvExpect.Kind() == reflect.Map {
|
||||
if rvValue.Kind() == reflect.Map {
|
||||
if rvExpect.Len() == rvValue.Len() {
|
||||
@ -336,4 +325,15 @@ func getBacktrace(skip...int) string {
|
||||
}
|
||||
}
|
||||
return backtrace
|
||||
}
|
||||
|
||||
// isNil checks whether <value> is nil.
|
||||
func isNil(value interface{}) bool {
|
||||
rv := reflect.ValueOf(value)
|
||||
switch rv.Kind() {
|
||||
case reflect.Slice, reflect.Array, reflect.Map, reflect.Ptr, reflect.Func:
|
||||
return rv.IsNil()
|
||||
default:
|
||||
return value == nil
|
||||
}
|
||||
}
|
@ -594,4 +594,21 @@ func QuoteMeta(str string) string {
|
||||
buf.WriteRune(char)
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// SearchArray searches string <s> in string slice <a> case-sensitively,
|
||||
// returns its index in <a>.
|
||||
// If <s> is not found in <a>, it returns -1.
|
||||
func SearchArray (a []string, s string) int {
|
||||
for i, v := range a {
|
||||
if s == v {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// InArray checks whether string <s> in slice <a>.
|
||||
func InArray (a []string, s string) bool {
|
||||
return SearchArray(a, s) != -1
|
||||
}
|
@ -383,3 +383,22 @@ func Test_ContainsAny(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func Test_SearchArray(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a := g.SliceStr{"a", "b", "c"}
|
||||
gtest.AssertEQ(gstr.SearchArray(a, "a"), 0)
|
||||
gtest.AssertEQ(gstr.SearchArray(a, "b"), 1)
|
||||
gtest.AssertEQ(gstr.SearchArray(a, "c"), 2)
|
||||
gtest.AssertEQ(gstr.SearchArray(a, "d"), -1)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_InArray(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
a := g.SliceStr{"a", "b", "c"}
|
||||
gtest.AssertEQ(gstr.InArray(a, "a"), true)
|
||||
gtest.AssertEQ(gstr.InArray(a, "b"), true)
|
||||
gtest.AssertEQ(gstr.InArray(a, "c"), true)
|
||||
gtest.AssertEQ(gstr.InArray(a, "d"), false)
|
||||
})
|
||||
}
|
||||
|
@ -7,8 +7,9 @@
|
||||
package grand
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"os"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -27,6 +28,7 @@ func init() {
|
||||
for {
|
||||
if n, err := rand.Read(buffer); err != nil {
|
||||
panic(err)
|
||||
os.Exit(1)
|
||||
} else {
|
||||
// 使用缓冲区数据进行一次完整的随机数生成
|
||||
for i := 0; i < n - 4; {
|
||||
@ -34,10 +36,18 @@ func init() {
|
||||
i ++
|
||||
}
|
||||
// 充分利用缓冲区数据,随机索引递增
|
||||
step = int(buffer[0])%10
|
||||
for i := 0; i < n; i++ {
|
||||
step = int(buffer[0])%10
|
||||
if step != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if step == 0 {
|
||||
step = 2
|
||||
}
|
||||
for i := 0; i < n - 4; {
|
||||
bufferChan <- binary.BigEndian.Uint32(buffer[i : i + 4])
|
||||
i += step
|
||||
bufferChan <- binary.BigEndian.Uint32(buffer[i : i + 4])
|
||||
i += step
|
||||
}
|
||||
}
|
||||
}
|
||||
|
17
geg/os/gtimer/gtimer-batch.go
Normal file
17
geg/os/gtimer/gtimer-batch.go
Normal file
@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/g/os/gtimer"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
for i := 0; i < 100000; i++ {
|
||||
gtimer.Add(time.Second, func() {
|
||||
|
||||
})
|
||||
}
|
||||
fmt.Println("start")
|
||||
time.Sleep(48*time.Hour)
|
||||
}
|
@ -2,9 +2,14 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/g/os/gtime"
|
||||
"github.com/gogf/gf/g/util/grand"
|
||||
)
|
||||
|
||||
|
||||
|
||||
func main() {
|
||||
fmt.Println(gtime.Now().Format(`Y-m-j G:i:su`))
|
||||
for {
|
||||
fmt.Println(grand.Intn(100))
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package gf
|
||||
|
||||
const VERSION = "v1.6.0"
|
||||
const VERSION = "v1.6.2"
|
||||
const AUTHORS = "john<john@goframe.org>"
|
||||
|
Loading…
Reference in New Issue
Block a user