Compare commits

..

26 Commits

Author SHA1 Message Date
66306464e1 add Pop/Pops functions for gset 2019-04-26 08:57:48 +08:00
dd34ac1722 add build-in function 'eq/ne/lt/le/gt/ge' for gview to replace the same functions in stdlib 2019-04-25 23:23:24 +08:00
34cb222b33 remove temprary function map parameter for gview when parsing template file and content 2019-04-25 22:14:20 +08:00
d39ef156de garray updates 2019-04-24 22:23:32 +08:00
f464dc7fb8 add NewFrom/NewIntSetFrom/NewStringSetFrom functions for gset; add more example for gset 2019-04-24 18:52:24 +08:00
d29b27a5df add Merge/Sum functions for gset 2019-04-24 18:15:50 +08:00
aadc6aa504 Merge pull request #114 from proptypes/master
fix: #112
2019-04-24 14:07:37 +08:00
e8c3dfa13e fix: #112
closes #112
2019-04-24 11:31:13 +08:00
9eea93cc6e change param type from string to interface{} for ghttp.ClientRequest 2019-04-23 20:12:44 +08:00
308cb55b6b version updates 2019-04-23 19:44:28 +08:00
75ada78f8f remove parameter bind from ghttp.RouterGroup.Bind 2019-04-23 19:39:35 +08:00
ecd86e3a12 add layout example for package gview 2019-04-23 19:11:38 +08:00
c1aa5eb717 Merge pull request #98 from qq976739120/gmap-test
新增测试方法
2019-04-23 18:56:58 +08:00
d2fed1198b Merge pull request #110 from jroam/master
增加gtime包下,format方法能直接格式化星期的数字型的值
2019-04-23 18:54:43 +08:00
a9f9261dbd add gregex.ReplaceFuncMatch/ReplaceStringFuncMatch functions for package gregex 2019-04-23 14:15:12 +08:00
161e0d6e97 edit var name to "weekMap" 2019-04-23 09:59:13 +08:00
3efe511f42 优化星期英文值和数字值的格式化功能 2019-04-22 23:13:35 +08:00
e6fb41504c 简写"w"参数的注释,增加周六值测试 2019-04-22 14:10:46 +08:00
a800f731dd 优化格式化星期值性能 2019-04-22 13:55:53 +08:00
f1a9fbb74e Merge branch 'master' of https://github.com/jroam/gf 2019-04-22 10:51:40 +08:00
cf81a73526 增加gtime包下,format能直接格式化星期的数字型的值 2019-04-22 10:51:24 +08:00
65036fffe8 Merge pull request #13 from gogf/master
日常更新
2019-04-22 10:49:28 +08:00
a69934a7e3 添加星期值的int形式 2019-04-21 19:36:06 +08:00
90e6f685b7 Merge pull request #12 from gogf/master
日常更新
2019-04-18 17:55:19 +08:00
Jay
16a4a5ba46 Gmap测试修改 2019-04-16 14:28:25 +08:00
Jay
b489eed4ef 新增测试方法 2019-04-12 10:59:05 +08:00
68 changed files with 1790 additions and 1398 deletions

View File

@ -8,7 +8,8 @@ package garray
import (
"bytes"
"github.com/gogf/gf/g/internal/rwmutex"
"fmt"
"github.com/gogf/gf/g/internal/rwmutex"
"github.com/gogf/gf/g/util/gconv"
"github.com/gogf/gf/g/util/grand"
"math"
@ -16,24 +17,20 @@ import (
)
type IntArray struct {
mu *rwmutex.RWMutex // 互斥锁
array []int // 底层数组
mu *rwmutex.RWMutex
array []int
}
// Create an empty array.
// The param <unsafe> used to specify whether using array with un-concurrent-safety,
// which is false in default, means concurrent-safe in default.
//
// 创建一个空的数组对象参数unsafe用于指定是否用于非并发安全场景默认为false表示并发安全。
// NewIntArray creates and returns an empty array.
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
// which is false in default.
func NewIntArray(unsafe...bool) *IntArray {
return NewIntArraySize(0, 0, unsafe...)
}
// Create an array with given size and cap.
// NewIntArraySize create and returns an array with given size and cap.
// The param <unsafe> used to specify whether using array with un-concurrent-safety,
// which is false in default, means concurrent-safe in default.
//
// 创建一个指定大小的数组对象参数unsafe用于指定是否用于非并发安全场景默认为false表示并发安全。
// which is false in default.
func NewIntArraySize(size int, cap int, unsafe...bool) *IntArray {
return &IntArray{
mu : rwmutex.New(unsafe...),
@ -41,11 +38,9 @@ func NewIntArraySize(size int, cap int, unsafe...bool) *IntArray {
}
}
// Create an array with given slice <array>.
// NewIntArrayFrom creates and returns an array with given slice <array>.
// The param <unsafe> used to specify whether using array with un-concurrent-safety,
// which is false in default, means concurrent-safe in default.
//
// 通过给定的slice变量创建数组对象参数unsafe用于指定是否用于非并发安全场景默认为false表示并发安全。
// which is false in default.
func NewIntArrayFrom(array []int, unsafe...bool) *IntArray {
return &IntArray{
mu : rwmutex.New(unsafe...),
@ -53,11 +48,9 @@ func NewIntArrayFrom(array []int, unsafe...bool) *IntArray {
}
}
// Create an array from a copy of given slice <array>.
// NewIntArrayFromCopy creates and returns an array from a copy of given slice <array>.
// The param <unsafe> used to specify whether using array with un-concurrent-safety,
// which is false in default, means concurrent-safe in default.
//
// 通过给定的slice拷贝创建数组对象参数unsafe用于指定是否用于非并发安全场景默认为false表示并发安全。
// which is false in default.
func NewIntArrayFromCopy(array []int, unsafe...bool) *IntArray {
newArray := make([]int, len(array))
copy(newArray, array)
@ -67,9 +60,8 @@ func NewIntArrayFromCopy(array []int, unsafe...bool) *IntArray {
}
}
// Get value by index.
//
// 获取指定索引的数据项, 调用方注意判断数组边界。
// Get returns the value of the specified index,
// the caller should notice the boundary of the array.
func (a *IntArray) Get(index int) int {
a.mu.RLock()
defer a.mu.RUnlock()
@ -77,9 +69,7 @@ func (a *IntArray) Get(index int) int {
return value
}
// Set value by index.
//
// 设置指定索引的数据项, 调用方注意判断数组边界。
// Set sets value to specified index.
func (a *IntArray) Set(index int, value int) *IntArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -87,9 +77,7 @@ func (a *IntArray) Set(index int, value int) *IntArray {
return a
}
// Set the underlying slice array with the given <array> param.
//
// 设置底层数组变量.
// SetArray sets the underlying slice array with the given <array>.
func (a *IntArray) SetArray(array []int) *IntArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -97,9 +85,7 @@ func (a *IntArray) SetArray(array []int) *IntArray {
return a
}
// Replace the array items by given <array> from the beginning of array.
//
// 使用指定数组替换到对应的索引元素值.
// Replace replaces the array items by given <array> from the beginning of array.
func (a *IntArray) Replace(array []int) *IntArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -113,9 +99,7 @@ func (a *IntArray) Replace(array []int) *IntArray {
return a
}
// Calculate the sum of values in an array.
//
// 对数组中的元素项求和。
// Sum returns the sum of values in an array.
func (a *IntArray) Sum() (sum int) {
a.mu.RLock()
defer a.mu.RUnlock()
@ -125,11 +109,9 @@ func (a *IntArray) Sum() (sum int) {
return
}
// Sort the array in increasing order.
// Sort sorts the array in increasing order.
// The param <reverse> controls whether sort
// in increasing order(default) or decreasing order
//
// 将数组排序(默认从低到高).
func (a *IntArray) Sort(reverse...bool) *IntArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -146,9 +128,7 @@ func (a *IntArray) Sort(reverse...bool) *IntArray {
return a
}
// Sort the array by custom function <less>.
//
// 使用自定义的排序函数将数组重新排序.
// SortFunc sorts the array by custom function <less>.
func (a *IntArray) SortFunc(less func(v1, v2 int) bool) *IntArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -158,9 +138,7 @@ func (a *IntArray) SortFunc(less func(v1, v2 int) bool) *IntArray {
return a
}
// Insert the <value> to the front of <index>.
//
// 在当前索引位置前插入一个数据项, 调用方注意判断数组边界。
// InsertBefore inserts the <value> to the front of <index>.
func (a *IntArray) InsertBefore(index int, value int) *IntArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -170,9 +148,7 @@ func (a *IntArray) InsertBefore(index int, value int) *IntArray {
return a
}
// Insert the <value> to the back of <index>.
//
// 在当前索引位置前插入一个数据项, 调用方注意判断数组边界。
// InsertAfter inserts the <value> to the back of <index>.
func (a *IntArray) InsertAfter(index int, value int) *IntArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -182,13 +158,11 @@ func (a *IntArray) InsertAfter(index int, value int) *IntArray {
return a
}
// Remove an item by index.
//
// 删除指定索引的数据项, 调用方注意判断数组边界。
// Remove removes an item by index.
func (a *IntArray) Remove(index int) int {
a.mu.Lock()
defer a.mu.Unlock()
// 边界删除判断,以提高删除效率
// Determine array boundaries when deleting to improve deletion efficiency.
if index == 0 {
value := a.array[0]
a.array = a.array[1 : ]
@ -198,15 +172,15 @@ func (a *IntArray) Remove(index int) int {
a.array = a.array[: index]
return value
}
// 如果非边界删除,会涉及到数组创建,那么删除的效率差一些
// If it is a non-boundary delete,
// it will involve the creation of an array,
// then the deletion is less efficient.
value := a.array[index]
a.array = append(a.array[ : index], a.array[index + 1 : ]...)
return value
}
// Push new items to the beginning of array.
//
// 将数据项添加到数组的最左端(索引为0)。
// PushLeft pushes one or multiple items to the beginning of array.
func (a *IntArray) PushLeft(value...int) *IntArray {
a.mu.Lock()
a.array = append(value, a.array...)
@ -214,9 +188,8 @@ func (a *IntArray) PushLeft(value...int) *IntArray {
return a
}
// Push new items to the end of array.
//
// 将数据项添加到数组的最右端(索引为length - 1), 等于: Append。
// PushRight pushes one or multiple items to the end of array.
// It equals to Append.
func (a *IntArray) PushRight(value...int) *IntArray {
a.mu.Lock()
a.array = append(a.array, value...)
@ -224,9 +197,7 @@ func (a *IntArray) PushRight(value...int) *IntArray {
return a
}
// Pop an item from the beginning of array.
//
// 将最左端(索引为0)的数据项移出数组,并返回该数据项。
// PopLeft pops and returns an item from the beginning of array.
func (a *IntArray) PopLeft() int {
a.mu.Lock()
defer a.mu.Unlock()
@ -235,9 +206,7 @@ func (a *IntArray) PopLeft() int {
return value
}
// Pop an item from the end of array.
//
// 将最右端(索引为length - 1)的数据项移出数组,并返回该数据项。
// PopRight pops and returns an item from the end of array.
func (a *IntArray) PopRight() int {
a.mu.Lock()
defer a.mu.Unlock()
@ -247,16 +216,12 @@ func (a *IntArray) PopRight() int {
return value
}
// PopRand picks an random item out of array.
//
// 随机将一个数据项移出数组,并返回该数据项。
// PopRand randomly pops and return an item out of array.
func (a *IntArray) PopRand() int {
return a.Remove(grand.Intn(len(a.array)))
}
// PopRands picks <size> items out of array.
//
// 随机将size个数据项移出数组并返回该数据项。
// PopRands randomly pops and returns <size> items out of array.
func (a *IntArray) PopRands(size int) []int {
a.mu.Lock()
defer a.mu.Unlock()
@ -272,9 +237,7 @@ func (a *IntArray) PopRands(size int) []int {
return array
}
// Pop <size> items from the beginning of array.
//
// 将最左端(首部)的size个数据项移出数组并返回该数据项。
// PopLefts pops and returns <size> items from the beginning of array.
func (a *IntArray) PopLefts(size int) []int {
a.mu.Lock()
defer a.mu.Unlock()
@ -287,9 +250,7 @@ func (a *IntArray) PopLefts(size int) []int {
return value
}
// Pop <size> items from the end of array.
//
// 将最右端(尾部)的size个数据项移出数组并返回该数据项
// PopRights pops and returns <size> items from the end of array.
func (a *IntArray) PopRights(size int) []int {
a.mu.Lock()
defer a.mu.Unlock()
@ -302,11 +263,9 @@ func (a *IntArray) PopRights(size int) []int {
return value
}
// Get items by range, returns array[start:end].
// Be aware that, if in concurrent-safe usage, it returns a copy of slice;
// Range picks and returns items by range, like array[start:end].
// Notice, if in concurrent-safe usage, it returns a copy of slice;
// else a pointer to the underlying data.
//
// 将最右端(尾部)的size个数据项移出数组并返回该数据项
func (a *IntArray) Range(start, end int) []int {
a.mu.RLock()
defer a.mu.RUnlock()
@ -333,8 +292,6 @@ func (a *IntArray) Range(start, end int) []int {
}
// See PushRight.
//
// 追加数据项, 等于: PushRight。
func (a *IntArray) Append(value...int) *IntArray {
a.mu.Lock()
a.array = append(a.array, value...)
@ -342,9 +299,7 @@ func (a *IntArray) Append(value...int) *IntArray {
return a
}
// Get the length of array.
//
// 数组长度。
// Len returns the length of array.
func (a *IntArray) Len() int {
a.mu.RLock()
length := len(a.array)
@ -352,11 +307,9 @@ func (a *IntArray) Len() int {
return length
}
// Get the underlying data of array.
// Be aware that, if in concurrent-safe usage, it returns a copy of slice;
// Slice returns the underlying data of array.
// Notice, if in concurrent-safe usage, it returns a copy of slice;
// else a pointer to the underlying data.
//
// 返回原始数据数组.
func (a *IntArray) Slice() []int {
array := ([]int)(nil)
if a.mu.IsSafe() {
@ -370,9 +323,7 @@ func (a *IntArray) Slice() []int {
return array
}
// Return a new array, which is a copy of current array.
//
// 克隆当前数组,返回当前数组的一个拷贝。
// Clone returns a new array, which is a copy of current array.
func (a *IntArray) Clone() (newArray *IntArray) {
a.mu.RLock()
array := make([]int, len(a.array))
@ -381,9 +332,7 @@ func (a *IntArray) Clone() (newArray *IntArray) {
return NewIntArrayFrom(array, !a.mu.IsSafe())
}
// Clear array.
//
// 清空数据数组。
// Clear deletes all items of current array.
func (a *IntArray) Clear() *IntArray {
a.mu.Lock()
if len(a.array) > 0 {
@ -393,17 +342,13 @@ func (a *IntArray) Clear() *IntArray {
return a
}
// Check whether a value exists in the array.
//
// 查找指定数值是否存在。
// Contains checks whether a value exists in the array.
func (a *IntArray) Contains(value int) bool {
return a.Search(value) != -1
}
// Search array by <value>, returns the index of <value>, returns -1 if not exists.
//
// 查找指定数值的索引位置,返回索引位置,如果查找不到则返回-1。
// Search searches array by <value>, returns the index of <value>,
// or returns -1 if not exists.
func (a *IntArray) Search(value int) int {
if len(a.array) == 0 {
return -1
@ -421,9 +366,7 @@ func (a *IntArray) Search(value int) int {
return result
}
// Unique the array, clear repeated values.
//
// 清理数组中重复的元素项。
// Unique uniques the array, clear repeated items.
func (a *IntArray) Unique() *IntArray {
a.mu.Lock()
for i := 0; i < len(a.array) - 1; i++ {
@ -437,9 +380,7 @@ func (a *IntArray) Unique() *IntArray {
return a
}
// Lock writing by callback function f.
//
// 使用自定义方法执行加锁修改操作。
// LockFunc locks writing by callback function <f>.
func (a *IntArray) LockFunc(f func(array []int)) *IntArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -447,9 +388,7 @@ func (a *IntArray) LockFunc(f func(array []int)) *IntArray {
return a
}
// Lock reading by callback function f.
//
// 使用自定义方法执行加锁读取操作。
// RLockFunc locks reading by callback function <f>.
func (a *IntArray) RLockFunc(f func(array []int)) *IntArray {
a.mu.RLock()
defer a.mu.RUnlock()
@ -457,11 +396,10 @@ func (a *IntArray) RLockFunc(f func(array []int)) *IntArray {
return a
}
// Merge two arrays. The parameter <array> can be any garray type or slice type.
// Merge merges <array> into current array.
// The parameter <array> can be any garray or slice type.
// The difference between Merge and Append is Append supports only specified slice type,
// but Merge supports more variable types.
//
// 合并两个数组, 支持任意的garray数组类型及slice类型.
// but Merge supports more parameter types.
func (a *IntArray) Merge(array interface{}) *IntArray {
switch v := array.(type) {
case *Array: a.Append(gconv.Ints(v.Slice())...)
@ -476,10 +414,8 @@ func (a *IntArray) Merge(array interface{}) *IntArray {
return a
}
// Fills an array with num entries of the value of the value parameter,
// keys starting at the startIndex parameter.
//
// 用value参数的值将数组填充num个条目位置由startIndex参数指定的开始。
// Fill fills an array with num entries of the value <value>,
// keys starting at the <startIndex> parameter.
func (a *IntArray) Fill(startIndex int, num int, value int) *IntArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -496,10 +432,9 @@ func (a *IntArray) Fill(startIndex int, num int, value int) *IntArray {
return a
}
// Chunks an array into arrays with size elements.
// Chunk splits an array into multiple arrays,
// the size of each array is determined by <size>.
// The last chunk may contain less than size elements.
//
// 将一个数组分割成多个数组其中每个数组的单元数目由size决定。最后一个数组的单元数目可能会少于size个。
func (a *IntArray) Chunk(size int) [][]int {
if size < 1 {
return nil
@ -520,14 +455,10 @@ func (a *IntArray) Chunk(size int) [][]int {
return n
}
// Pad array to the specified length with a value.
// Pad pads array to the specified length with <value>.
// If size is positive then the array is padded on the right, or negative on the left.
// If the absolute value of size is less than or equal to the length of the array
// If the absolute value of <size> is less than or equal to the length of the array
// then no padding takes place.
//
// 返回数组的一个拷贝并用value将其填补到size指定的长度。
// 如果size为正数则填补到数组的右侧如果为负数则从左侧开始填补。
// 如果size的绝对值小于或等于数组的长度则没有任何填补。
func (a *IntArray) Pad(size int, value int) *IntArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -551,12 +482,9 @@ func (a *IntArray) Pad(size int, value int) *IntArray {
return a
}
// Extract a slice of the array(If in concurrent safe usage,
// it returns a copy of the slice; else a pointer).
// It returns the sequence of elements from the array array as specified
// by the offset and length parameters.
//
// 返回根据offset和size参数所指定的数组中的一段序列。
// SubSlice returns a slice of elements from the array as specified
// by the <offset> and <size> parameters.
// If in concurrent safe usage, it returns a copy of the slice; else a pointer.
func (a *IntArray) SubSlice(offset, size int) []int {
a.mu.RLock()
defer a.mu.RUnlock()
@ -575,18 +503,14 @@ func (a *IntArray) SubSlice(offset, size int) []int {
}
}
// Rand gets one random entry from array.
//
// 从数组中随机获得1个元素项(不删除)。
// Rand randomly returns one item from array(no deleting).
func (a *IntArray) Rand() int {
a.mu.RLock()
defer a.mu.RUnlock()
return a.array[grand.Intn(len(a.array))]
}
// Rands gets one or more random entries from array(a copy).
//
// 从数组中随机拷贝size个元素项构成slice返回。
// Rands randomly returns <size> items from array(no deleting).
func (a *IntArray) Rands(size int) []int {
a.mu.RLock()
defer a.mu.RUnlock()
@ -603,9 +527,7 @@ func (a *IntArray) Rands(size int) []int {
return n
}
// Randomly shuffles the array.
//
// 随机打乱当前数组。
// Shuffle randomly shuffles the array.
func (a *IntArray) Shuffle() *IntArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -615,9 +537,7 @@ func (a *IntArray) Shuffle() *IntArray {
return a
}
// Make array with elements in reverse order.
//
// 将当前数组反转。
// Reverse makes array with elements in reverse order.
func (a *IntArray) Reverse() *IntArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -627,9 +547,7 @@ func (a *IntArray) Reverse() *IntArray {
return a
}
// Join array elements with a string.
//
// 使用glue字符串串连当前数组的元素项构造成新的字符串返回。
// Join joins array elements with a string <glue>.
func (a *IntArray) Join(glue string) string {
a.mu.RLock()
defer a.mu.RUnlock()
@ -641,4 +559,22 @@ func (a *IntArray) Join(glue string) string {
}
}
return buffer.String()
}
// CountValues counts the number of occurrences of all values in the array.
func (a *IntArray) CountValues() map[int]int {
m := make(map[int]int)
a.mu.RLock()
defer a.mu.RUnlock()
for _, v := range a.array {
m[v]++
}
return m
}
// String returns current array as a string.
func (a *IntArray) String() string {
a.mu.RLock()
defer a.mu.RUnlock()
return fmt.Sprint(a.array)
}

View File

@ -17,15 +17,13 @@ import (
)
type Array struct {
mu *rwmutex.RWMutex // 互斥锁
array []interface{} // 底层数组
mu *rwmutex.RWMutex
array []interface{}
}
// Create an empty array.
// The param <unsafe> used to specify whether using array with un-concurrent-safety,
// which is false in default, means concurrent-safe in default.
//
// 创建一个空的数组对象参数unsafe用于指定是否用于非并发安全场景默认为false表示并发安全。
// New creates and returns an empty array.
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
// which is false in default.
func New(unsafe...bool) *Array {
return NewArraySize(0, 0, unsafe...)
}
@ -35,11 +33,9 @@ func NewArray(unsafe...bool) *Array {
return NewArraySize(0, 0, unsafe...)
}
// Create an array with given size and cap.
// NewArraySize create and returns an array with given size and cap.
// The param <unsafe> used to specify whether using array with un-concurrent-safety,
// which is false in default, means concurrent-safe in default.
//
// 创建一个指定大小的数组对象参数unsafe用于指定是否用于非并发安全场景默认为false表示并发安全。
// which is false in default.
func NewArraySize(size int, cap int, unsafe...bool) *Array {
return &Array{
mu : rwmutex.New(unsafe...),
@ -57,11 +53,9 @@ func NewFromCopy(array []interface{}, unsafe...bool) *Array {
return NewArrayFromCopy(array, unsafe...)
}
// Create an array with given slice <array>.
// NewArrayFrom creates and returns an array with given slice <array>.
// The param <unsafe> used to specify whether using array with un-concurrent-safety,
// which is false in default, means concurrent-safe in default.
//
// 通过给定的slice变量创建数组对象参数unsafe用于指定是否用于非并发安全场景默认为false表示并发安全。
// which is false in default.
func NewArrayFrom(array []interface{}, unsafe...bool) *Array {
return &Array{
mu : rwmutex.New(unsafe...),
@ -69,11 +63,9 @@ func NewArrayFrom(array []interface{}, unsafe...bool) *Array {
}
}
// Create an array from a copy of given slice <array>.
// NewArrayFromCopy creates and returns an array from a copy of given slice <array>.
// The param <unsafe> used to specify whether using array with un-concurrent-safety,
// which is false in default, means concurrent-safe in default.
//
// 通过给定的slice拷贝创建数组对象参数unsafe用于指定是否用于非并发安全场景默认为false表示并发安全。
// which is false in default.
func NewArrayFromCopy(array []interface{}, unsafe...bool) *Array {
newArray := make([]interface{}, len(array))
copy(newArray, array)
@ -83,9 +75,8 @@ func NewArrayFromCopy(array []interface{}, unsafe...bool) *Array {
}
}
// Get value by index.
//
// 获取指定索引的数据项, 调用方注意判断数组边界
// Get returns the value of the specified index,
// the caller should notice the boundary of the array.
func (a *Array) Get(index int) interface{} {
a.mu.RLock()
defer a.mu.RUnlock()
@ -93,9 +84,7 @@ func (a *Array) Get(index int) interface{} {
return value
}
// Set value by index.
//
// 设置指定索引的数据项, 调用方注意判断数组边界
// Set sets value to specified index.
func (a *Array) Set(index int, value interface{}) *Array {
a.mu.Lock()
defer a.mu.Unlock()
@ -103,9 +92,7 @@ func (a *Array) Set(index int, value interface{}) *Array {
return a
}
// Set the underlying slice array with the given <array> param.
//
// 设置底层数组变量.
// SetArray sets the underlying slice array with the given <array>.
func (a *Array) SetArray(array []interface{}) *Array {
a.mu.Lock()
defer a.mu.Unlock()
@ -113,9 +100,7 @@ func (a *Array) SetArray(array []interface{}) *Array {
return a
}
// Replace the array items by given <array> from the beginning of array.
//
// 使用指定数组替换到对应的索引元素值.
// Replace replaces the array items by given <array> from the beginning of array.
func (a *Array) Replace(array []interface{}) *Array {
a.mu.Lock()
defer a.mu.Unlock()
@ -129,9 +114,7 @@ func (a *Array) Replace(array []interface{}) *Array {
return a
}
// Calculate the sum of values in an array.
//
// 对数组中的元素项求和(将元素值转换为int类型后叠加)。
// Sum returns the sum of values in an array.
func (a *Array) Sum() (sum int) {
a.mu.RLock()
defer a.mu.RUnlock()
@ -141,9 +124,7 @@ func (a *Array) Sum() (sum int) {
return
}
// Sort the array by custom function <less>.
//
// 使用自定义的排序函数将数组重新排序.
// SortFunc sorts the array by custom function <less>.
func (a *Array) SortFunc(less func(v1, v2 interface{}) bool) *Array {
a.mu.Lock()
defer a.mu.Unlock()
@ -153,9 +134,7 @@ func (a *Array) SortFunc(less func(v1, v2 interface{}) bool) *Array {
return a
}
// Insert the <value> to the front of <index>.
//
// 在当前索引位置前插入一个数据项, 调用方注意判断数组边界。
// InsertBefore inserts the <value> to the front of <index>.
func (a *Array) InsertBefore(index int, value interface{}) *Array {
a.mu.Lock()
defer a.mu.Unlock()
@ -165,9 +144,7 @@ func (a *Array) InsertBefore(index int, value interface{}) *Array {
return a
}
// Insert the <value> to the back of <index>.
//
// 在当前索引位置前插入一个数据项, 调用方注意判断数组边界。
// InsertAfter inserts the <value> to the back of <index>.
func (a *Array) InsertAfter(index int, value interface{}) *Array {
a.mu.Lock()
defer a.mu.Unlock()
@ -177,13 +154,11 @@ func (a *Array) InsertAfter(index int, value interface{}) *Array {
return a
}
// Remove an item by index.
//
// 删除指定索引的数据项, 调用方注意判断数组边界。
// Remove removes an item by index.
func (a *Array) Remove(index int) interface{} {
a.mu.Lock()
defer a.mu.Unlock()
// 边界删除判断,以提高删除效率
// Determine array boundaries when deleting to improve deletion efficiency。
if index == 0 {
value := a.array[0]
a.array = a.array[1 : ]
@ -193,15 +168,15 @@ func (a *Array) Remove(index int) interface{} {
a.array = a.array[: index]
return value
}
// 如果非边界删除,会涉及到数组创建,那么删除的效率差一些
// If it is a non-boundary delete,
// it will involve the creation of an array,
// then the deletion is less efficient.
value := a.array[index]
a.array = append(a.array[ : index], a.array[index + 1 : ]...)
return value
}
// Push new items to the beginning of array.
//
// 将数据项添加到数组的最左端(索引为0)。
// PushLeft pushes one or multiple items to the beginning of array.
func (a *Array) PushLeft(value...interface{}) *Array {
a.mu.Lock()
a.array = append(value, a.array...)
@ -209,9 +184,8 @@ func (a *Array) PushLeft(value...interface{}) *Array {
return a
}
// Push new items to the end of array.
//
// 将数据项添加到数组的最右端(索引为length - 1), 等于: Append。
// PushRight pushes one or multiple items to the end of array.
// It equals to Append.
func (a *Array) PushRight(value...interface{}) *Array {
a.mu.Lock()
a.array = append(a.array, value...)
@ -219,16 +193,12 @@ func (a *Array) PushRight(value...interface{}) *Array {
return a
}
// PopRand picks an random item out of array.
//
// 随机将一个数据项移出数组,并返回该数据项。
// PopRand randomly pops and return an item out of array.
func (a *Array) PopRand() interface{} {
return a.Remove(grand.Intn(len(a.array)))
}
// PopRands picks <size> items out of array.
//
// 随机将size个数据项移出数组并返回该数据项。
// PopRands randomly pops and returns <size> items out of array.
func (a *Array) PopRands(size int) []interface{} {
a.mu.Lock()
defer a.mu.Unlock()
@ -244,9 +214,7 @@ func (a *Array) PopRands(size int) []interface{} {
return array
}
// Pop an item from the beginning of array.
//
// 将最左端(索引为0)的数据项移出数组,并返回该数据项。
// PopLeft pops and returns an item from the beginning of array.
func (a *Array) PopLeft() interface{} {
a.mu.Lock()
defer a.mu.Unlock()
@ -255,9 +223,7 @@ func (a *Array) PopLeft() interface{} {
return value
}
// Pop an item from the end of array.
//
// 将最右端(索引为length - 1)的数据项移出数组,并返回该数据项。
// PopRight pops and returns an item from the end of array.
func (a *Array) PopRight() interface{} {
a.mu.Lock()
defer a.mu.Unlock()
@ -267,9 +233,7 @@ func (a *Array) PopRight() interface{} {
return value
}
// Pop <size> items from the beginning of array.
//
// 将最左端(首部)的size个数据项移出数组并返回该数据项
// PopLefts pops and returns <size> items from the beginning of array.
func (a *Array) PopLefts(size int) []interface{} {
a.mu.Lock()
defer a.mu.Unlock()
@ -282,9 +246,7 @@ func (a *Array) PopLefts(size int) []interface{} {
return value
}
// Pop <size> items from the end of array.
//
// 将最右端(尾部)的size个数据项移出数组并返回该数据项
// PopRights pops and returns <size> items from the end of array.
func (a *Array) PopRights(size int) []interface{} {
a.mu.Lock()
defer a.mu.Unlock()
@ -297,11 +259,9 @@ func (a *Array) PopRights(size int) []interface{} {
return value
}
// Get items by range, returns array[start:end].
// Be aware that, if in concurrent-safe usage, it returns a copy of slice;
// Range picks and returns items by range, like array[start:end].
// Notice, if in concurrent-safe usage, it returns a copy of slice;
// else a pointer to the underlying data.
//
// 将最右端(尾部)的size个数据项移出数组并返回该数据项
func (a *Array) Range(start, end int) []interface{} {
a.mu.RLock()
defer a.mu.RUnlock()
@ -328,16 +288,12 @@ func (a *Array) Range(start, end int) []interface{} {
}
// See PushRight.
//
// 追加数据项, 等于: PushRight。
func (a *Array) Append(value...interface{}) *Array {
a.PushRight(value...)
return a
}
// Get the length of array.
//
// 数组长度。
// Len returns the length of array.
func (a *Array) Len() int {
a.mu.RLock()
length := len(a.array)
@ -345,11 +301,9 @@ func (a *Array) Len() int {
return length
}
// Get the underlying data of array.
// Be aware that, if in concurrent-safe usage, it returns a copy of slice;
// Slice returns the underlying data of array.
// Notice, if in concurrent-safe usage, it returns a copy of slice;
// else a pointer to the underlying data.
//
// 返回原始数据数组.
func (a *Array) Slice() []interface{} {
array := ([]interface{})(nil)
if a.mu.IsSafe() {
@ -363,9 +317,7 @@ func (a *Array) Slice() []interface{} {
return array
}
// Return a new array, which is a copy of current array.
//
// 克隆当前数组,返回当前数组的一个拷贝。
// Clone returns a new array, which is a copy of current array.
func (a *Array) Clone() (newArray *Array) {
a.mu.RLock()
array := make([]interface{}, len(a.array))
@ -374,9 +326,7 @@ func (a *Array) Clone() (newArray *Array) {
return NewArrayFrom(array, !a.mu.IsSafe())
}
// Clear array.
//
// 清空数据数组
// Clear deletes all items of current array.
func (a *Array) Clear() *Array {
a.mu.Lock()
if len(a.array) > 0 {
@ -386,16 +336,13 @@ func (a *Array) Clear() *Array {
return a
}
// Check whether a value exists in the array.
//
// 查找指定数值是否存在
// Contains checks whether a value exists in the array.
func (a *Array) Contains(value interface{}) bool {
return a.Search(value) != -1
}
// Search array by <value>, returns the index of <value>, returns -1 if not exists.
//
// 查找指定数值的索引位置,返回索引位置,如果查找不到则返回-1
// Search searches array by <value>, returns the index of <value>,
// or returns -1 if not exists.
func (a *Array) Search(value interface{}) int {
if len(a.array) == 0 {
return -1
@ -413,9 +360,7 @@ func (a *Array) Search(value interface{}) int {
return result
}
// Unique the array, clear repeated values.
//
// 清理数组中重复的元素项
// Unique uniques the array, clear repeated items.
func (a *Array) Unique() *Array {
a.mu.Lock()
for i := 0; i < len(a.array) - 1; i++ {
@ -429,9 +374,7 @@ func (a *Array) Unique() *Array {
return a
}
// Lock writing by callback function f.
//
// 使用自定义方法执行加锁修改操作
// LockFunc locks writing by callback function <f>.
func (a *Array) LockFunc(f func(array []interface{})) *Array {
a.mu.Lock()
defer a.mu.Unlock()
@ -439,9 +382,7 @@ func (a *Array) LockFunc(f func(array []interface{})) *Array {
return a
}
// Lock reading by callback function f.
//
// 使用自定义方法执行加锁读取操作
// RLockFunc locks reading by callback function <f>.
func (a *Array) RLockFunc(f func(array []interface{})) *Array {
a.mu.RLock()
defer a.mu.RUnlock()
@ -449,11 +390,10 @@ func (a *Array) RLockFunc(f func(array []interface{})) *Array {
return a
}
// Merge two arrays. The parameter <array> can be any garray type or slice type.
// Merge merges <array> into current array.
// The parameter <array> can be any garray or slice type.
// The difference between Merge and Append is Append supports only specified slice type,
// but Merge supports more variable types.
//
// 合并两个数组, 支持任意的garray数组类型及slice类型.
// but Merge supports more parameter types.
func (a *Array) Merge(array interface{}) *Array {
switch v := array.(type) {
case *Array: a.Append(gconv.Interfaces(v.Slice())...)
@ -468,10 +408,8 @@ func (a *Array) Merge(array interface{}) *Array {
return a
}
// Fills an array with num entries of the value of the value parameter,
// keys starting at the start_index parameter.
//
// 用value参数的值将数组填充num个条目位置由startIndex参数指定的开始。
// Fill fills an array with num entries of the value <value>,
// keys starting at the <startIndex> parameter.
func (a *Array) Fill(startIndex int, num int, value interface{}) *Array {
a.mu.Lock()
defer a.mu.Unlock()
@ -488,10 +426,9 @@ func (a *Array) Fill(startIndex int, num int, value interface{}) *Array {
return a
}
// Chunks an array into arrays with size elements.
// Chunk splits an array into multiple arrays,
// the size of each array is determined by <size>.
// The last chunk may contain less than size elements.
//
// 将一个数组分割成多个数组其中每个数组的单元数目由size决定。最后一个数组的单元数目可能会少于size个。
func (a *Array) Chunk(size int) [][]interface{} {
if size < 1 {
return nil
@ -512,15 +449,10 @@ func (a *Array) Chunk(size int) [][]interface{} {
return n
}
// Pad array to the specified length with a value.
// If size is positive then the array is padded on the right,
// if it's negative then on the left.
// If the absolute value of size is less than or equal to the length of the array
// Pad pads array to the specified length with <value>.
// If size is positive then the array is padded on the right, or negative on the left.
// If the absolute value of <size> is less than or equal to the length of the array
// then no padding takes place.
//
// 返回数组的一个拷贝并用value将其填补到size指定的长度。
// 如果size为正数则填补到数组的右侧如果为负数则从左侧开始填补。
// 如果size的绝对值小于或等于数组的长度则没有任何填补。
func (a *Array) Pad(size int, val interface{}) *Array {
a.mu.Lock()
defer a.mu.Unlock()
@ -544,10 +476,9 @@ func (a *Array) Pad(size int, val interface{}) *Array {
return a
}
// Extract a slice of the array(If in concurrent safe usage, it returns a copy of the slice; else a pointer).
// It returns the sequence of elements from the array array as specified by the offset and length parameters.
//
// 返回根据offset和size参数所指定的数组中的一段序列。
// SubSlice returns a slice of elements from the array as specified
// by the <offset> and <size> parameters.
// If in concurrent safe usage, it returns a copy of the slice; else a pointer.
func (a *Array) SubSlice(offset, size int) []interface{} {
a.mu.RLock()
defer a.mu.RUnlock()
@ -566,18 +497,14 @@ func (a *Array) SubSlice(offset, size int) []interface{} {
}
}
// Rand gets one random entry from array.
//
// 从数组中随机获得1个元素项(不删除)。
// Rand randomly returns one item from array(no deleting).
func (a *Array) Rand() interface{} {
a.mu.RLock()
defer a.mu.RUnlock()
return a.array[grand.Intn(len(a.array))]
}
// Rands gets one or more random entries from array(a copy).
//
// 从数组中随机拷贝size个元素项构成slice返回。
// Rands randomly returns <size> items from array(no deleting).
func (a *Array) Rands(size int) []interface{} {
a.mu.RLock()
defer a.mu.RUnlock()
@ -594,9 +521,7 @@ func (a *Array) Rands(size int) []interface{} {
return n
}
// Randomly shuffles the array.
//
// 随机打乱当前数组。
// Shuffle randomly shuffles the array.
func (a *Array) Shuffle() *Array {
a.mu.Lock()
defer a.mu.Unlock()
@ -606,9 +531,7 @@ func (a *Array) Shuffle() *Array {
return a
}
// Make array with elements in reverse order.
//
// 将当前数组反转。
// Reverse makes array with elements in reverse order.
func (a *Array) Reverse() *Array {
a.mu.Lock()
defer a.mu.Unlock()
@ -618,9 +541,7 @@ func (a *Array) Reverse() *Array {
return a
}
// Join array elements with a string.
//
// 使用glue字符串串连当前数组的元素项构造成新的字符串返回。
// Join joins array elements with a string <glue>.
func (a *Array) Join(glue string) string {
a.mu.RLock()
defer a.mu.RUnlock()
@ -634,9 +555,7 @@ func (a *Array) Join(glue string) string {
return buffer.String()
}
// Counts all the values of an array.
//
// 统计数组中所有的值出现的次数.
// CountValues counts the number of occurrences of all values in the array.
func (a *Array) CountValues() map[interface{}]int {
m := make(map[interface{}]int)
a.mu.RLock()
@ -648,8 +567,6 @@ func (a *Array) CountValues() map[interface{}]int {
}
// String returns current array as a string.
//
// 将当前数组转换为字符串返回。
func (a *Array) String() string {
a.mu.RLock()
defer a.mu.RUnlock()

View File

@ -8,7 +8,8 @@ package garray
import (
"bytes"
"github.com/gogf/gf/g/internal/rwmutex"
"fmt"
"github.com/gogf/gf/g/internal/rwmutex"
"github.com/gogf/gf/g/util/gconv"
"github.com/gogf/gf/g/util/grand"
"math"
@ -17,24 +18,20 @@ import (
)
type StringArray struct {
mu *rwmutex.RWMutex // 互斥锁
array []string // 底层数组
mu *rwmutex.RWMutex
array []string
}
// Create an empty array.
// The param <unsafe> used to specify whether using array with un-concurrent-safety,
// which is false in default, means concurrent-safe in default.
//
// 创建一个空的数组对象参数unsafe用于指定是否用于非并发安全场景默认为false表示并发安全。
// NewStringArray creates and returns an empty array.
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
// which is false in default.
func NewStringArray(unsafe...bool) *StringArray {
return NewStringArraySize(0, 0, unsafe...)
}
// Create an array with given size and cap.
// NewStringArraySize create and returns an array with given size and cap.
// The param <unsafe> used to specify whether using array with un-concurrent-safety,
// which is false in default, means concurrent-safe in default.
//
// 创建一个指定大小的数组对象参数unsafe用于指定是否用于非并发安全场景默认为false表示并发安全。
// which is false in default.
func NewStringArraySize(size int, cap int, unsafe...bool) *StringArray {
return &StringArray{
mu : rwmutex.New(unsafe...),
@ -42,11 +39,9 @@ func NewStringArraySize(size int, cap int, unsafe...bool) *StringArray {
}
}
// Create an array with given slice <array>.
// NewStringArrayFrom creates and returns an array with given slice <array>.
// The param <unsafe> used to specify whether using array with un-concurrent-safety,
// which is false in default, means concurrent-safe in default.
//
// 通过给定的slice变量创建数组对象参数unsafe用于指定是否用于非并发安全场景默认为false表示并发安全。
// which is false in default.
func NewStringArrayFrom(array []string, unsafe...bool) *StringArray {
return &StringArray {
mu : rwmutex.New(unsafe...),
@ -54,11 +49,9 @@ func NewStringArrayFrom(array []string, unsafe...bool) *StringArray {
}
}
// Create an array from a copy of given slice <array>.
// NewStringArrayFromCopy creates and returns an array from a copy of given slice <array>.
// The param <unsafe> used to specify whether using array with un-concurrent-safety,
// which is false in default, means concurrent-safe in default.
//
// 通过给定的slice拷贝创建数组对象参数unsafe用于指定是否用于非并发安全场景默认为false表示并发安全。
// which is false in default.
func NewStringArrayFromCopy(array []string, unsafe...bool) *StringArray {
newArray := make([]string, len(array))
copy(newArray, array)
@ -68,9 +61,8 @@ func NewStringArrayFromCopy(array []string, unsafe...bool) *StringArray {
}
}
// Get value by index.
//
// 获取指定索引的数据项, 调用方注意判断数组边界。
// Get returns the value of the specified index,
// the caller should notice the boundary of the array.
func (a *StringArray) Get(index int) string {
a.mu.RLock()
defer a.mu.RUnlock()
@ -78,9 +70,7 @@ func (a *StringArray) Get(index int) string {
return value
}
// Set value by index.
//
// 设置指定索引的数据项, 调用方注意判断数组边界。
// Set sets value to specified index.
func (a *StringArray) Set(index int, value string) *StringArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -88,9 +78,7 @@ func (a *StringArray) Set(index int, value string) *StringArray {
return a
}
// Set the underlying slice array with the given <array> param.
//
// 设置底层数组变量.
// SetArray sets the underlying slice array with the given <array>.
func (a *StringArray) SetArray(array []string) *StringArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -98,9 +86,7 @@ func (a *StringArray) SetArray(array []string) *StringArray {
return a
}
// Replace the array items by given <array> from the beginning of array.
//
// 使用指定数组替换到对应的索引元素值.
// Replace replaces the array items by given <array> from the beginning of array.
func (a *StringArray) Replace(array []string) *StringArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -114,9 +100,7 @@ func (a *StringArray) Replace(array []string) *StringArray {
return a
}
// Calculate the sum of values in an array.
//
// 对数组中的元素项求和(将元素值转换为int类型后叠加)。
// Sum returns the sum of values in an array.
func (a *StringArray) Sum() (sum int) {
a.mu.RLock()
defer a.mu.RUnlock()
@ -126,11 +110,9 @@ func (a *StringArray) Sum() (sum int) {
return
}
// Sort the array in increasing order.
// Sort sorts the array in increasing order.
// The param <reverse> controls whether sort
// in increasing order(default) or decreasing order
//
// 将数组排序(默认从低到高).
func (a *StringArray) Sort(reverse...bool) *StringArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -147,9 +129,7 @@ func (a *StringArray) Sort(reverse...bool) *StringArray {
return a
}
// Sort the array by custom function <less>.
//
// 使用自定义的排序函数将数组重新排序.
// SortFunc sorts the array by custom function <less>.
func (a *StringArray) SortFunc(less func(v1, v2 string) bool) *StringArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -159,9 +139,7 @@ func (a *StringArray) SortFunc(less func(v1, v2 string) bool) *StringArray {
return a
}
// Insert the <value> to the front of <index>.
//
// 在当前索引位置前插入一个数据项, 调用方注意判断数组边界。
// InsertBefore inserts the <value> to the front of <index>.
func (a *StringArray) InsertBefore(index int, value string) *StringArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -171,9 +149,7 @@ func (a *StringArray) InsertBefore(index int, value string) *StringArray {
return a
}
// Insert the <value> to the back of <index>.
//
// 在当前索引位置前插入一个数据项, 调用方注意判断数组边界。
// InsertAfter inserts the <value> to the back of <index>.
func (a *StringArray) InsertAfter(index int, value string) *StringArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -183,13 +159,11 @@ func (a *StringArray) InsertAfter(index int, value string) *StringArray {
return a
}
// Remove an item by index.
//
// 删除指定索引的数据项, 调用方注意判断数组边界。
// Remove removes an item by index.
func (a *StringArray) Remove(index int) string {
a.mu.Lock()
defer a.mu.Unlock()
// 边界删除判断,以提高删除效率
// Determine array boundaries when deleting to improve deletion efficiency。
if index == 0 {
value := a.array[0]
a.array = a.array[1 : ]
@ -199,15 +173,15 @@ func (a *StringArray) Remove(index int) string {
a.array = a.array[: index]
return value
}
// 如果非边界删除,会涉及到数组创建,那么删除的效率差一些
// If it is a non-boundary delete,
// it will involve the creation of an array,
// then the deletion is less efficient.
value := a.array[index]
a.array = append(a.array[ : index], a.array[index + 1 : ]...)
return value
}
// Push new items to the beginning of array.
//
// 将数据项添加到数组的最左端(索引为0)。
// PushLeft pushes one or multiple items to the beginning of array.
func (a *StringArray) PushLeft(value...string) *StringArray {
a.mu.Lock()
a.array = append(value, a.array...)
@ -215,9 +189,8 @@ func (a *StringArray) PushLeft(value...string) *StringArray {
return a
}
// Push new items to the end of array.
//
// 将数据项添加到数组的最右端(索引为length - 1), 等于: Append。
// PushRight pushes one or multiple items to the end of array.
// It equals to Append.
func (a *StringArray) PushRight(value...string) *StringArray {
a.mu.Lock()
a.array = append(a.array, value...)
@ -225,9 +198,7 @@ func (a *StringArray) PushRight(value...string) *StringArray {
return a
}
// Pop an item from the beginning of array.
//
// 将最左端(索引为0)的数据项移出数组,并返回该数据项。
// PopLeft pops and returns an item from the beginning of array.
func (a *StringArray) PopLeft() string {
a.mu.Lock()
defer a.mu.Unlock()
@ -236,9 +207,7 @@ func (a *StringArray) PopLeft() string {
return value
}
// Pop an item from the end of array.
//
// 将最右端(索引为length - 1)的数据项移出数组,并返回该数据项。
// PopRight pops and returns an item from the end of array.
func (a *StringArray) PopRight() string {
a.mu.Lock()
defer a.mu.Unlock()
@ -248,16 +217,12 @@ func (a *StringArray) PopRight() string {
return value
}
// PopRand picks an random item out of array.
//
// 随机将一个数据项移出数组,并返回该数据项。
// PopRand randomly pops and return an item out of array.
func (a *StringArray) PopRand() string {
return a.Remove(grand.Intn(len(a.array)))
}
// PopRands picks <size> items out of array.
//
// 随机将size个数据项移出数组并返回该数据项。
// PopRands randomly pops and returns <size> items out of array.
func (a *StringArray) PopRands(size int) []string {
a.mu.Lock()
defer a.mu.Unlock()
@ -273,9 +238,7 @@ func (a *StringArray) PopRands(size int) []string {
return array
}
// Pop <size> items from the beginning of array.
//
// 将最左端(首部)的size个数据项移出数组并返回该数据项
// PopLefts pops and returns <size> items from the beginning of array.
func (a *StringArray) PopLefts(size int) []string {
a.mu.Lock()
defer a.mu.Unlock()
@ -288,9 +251,7 @@ func (a *StringArray) PopLefts(size int) []string {
return value
}
// Pop <size> items from the end of array.
//
// 将最右端(尾部)的size个数据项移出数组并返回该数据项
// PopRights pops and returns <size> items from the end of array.
func (a *StringArray) PopRights(size int) []string {
a.mu.Lock()
defer a.mu.Unlock()
@ -303,11 +264,9 @@ func (a *StringArray) PopRights(size int) []string {
return value
}
// Get items by range, returns array[start:end].
// Be aware that, if in concurrent-safe usage, it returns a copy of slice;
// Range picks and returns items by range, like array[start:end].
// Notice, if in concurrent-safe usage, it returns a copy of slice;
// else a pointer to the underlying data.
//
// 将最右端(尾部)的size个数据项移出数组并返回该数据项
func (a *StringArray) Range(start, end int) []string {
a.mu.RLock()
defer a.mu.RUnlock()
@ -334,8 +293,6 @@ func (a *StringArray) Range(start, end int) []string {
}
// See PushRight.
//
// 追加数据项, 等于: PushRight。
func (a *StringArray) Append(value...string) *StringArray {
a.mu.Lock()
a.array = append(a.array, value...)
@ -343,9 +300,7 @@ func (a *StringArray) Append(value...string) *StringArray {
return a
}
// Get the length of array.
//
// 数组长度。
// Len returns the length of array.
func (a *StringArray) Len() int {
a.mu.RLock()
length := len(a.array)
@ -353,11 +308,9 @@ func (a *StringArray) Len() int {
return length
}
// Get the underlying data of array.
// Be aware that, if in concurrent-safe usage, it returns a copy of slice;
// Slice returns the underlying data of array.
// Notice, if in concurrent-safe usage, it returns a copy of slice;
// else a pointer to the underlying data.
//
// 返回原始数据数组.
func (a *StringArray) Slice() []string {
array := ([]string)(nil)
if a.mu.IsSafe() {
@ -371,9 +324,7 @@ func (a *StringArray) Slice() []string {
return array
}
// Return a new array, which is a copy of current array.
//
// 克隆当前数组,返回当前数组的一个拷贝。
// Clone returns a new array, which is a copy of current array.
func (a *StringArray) Clone() (newArray *StringArray) {
a.mu.RLock()
array := make([]string, len(a.array))
@ -382,9 +333,7 @@ func (a *StringArray) Clone() (newArray *StringArray) {
return NewStringArrayFrom(array, !a.mu.IsSafe())
}
// Clear array.
//
// 清空数据数组。
// Clear deletes all items of current array.
func (a *StringArray) Clear() *StringArray {
a.mu.Lock()
if len(a.array) > 0 {
@ -394,16 +343,13 @@ func (a *StringArray) Clear() *StringArray {
return a
}
// Check whether a value exists in the array.
//
// 查找指定数值是否存在。
// Contains checks whether a value exists in the array.
func (a *StringArray) Contains(value string) bool {
return a.Search(value) != -1
}
// Search array by <value>, returns the index of <value>, returns -1 if not exists.
//
// 查找指定数值的索引位置,返回索引位置,如果查找不到则返回-1。
// Search searches array by <value>, returns the index of <value>,
// or returns -1 if not exists.
func (a *StringArray) Search(value string) int {
if len(a.array) == 0 {
return -1
@ -420,9 +366,7 @@ func (a *StringArray) Search(value string) int {
return result
}
// Unique the array, clear repeated values.
//
// 清理数组中重复的元素项。
// Unique uniques the array, clear repeated items.
func (a *StringArray) Unique() *StringArray {
a.mu.Lock()
for i := 0; i < len(a.array) - 1; i++ {
@ -436,9 +380,7 @@ func (a *StringArray) Unique() *StringArray {
return a
}
// Lock writing by callback function f.
//
// 使用自定义方法执行加锁修改操作。
// LockFunc locks writing by callback function <f>.
func (a *StringArray) LockFunc(f func(array []string)) *StringArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -446,9 +388,7 @@ func (a *StringArray) LockFunc(f func(array []string)) *StringArray {
return a
}
// Lock reading by callback function f.
//
// 使用自定义方法执行加锁读取操作。
// RLockFunc locks reading by callback function <f>.
func (a *StringArray) RLockFunc(f func(array []string)) *StringArray {
a.mu.RLock()
defer a.mu.RUnlock()
@ -456,11 +396,10 @@ func (a *StringArray) RLockFunc(f func(array []string)) *StringArray {
return a
}
// Merge two arrays. The parameter <array> can be any garray type or slice type.
// Merge merges <array> into current array.
// The parameter <array> can be any garray or slice type.
// The difference between Merge and Append is Append supports only specified slice type,
// but Merge supports more variable types.
//
// 合并两个数组, 支持任意的garray数组类型及slice类型.
// but Merge supports more parameter types.
func (a *StringArray) Merge(array interface{}) *StringArray {
switch v := array.(type) {
case *Array: a.Append(gconv.Strings(v.Slice())...)
@ -475,10 +414,8 @@ func (a *StringArray) Merge(array interface{}) *StringArray {
return a
}
// Fills an array with num entries of the value of the value parameter,
// keys starting at the start_index parameter.
//
// 用value参数的值将数组填充num个条目位置由startIndex参数指定的开始。
// Fill fills an array with num entries of the value <value>,
// keys starting at the <startIndex> parameter.
func (a *StringArray) Fill(startIndex int, num int, value string) *StringArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -495,10 +432,9 @@ func (a *StringArray) Fill(startIndex int, num int, value string) *StringArray {
return a
}
// Chunks an array into arrays with size elements.
// Chunk splits an array into multiple arrays,
// the size of each array is determined by <size>.
// The last chunk may contain less than size elements.
//
// 将一个数组分割成多个数组其中每个数组的单元数目由size决定。最后一个数组的单元数目可能会少于size个。
func (a *StringArray) Chunk(size int) [][]string {
if size < 1 {
return nil
@ -519,15 +455,10 @@ func (a *StringArray) Chunk(size int) [][]string {
return n
}
// Pad array to the specified length with a value.
// If size is positive then the array is padded on the right,
// if it's negative then on the left.
// If the absolute value of size is less than or equal to the length of the array
// Pad pads array to the specified length with <value>.
// If size is positive then the array is padded on the right, or negative on the left.
// If the absolute value of <size> is less than or equal to the length of the array
// then no padding takes place.
//
// 返回数组的一个拷贝并用value将其填补到size指定的长度。
// 如果size为正数则填补到数组的右侧如果为负数则从左侧开始填补。
// 如果size的绝对值小于或等于数组的长度则没有任何填补。
func (a *StringArray) Pad(size int, value string) *StringArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -551,12 +482,9 @@ func (a *StringArray) Pad(size int, value string) *StringArray {
return a
}
// Extract a slice of the array(If in concurrent safe usage,
// it returns a copy of the slice; else a pointer).
// It returns the sequence of elements from the array array as specified
// by the offset and length parameters.
//
// 返回根据offset和size参数所指定的数组中的一段序列。
// SubSlice returns a slice of elements from the array as specified
// by the <offset> and <size> parameters.
// If in concurrent safe usage, it returns a copy of the slice; else a pointer.
func (a *StringArray) SubSlice(offset, size int) []string {
a.mu.RLock()
defer a.mu.RUnlock()
@ -575,18 +503,14 @@ func (a *StringArray) SubSlice(offset, size int) []string {
}
}
// Rand gets one random entry from array.
//
// 从数组中随机获得1个元素项(不删除)。
// Rand randomly returns one item from array(no deleting).
func (a *StringArray) Rand() string {
a.mu.RLock()
defer a.mu.RUnlock()
return a.array[grand.Intn(len(a.array))]
}
// Rands gets one or more random entries from array(a copy).
//
// 从数组中随机拷贝size个元素项构成slice返回。
// Rands randomly returns <size> items from array(no deleting).
func (a *StringArray) Rands(size int) []string {
a.mu.RLock()
defer a.mu.RUnlock()
@ -603,9 +527,7 @@ func (a *StringArray) Rands(size int) []string {
return n
}
// Randomly shuffles the array.
//
// 随机打乱当前数组。
// Shuffle randomly shuffles the array.
func (a *StringArray) Shuffle() *StringArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -615,9 +537,7 @@ func (a *StringArray) Shuffle() *StringArray {
return a
}
// Make array with elements in reverse order.
//
// 将当前数组反转。
// Reverse makes array with elements in reverse order.
func (a *StringArray) Reverse() *StringArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -627,9 +547,7 @@ func (a *StringArray) Reverse() *StringArray {
return a
}
// Join array elements with a string.
//
// 使用glue字符串串连当前数组的元素项构造成新的字符串返回。
// Join joins array elements with a string <glue>.
func (a *StringArray) Join(glue string) string {
a.mu.RLock()
defer a.mu.RUnlock()
@ -643,3 +561,20 @@ func (a *StringArray) Join(glue string) string {
return buffer.String()
}
// CountValues counts the number of occurrences of all values in the array.
func (a *StringArray) CountValues() map[string]int {
m := make(map[string]int)
a.mu.RLock()
defer a.mu.RUnlock()
for _, v := range a.array {
m[v]++
}
return m
}
// String returns current array as a string.
func (a *StringArray) String() string {
a.mu.RLock()
defer a.mu.RUnlock()
return fmt.Sprint(a.array)
}

View File

@ -8,7 +8,8 @@ package garray
import (
"bytes"
"github.com/gogf/gf/g/container/gtype"
"fmt"
"github.com/gogf/gf/g/container/gtype"
"github.com/gogf/gf/g/internal/rwmutex"
"github.com/gogf/gf/g/util/gconv"
"github.com/gogf/gf/g/util/grand"
@ -16,28 +17,24 @@ import (
"sort"
)
// 默认按照从小到大进行排序
// It's using increasing order in default.
type SortedIntArray struct {
mu *rwmutex.RWMutex // 互斥锁
array []int // 底层数组
unique *gtype.Bool // 是否要求不能重复(默认false)
compareFunc func(v1, v2 int) int // 比较函数,返回值 -1: v1 < v20: v1 == v21: v1 > v2
mu *rwmutex.RWMutex
array []int
unique *gtype.Bool // Whether enable unique feature(false)
compareFunc func(v1, v2 int) int // Comparison function(it returns -1: v1 < v2; 0: v1 == v2; 1: v1 > v2)
}
// Create an empty sorted array.
// The param <unsafe> used to specify whether using array with un-concurrent-safety,
// which is false in default, means concurrent-safe in default.
//
// 创建一个空的排序数组对象参数unsafe用于指定是否用于非并发安全场景默认为false表示并发安全。
// NewSortedIntArray creates and returns an empty sorted array.
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
// which is false in default.
func NewSortedIntArray(unsafe...bool) *SortedIntArray {
return NewSortedIntArraySize(0, unsafe...)
}
// Create a sorted array with given size and cap.
// NewSortedIntArraySize create and returns an sorted array with given size and cap.
// The param <unsafe> used to specify whether using array with un-concurrent-safety,
// which is false in default, means concurrent-safe in default.
//
// 创建一个指定大小的排序数组对象参数unsafe用于指定是否用于非并发安全场景默认为false表示并发安全。
// which is false in default.
func NewSortedIntArraySize(cap int, unsafe...bool) *SortedIntArray {
return &SortedIntArray {
mu : rwmutex.New(unsafe...),
@ -55,11 +52,9 @@ func NewSortedIntArraySize(cap int, unsafe...bool) *SortedIntArray {
}
}
// Create an array with given slice <array>.
// NewIntArrayFrom creates and returns an sorted array with given slice <array>.
// The param <unsafe> used to specify whether using array with un-concurrent-safety,
// which is false in default, means concurrent-safe in default.
//
// 通过给定的slice变量创建排序数组对象参数unsafe用于指定是否用于非并发安全场景默认为false表示并发安全。
// which is false in default.
func NewSortedIntArrayFrom(array []int, unsafe...bool) *SortedIntArray {
a := NewSortedIntArraySize(0, unsafe...)
a.array = array
@ -67,11 +62,9 @@ func NewSortedIntArrayFrom(array []int, unsafe...bool) *SortedIntArray {
return a
}
// Create an array from a copy of given slice <array>.
// NewSortedIntArrayFromCopy creates and returns an sorted array from a copy of given slice <array>.
// The param <unsafe> used to specify whether using array with un-concurrent-safety,
// which is false in default, means concurrent-safe in default.
//
// 通过给定的slice拷贝创建数组对象参数unsafe用于指定是否用于非并发安全场景默认为false表示并发安全。
// which is false in default.
func NewSortedIntArrayFromCopy(array []int, unsafe...bool) *SortedIntArray {
newArray := make([]int, len(array))
copy(newArray, array)
@ -81,9 +74,7 @@ func NewSortedIntArrayFromCopy(array []int, unsafe...bool) *SortedIntArray {
}
}
// Set the underlying slice array with the given <array> param.
//
// 设置底层数组变量.
// SetArray sets the underlying slice array with the given <array>.
func (a *SortedIntArray) SetArray(array []int) *SortedIntArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -92,9 +83,9 @@ func (a *SortedIntArray) SetArray(array []int) *SortedIntArray {
return a
}
// Sort the array in increasing order.
//
// 将数组排序(默认从低到高).
// Sort sorts the array in increasing order.
// The param <reverse> controls whether sort
// in increasing order(default) or decreasing order.
func (a *SortedIntArray) Sort() *SortedIntArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -102,9 +93,7 @@ func (a *SortedIntArray) Sort() *SortedIntArray {
return a
}
// And values to sorted array, the array always keeps sorted.
//
// 添加数据项.
// Add adds one or multiple values to sorted array, the array always keeps sorted.
func (a *SortedIntArray) Add(values...int) *SortedIntArray {
if len(values) == 0 {
return a
@ -120,7 +109,6 @@ func (a *SortedIntArray) Add(values...int) *SortedIntArray {
a.array = append(a.array, value)
continue
}
// 加到指定索引后面
if cmp > 0 {
index++
}
@ -131,9 +119,8 @@ func (a *SortedIntArray) Add(values...int) *SortedIntArray {
return a
}
// Get value by index.
//
// 获取指定索引的数据项, 调用方注意判断数组边界。
// Get returns the value of the specified index,
// the caller should notice the boundary of the array.
func (a *SortedIntArray) Get(index int) int {
a.mu.RLock()
defer a.mu.RUnlock()
@ -141,13 +128,11 @@ func (a *SortedIntArray) Get(index int) int {
return value
}
// Remove an item by index.
//
// 删除指定索引的数据项, 调用方注意判断数组边界。
// Remove removes an item by index.
func (a *SortedIntArray) Remove(index int) int {
a.mu.Lock()
defer a.mu.Unlock()
// 边界删除判断,以提高删除效率
// Determine array boundaries when deleting to improve deletion efficiency.
if index == 0 {
value := a.array[0]
a.array = a.array[1 : ]
@ -157,15 +142,15 @@ func (a *SortedIntArray) Remove(index int) int {
a.array = a.array[: index]
return value
}
// 如果非边界删除,会涉及到数组创建,那么删除的效率差一些
// If it is a non-boundary delete,
// it will involve the creation of an array,
// then the deletion is less efficient.
value := a.array[index]
a.array = append(a.array[ : index], a.array[index + 1 : ]...)
return value
}
// Push new items to the beginning of array.
//
// 将数据项添加到数组的最左端(索引为0)。
// PopLeft pops and returns an item from the beginning of array.
func (a *SortedIntArray) PopLeft() int {
a.mu.Lock()
defer a.mu.Unlock()
@ -174,9 +159,7 @@ func (a *SortedIntArray) PopLeft() int {
return value
}
// Push new items to the end of array.
//
// 将数据项添加到数组的最右端(索引为length - 1)。
// PopRight pops and returns an item from the end of array.
func (a *SortedIntArray) PopRight() int {
a.mu.Lock()
defer a.mu.Unlock()
@ -186,16 +169,12 @@ func (a *SortedIntArray) PopRight() int {
return value
}
// PopRand picks an random item out of array.
//
// 随机将一个数据项移出数组,并返回该数据项。
// PopRand randomly pops and return an item out of array.
func (a *SortedIntArray) PopRand() int {
return a.Remove(grand.Intn(len(a.array)))
}
// PopRands picks <size> items out of array.
//
// 随机将size个数据项移出数组并返回该数据项。
// PopRands randomly pops and returns <size> items out of array.
func (a *SortedIntArray) PopRands(size int) []int {
a.mu.Lock()
defer a.mu.Unlock()
@ -211,9 +190,7 @@ func (a *SortedIntArray) PopRands(size int) []int {
return array
}
// Pop <size> items from the beginning of array.
//
// 将最左端(首部)的size个数据项移出数组并返回该数据项
// PopLefts pops and returns <size> items from the beginning of array.
func (a *SortedIntArray) PopLefts(size int) []int {
a.mu.Lock()
defer a.mu.Unlock()
@ -226,9 +203,7 @@ func (a *SortedIntArray) PopLefts(size int) []int {
return value
}
// Pop <size> items from the end of array.
//
// 将最右端(尾部)的size个数据项移出数组并返回该数据项
// PopRights pops and returns <size> items from the end of array.
func (a *SortedIntArray) PopRights(size int) []int {
a.mu.Lock()
defer a.mu.Unlock()
@ -241,11 +216,9 @@ func (a *SortedIntArray) PopRights(size int) []int {
return value
}
// Get items by range, returns array[start:end].
// Be aware that, if in concurrent-safe usage, it returns a copy of slice;
// Range picks and returns items by range, like array[start:end].
// Notice, if in concurrent-safe usage, it returns a copy of slice;
// else a pointer to the underlying data.
//
// 将最右端(尾部)的size个数据项移出数组并返回该数据项
func (a *SortedIntArray) Range(start, end int) []int {
a.mu.RLock()
defer a.mu.RUnlock()
@ -271,9 +244,7 @@ func (a *SortedIntArray) Range(start, end int) []int {
return array
}
// Get the length of array.
//
// 数组长度。
// Len returns the length of array.
func (a *SortedIntArray) Len() int {
a.mu.RLock()
length := len(a.array)
@ -281,9 +252,7 @@ func (a *SortedIntArray) Len() int {
return length
}
// Calculate the sum of values in an array.
//
// 对数组中的元素项求和。
// Sum returns the sum of values in an array.
func (a *SortedIntArray) Sum() (sum int) {
a.mu.RLock()
defer a.mu.RUnlock()
@ -293,11 +262,9 @@ func (a *SortedIntArray) Sum() (sum int) {
return
}
// Get the underlying data of array.
// Be aware that, if in concurrent-safe usage, it returns a copy of slice;
// Slice returns the underlying data of array.
// Notice, if in concurrent-safe usage, it returns a copy of slice;
// else a pointer to the underlying data.
//
// 返回原始数据数组.
func (a *SortedIntArray) Slice() []int {
array := ([]int)(nil)
if a.mu.IsSafe() {
@ -311,24 +278,19 @@ func (a *SortedIntArray) Slice() []int {
return array
}
// Check whether a value exists in the array.
//
// 查找指定数值是否存在。
// Contains checks whether a value exists in the array.
func (a *SortedIntArray) Contains(value int) bool {
return a.Search(value) == 0
}
// Search array by <value>, returns the index of <value>, returns -1 if not exists.
//
// 查找指定数值的索引位置,返回索引位置,如果查找不到则返回-1。
// Search searches array by <value>, returns the index of <value>,
// or returns -1 if not exists.
func (a *SortedIntArray) Search(value int) (index int) {
index, _ = a.binSearch(value, true)
return
}
// Binary search.
//
// 二分查找.
func (a *SortedIntArray) binSearch(value int, lock bool) (index int, result int) {
if len(a.array) == 0 {
return -1, -2
@ -354,11 +316,9 @@ func (a *SortedIntArray) binSearch(value int, lock bool) (index int, result int)
return mid, cmp
}
// Set unique mark to the array,
// SetUnique sets unique mark to the array,
// which means it does not contain any repeated items.
// It also do unique check, remove all repeated items.
//
// 设置是否允许数组唯一.
func (a *SortedIntArray) SetUnique(unique bool) *SortedIntArray {
oldUnique := a.unique.Val()
a.unique.Set(unique)
@ -368,9 +328,7 @@ func (a *SortedIntArray) SetUnique(unique bool) *SortedIntArray {
return a
}
// Do unique check, remove all repeated items.
//
// 清理数组中重复的元素项.
// Unique uniques the array, clear repeated items.
func (a *SortedIntArray) Unique() *SortedIntArray {
a.mu.Lock()
i := 0
@ -388,9 +346,7 @@ func (a *SortedIntArray) Unique() *SortedIntArray {
return a
}
// Return a new array, which is a copy of current array.
//
// 克隆当前数组,返回当前数组的一个拷贝。
// Clone returns a new array, which is a copy of current array.
func (a *SortedIntArray) Clone() (newArray *SortedIntArray) {
a.mu.RLock()
array := make([]int, len(a.array))
@ -399,9 +355,7 @@ func (a *SortedIntArray) Clone() (newArray *SortedIntArray) {
return NewSortedIntArrayFrom(array, !a.mu.IsSafe())
}
// Clear array.
//
// 清空数据数组。
// Clear deletes all items of current array.
func (a *SortedIntArray) Clear() *SortedIntArray {
a.mu.Lock()
if len(a.array) > 0 {
@ -411,9 +365,7 @@ func (a *SortedIntArray) Clear() *SortedIntArray {
return a
}
// Lock writing by callback function f.
//
// 使用自定义方法执行加锁修改操作。
// LockFunc locks writing by callback function <f>.
func (a *SortedIntArray) LockFunc(f func(array []int)) *SortedIntArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -421,9 +373,7 @@ func (a *SortedIntArray) LockFunc(f func(array []int)) *SortedIntArray {
return a
}
// Lock reading by callback function f.
//
// 使用自定义方法执行加锁读取操作。
// RLockFunc locks reading by callback function <f>.
func (a *SortedIntArray) RLockFunc(f func(array []int)) *SortedIntArray {
a.mu.RLock()
defer a.mu.RUnlock()
@ -431,11 +381,10 @@ func (a *SortedIntArray) RLockFunc(f func(array []int)) *SortedIntArray {
return a
}
// Merge two arrays. The parameter <array> can be any garray type or slice type.
// The difference between Merge and Add is Add supports only specified slice type,
// but Merge supports more variable types.
//
// 合并两个数组, 支持任意的garray数组类型及slice类型.
// Merge merges <array> into current array.
// The parameter <array> can be any garray or slice type.
// The difference between Merge and Append is Append supports only specified slice type,
// but Merge supports more parameter types.
func (a *SortedIntArray) Merge(array interface{}) *SortedIntArray {
switch v := array.(type) {
case *Array: a.Add(gconv.Ints(v.Slice())...)
@ -450,10 +399,9 @@ func (a *SortedIntArray) Merge(array interface{}) *SortedIntArray {
return a
}
// Chunks an array into arrays with size elements.
// Chunk splits an array into multiple arrays,
// the size of each array is determined by <size>.
// The last chunk may contain less than size elements.
//
// 将一个数组分割成多个数组其中每个数组的单元数目由size决定。最后一个数组的单元数目可能会少于size个。
func (a *SortedIntArray) Chunk(size int) [][]int {
if size < 1 {
return nil
@ -474,12 +422,9 @@ func (a *SortedIntArray) Chunk(size int) [][]int {
return n
}
// Extract a slice of the array(If in concurrent safe usage,
// it returns a copy of the slice; else a pointer).
// It returns the sequence of elements from the array array as specified
// by the offset and length parameters.
//
// 返回根据offset和size参数所指定的数组中的一段序列。
// SubSlice returns a slice of elements from the array as specified
// by the <offset> and <size> parameters.
// If in concurrent safe usage, it returns a copy of the slice; else a pointer.
func (a *SortedIntArray) SubSlice(offset, size int) []int {
a.mu.RLock()
defer a.mu.RUnlock()
@ -498,18 +443,14 @@ func (a *SortedIntArray) SubSlice(offset, size int) []int {
}
}
// Rand gets one random entry from array.
//
// 从数组中随机获得1个元素项(不删除)。
// Rand randomly returns one item from array(no deleting).
func (a *SortedIntArray) Rand() int {
a.mu.RLock()
defer a.mu.RUnlock()
return a.array[grand.Intn(len(a.array))]
}
// Rands gets one or more random entries from array(a copy).
//
// 从数组中随机拷贝size个元素项构成slice返回。
// Rands randomly returns <size> items from array(no deleting).
func (a *SortedIntArray) Rands(size int) []int {
a.mu.RLock()
defer a.mu.RUnlock()
@ -526,9 +467,7 @@ func (a *SortedIntArray) Rands(size int) []int {
return n
}
// Join array elements with a string.
//
// 使用glue字符串串连当前数组的元素项构造成新的字符串返回。
// Join joins array elements with a string <glue>.
func (a *SortedIntArray) Join(glue string) string {
a.mu.RLock()
defer a.mu.RUnlock()
@ -540,4 +479,22 @@ func (a *SortedIntArray) Join(glue string) string {
}
}
return buffer.String()
}
// CountValues counts the number of occurrences of all values in the array.
func (a *SortedIntArray) CountValues() map[int]int {
m := make(map[int]int)
a.mu.RLock()
defer a.mu.RUnlock()
for _, v := range a.array {
m[v]++
}
return m
}
// String returns current array as a string.
func (a *SortedIntArray) String() string {
a.mu.RLock()
defer a.mu.RUnlock()
return fmt.Sprint(a.array)
}

View File

@ -8,7 +8,8 @@ package garray
import (
"bytes"
"github.com/gogf/gf/g/container/gtype"
"fmt"
"github.com/gogf/gf/g/container/gtype"
"github.com/gogf/gf/g/internal/rwmutex"
"github.com/gogf/gf/g/util/gconv"
"github.com/gogf/gf/g/util/grand"
@ -16,36 +17,27 @@ import (
"sort"
)
// 默认按照从小到大进行排序
// It's using increasing order in default.
type SortedArray struct {
mu *rwmutex.RWMutex // 互斥锁
array []interface{} // 底层数组
unique *gtype.Bool // 是否要求不能重复
compareFunc func(v1, v2 interface{}) int // 比较函数,返回值 -1: v1 < v20: v1 == v21: v1 > v2
mu *rwmutex.RWMutex
array []interface{}
unique *gtype.Bool // Whether enable unique feature(false)
compareFunc func(v1, v2 interface{}) int // Comparison function(it returns -1: v1 < v2; 0: v1 == v2; 1: v1 > v2)
}
// Create an empty sorted array.
// The param <unsafe> used to specify whether using array with un-concurrent-safety,
// which is false in default, means concurrent-safe in default.
// NewSortedArray creates and returns an empty sorted array.
// The param <unsafe> used to specify whether using array with un-concurrent-safety, which is false in default.
// The param <compareFunc> used to compare values to sort in array,
// if it returns value < 0, means v1 < v2;
// if it returns value = 0, means v1 = v2;
// if it returns value > 0, means v1 > v2;
//
// 创建一个空的排序数组对象参数unsafe用于指定是否用于非并发安全场景默认为false表示并发安全。
// 参数compareFunc用于指定排序方法
// 如果返回值 < 0, 表示 v1 < v2;
// 如果返回值 = 0, 表示 v1 = v2;
// 如果返回值 > 0, 表示 v1 > v2;
func NewSortedArray(compareFunc func(v1, v2 interface{}) int, unsafe...bool) *SortedArray {
return NewSortedArraySize(0, compareFunc, unsafe...)
}
// Create a sorted array with given size and cap.
// NewSortedArraySize create and returns an sorted array with given size and cap.
// The param <unsafe> used to specify whether using array with un-concurrent-safety,
// which is false in default, means concurrent-safe in default.
//
// 创建一个指定大小的排序数组对象参数unsafe用于指定是否用于非并发安全场景默认为false表示并发安全。
// which is false in default.
func NewSortedArraySize(cap int, compareFunc func(v1, v2 interface{}) int, unsafe...bool) *SortedArray {
return &SortedArray{
mu : rwmutex.New(unsafe...),
@ -55,11 +47,9 @@ func NewSortedArraySize(cap int, compareFunc func(v1, v2 interface{}) int, unsaf
}
}
// Create an array with given slice <array>.
// NewSortedArrayFrom creates and returns an sorted array with given slice <array>.
// The param <unsafe> used to specify whether using array with un-concurrent-safety,
// which is false in default, means concurrent-safe in default.
//
// 通过给定的slice变量创建排序数组对象参数unsafe用于指定是否用于非并发安全场景默认为false表示并发安全。
// which is false in default.
func NewSortedArrayFrom(array []interface{}, compareFunc func(v1, v2 interface{}) int, unsafe...bool) *SortedArray {
a := NewSortedArraySize(0, compareFunc, unsafe...)
a.array = array
@ -69,11 +59,9 @@ func NewSortedArrayFrom(array []interface{}, compareFunc func(v1, v2 interface{}
return a
}
// Create an array from a copy of given slice <array>.
// NewSortedArrayFromCopy creates and returns an sorted array from a copy of given slice <array>.
// The param <unsafe> used to specify whether using array with un-concurrent-safety,
// which is false in default, means concurrent-safe in default.
//
// 通过给定的slice拷贝创建数组对象参数unsafe用于指定是否用于非并发安全场景默认为false表示并发安全。
// which is false in default.
func NewSortedArrayFromCopy(array []interface{}, unsafe...bool) *SortedArray {
newArray := make([]interface{}, len(array))
copy(newArray, array)
@ -83,9 +71,7 @@ func NewSortedArrayFromCopy(array []interface{}, unsafe...bool) *SortedArray {
}
}
// Set the underlying slice array with the given <array> param.
//
// 设置底层数组变量.
// SetArray sets the underlying slice array with the given <array>.
func (a *SortedArray) SetArray(array []interface{}) *SortedArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -96,9 +82,9 @@ func (a *SortedArray) SetArray(array []interface{}) *SortedArray {
return a
}
// Sort the array by comparing function.
//
// 将数组按照比较方法进行排序.
// Sort sorts the array in increasing order.
// The param <reverse> controls whether sort
// in increasing order(default) or decreasing order
func (a *SortedArray) Sort() *SortedArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -108,9 +94,7 @@ func (a *SortedArray) Sort() *SortedArray {
return a
}
// And values to sorted array, the array always keeps sorted.
//
// 添加数据项.
// Add adds one or multiple values to sorted array, the array always keeps sorted.
func (a *SortedArray) Add(values...interface{}) *SortedArray {
if len(values) == 0 {
return a
@ -126,7 +110,6 @@ func (a *SortedArray) Add(values...interface{}) *SortedArray {
a.array = append(a.array, value)
continue
}
// 加到指定索引后面
if cmp > 0 {
index++
}
@ -137,9 +120,8 @@ func (a *SortedArray) Add(values...interface{}) *SortedArray {
return a
}
// Get value by index.
//
// 获取指定索引的数据项, 调用方注意判断数组边界。
// Get returns the value of the specified index,
// the caller should notice the boundary of the array.
func (a *SortedArray) Get(index int) interface{} {
a.mu.RLock()
defer a.mu.RUnlock()
@ -147,13 +129,11 @@ func (a *SortedArray) Get(index int) interface{} {
return value
}
// Remove an item by index.
//
// 删除指定索引的数据项, 调用方注意判断数组边界。
// Remove removes an item by index.
func (a *SortedArray) Remove(index int) interface{} {
a.mu.Lock()
defer a.mu.Unlock()
// 边界删除判断,以提高删除效率
// Determine array boundaries when deleting to improve deletion efficiency.
if index == 0 {
value := a.array[0]
a.array = a.array[1 : ]
@ -163,15 +143,15 @@ func (a *SortedArray) Remove(index int) interface{} {
a.array = a.array[: index]
return value
}
// 如果非边界删除,会涉及到数组创建,那么删除的效率差一些
// If it is a non-boundary delete,
// it will involve the creation of an array,
// then the deletion is less efficient.
value := a.array[index]
a.array = append(a.array[ : index], a.array[index + 1 : ]...)
return value
}
// Push new items to the beginning of array.
//
// 将数据项添加到数组的最左端(索引为0)。
// PopLeft pops and returns an item from the beginning of array.
func (a *SortedArray) PopLeft() interface{} {
a.mu.Lock()
defer a.mu.Unlock()
@ -180,9 +160,7 @@ func (a *SortedArray) PopLeft() interface{} {
return value
}
// Push new items to the end of array.
//
// 将数据项添加到数组的最右端(索引为length - 1)。
// PopRight pops and returns an item from the end of array.
func (a *SortedArray) PopRight() interface{} {
a.mu.Lock()
defer a.mu.Unlock()
@ -192,16 +170,12 @@ func (a *SortedArray) PopRight() interface{} {
return value
}
// PopRand picks an random item out of array.
//
// 随机将一个数据项移出数组,并返回该数据项。
// PopRand randomly pops and return an item out of array.
func (a *SortedArray) PopRand() interface{} {
return a.Remove(grand.Intn(len(a.array)))
}
// PopRands picks <size> items out of array.
//
// 随机将size个数据项移出数组并返回该数据项。
// PopRands randomly pops and returns <size> items out of array.
func (a *SortedArray) PopRands(size int) []interface{} {
a.mu.Lock()
defer a.mu.Unlock()
@ -217,9 +191,7 @@ func (a *SortedArray) PopRands(size int) []interface{} {
return array
}
// Pop <size> items from the beginning of array.
//
// 将最左端(首部)的size个数据项移出数组并返回该数据项
// PopLefts pops and returns <size> items from the beginning of array.
func (a *SortedArray) PopLefts(size int) []interface{} {
a.mu.Lock()
defer a.mu.Unlock()
@ -232,9 +204,7 @@ func (a *SortedArray) PopLefts(size int) []interface{} {
return value
}
// Pop <size> items from the end of array.
//
// 将最右端(尾部)的size个数据项移出数组并返回该数据项
// PopRights pops and returns <size> items from the end of array.
func (a *SortedArray) PopRights(size int) []interface{} {
a.mu.Lock()
defer a.mu.Unlock()
@ -247,11 +217,9 @@ func (a *SortedArray) PopRights(size int) []interface{} {
return value
}
// Get items by range, returns array[start:end].
// Be aware that, if in concurrent-safe usage, it returns a copy of slice;
// Range picks and returns items by range, like array[start:end].
// Notice, if in concurrent-safe usage, it returns a copy of slice;
// else a pointer to the underlying data.
//
// 将最右端(尾部)的size个数据项移出数组并返回该数据项
func (a *SortedArray) Range(start, end int) []interface{} {
a.mu.RLock()
defer a.mu.RUnlock()
@ -277,9 +245,7 @@ func (a *SortedArray) Range(start, end int) []interface{} {
return array
}
// Calculate the sum of values in an array.
//
// 对数组中的元素项求和(将元素值转换为int类型后叠加)。
// Sum returns the sum of values in an array.
func (a *SortedArray) Sum() (sum int) {
a.mu.RLock()
defer a.mu.RUnlock()
@ -289,9 +255,7 @@ func (a *SortedArray) Sum() (sum int) {
return
}
// Get the length of array.
//
// 数组长度。
// Len returns the length of array.
func (a *SortedArray) Len() int {
a.mu.RLock()
length := len(a.array)
@ -299,11 +263,9 @@ func (a *SortedArray) Len() int {
return length
}
// Get the underlying data of array.
// Be aware that, if in concurrent-safe usage, it returns a copy of slice;
// Slice returns the underlying data of array.
// Notice, if in concurrent-safe usage, it returns a copy of slice;
// else a pointer to the underlying data.
//
// 返回原始数据数组.
func (a *SortedArray) Slice() []interface{} {
array := ([]interface{})(nil)
if a.mu.IsSafe() {
@ -317,25 +279,19 @@ func (a *SortedArray) Slice() []interface{} {
return array
}
// Check whether a value exists in the array.
//
// 查找指定数值是否存在。
// Contains checks whether a value exists in the array.
func (a *SortedArray) Contains(value interface{}) bool {
return a.Search(value) == 0
}
// Search array by <value>, returns the index of <value>, returns -1 if not exists.
//
// 查找指定数值的索引位置,返回索引位置,如果查找不到则返回-1。
// Search searches array by <value>, returns the index of <value>,
// or returns -1 if not exists.
func (a *SortedArray) Search(value interface{}) (index int) {
index, _ = a.binSearch(value, true)
return
}
// Binary search.
//
// 二分查找。查找指定数值的索引位置,返回索引位置(具体匹配位置或者最后对比位置)及查找结果
// 返回值: 最后比较位置, 比较结果。
func (a *SortedArray) binSearch(value interface{}, lock bool)(index int, result int) {
if len(a.array) == 0 {
return -1, -2
@ -361,11 +317,9 @@ func (a *SortedArray) binSearch(value interface{}, lock bool)(index int, result
return mid, cmp
}
// Set unique mark to the array,
// SetUnique sets unique mark to the array,
// which means it does not contain any repeated items.
// It also do unique check, remove all repeated items.
//
// 设置是否允许数组唯一.
func (a *SortedArray) SetUnique(unique bool) *SortedArray {
oldUnique := a.unique.Val()
a.unique.Set(unique)
@ -375,9 +329,7 @@ func (a *SortedArray) SetUnique(unique bool) *SortedArray {
return a
}
// Do unique check, remove all repeated items.
//
// 清理数组中重复的元素项.
// Unique uniques the array, clear repeated items.
func (a *SortedArray) Unique() *SortedArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -395,9 +347,7 @@ func (a *SortedArray) Unique() *SortedArray {
return a
}
// Return a new array, which is a copy of current array.
//
// 克隆当前数组,返回当前数组的一个拷贝。
// Clone returns a new array, which is a copy of current array.
func (a *SortedArray) Clone() (newArray *SortedArray) {
a.mu.RLock()
array := make([]interface{}, len(a.array))
@ -406,9 +356,7 @@ func (a *SortedArray) Clone() (newArray *SortedArray) {
return NewSortedArrayFrom(array, a.compareFunc, !a.mu.IsSafe())
}
// Clear array.
//
// 清空数据数组。
// Clear deletes all items of current array.
func (a *SortedArray) Clear() *SortedArray {
a.mu.Lock()
if len(a.array) > 0 {
@ -418,9 +366,7 @@ func (a *SortedArray) Clear() *SortedArray {
return a
}
// Lock writing by callback function f.
//
// 使用自定义方法执行加锁修改操作。
// LockFunc locks writing by callback function <f>.
func (a *SortedArray) LockFunc(f func(array []interface{})) *SortedArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -428,9 +374,7 @@ func (a *SortedArray) LockFunc(f func(array []interface{})) *SortedArray {
return a
}
// Lock reading by callback function f.
//
// 使用自定义方法执行加锁读取操作。
// RLockFunc locks reading by callback function <f>.
func (a *SortedArray) RLockFunc(f func(array []interface{})) *SortedArray {
a.mu.RLock()
defer a.mu.RUnlock()
@ -438,11 +382,10 @@ func (a *SortedArray) RLockFunc(f func(array []interface{})) *SortedArray {
return a
}
// Merge two arrays. The parameter <array> can be any garray type or slice type.
// The difference between Merge and Add is Add supports only specified slice type,
// but Merge supports more variable types.
//
// 合并两个数组, 支持任意的garray数组类型及slice类型.
// Merge merges <array> into current array.
// The parameter <array> can be any garray or slice type.
// The difference between Merge and Append is Append supports only specified slice type,
// but Merge supports more parameter types.
func (a *SortedArray) Merge(array interface{}) *SortedArray {
switch v := array.(type) {
case *Array: a.Add(gconv.Interfaces(v.Slice())...)
@ -457,10 +400,9 @@ func (a *SortedArray) Merge(array interface{}) *SortedArray {
return a
}
// Chunks an array into arrays with size elements.
// Chunk splits an array into multiple arrays,
// the size of each array is determined by <size>.
// The last chunk may contain less than size elements.
//
// 将一个数组分割成多个数组其中每个数组的单元数目由size决定。最后一个数组的单元数目可能会少于size个。
func (a *SortedArray) Chunk(size int) [][]interface{} {
if size < 1 {
return nil
@ -481,12 +423,9 @@ func (a *SortedArray) Chunk(size int) [][]interface{} {
return n
}
// Extract a slice of the array(If in concurrent safe usage,
// it returns a copy of the slice; else a pointer).
// It returns the sequence of elements from the array array as specified
// by the offset and length parameters.
//
// 返回根据offset和size参数所指定的数组中的一段序列。
// SubSlice returns a slice of elements from the array as specified
// by the <offset> and <size> parameters.
// If in concurrent safe usage, it returns a copy of the slice; else a pointer.
func (a *SortedArray) SubSlice(offset, size int) []interface{} {
a.mu.RLock()
defer a.mu.RUnlock()
@ -505,18 +444,14 @@ func (a *SortedArray) SubSlice(offset, size int) []interface{} {
}
}
// Rand gets one random entry from array.
//
// 从数组中随机获得1个元素项(不删除)。
// Rand randomly returns one item from array(no deleting).
func (a *SortedArray) Rand() interface{} {
a.mu.RLock()
defer a.mu.RUnlock()
return a.array[grand.Intn(len(a.array))]
}
// Rands gets one or more random entries from array(a copy).
//
// 从数组中随机拷贝size个元素项构成slice返回。
// Rands randomly returns <size> items from array(no deleting).
func (a *SortedArray) Rands(size int) []interface{} {
a.mu.RLock()
defer a.mu.RUnlock()
@ -533,9 +468,7 @@ func (a *SortedArray) Rands(size int) []interface{} {
return n
}
// Join array elements with a string.
//
// 使用glue字符串串连当前数组的元素项构造成新的字符串返回。
// Join joins array elements with a string <glue>.
func (a *SortedArray) Join(glue string) string {
a.mu.RLock()
defer a.mu.RUnlock()
@ -547,4 +480,22 @@ func (a *SortedArray) Join(glue string) string {
}
}
return buffer.String()
}
// CountValues counts the number of occurrences of all values in the array.
func (a *SortedArray) CountValues() map[interface{}]int {
m := make(map[interface{}]int)
a.mu.RLock()
defer a.mu.RUnlock()
for _, v := range a.array {
m[v]++
}
return m
}
// String returns current array as a string.
func (a *SortedArray) String() string {
a.mu.RLock()
defer a.mu.RUnlock()
return fmt.Sprint(a.array)
}

View File

@ -8,7 +8,8 @@ package garray
import (
"bytes"
"github.com/gogf/gf/g/container/gtype"
"fmt"
"github.com/gogf/gf/g/container/gtype"
"github.com/gogf/gf/g/internal/rwmutex"
"github.com/gogf/gf/g/util/gconv"
"github.com/gogf/gf/g/util/grand"
@ -17,28 +18,24 @@ import (
"strings"
)
// 默认按照从小到大进行排序
// It's using increasing order in default.
type SortedStringArray struct {
mu *rwmutex.RWMutex // 互斥锁
array []string // 底层数组
unique *gtype.Bool // 是否要求不能重复
compareFunc func(v1, v2 string) int // 比较函数,返回值 -1: v1 < v20: v1 == v21: v1 > v2
mu *rwmutex.RWMutex
array []string
unique *gtype.Bool // Whether enable unique feature(false)
compareFunc func(v1, v2 string) int // Comparison function(it returns -1: v1 < v2; 0: v1 == v2; 1: v1 > v2)
}
// Create an empty sorted array.
// The param <unsafe> used to specify whether using array with un-concurrent-safety,
// which is false in default, means concurrent-safe in default.
//
// 创建一个空的排序数组对象参数unsafe用于指定是否用于非并发安全场景默认为false表示并发安全。
// NewSortedStringArray creates and returns an empty sorted array.
// The param <unsafe> used to specify whether using array in un-concurrent-safety,
// which is false in default.
func NewSortedStringArray(unsafe...bool) *SortedStringArray {
return NewSortedStringArraySize(0, unsafe...)
}
// Create a sorted array with given size and cap.
// NewSortedStringArraySize create and returns an sorted array with given size and cap.
// The param <unsafe> used to specify whether using array with un-concurrent-safety,
// which is false in default, means concurrent-safe in default.
//
// 创建一个指定大小的排序数组对象参数unsafe用于指定是否用于非并发安全场景默认为false表示并发安全。
// which is false in default.
func NewSortedStringArraySize(cap int, unsafe...bool) *SortedStringArray {
return &SortedStringArray {
mu : rwmutex.New(unsafe...),
@ -50,11 +47,9 @@ func NewSortedStringArraySize(cap int, unsafe...bool) *SortedStringArray {
}
}
// Create an array with given slice <array>.
// NewSortedStringArrayFrom creates and returns an sorted array with given slice <array>.
// The param <unsafe> used to specify whether using array with un-concurrent-safety,
// which is false in default, means concurrent-safe in default.
//
// 通过给定的slice变量创建排序数组对象参数unsafe用于指定是否用于非并发安全场景默认为false表示并发安全。
// which is false in default.
func NewSortedStringArrayFrom(array []string, unsafe...bool) *SortedStringArray {
a := NewSortedStringArraySize(0, unsafe...)
a.array = array
@ -62,11 +57,9 @@ func NewSortedStringArrayFrom(array []string, unsafe...bool) *SortedStringArray
return a
}
// Create an array from a copy of given slice <array>.
// NewSortedStringArrayFromCopy creates and returns an sorted array from a copy of given slice <array>.
// The param <unsafe> used to specify whether using array with un-concurrent-safety,
// which is false in default, means concurrent-safe in default.
//
// 通过给定的slice拷贝创建数组对象参数unsafe用于指定是否用于非并发安全场景默认为false表示并发安全。
// which is false in default.
func NewSortedStringArrayFromCopy(array []string, unsafe...bool) *SortedStringArray {
newArray := make([]string, len(array))
copy(newArray, array)
@ -76,9 +69,7 @@ func NewSortedStringArrayFromCopy(array []string, unsafe...bool) *SortedStringAr
}
}
// Set the underlying slice array with the given <array> param.
//
// 设置底层数组变量.
// SetArray sets the underlying slice array with the given <array>.
func (a *SortedStringArray) SetArray(array []string) *SortedStringArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -87,9 +78,9 @@ func (a *SortedStringArray) SetArray(array []string) *SortedStringArray {
return a
}
// Sort the array in increasing order.
//
// 将数组排序(默认从低到高).
// Sort sorts the array in increasing order.
// The param <reverse> controls whether sort
// in increasing order(default) or decreasing order.
func (a *SortedStringArray) Sort() *SortedStringArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -97,9 +88,7 @@ func (a *SortedStringArray) Sort() *SortedStringArray {
return a
}
// And values to sorted array, the array always keeps sorted.
//
// 添加数据项.
// Add adds one or multiple values to sorted array, the array always keeps sorted.
func (a *SortedStringArray) Add(values...string) *SortedStringArray {
if len(values) == 0 {
return a
@ -115,7 +104,6 @@ func (a *SortedStringArray) Add(values...string) *SortedStringArray {
a.array = append(a.array, value)
continue
}
// 加到指定索引后面
if cmp > 0 {
index++
}
@ -126,9 +114,8 @@ func (a *SortedStringArray) Add(values...string) *SortedStringArray {
return a
}
// Get value by index.
//
// 获取指定索引的数据项, 调用方注意判断数组边界。
// Get returns the value of the specified index,
// the caller should notice the boundary of the array.
func (a *SortedStringArray) Get(index int) string {
a.mu.RLock()
defer a.mu.RUnlock()
@ -136,13 +123,11 @@ func (a *SortedStringArray) Get(index int) string {
return value
}
// Remove an item by index.
//
// 删除指定索引的数据项, 调用方注意判断数组边界。
// Remove removes an item by index.
func (a *SortedStringArray) Remove(index int) string {
a.mu.Lock()
defer a.mu.Unlock()
// 边界删除判断,以提高删除效率
// Determine array boundaries when deleting to improve deletion efficiency.
if index == 0 {
value := a.array[0]
a.array = a.array[1 : ]
@ -152,15 +137,15 @@ func (a *SortedStringArray) Remove(index int) string {
a.array = a.array[: index]
return value
}
// 如果非边界删除,会涉及到数组创建,那么删除的效率差一些
// If it is a non-boundary delete,
// it will involve the creation of an array,
// then the deletion is less efficient.
value := a.array[index]
a.array = append(a.array[ : index], a.array[index + 1 : ]...)
return value
}
// Push new items to the beginning of array.
//
// 将数据项添加到数组的最左端(索引为0)。
// PopLeft pops and returns an item from the beginning of array.
func (a *SortedStringArray) PopLeft() string {
a.mu.Lock()
defer a.mu.Unlock()
@ -169,9 +154,7 @@ func (a *SortedStringArray) PopLeft() string {
return value
}
// Push new items to the end of array.
//
// 将数据项添加到数组的最右端(索引为length - 1)。
// PopRight pops and returns an item from the end of array.
func (a *SortedStringArray) PopRight() string {
a.mu.Lock()
defer a.mu.Unlock()
@ -181,16 +164,12 @@ func (a *SortedStringArray) PopRight() string {
return value
}
// PopRand picks an random item out of array.
//
// 随机将一个数据项移出数组,并返回该数据项。
// PopRand randomly pops and return an item out of array.
func (a *SortedStringArray) PopRand() string {
return a.Remove(grand.Intn(len(a.array)))
}
// PopRands picks <size> items out of array.
//
// 随机将size个数据项移出数组并返回该数据项。
// PopRands randomly pops and returns <size> items out of array.
func (a *SortedStringArray) PopRands(size int) []string {
a.mu.Lock()
defer a.mu.Unlock()
@ -206,9 +185,7 @@ func (a *SortedStringArray) PopRands(size int) []string {
return array
}
// Pop <size> items from the beginning of array.
//
// 将最左端(首部)的size个数据项移出数组并返回该数据项
// PopLefts pops and returns <size> items from the beginning of array.
func (a *SortedStringArray) PopLefts(size int) []string {
a.mu.Lock()
defer a.mu.Unlock()
@ -221,9 +198,7 @@ func (a *SortedStringArray) PopLefts(size int) []string {
return value
}
// Pop <size> items from the end of array.
//
// 将最右端(尾部)的size个数据项移出数组并返回该数据项
// PopRights pops and returns <size> items from the end of array.
func (a *SortedStringArray) PopRights(size int) []string {
a.mu.Lock()
defer a.mu.Unlock()
@ -236,11 +211,9 @@ func (a *SortedStringArray) PopRights(size int) []string {
return value
}
// Get items by range, returns array[start:end].
// Be aware that, if in concurrent-safe usage, it returns a copy of slice;
// Range picks and returns items by range, like array[start:end].
// Notice, if in concurrent-safe usage, it returns a copy of slice;
// else a pointer to the underlying data.
//
// 将最右端(尾部)的size个数据项移出数组并返回该数据项
func (a *SortedStringArray) Range(start, end int) []string {
a.mu.RLock()
defer a.mu.RUnlock()
@ -266,9 +239,7 @@ func (a *SortedStringArray) Range(start, end int) []string {
return array
}
// Calculate the sum of values in an array.
//
// 对数组中的元素项求和(将元素值转换为int类型后叠加)。
// Sum returns the sum of values in an array.
func (a *SortedStringArray) Sum() (sum int) {
a.mu.RLock()
defer a.mu.RUnlock()
@ -278,9 +249,7 @@ func (a *SortedStringArray) Sum() (sum int) {
return
}
// Get the length of array.
//
// 数组长度。
// Len returns the length of array.
func (a *SortedStringArray) Len() int {
a.mu.RLock()
length := len(a.array)
@ -288,11 +257,9 @@ func (a *SortedStringArray) Len() int {
return length
}
// Get the underlying data of array.
// Be aware that, if in concurrent-safe usage, it returns a copy of slice;
// Slice returns the underlying data of array.
// Notice, if in concurrent-safe usage, it returns a copy of slice;
// else a pointer to the underlying data.
//
// 返回原始数据数组.
func (a *SortedStringArray) Slice() []string {
array := ([]string)(nil)
if a.mu.IsSafe() {
@ -306,24 +273,19 @@ func (a *SortedStringArray) Slice() []string {
return array
}
// Check whether a value exists in the array.
//
// 查找指定数值是否存在。
// Contains checks whether a value exists in the array.
func (a *SortedStringArray) Contains(value string) bool {
return a.Search(value) == 0
}
// Search array by <value>, returns the index of <value>, returns -1 if not exists.
//
// 查找指定数值的索引位置,返回索引位置,如果查找不到则返回-1。
// Search searches array by <value>, returns the index of <value>,
// or returns -1 if not exists.
func (a *SortedStringArray) Search(value string) (index int) {
index, _ = a.binSearch(value, true)
return
}
// Binary search.
//
// 二分查找.
func (a *SortedStringArray) binSearch(value string, lock bool) (index int, result int) {
if len(a.array) == 0 {
return -1, -2
@ -349,11 +311,9 @@ func (a *SortedStringArray) binSearch(value string, lock bool) (index int, resul
return mid, cmp
}
// Set unique mark to the array,
// SetUnique sets unique mark to the array,
// which means it does not contain any repeated items.
// It also do unique check, remove all repeated items.
//
// 设置是否允许数组唯一.
func (a *SortedStringArray) SetUnique(unique bool) *SortedStringArray {
oldUnique := a.unique.Val()
a.unique.Set(unique)
@ -363,9 +323,7 @@ func (a *SortedStringArray) SetUnique(unique bool) *SortedStringArray {
return a
}
// Do unique check, remove all repeated items.
//
// 清理数组中重复的元素项.
// Unique uniques the array, clear repeated items.
func (a *SortedStringArray) Unique() *SortedStringArray {
a.mu.Lock()
i := 0
@ -383,9 +341,7 @@ func (a *SortedStringArray) Unique() *SortedStringArray {
return a
}
// Return a new array, which is a copy of current array.
//
// 克隆当前数组,返回当前数组的一个拷贝。
// Clone returns a new array, which is a copy of current array.
func (a *SortedStringArray) Clone() (newArray *SortedStringArray) {
a.mu.RLock()
array := make([]string, len(a.array))
@ -394,9 +350,7 @@ func (a *SortedStringArray) Clone() (newArray *SortedStringArray) {
return NewSortedStringArrayFrom(array, !a.mu.IsSafe())
}
// Clear array.
//
// 清空数据数组。
// Clear deletes all items of current array.
func (a *SortedStringArray) Clear() *SortedStringArray {
a.mu.Lock()
if len(a.array) > 0 {
@ -406,9 +360,7 @@ func (a *SortedStringArray) Clear() *SortedStringArray {
return a
}
// Lock writing by callback function f.
//
// 使用自定义方法执行加锁修改操作。
// LockFunc locks writing by callback function <f>.
func (a *SortedStringArray) LockFunc(f func(array []string)) *SortedStringArray {
a.mu.Lock()
defer a.mu.Unlock()
@ -416,9 +368,7 @@ func (a *SortedStringArray) LockFunc(f func(array []string)) *SortedStringArray
return a
}
// Lock reading by callback function f.
//
// 使用自定义方法执行加锁读取操作。
// RLockFunc locks reading by callback function <f>.
func (a *SortedStringArray) RLockFunc(f func(array []string)) *SortedStringArray {
a.mu.RLock()
defer a.mu.RUnlock()
@ -426,11 +376,10 @@ func (a *SortedStringArray) RLockFunc(f func(array []string)) *SortedStringArray
return a
}
// Merge two arrays. The parameter <array> can be any garray type or slice type.
// The difference between Merge and Add is Add supports only specified slice type,
// but Merge supports more variable types.
//
// 合并两个数组, 支持任意的garray数组类型及slice类型.
// Merge merges <array> into current array.
// The parameter <array> can be any garray or slice type.
// The difference between Merge and Append is Append supports only specified slice type,
// but Merge supports more parameter types.
func (a *SortedStringArray) Merge(array interface{}) *SortedStringArray {
switch v := array.(type) {
case *Array: a.Add(gconv.Strings(v.Slice())...)
@ -445,10 +394,9 @@ func (a *SortedStringArray) Merge(array interface{}) *SortedStringArray {
return a
}
// Chunks an array into arrays with size elements.
// Chunk splits an array into multiple arrays,
// the size of each array is determined by <size>.
// The last chunk may contain less than size elements.
//
// 将一个数组分割成多个数组其中每个数组的单元数目由size决定。最后一个数组的单元数目可能会少于size个。
func (a *SortedStringArray) Chunk(size int) [][]string {
if size < 1 {
return nil
@ -469,12 +417,9 @@ func (a *SortedStringArray) Chunk(size int) [][]string {
return n
}
// Extract a slice of the array(If in concurrent safe usage,
// it returns a copy of the slice; else a pointer).
// It returns the sequence of elements from the array array as specified
// by the offset and length parameters.
//
// 返回根据offset和size参数所指定的数组中的一段序列。
// SubSlice returns a slice of elements from the array as specified
// by the <offset> and <size> parameters.
// If in concurrent safe usage, it returns a copy of the slice; else a pointer.
func (a *SortedStringArray) SubSlice(offset, size int) []string {
a.mu.RLock()
defer a.mu.RUnlock()
@ -493,18 +438,14 @@ func (a *SortedStringArray) SubSlice(offset, size int) []string {
}
}
// Rand gets one random entry from array.
//
// 从数组中随机获得1个元素项(不删除)。
// Rand randomly returns one item from array(no deleting).
func (a *SortedStringArray) Rand() string {
a.mu.RLock()
defer a.mu.RUnlock()
return a.array[grand.Intn(len(a.array))]
}
// Rands gets one or more random entries from array(a copy).
//
// 从数组中随机拷贝size个元素项构成slice返回。
// Rands randomly returns <size> items from array(no deleting).
func (a *SortedStringArray) Rands(size int) []string {
a.mu.RLock()
defer a.mu.RUnlock()
@ -521,9 +462,7 @@ func (a *SortedStringArray) Rands(size int) []string {
return n
}
// Join array elements with a string.
//
// 使用glue字符串串连当前数组的元素项构造成新的字符串返回。
// Join joins array elements with a string <glue>.
func (a *SortedStringArray) Join(glue string) string {
a.mu.RLock()
defer a.mu.RUnlock()
@ -535,4 +474,22 @@ func (a *SortedStringArray) Join(glue string) string {
}
}
return buffer.String()
}
// CountValues counts the number of occurrences of all values in the array.
func (a *SortedStringArray) CountValues() map[string]int {
m := make(map[string]int)
a.mu.RLock()
defer a.mu.RUnlock()
for _, v := range a.array {
m[v]++
}
return m
}
// String returns current array as a string.
func (a *SortedStringArray) String() string {
a.mu.RLock()
defer a.mu.RUnlock()
return fmt.Sprint(a.array)
}

View File

@ -289,6 +289,10 @@ func (l *List) RemoveAll() {
l.mu.Unlock()
}
func (l *List) Clear() {
l.RemoveAll()
}
// 读锁操作
func (l *List) RLockFunc(f func(list *list.List)) {
l.mu.RLock()

View File

@ -51,18 +51,54 @@ func Test_IntBoolMap_Set_Fun(t *testing.T) {
gtest.Assert(m.Get(1), true)
gtest.Assert(m.Get(2), true)
gtest.Assert(m.SetIfNotExistFunc(1, getBool), false)
gtest.Assert(m.SetIfNotExistFunc(4, getBool), true)
gtest.Assert(m.SetIfNotExistFuncLock(2, getBool), false)
gtest.Assert(m.SetIfNotExistFuncLock(3, getBool), true)
}
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_Iterator(t *testing.T){
expect := map[int]bool{1: true, 2: false}
m := gmap.NewIntBoolMapFrom(expect)
m.Iterator(func(k int, v bool) bool {
gtest.Assert(expect[k], v)
return true
})
// 断言返回值对遍历控制
i := 0
j := 0
m.Iterator(func(k int, v bool) bool {
i++
return true
})
m.Iterator(func(k int, v bool) bool {
j++
return false
})
gtest.Assert(i, 2)
gtest.Assert(j, 1)
}
func Test_IntBoolMap_Lock(t *testing.T){
expect := map[int]bool{1: true, 2: false}
m := gmap.NewIntBoolMapFrom(expect)
m.LockFunc(func(m map[int]bool) {
gtest.Assert(m, expect)
})
m.RLockFunc(func(m map[int]bool) {
gtest.Assert(m, expect)
})
}
func Test_IntBoolMap_Clone(t *testing.T) {
//clone 方法是深克隆

View File

@ -55,7 +55,11 @@ func Test_IntIntMap_Set_Fun(t *testing.T) {
gtest.Assert(m.Get(1), 123)
gtest.Assert(m.Get(2), 123)
gtest.Assert(m.SetIfNotExistFunc(1, getInt), false)
gtest.Assert(m.SetIfNotExistFunc(3, getInt), true)
gtest.Assert(m.SetIfNotExistFuncLock(2, getInt), false)
gtest.Assert(m.SetIfNotExistFuncLock(4, getInt), true)
}
func Test_IntIntMap_Batch(t *testing.T) {
@ -68,6 +72,39 @@ func Test_IntIntMap_Batch(t *testing.T) {
gtest.Assert(m.Map(), map[int]int{3: 3})
}
func Test_IntIntMap_Iterator(t *testing.T){
expect := map[int]int{1: 1, 2: 2}
m := gmap.NewIntIntMapFrom(expect)
m.Iterator(func(k int, v int) bool {
gtest.Assert(expect[k], v)
return true
})
// 断言返回值对遍历控制
i := 0
j := 0
m.Iterator(func(k int, v int) bool {
i++
return true
})
m.Iterator(func(k int, v int) bool {
j++
return false
})
gtest.Assert(i, 2)
gtest.Assert(j, 1)
}
func Test_IntIntMap_Lock(t *testing.T){
expect := map[int]int{1: 1, 2: 2}
m := gmap.NewIntIntMapFrom(expect)
m.LockFunc(func(m map[int]int) {
gtest.Assert(m, expect)
})
m.RLockFunc(func(m map[int]int) {
gtest.Assert(m, expect)
})
}
func Test_IntIntMap_Clone(t *testing.T) {
//clone 方法是深克隆
m := gmap.NewIntIntMapFrom(map[int]int{1: 1, 2: 2})

View File

@ -54,20 +54,57 @@ func Test_IntInterfaceMap_Set_Fun(t *testing.T) {
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.SetIfNotExistFunc(3, getInterface), true)
gtest.Assert(m.SetIfNotExistFuncLock(2, getInterface), false)
gtest.Assert(m.SetIfNotExistFuncLock(4, getInterface), true)
}
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_Iterator(t *testing.T){
expect := map[int]interface{}{1: 1, 2: "2"}
m := gmap.NewIntInterfaceMapFrom(expect)
m.Iterator(func(k int, v interface{}) bool {
gtest.Assert(expect[k], v)
return true
})
// 断言返回值对遍历控制
i := 0
j := 0
m.Iterator(func(k int, v interface{}) bool {
i++
return true
})
m.Iterator(func(k int, v interface{}) bool {
j++
return false
})
gtest.Assert(i, "2")
gtest.Assert(j, 1)
}
func Test_IntInterfaceMap_Lock(t *testing.T){
expect := map[int]interface{}{1: 1, 2: "2"}
m := gmap.NewIntInterfaceMapFrom(expect)
m.LockFunc(func(m map[int]interface{}) {
gtest.Assert(m, expect)
})
m.RLockFunc(func(m map[int]interface{}) {
gtest.Assert(m, expect)
})
}
func Test_IntInterfaceMap_Clone(t *testing.T) {
//clone 方法是深克隆
m := gmap.NewIntInterfaceMapFrom(map[int]interface{}{1: 1, 2: "2"})

View File

@ -60,19 +60,55 @@ func Test_IntStringMap_Set_Fun(t *testing.T) {
gtest.Assert(m.Get(1), "z")
gtest.Assert(m.Get(2), "z")
gtest.Assert(m.SetIfNotExistFunc(1, getString), false)
gtest.Assert(m.SetIfNotExistFunc(3, getString), true)
gtest.Assert(m.SetIfNotExistFuncLock(2, getString), false)
gtest.Assert(m.SetIfNotExistFuncLock(4, getString), true)
}
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_Iterator(t *testing.T){
expect := map[int]string{1: "a", 2: "b"}
m := gmap.NewIntStringMapFrom(expect)
m.Iterator(func(k int, v string) bool {
gtest.Assert(expect[k], v)
return true
})
// 断言返回值对遍历控制
i := 0
j := 0
m.Iterator(func(k int, v string) bool {
i++
return true
})
m.Iterator(func(k int, v string) bool {
j++
return false
})
gtest.Assert(i, 2)
gtest.Assert(j, 1)
}
func Test_IntStringMap_Lock(t *testing.T){
expect := map[int]string{1: "a", 2: "b", 3: "c"}
m := gmap.NewIntStringMapFrom(expect)
m.LockFunc(func(m map[int]string) {
gtest.Assert(m, expect)
})
m.RLockFunc(func(m map[int]string) {
gtest.Assert(m, expect)
})
}
func Test_IntStringMap_Clone(t *testing.T) {
//clone 方法是深克隆
m := gmap.NewIntStringMapFrom(map[int]string{1: "a", 2: "b", 3: "c"})

View File

@ -12,6 +12,7 @@ func getValue() interface{} {
func callBack(k interface{}, v interface{}) bool {
return true
}
func Test_Map_Basic(t *testing.T) {
gtest.Case(t, func() {
m := gmap.New()
@ -63,11 +64,44 @@ func Test_Map_Set_Fun(t *testing.T) {
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_Iterator(t *testing.T){
expect :=map[interface{}]interface{}{1: 1, "key1": "val1"}
m := gmap.NewFrom(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_Map_Lock(t *testing.T){
expect :=map[interface{}]interface{}{1: 1, "key1": "val1"}
m := gmap.NewFrom(expect)
m.LockFunc(func(m map[interface{}]interface{}) {
gtest.Assert(m, expect)
})
m.RLockFunc(func(m map[interface{}]interface{}) {
gtest.Assert(m, expect)
})
}
func Test_Map_Clone(t *testing.T) {
//clone 方法是深克隆

View File

@ -6,8 +6,7 @@ import (
"testing"
)
func StringBoolCallBack( string, bool) bool {
func StringBoolCallBack(string, bool) bool {
return true
}
func Test_StringBoolMap_Basic(t *testing.T) {
@ -49,19 +48,57 @@ func Test_StringBoolMap_Set_Fun(t *testing.T) {
gtest.Assert(m.Get("a"), true)
gtest.Assert(m.Get("b"), true)
gtest.Assert(m.SetIfNotExistFunc("a", getBool), false)
gtest.Assert(m.SetIfNotExistFunc("c", getBool), true)
gtest.Assert(m.SetIfNotExistFuncLock("b", getBool), false)
gtest.Assert(m.SetIfNotExistFuncLock("d", getBool), true)
}
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_Iterator(t *testing.T) {
expect := map[string]bool{"a": true, "b": false}
m := gmap.NewStringBoolMapFrom(expect)
m.Iterator(func(k string, v bool) bool {
gtest.Assert(expect[k], v)
return true
})
// 断言返回值对遍历控制
i := 0
j := 0
m.Iterator(func(k string, v bool) bool {
i++
return true
})
m.Iterator(func(k string, v bool) bool {
j++
return false
})
gtest.Assert(i, 2)
gtest.Assert(j, 1)
}
func Test_StringBoolMap_Lock(t *testing.T) {
expect := map[string]bool{"a": true, "b": false}
m := gmap.NewStringBoolMapFrom(expect)
m.LockFunc(func(m map[string]bool) {
gtest.Assert(m, expect)
})
m.RLockFunc(func(m map[string]bool) {
gtest.Assert(m, expect)
})
}
func Test_StringBoolMap_Clone(t *testing.T) {
//clone 方法是深克隆
m := gmap.NewStringBoolMapFrom(map[string]bool{"a": true, "b": false})

View File

@ -55,18 +55,55 @@ func Test_StringIntMap_Set_Fun(t *testing.T) {
gtest.Assert(m.Get("a"), 123)
gtest.Assert(m.Get("b"), 123)
gtest.Assert(m.SetIfNotExistFunc("a", getInt), false)
gtest.Assert(m.SetIfNotExistFunc("c", getInt), true)
gtest.Assert(m.SetIfNotExistFuncLock("b", getInt), false)
gtest.Assert(m.SetIfNotExistFuncLock("d", getInt), true)
}
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_Iterator(t *testing.T) {
expect := map[string]int{"a": 1, "b": 2}
m := gmap.NewStringIntMapFrom(expect)
m.Iterator(func(k string, v int) bool {
gtest.Assert(expect[k], v)
return true
})
// 断言返回值对遍历控制
i := 0
j := 0
m.Iterator(func(k string, v int) bool {
i++
return true
})
m.Iterator(func(k string, v int) bool {
j++
return false
})
gtest.Assert(i, 2)
gtest.Assert(j, 1)
}
func Test_StringIntMap_Lock(t *testing.T) {
expect := map[string]int{"a": 1, "b": 2}
m := gmap.NewStringIntMapFrom(expect)
m.LockFunc(func(m map[string]int) {
gtest.Assert(m, expect)
})
m.RLockFunc(func(m map[string]int) {
gtest.Assert(m, expect)
})
}
func Test_StringIntMap_Clone(t *testing.T) {
//clone 方法是深克隆

View File

@ -53,19 +53,55 @@ func Test_StringInterfaceMap_Set_Fun(t *testing.T) {
gtest.Assert(m.Get("a"), 123)
gtest.Assert(m.Get("b"), 123)
gtest.Assert(m.SetIfNotExistFunc("a", getInterface), false)
gtest.Assert(m.SetIfNotExistFunc("c", getInterface), true)
gtest.Assert(m.SetIfNotExistFuncLock("b", getInterface), false)
gtest.Assert(m.SetIfNotExistFuncLock("d", getInterface), true)
}
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_Iterator(t *testing.T) {
expect := map[string]interface{}{"a": true, "b": false}
m := gmap.NewStringInterfaceMapFrom(expect)
m.Iterator(func(k string, v interface{}) bool {
gtest.Assert(expect[k], v)
return true
})
// 断言返回值对遍历控制
i := 0
j := 0
m.Iterator(func(k string, v interface{}) bool {
i++
return true
})
m.Iterator(func(k string, v interface{}) bool {
j++
return false
})
gtest.Assert(i, 2)
gtest.Assert(j, 1)
}
func Test_StringInterfaceMap_Lock(t *testing.T) {
expect := map[string]interface{}{"a": true, "b": false}
m := gmap.NewStringInterfaceMapFrom(expect)
m.LockFunc(func(m map[string]interface{}) {
gtest.Assert(m, expect)
})
m.RLockFunc(func(m map[string]interface{}) {
gtest.Assert(m, expect)
})
}
func Test_StringInterfaceMap_Clone(t *testing.T) {
//clone 方法是深克隆
m := gmap.NewStringInterfaceMapFrom(map[string]interface{}{"a": 1, "b": "2"})

View File

@ -54,19 +54,54 @@ func Test_StringStringMap_Set_Fun(t *testing.T) {
gtest.Assert(m.Get("a"), "z")
gtest.Assert(m.Get("b"), "z")
gtest.Assert(m.SetIfNotExistFunc("a", getString), false)
gtest.Assert(m.SetIfNotExistFunc("c", getString), true)
gtest.Assert(m.SetIfNotExistFuncLock("b", getString), false)
gtest.Assert(m.SetIfNotExistFuncLock("d", getString), true)
}
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_Iterator(t *testing.T) {
expect := map[string]string{"a": "a", "b": "b"}
m := gmap.NewStringStringMapFrom(expect)
m.Iterator(func(k string, v string) bool {
gtest.Assert(expect[k], v)
return true
})
// 断言返回值对遍历控制
i := 0
j := 0
m.Iterator(func(k string, v string) bool {
i++
return true
})
m.Iterator(func(k string, v string) bool {
j++
return false
})
gtest.Assert(i, 2)
gtest.Assert(j, 1)
}
func Test_StringStringMap_Lock(t *testing.T) {
expect := map[string]string{"a": "a", "b": "b"}
m := gmap.NewStringStringMapFrom(expect)
m.LockFunc(func(m map[string]string) {
gtest.Assert(m, expect)
})
m.RLockFunc(func(m map[string]string) {
gtest.Assert(m, expect)
})
}
func Test_StringStringMap_Clone(t *testing.T) {
//clone 方法是深克隆
m := gmap.NewStringStringMapFrom(map[string]string{"a": "a", "b": "b", "c": "c"})

View File

@ -4,14 +4,18 @@
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
// Package gqueue provides a dynamic/static concurrent-safe(alternative) queue.
// Package gqueue provides a dynamic/static concurrent-safe queue.
//
// 并发安全动态队列.
// Features:
//
// 1. FIFO queue(data -> list -> chan);
//
// 2. Fast creation and initialization;
//
// 3. Support dynamic queue size(unlimited queue size);
//
// 4. Blocking when reading data from queue;
//
// 特点:
// 1. 动态队列初始化速度快;
// 2. 动态的队列大小(不限大小)
// 3. 取数据时如果队列为空那么会阻塞等待;
package gqueue
import (
@ -19,27 +23,21 @@ import (
"math"
)
// 1、这是一个先进先出的队列(chan <-- list)
//
// 2、当创建Queue对象时限定大小那么等同于一个同步的chan并发安全队列
//
// 3、不限制大小时list链表用以存储数据临时chan负责为客户端读取数据当从chan获取数据时list往chan中不停补充数据
//
// 4、由于功能主体是chan那么操作仍然像chan那样具有阻塞效果
type Queue struct {
limit int // 队列限制大小
list *glist.List // 底层数据链表
events chan struct{} // 写入事件通知
closed chan struct{} // 队列关闭通知
C chan interface{} // 队列数据读取
limit int // Limit for queue size.
list *glist.List // Underlying list structure for data maintaining.
events chan struct{} // Events for data writing.
closed chan struct{} // Events for queue closing.
C chan interface{} // Underlying channel for data reading.
}
const (
// 动态队列缓冲区大小
// Size for queue buffer.
gDEFAULT_QUEUE_SIZE = 10000
)
// 队列大小为非必须参数,默认不限制
// New returns a queue object.
// Param <limit> is optional and it is not limited by default.
func New(limit...int) *Queue {
q := &Queue {
closed : make(chan struct{}, 0),
@ -56,7 +54,8 @@ func New(limit...int) *Queue {
return q
}
// 异步list->chan同步队列
// startAsyncLoop starts an asynchronous goroutine,
// which handles the data synchronization from list <q.list> to channel <q.C>.
func (q *Queue) startAsyncLoop() {
for {
select {
@ -84,7 +83,8 @@ func (q *Queue) startAsyncLoop() {
}
}
// 将数据压入队列, 队尾
// Push pushes the data <v> into the queue.
// Note that it would panics if the Push method is called after the queue is closed.
func (q *Queue) Push(v interface{}) {
if q.limit > 0 {
q.C <- v
@ -94,19 +94,22 @@ func (q *Queue) Push(v interface{}) {
}
}
// 从队头先进先出地从队列取出一项数据
// Pop pops an item from the queue in FIFO way.
// Note that it would return nil immediately if the Pop method is called after the queue is closed.
func (q *Queue) Pop() interface{} {
return <- q.C
}
// 关闭队列(通知所有通过Pop*阻塞的协程退出)
// Close closes the queue.
// Notice: It would notify all goroutines exit immediately,
// which are blocked reading by Pop method).
func (q *Queue) Close() {
close(q.C)
close(q.events)
close(q.closed)
}
// 获取当前队列大小
// Size returns the length of the queue.
func (q *Queue) Size() int {
return len(q.C) + q.list.Len()
}

View File

@ -18,18 +18,14 @@ type Set struct {
m map[interface{}]struct{}
}
// Create a set, which contains un-repeated items.
// The param <unsafe> used to specify whether using array with un-concurrent-safety,
// which is false in default, means concurrent-safe in default.
//
// 创建一个空的集合对象参数unsafe用于指定是否用于非并发安全场景默认为false表示并发安全。
// New create and returns a new set, which contains un-repeated items.
// The param <unsafe> used to specify whether using set in un-concurrent-safety,
// which is false in default.
func New(unsafe...bool) *Set {
return NewSet(unsafe...)
}
// See New.
//
// 同New.
func NewSet(unsafe...bool) *Set {
return &Set{
m : make(map[interface{}]struct{}),
@ -37,10 +33,21 @@ func NewSet(unsafe...bool) *Set {
}
}
// Iterate the set by given callback <f>,
// NewFrom returns a new set from <items>.
// Parameter <items> can be either a variable of any type, or a slice.
func NewFrom(items interface{}, unsafe...bool) *Set {
m := make(map[interface{}]struct{})
for _, v := range gconv.Interfaces(items) {
m[v] = struct{}{}
}
return &Set{
m : m,
mu : rwmutex.New(unsafe...),
}
}
// Iterator iterates the set with given callback function <f>,
// if <f> returns true then continue iterating; or false to stop.
//
// 给定回调函数对原始内容进行遍历回调函数返回true表示继续遍历否则停止遍历。
func (set *Set) Iterator(f func (v interface{}) bool) *Set {
set.mu.RLock()
defer set.mu.RUnlock()
@ -52,9 +59,7 @@ func (set *Set) Iterator(f func (v interface{}) bool) *Set {
return set
}
// Add one or multiple items to the set.
//
// 添加元素项到集合中(支持多个).
// Add adds one or multiple items to the set.
func (set *Set) Add(item...interface{}) *Set {
set.mu.Lock()
for _, v := range item {
@ -64,9 +69,7 @@ func (set *Set) Add(item...interface{}) *Set {
return set
}
// Check whether the set contains <item>.
//
// 键是否存在.
// Contains checks whether the set contains <item>.
func (set *Set) Contains(item interface{}) bool {
set.mu.RLock()
_, exists := set.m[item]
@ -74,9 +77,7 @@ func (set *Set) Contains(item interface{}) bool {
return exists
}
// Remove <item> from set.
//
// 删除元素项。
// Remove deletes <item> from set.
func (set *Set) Remove(item interface{}) *Set {
set.mu.Lock()
delete(set.m, item)
@ -84,9 +85,7 @@ func (set *Set) Remove(item interface{}) *Set {
return set
}
// Get size of the set.
//
// 获得集合大小。
// Size returns the size of the set.
func (set *Set) Size() int {
set.mu.RLock()
l := len(set.m)
@ -94,9 +93,7 @@ func (set *Set) Size() int {
return l
}
// Clear the set.
//
// 清空集合。
// Clear deletes all items of the set.
func (set *Set) Clear() *Set {
set.mu.Lock()
set.m = make(map[interface{}]struct{})
@ -104,9 +101,7 @@ func (set *Set) Clear() *Set {
return set
}
// Get the copy of items from set as slice.
//
// 获得集合元素项列表.
// Slice returns the a of items of the set as slice.
func (set *Set) Slice() []interface{} {
set.mu.RLock()
i := 0
@ -119,23 +114,17 @@ func (set *Set) Slice() []interface{} {
return ret
}
// Join set items with a string.
//
// 使用glue字符串串连当前集合的元素项构造成新的字符串返回。
// Join joins items with a string <glue>.
func (set *Set) Join(glue string) string {
return strings.Join(gconv.Strings(set.Slice()), ",")
}
// Return set items as a string, which are joined by char ','.
//
// 使用glue字符串串连当前集合的元素项构造成新的字符串返回。
// String returns items as a string, which are joined by char ','.
func (set *Set) String() string {
return set.Join(",")
}
// Lock writing by callback function f.
//
// 使用自定义方法执行加锁修改操作。
// LockFunc locks writing with callback function <f>.
func (set *Set) LockFunc(f func(m map[interface{}]struct{})) *Set {
set.mu.Lock()
defer set.mu.Unlock()
@ -143,9 +132,7 @@ func (set *Set) LockFunc(f func(m map[interface{}]struct{})) *Set {
return set
}
// Lock reading by callback function f.
//
// 使用自定义方法执行加锁读取操作。
// RLockFunc locks reading with callback function <f>.
func (set *Set) RLockFunc(f func(m map[interface{}]struct{})) *Set {
set.mu.RLock()
defer set.mu.RUnlock()
@ -153,9 +140,7 @@ func (set *Set) RLockFunc(f func(m map[interface{}]struct{})) *Set {
return set
}
// Check whether the two sets equal.
//
// 判断两个集合是否相等.
// Equal checks whether the two sets equal.
func (set *Set) Equal(other *Set) bool {
if set == other {
return true
@ -175,9 +160,7 @@ func (set *Set) Equal(other *Set) bool {
return true
}
// Check whether the current set is sub-set of <other>.
//
// 判断当前集合是否为other集合的子集.
// IsSubsetOf checks whether the current set is a sub-set of <other>.
func (set *Set) IsSubsetOf(other *Set) bool {
if set == other {
return true
@ -194,10 +177,8 @@ func (set *Set) IsSubsetOf(other *Set) bool {
return true
}
// Returns a new set which is the union of <set> and <other>.
// Which means, all the items in <newSet> is in <set> or in <other>.
//
// 并集, 返回新的集合属于set或属于others的元素为元素的集合.
// Union returns a new set which is the union of <set> and <others>.
// Which means, all the items in <newSet> are in <set> or in <others>.
func (set *Set) Union(others ... *Set) (newSet *Set) {
newSet = NewSet(true)
set.mu.RLock()
@ -222,10 +203,8 @@ func (set *Set) Union(others ... *Set) (newSet *Set) {
return
}
// Returns a new set which is the difference set from <set> to <other>.
// Which means, all the items in <newSet> is in <set> and not in <other>.
//
// 差集, 返回新的集合: 属于set且不属于others的元素为元素的集合.
// Diff returns a new set which is the difference set from <set> to <others>.
// Which means, all the items in <newSet> are in <set> but not in <others>.
func (set *Set) Diff(others...*Set) (newSet *Set) {
newSet = NewSet(true)
set.mu.RLock()
@ -245,10 +224,8 @@ func (set *Set) Diff(others...*Set) (newSet *Set) {
return
}
// Returns a new set which is the intersection from <set> to <other>.
// Which means, all the items in <newSet> is in <set> and also in <other>.
//
// 交集, 返回新的集合: 属于set且属于others的元素为元素的集合.
// Intersect returns a new set which is the intersection from <set> to <others>.
// Which means, all the items in <newSet> are in <set> and also in <others>.
func (set *Set) Intersect(others...*Set) (newSet *Set) {
newSet = NewSet(true)
set.mu.RLock()
@ -269,11 +246,11 @@ func (set *Set) Intersect(others...*Set) (newSet *Set) {
return
}
// Returns a new set which is the complement from <set> to <full>.
// Which means, all the items in <newSet> is in <full> and not in <set>.
// Complement returns a new set which is the complement from <set> to <full>.
// Which means, all the items in <newSet> are in <full> and not in <set>.
//
// 补集, 返回新的集合: (前提: set应当为full的子集)属于全集full不属于集合set的元素组成的集合.
// 如果给定的full集合不是set的全集时返回full与set的差集.
// It returns the difference between <full> and <set>
// if the given set <full> is not the full set of <set>.
func (set *Set) Complement(full *Set) (newSet *Set) {
newSet = NewSet(true)
set.mu.RLock()
@ -288,4 +265,63 @@ func (set *Set) Complement(full *Set) (newSet *Set) {
}
}
return
}
// Merge adds items from <others> sets into <set>.
func (set *Set) Merge(others ... *Set) *Set {
set.mu.Lock()
defer set.mu.Unlock()
for _, other := range others {
if set != other {
other.mu.RLock()
}
for k, v := range other.m {
set.m[k] = v
}
if set != other {
other.mu.RUnlock()
}
}
return set
}
// Sum sums items.
// Note: The items should be converted to int type,
// or you'd get a result that you unexpected.
func (set *Set) Sum() (sum int) {
set.mu.RLock()
defer set.mu.RUnlock()
for k, _ := range set.m {
sum += gconv.Int(k)
}
return
}
// Pops randomly pops an item from set.
func (set *Set) Pop(size int) interface{} {
set.mu.RLock()
defer set.mu.RUnlock()
for k, _ := range set.m {
return k
}
return nil
}
// Pops randomly pops <size> items from set.
func (set *Set) Pops(size int) []interface{} {
set.mu.RLock()
defer set.mu.RUnlock()
if size > len(set.m) {
size = len(set.m)
}
index := 0
array := make([]interface{}, size)
for k, _ := range set.m {
array[index] = k
index++
if index == size {
break
}
}
return array
}

View File

@ -18,11 +18,9 @@ type IntSet struct {
m map[int]struct{}
}
// Create a set, which contains un-repeated items.
// The param <unsafe> used to specify whether using array with un-concurrent-safety,
// which is false in default, means concurrent-safe in default.
//
// 创建一个空的集合对象参数unsafe用于指定是否用于非并发安全场景默认为false表示并发安全。
// New create and returns a new set, which contains un-repeated items.
// The param <unsafe> used to specify whether using set in un-concurrent-safety,
// which is false in default.
func NewIntSet(unsafe...bool) *IntSet {
return &IntSet{
m : make(map[int]struct{}),
@ -30,10 +28,20 @@ func NewIntSet(unsafe...bool) *IntSet {
}
}
// Iterate the set by given callback <f>,
// NewIntSetFrom returns a new set from <items>.
func NewIntSetFrom(items []int, unsafe...bool) *IntSet {
m := make(map[int]struct{})
for _, v := range items {
m[v] = struct{}{}
}
return &IntSet{
m : m,
mu : rwmutex.New(unsafe...),
}
}
// Iterator iterates the set with given callback function <f>,
// if <f> returns true then continue iterating; or false to stop.
//
// 给定回调函数对原始内容进行遍历回调函数返回true表示继续遍历否则停止遍历。
func (set *IntSet) Iterator(f func (v int) bool) *IntSet {
set.mu.RLock()
defer set.mu.RUnlock()
@ -45,9 +53,7 @@ func (set *IntSet) Iterator(f func (v int) bool) *IntSet {
return set
}
// Add one or multiple items to the set.
//
// 添加元素项到集合中(支持多个).
// Add adds one or multiple items to the set.
func (set *IntSet) Add(item...int) *IntSet {
set.mu.Lock()
for _, v := range item {
@ -57,9 +63,7 @@ func (set *IntSet) Add(item...int) *IntSet {
return set
}
// Check whether the set contains <item>.
//
// 键是否存在.
// Contains checks whether the set contains <item>.
func (set *IntSet) Contains(item int) bool {
set.mu.RLock()
_, exists := set.m[item]
@ -67,9 +71,7 @@ func (set *IntSet) Contains(item int) bool {
return exists
}
// Remove <item> from set.
//
// 删除元素项。
// Remove deletes <item> from set.
func (set *IntSet) Remove(item int) *IntSet {
set.mu.Lock()
delete(set.m, item)
@ -77,9 +79,7 @@ func (set *IntSet) Remove(item int) *IntSet {
return set
}
// Get size of the set.
//
// 获得集合大小。
// Size returns the size of the set.
func (set *IntSet) Size() int {
set.mu.RLock()
l := len(set.m)
@ -87,9 +87,7 @@ func (set *IntSet) Size() int {
return l
}
// Clear the set.
//
// 清空集合。
// Clear deletes all items of the set.
func (set *IntSet) Clear() *IntSet {
set.mu.Lock()
set.m = make(map[int]struct{})
@ -97,9 +95,7 @@ func (set *IntSet) Clear() *IntSet {
return set
}
// Get the copy of items from set as slice.
//
// 获得集合元素项列表.
// Slice returns the a of items of the set as slice.
func (set *IntSet) Slice() []int {
set.mu.RLock()
ret := make([]int, len(set.m))
@ -112,23 +108,17 @@ func (set *IntSet) Slice() []int {
return ret
}
// Join set items with a string.
//
// 使用glue字符串串连当前集合的元素项构造成新的字符串返回。
// Join joins items with a string <glue>.
func (set *IntSet) Join(glue string) string {
return strings.Join(gconv.Strings(set.Slice()), ",")
}
// Return set items as a string, which are joined by char ','.
//
// 使用glue字符串串连当前集合的元素项构造成新的字符串返回。
// String returns items as a string, which are joined by char ','.
func (set *IntSet) String() string {
return set.Join(",")
}
// Lock writing by callback function f.
//
// 使用自定义方法执行加锁修改操作。
// LockFunc locks writing with callback function <f>.
func (set *IntSet) LockFunc(f func(m map[int]struct{})) *IntSet {
set.mu.Lock()
defer set.mu.Unlock()
@ -136,9 +126,7 @@ func (set *IntSet) LockFunc(f func(m map[int]struct{})) *IntSet {
return set
}
// Lock reading by callback function f.
//
// 使用自定义方法执行加锁读取操作。
// RLockFunc locks reading with callback function <f>.
func (set *IntSet) RLockFunc(f func(m map[int]struct{})) *IntSet {
set.mu.RLock()
defer set.mu.RUnlock()
@ -146,9 +134,7 @@ func (set *IntSet) RLockFunc(f func(m map[int]struct{})) *IntSet {
return set
}
// Check whether the two sets equal.
//
// 判断两个集合是否相等.
// Equal checks whether the two sets equal.
func (set *IntSet) Equal(other *IntSet) bool {
if set == other {
return true
@ -168,9 +154,7 @@ func (set *IntSet) Equal(other *IntSet) bool {
return true
}
// Check whether the current set is sub-set of <other>.
//
// 判断当前集合是否为other集合的子集.
// IsSubsetOf checks whether the current set is a sub-set of <other>.
func (set *IntSet) IsSubsetOf(other *IntSet) bool {
if set == other {
return true
@ -187,10 +171,8 @@ func (set *IntSet) IsSubsetOf(other *IntSet) bool {
return true
}
// Returns a new set which is the union of <set> and <other>.
// Which means, all the items in <newSet> is in <set> or in <other>.
//
// 并集, 返回新的集合属于set或属于others的元素为元素的集合.
// Union returns a new set which is the union of <set> and <other>.
// Which means, all the items in <newSet> are in <set> or in <other>.
func (set *IntSet) Union(others ... *IntSet) (newSet *IntSet) {
newSet = NewIntSet(true)
set.mu.RLock()
@ -215,10 +197,8 @@ func (set *IntSet) Union(others ... *IntSet) (newSet *IntSet) {
return
}
// Returns a new set which is the difference set from <set> to <other>.
// Which means, all the items in <newSet> is in <set> and not in <other>.
//
// 差集, 返回新的集合: 属于set且不属于others的元素为元素的集合.
// Diff returns a new set which is the difference set from <set> to <other>.
// Which means, all the items in <newSet> are in <set> but not in <other>.
func (set *IntSet) Diff(others...*IntSet) (newSet *IntSet) {
newSet = NewIntSet(true)
set.mu.RLock()
@ -238,10 +218,8 @@ func (set *IntSet) Diff(others...*IntSet) (newSet *IntSet) {
return
}
// Returns a new set which is the intersection from <set> to <other>.
// Which means, all the items in <newSet> is in <set> and also in <other>.
//
// 交集, 返回新的集合: 属于set且属于others的元素为元素的集合.
// Intersect returns a new set which is the intersection from <set> to <other>.
// Which means, all the items in <newSet> are in <set> and also in <other>.
func (set *IntSet) Intersect(others...*IntSet) (newSet *IntSet) {
newSet = NewIntSet(true)
set.mu.RLock()
@ -262,11 +240,11 @@ func (set *IntSet) Intersect(others...*IntSet) (newSet *IntSet) {
return
}
// Returns a new set which is the complement from <set> to <full>.
// Which means, all the items in <newSet> is in <full> and not in <set>.
// Complement returns a new set which is the complement from <set> to <full>.
// Which means, all the items in <newSet> are in <full> and not in <set>.
//
// 补集, 返回新的集合: (前提: set应当为full的子集)属于全集full不属于集合set的元素组成的集合.
// 如果给定的full集合不是set的全集时返回full与set的差集.
// It returns the difference between <full> and <set>
// if the given set <full> is not the full set of <set>.
func (set *IntSet) Complement(full *IntSet) (newSet *IntSet) {
newSet = NewIntSet(true)
set.mu.RLock()
@ -282,3 +260,62 @@ func (set *IntSet) Complement(full *IntSet) (newSet *IntSet) {
}
return
}
// Merge adds items from <others> sets into <set>.
func (set *IntSet) Merge(others ... *IntSet) *IntSet {
set.mu.Lock()
defer set.mu.Unlock()
for _, other := range others {
if set != other {
other.mu.RLock()
}
for k, v := range other.m {
set.m[k] = v
}
if set != other {
other.mu.RUnlock()
}
}
return set
}
// Sum sums items.
// Note: The items should be converted to int type,
// or you'd get a result that you unexpected.
func (set *IntSet) Sum() (sum int) {
set.mu.RLock()
defer set.mu.RUnlock()
for k, _ := range set.m {
sum += k
}
return
}
// Pops randomly pops an item from set.
func (set *IntSet) Pop(size int) int {
set.mu.RLock()
defer set.mu.RUnlock()
for k, _ := range set.m {
return k
}
return 0
}
// Pops randomly pops <size> items from set.
func (set *IntSet) Pops(size int) []int {
set.mu.RLock()
defer set.mu.RUnlock()
if size > len(set.m) {
size = len(set.m)
}
index := 0
array := make([]int, size)
for k, _ := range set.m {
array[index] = k
index++
if index == size {
break
}
}
return array
}

View File

@ -9,7 +9,8 @@ package gset
import (
"github.com/gogf/gf/g/internal/rwmutex"
"strings"
"github.com/gogf/gf/g/util/gconv"
"strings"
)
type StringSet struct {
@ -17,11 +18,9 @@ type StringSet struct {
m map[string]struct{}
}
// Create a set, which contains un-repeated items.
// The param <unsafe> used to specify whether using array with un-concurrent-safety,
// which is false in default, means concurrent-safe in default.
//
// 创建一个空的集合对象参数unsafe用于指定是否用于非并发安全场景默认为false表示并发安全。
// New create and returns a new set, which contains un-repeated items.
// The param <unsafe> used to specify whether using set in un-concurrent-safety,
// which is false in default.
func NewStringSet(unsafe...bool) *StringSet {
return &StringSet {
m : make(map[string]struct{}),
@ -29,10 +28,20 @@ func NewStringSet(unsafe...bool) *StringSet {
}
}
// Iterate the set by given callback <f>,
// NewStringSetFrom returns a new set from <items>.
func NewStringSetFrom(items []string, unsafe...bool) *StringSet {
m := make(map[string]struct{})
for _, v := range items {
m[v] = struct{}{}
}
return &StringSet{
m : m,
mu : rwmutex.New(unsafe...),
}
}
// Iterator iterates the set with given callback function <f>,
// if <f> returns true then continue iterating; or false to stop.
//
// 给定回调函数对原始内容进行遍历回调函数返回true表示继续遍历否则停止遍历。
func (set *StringSet) Iterator(f func (v string) bool) *StringSet {
set.mu.RLock()
defer set.mu.RUnlock()
@ -44,9 +53,7 @@ func (set *StringSet) Iterator(f func (v string) bool) *StringSet {
return set
}
// Add one or multiple items to the set.
//
// 添加元素项到集合中(支持多个).
// Add adds one or multiple items to the set.
func (set *StringSet) Add(item...string) *StringSet {
set.mu.Lock()
for _, v := range item {
@ -56,9 +63,7 @@ func (set *StringSet) Add(item...string) *StringSet {
return set
}
// Check whether the set contains <item>.
//
// 键是否存在.
// Contains checks whether the set contains <item>.
func (set *StringSet) Contains(item string) bool {
set.mu.RLock()
_, exists := set.m[item]
@ -66,9 +71,7 @@ func (set *StringSet) Contains(item string) bool {
return exists
}
// Remove <item> from set.
//
// 删除元素项。
// Remove deletes <item> from set.
func (set *StringSet) Remove(item string) *StringSet {
set.mu.Lock()
delete(set.m, item)
@ -76,9 +79,7 @@ func (set *StringSet) Remove(item string) *StringSet {
return set
}
// Get size of the set.
//
// 获得集合大小。
// Size returns the size of the set.
func (set *StringSet) Size() int {
set.mu.RLock()
l := len(set.m)
@ -86,9 +87,7 @@ func (set *StringSet) Size() int {
return l
}
// Clear the set.
//
// 清空集合。
// Clear deletes all items of the set.
func (set *StringSet) Clear() *StringSet {
set.mu.Lock()
set.m = make(map[string]struct{})
@ -96,9 +95,7 @@ func (set *StringSet) Clear() *StringSet {
return set
}
// Get the copy of items from set as slice.
//
// 获得集合元素项列表.
// Slice returns the a of items of the set as slice.
func (set *StringSet) Slice() []string {
set.mu.RLock()
ret := make([]string, len(set.m))
@ -112,23 +109,17 @@ func (set *StringSet) Slice() []string {
return ret
}
// Join set items with a string.
//
// 使用glue字符串串连当前集合的元素项构造成新的字符串返回。
// Join joins items with a string <glue>.
func (set *StringSet) Join(glue string) string {
return strings.Join(set.Slice(), ",")
}
// Return set items as a string, which are joined by char ','.
//
// 使用glue字符串串连当前集合的元素项构造成新的字符串返回。
// String returns items as a string, which are joined by char ','.
func (set *StringSet) String() string {
return set.Join(",")
}
// Lock writing by callback function f.
//
// 使用自定义方法执行加锁修改操作。
// LockFunc locks writing with callback function <f>.
func (set *StringSet) LockFunc(f func(m map[string]struct{})) *StringSet {
set.mu.Lock()
defer set.mu.Unlock()
@ -136,9 +127,7 @@ func (set *StringSet) LockFunc(f func(m map[string]struct{})) *StringSet {
return set
}
// Lock reading by callback function f.
//
// 使用自定义方法执行加锁读取操作。
// RLockFunc locks reading with callback function <f>.
func (set *StringSet) RLockFunc(f func(m map[string]struct{})) *StringSet {
set.mu.RLock()
defer set.mu.RUnlock()
@ -146,9 +135,7 @@ func (set *StringSet) RLockFunc(f func(m map[string]struct{})) *StringSet {
return set
}
// Check whether the two sets equal.
//
// 判断两个集合是否相等.
// Equal checks whether the two sets equal.
func (set *StringSet) Equal(other *StringSet) bool {
if set == other {
return true
@ -168,9 +155,7 @@ func (set *StringSet) Equal(other *StringSet) bool {
return true
}
// Check whether the current set is sub-set of <other>.
//
// 判断当前集合是否为other集合的子集.
// IsSubsetOf checks whether the current set is a sub-set of <other>.
func (set *StringSet) IsSubsetOf(other *StringSet) bool {
if set == other {
return true
@ -187,10 +172,8 @@ func (set *StringSet) IsSubsetOf(other *StringSet) bool {
return true
}
// Returns a new set which is the union of <set> and <other>.
// Which means, all the items in <newSet> is in <set> or in <other>.
//
// 并集, 返回新的集合属于set或属于others的元素为元素的集合.
// Union returns a new set which is the union of <set> and <other>.
// Which means, all the items in <newSet> are in <set> or in <other>.
func (set *StringSet) Union(others ... *StringSet) (newSet *StringSet) {
newSet = NewStringSet(true)
set.mu.RLock()
@ -215,10 +198,8 @@ func (set *StringSet) Union(others ... *StringSet) (newSet *StringSet) {
return
}
// Returns a new set which is the difference set from <set> to <other>.
// Which means, all the items in <newSet> is in <set> and not in <other>.
//
// 差集, 返回新的集合: 属于set且不属于others的元素为元素的集合.
// Diff returns a new set which is the difference set from <set> to <other>.
// Which means, all the items in <newSet> are in <set> but not in <other>.
func (set *StringSet) Diff(others...*StringSet) (newSet *StringSet) {
newSet = NewStringSet(true)
set.mu.RLock()
@ -238,10 +219,8 @@ func (set *StringSet) Diff(others...*StringSet) (newSet *StringSet) {
return
}
// Returns a new set which is the intersection from <set> to <other>.
// Which means, all the items in <newSet> is in <set> and also in <other>.
//
// 交集, 返回新的集合: 属于set且属于others的元素为元素的集合.
// Intersect returns a new set which is the intersection from <set> to <other>.
// Which means, all the items in <newSet> are in <set> and also in <other>.
func (set *StringSet) Intersect(others...*StringSet) (newSet *StringSet) {
newSet = NewStringSet(true)
set.mu.RLock()
@ -262,11 +241,11 @@ func (set *StringSet) Intersect(others...*StringSet) (newSet *StringSet) {
return
}
// Returns a new set which is the complement from <set> to <full>.
// Which means, all the items in <newSet> is in <full> and not in <set>.
// Complement returns a new set which is the complement from <set> to <full>.
// Which means, all the items in <newSet> are in <full> and not in <set>.
//
// 补集, 返回新的集合: (前提: set应当为full的子集)属于全集full不属于集合set的元素组成的集合.
// 如果给定的full集合不是set的全集时返回full与set的差集.
// It returns the difference between <full> and <set>
// if the given set <full> is not the full set of <set>.
func (set *StringSet) Complement(full *StringSet) (newSet *StringSet) {
newSet = NewStringSet(true)
set.mu.RLock()
@ -282,3 +261,62 @@ func (set *StringSet) Complement(full *StringSet) (newSet *StringSet) {
}
return
}
// Merge adds items from <others> sets into <set>.
func (set *StringSet) Merge(others ... *StringSet) *StringSet {
set.mu.Lock()
defer set.mu.Unlock()
for _, other := range others {
if set != other {
other.mu.RLock()
}
for k, v := range other.m {
set.m[k] = v
}
if set != other {
other.mu.RUnlock()
}
}
return set
}
// Sum sums items.
// Note: The items should be converted to int type,
// or you'd get a result that you unexpected.
func (set *StringSet) Sum() (sum int) {
set.mu.RLock()
defer set.mu.RUnlock()
for k, _ := range set.m {
sum += gconv.Int(k)
}
return
}
// Pops randomly pops an item from set.
func (set *StringSet) Pop(size int) string {
set.mu.RLock()
defer set.mu.RUnlock()
for k, _ := range set.m {
return k
}
return ""
}
// Pops randomly pops <size> items from set.
func (set *StringSet) Pops(size int) []string {
set.mu.RLock()
defer set.mu.RUnlock()
if size > len(set.m) {
size = len(set.m)
}
index := 0
array := make([]string, size)
for k, _ := range set.m {
array[index] = k
index++
if index == size {
break
}
}
return array
}

View File

@ -61,7 +61,10 @@ func Decrypt(cipherText []byte, key []byte, iv...[]byte) ([]byte, error) {
blockModel := cipher.NewCBCDecrypter(block, ivValue)
plainText := make([]byte, len(cipherText))
blockModel.CryptBlocks(plainText, cipherText)
plainText = PKCS5UnPadding(plainText)
plainText, e := PKCS5UnPadding(plainText, blockSize)
if e != nil {
return nil, e
}
return plainText, nil
}
@ -72,8 +75,27 @@ func PKCS5Padding(src []byte, blockSize int) []byte {
return append(src, padtext...)
}
func PKCS5UnPadding(src []byte) []byte {
func PKCS5UnPadding(src []byte, blockSize int) ([]byte, error) {
length := len(src)
if blockSize <= 0 {
return nil, errors.New("invalid blocklen")
}
if length%blockSize != 0 || length == 0 {
return nil, errors.New("invalid data len")
}
unpadding := int(src[length - 1])
return src[:(length - unpadding)]
}
if unpadding > blockSize || unpadding == 0 {
return nil, errors.New("invalid padding")
}
padding := src[length - unpadding:]
for i := 0; i < unpadding; i++ {
if padding[i] != byte(unpadding) {
return nil, errors.New("invalid padding")
}
}
return src[:(length - unpadding)], nil
}

View File

@ -22,6 +22,7 @@ var (
key_16 = []byte("1234567891234567")
key_24 = []byte("123456789123456789123456")
key_32 = []byte("12345678912345678912345678912345")
keys = []byte("12345678912345678912345678912346")
)
func TestEncrypt(t *testing.T) {
@ -58,5 +59,9 @@ func TestDecrypt(t *testing.T) {
decrypt, err = gaes.Decrypt(encrypt, key_32, iv)
gtest.Assert(err, nil)
gtest.Assert(string(decrypt), string(content))
encrypt, err = gaes.Encrypt(content, key_32, iv)
decrypt, err = gaes.Decrypt(encrypt, keys, iv)
gtest.Assert(err, "invalid padding")
})
}

View File

@ -18,7 +18,6 @@ type View struct {
mu sync.RWMutex // 并发互斥锁
view *gview.View // 底层视图对象
data gview.Params // 视图数据/模板变量
fmap gview.FuncMap // 绑定的模板函数
response *ghttp.Response // 数据返回对象
}
@ -27,7 +26,6 @@ func NewView(w *ghttp.Response) *View {
return &View {
view : gins.View(),
data : make(gview.Params),
fmap : make(gview.FuncMap),
response : w,
}
}
@ -48,18 +46,11 @@ func (view *View) Assign(key string, value interface{}) {
view.mu.Unlock()
}
// 绑定自定义模板函数
func (view *View) BindFunc(name string, function interface{}){
view.mu.Lock()
view.fmap[name] = function
view.mu.Unlock()
}
// 解析模板,并返回解析后的内容
func (view *View) Parse(file string) (string, error) {
view.mu.RLock()
defer view.mu.RUnlock()
buffer, err := view.response.ParseTpl(file, view.data, view.fmap)
buffer, err := view.response.ParseTpl(file, view.data)
return buffer, err
}
@ -67,7 +58,7 @@ func (view *View) Parse(file string) (string, error) {
func (view *View) ParseContent(content string) (string, error) {
view.mu.RLock()
defer view.mu.RUnlock()
buffer, err := view.response.ParseTplContent(content, view.data, view.fmap)
buffer, err := view.response.ParseTplContent(content, view.data)
return buffer, err
}

View File

@ -12,85 +12,85 @@ func Get(url string) (*ClientResponse, error) {
return DoRequest("GET", url)
}
func Put(url string, data...string) (*ClientResponse, error) {
func Put(url string, data...interface{}) (*ClientResponse, error) {
return DoRequest("PUT", url, data...)
}
func Post(url string, data...string) (*ClientResponse, error) {
func Post(url string, data...interface{}) (*ClientResponse, error) {
return DoRequest("POST", url, data...)
}
func Delete(url string, data...string) (*ClientResponse, error) {
func Delete(url string, data...interface{}) (*ClientResponse, error) {
return DoRequest("DELETE", url, data...)
}
func Head(url string, data...string) (*ClientResponse, error) {
func Head(url string, data...interface{}) (*ClientResponse, error) {
return DoRequest("HEAD", url, data...)
}
func Patch(url string, data...string) (*ClientResponse, error) {
func Patch(url string, data...interface{}) (*ClientResponse, error) {
return DoRequest("PATCH", url, data...)
}
func Connect(url string, data...string) (*ClientResponse, error) {
func Connect(url string, data...interface{}) (*ClientResponse, error) {
return DoRequest("CONNECT", url, data...)
}
func Options(url string, data...string) (*ClientResponse, error) {
func Options(url string, data...interface{}) (*ClientResponse, error) {
return DoRequest("OPTIONS", url, data...)
}
func Trace(url string, data...string) (*ClientResponse, error) {
func Trace(url string, data...interface{}) (*ClientResponse, error) {
return DoRequest("TRACE", url, data...)
}
// 该方法支持二进制提交数据
func DoRequest(method, url string, data...string) (*ClientResponse, error) {
func DoRequest(method, url string, data...interface{}) (*ClientResponse, error) {
return NewClient().DoRequest(method, url, data...)
}
// GET请求并返回服务端结果(内部会自动读取服务端返回结果并关闭缓冲区指针)
func GetContent(url string, data...string) string {
func GetContent(url string, data...interface{}) string {
return RequestContent("GET", url, data...)
}
// PUT请求并返回服务端结果(内部会自动读取服务端返回结果并关闭缓冲区指针)
func PutContent(url string, data...string) string {
func PutContent(url string, data...interface{}) string {
return RequestContent("PUT", url, data...)
}
// POST请求并返回服务端结果(内部会自动读取服务端返回结果并关闭缓冲区指针)
func PostContent(url string, data...string) string {
func PostContent(url string, data...interface{}) string {
return RequestContent("POST", url, data...)
}
// DELETE请求并返回服务端结果(内部会自动读取服务端返回结果并关闭缓冲区指针)
func DeleteContent(url string, data...string) string {
func DeleteContent(url string, data...interface{}) string {
return RequestContent("DELETE", url, data...)
}
func HeadContent(url string, data...string) string {
func HeadContent(url string, data...interface{}) string {
return RequestContent("HEAD", url, data...)
}
func PatchContent(url string, data...string) string {
func PatchContent(url string, data...interface{}) string {
return RequestContent("PATCH", url, data...)
}
func ConnectContent(url string, data...string) string {
func ConnectContent(url string, data...interface{}) string {
return RequestContent("CONNECT", url, data...)
}
func OptionsContent(url string, data...string) string {
func OptionsContent(url string, data...interface{}) string {
return RequestContent("OPTIONS", url, data...)
}
func TraceContent(url string, data...string) string {
func TraceContent(url string, data...interface{}) string {
return RequestContent("TRACE", url, data...)
}
// 请求并返回服务端结果(内部会自动读取服务端返回结果并关闭缓冲区指针)
func RequestContent(method string, url string, data...string) string {
func RequestContent(method string, url string, data...interface{}) string {
return NewClient().DoRequestContent(method, url, data...)
}

View File

@ -69,20 +69,20 @@ func (c *Client) Get(url string) (*ClientResponse, error) {
}
// PUT请求
func (c *Client) Put(url string, data...string) (*ClientResponse, error) {
func (c *Client) Put(url string, data...interface{}) (*ClientResponse, error) {
return c.DoRequest("PUT", url, data...)
}
// POST请求提交数据默认使用表单方式提交数据(绝大部分场景下也是如此)。
// 如果服务端对Content-Type有要求可使用Client对象进行请求单独设置相关属性。
// 支持文件上传需要字段格式为FieldName=@file:
func (c *Client) Post(url string, data...string) (*ClientResponse, error) {
func (c *Client) Post(url string, data...interface{}) (*ClientResponse, error) {
if len(c.prefix) > 0 {
url = c.prefix + url
}
param := ""
if len(data) > 0 {
param = data[0]
param = BuildParams(data[0])
}
req := (*http.Request)(nil)
if strings.Contains(param, "@file:") {
@ -178,72 +178,72 @@ func (c *Client) Post(url string, data...string) (*ClientResponse, error) {
}
// DELETE请求
func (c *Client) Delete(url string, data...string) (*ClientResponse, error) {
func (c *Client) Delete(url string, data...interface{}) (*ClientResponse, error) {
return c.DoRequest("DELETE", url, data...)
}
func (c *Client) Head(url string, data...string) (*ClientResponse, error) {
func (c *Client) Head(url string, data...interface{}) (*ClientResponse, error) {
return c.DoRequest("HEAD", url, data...)
}
func (c *Client) Patch(url string, data...string) (*ClientResponse, error) {
func (c *Client) Patch(url string, data...interface{}) (*ClientResponse, error) {
return c.DoRequest("PATCH", url, data...)
}
func (c *Client) Connect(url string, data...string) (*ClientResponse, error) {
func (c *Client) Connect(url string, data...interface{}) (*ClientResponse, error) {
return c.DoRequest("CONNECT", url, data...)
}
func (c *Client) Options(url string, data...string) (*ClientResponse, error) {
func (c *Client) Options(url string, data...interface{}) (*ClientResponse, error) {
return c.DoRequest("OPTIONS", url, data...)
}
func (c *Client) Trace(url string, data...string) (*ClientResponse, error) {
func (c *Client) Trace(url string, data...interface{}) (*ClientResponse, error) {
return c.DoRequest("TRACE", url, data...)
}
// GET请求并返回服务端结果(内部会自动读取服务端返回结果并关闭缓冲区指针)
func (c *Client) GetContent(url string, data...string) string {
func (c *Client) GetContent(url string, data...interface{}) string {
return c.DoRequestContent("GET", url, data...)
}
// PUT请求并返回服务端结果(内部会自动读取服务端返回结果并关闭缓冲区指针)
func (c *Client) PutContent(url string, data...string) string {
func (c *Client) PutContent(url string, data...interface{}) string {
return c.DoRequestContent("PUT", url, data...)
}
// POST请求并返回服务端结果(内部会自动读取服务端返回结果并关闭缓冲区指针)
func (c *Client) PostContent(url string, data...string) string {
func (c *Client) PostContent(url string, data...interface{}) string {
return c.DoRequestContent("POST", url, data...)
}
// DELETE请求并返回服务端结果(内部会自动读取服务端返回结果并关闭缓冲区指针)
func (c *Client) DeleteContent(url string, data...string) string {
func (c *Client) DeleteContent(url string, data...interface{}) string {
return c.DoRequestContent("DELETE", url, data...)
}
func (c *Client) HeadContent(url string, data...string) string {
func (c *Client) HeadContent(url string, data...interface{}) string {
return c.DoRequestContent("HEAD", url, data...)
}
func (c *Client) PatchContent(url string, data...string) string {
func (c *Client) PatchContent(url string, data...interface{}) string {
return c.DoRequestContent("PATCH", url, data...)
}
func (c *Client) ConnectContent(url string, data...string) string {
func (c *Client) ConnectContent(url string, data...interface{}) string {
return c.DoRequestContent("CONNECT", url, data...)
}
func (c *Client) OptionsContent(url string, data...string) string {
func (c *Client) OptionsContent(url string, data...interface{}) string {
return c.DoRequestContent("OPTIONS", url, data...)
}
func (c *Client) TraceContent(url string, data...string) string {
func (c *Client) TraceContent(url string, data...interface{}) string {
return c.DoRequestContent("TRACE", url, data...)
}
// 请求并返回服务端结果(内部会自动读取服务端返回结果并关闭缓冲区指针)
func (c *Client) DoRequestContent(method string, url string, data...string) string {
func (c *Client) DoRequestContent(method string, url string, data...interface{}) string {
response, err := c.DoRequest(method, url, data...)
if err != nil {
return ""
@ -253,7 +253,7 @@ func (c *Client) DoRequestContent(method string, url string, data...string) stri
}
// 请求并返回response对象该方法支持二进制提交数据
func (c *Client) DoRequest(method, url string, data...string) (*ClientResponse, error) {
func (c *Client) DoRequest(method, url string, data...interface{}) (*ClientResponse, error) {
if strings.EqualFold("POST", method) {
return c.Post(url, data...)
}
@ -262,7 +262,7 @@ func (c *Client) DoRequest(method, url string, data...string) (*ClientResponse,
}
param := ""
if len(data) > 0 {
param = data[0]
param = BuildParams(data[0])
}
req, err := http.NewRequest(strings.ToUpper(method), url, bytes.NewReader([]byte(param)))
if err != nil {

View File

@ -8,21 +8,28 @@ package ghttp
import (
"github.com/gogf/gf/g/encoding/gurl"
"strings"
"github.com/gogf/gf/g/util/gconv"
"strings"
)
// 构建请求参数,将参数进行urlencode编码
func BuildParams(params map[string]string) string {
var s string
for k, v := range params {
if len(s) > 0 {
s += "&"
// 构建请求参数,参数支持任意数据类型常见参数类型为string/map。
// 如果参数为map类型参数值将会进行urlencode编码。
func BuildParams(params interface{}) (encodedParamStr string) {
m := gconv.Map(params)
if len(m) == 0 {
return gconv.String(params)
}
s := ""
for k, v := range m {
if len(encodedParamStr) > 0 {
encodedParamStr += "&"
}
if len(v) > 6 && strings.Compare(v[0 : 6], "@file:") == 0 {
s += k + "=" + v
s = gconv.String(v)
if len(s) > 6 && strings.Compare(s[0 : 6], "@file:") == 0 {
encodedParamStr += k + "=" + s
} else {
s += k + "=" + gurl.Encode(v)
encodedParamStr += k + "=" + gurl.Encode(s)
}
}
return s
return
}

View File

@ -13,13 +13,9 @@ import (
)
// 展示模板,可以给定模板参数,及临时的自定义模板函数
func (r *Response) WriteTpl(tpl string, params map[string]interface{}, funcMap...map[string]interface{}) error {
fmap := make(gview.FuncMap)
if len(funcMap) > 0 {
fmap = funcMap[0]
}
if b, err := r.ParseTpl(tpl, params, fmap); err != nil {
r.Write("Tpl Parsing Error: " + err.Error())
func (r *Response) WriteTpl(tpl string, params...gview.Params) error {
if b, err := r.ParseTpl(tpl, params...); err != nil {
r.Write("Template Parsing Error: " + err.Error())
return err
} else {
r.Write(b)
@ -28,13 +24,9 @@ func (r *Response) WriteTpl(tpl string, params map[string]interface{}, funcMap..
}
// 展示模板内容,可以给定模板参数,及临时的自定义模板函数
func (r *Response) WriteTplContent(content string, params map[string]interface{}, funcMap...map[string]interface{}) error {
fmap := make(gview.FuncMap)
if len(funcMap) > 0 {
fmap = funcMap[0]
}
if b, err := r.ParseTplContent(content, params, fmap); err != nil {
r.Write("Tpl Parsing Error: " + err.Error())
func (r *Response) WriteTplContent(content string, params...gview.Params) error {
if b, err := r.ParseTplContent(content, params...); err != nil {
r.Write("Template Parsing Error: " + err.Error())
return err
} else {
r.Write(b)
@ -43,61 +35,27 @@ func (r *Response) WriteTplContent(content string, params map[string]interface{}
}
// 解析模板文件,并返回模板内容
func (r *Response) ParseTpl(tpl string, params gview.Params, funcMap...map[string]interface{}) (string, error) {
m := make(gview.FuncMap)
if len(funcMap) > 0 {
m = funcMap[0]
}
return gins.View().Parse(tpl, r.buildInVars(params), r.buildInFuncs(m))
func (r *Response) ParseTpl(tpl string, params...gview.Params) (string, error) {
return gins.View().Parse(tpl, r.buildInVars(params...))
}
// 解析并返回模板内容
func (r *Response) ParseTplContent(content string, params gview.Params, funcMap...map[string]interface{}) (string, error) {
m := make(gview.FuncMap)
if len(funcMap) > 0 {
m = funcMap[0]
}
return gins.View().ParseContent(content, r.buildInVars(params), r.buildInFuncs(m))
func (r *Response) ParseTplContent(content string, params...gview.Params) (string, error) {
return gins.View().ParseContent(content, r.buildInVars(params...))
}
// 内置变量
func (r *Response) buildInVars(params map[string]interface{}) map[string]interface{} {
if params == nil {
params = make(map[string]interface{})
}
c := gins.Config()
if c.GetFilePath() != "" {
params["Config"] = c.GetMap("")
// 内置变量/对象
func (r *Response) buildInVars(params...map[string]interface{}) map[string]interface{} {
vars := map[string]interface{}(nil)
if len(params) > 0 {
vars = params[0]
} else {
params["Config"] = nil
vars = make(map[string]interface{})
}
params["Cookie"] = r.request.Cookie.Map()
params["Session"] = r.request.Session.Data()
return params
}
// 内置函数
func (r *Response) buildInFuncs(funcMap map[string]interface{}) map[string]interface{} {
if funcMap == nil {
funcMap = make(map[string]interface{})
}
funcMap["get"] = r.funcGet
funcMap["post"] = r.funcPost
funcMap["request"] = r.funcRequest
return funcMap
}
// 模板内置函数: get
func (r *Response) funcGet(key string, def...string) string {
return r.request.GetQueryString(key, def...)
}
// 模板内置函数: post
func (r *Response) funcPost(key string, def...string) string {
return r.request.GetPostString(key, def...)
}
// 模板内置函数: request
func (r *Response) funcRequest(key string, def...string) string {
return r.request.Get(key, def...)
vars["Config"] = gins.Config().GetMap("")
vars["Cookie"] = r.request.Cookie.Map()
vars["Session"] = r.request.Session.Map()
vars["Get"] = r.request.GetQueryMap()
vars["Post"] = r.request.GetPostMap()
return vars
}

View File

@ -15,7 +15,8 @@ import (
"github.com/gogf/gf/g/container/gtype"
"github.com/gogf/gf/g/os/gcache"
"github.com/gogf/gf/g/os/genv"
"github.com/gogf/gf/g/os/glog"
"github.com/gogf/gf/g/os/gfile"
"github.com/gogf/gf/g/os/glog"
"github.com/gogf/gf/g/os/gproc"
"github.com/gogf/gf/g/os/gtimer"
"github.com/gogf/gf/g/text/gregex"
@ -108,9 +109,9 @@ const (
HOOK_BEFORE_OUTPUT = "BeforeOutput"
HOOK_AFTER_OUTPUT = "AfterOutput"
// deprecated.
// Deprecated.
HOOK_BEFORE_CLOSE = "BeforeClose"
// deprecated.
// Deprecated.
HOOK_AFTER_CLOSE = "AfterClose"
HTTP_METHODS = "GET,PUT,POST,DELETE,PATCH,HEAD,CONNECT,OPTIONS,TRACE"
@ -188,10 +189,10 @@ func serverProcessInit() {
go handleProcessMessage()
}
// 是否处于开发环境
//if gfile.MainPkgPath() != "" {
// glog.Debug("GF notices that you're in develop environment, so error logs are auto enabled to stdout.")
//}
// 是否处于开发环境这里调用该方法初始化main包路径值
// 防止异步服务goroutine获取main包路径失败
// 该方法只有在main协程中才会执行。
gfile.MainPkgPath()
}
// 获取/创建一个默认配置的HTTP Server(默认监听端口是80)

View File

@ -47,7 +47,7 @@ func (d *Domain) Group(prefix...string) *RouterGroup {
}
// 执行分组路由批量绑定
func (g *RouterGroup) Bind(group string, items []GroupItem) {
func (g *RouterGroup) Bind(items []GroupItem) {
for _, item := range items {
if len(item) < 3 {
glog.Fatalfln("invalid router item: %s", item)

View File

@ -50,7 +50,7 @@ func (s *Server)BindController(pattern string, c Controller, methods...string) {
if _, ok := v.Method(i).Interface().(func()); !ok {
if len(methodMap) > 0 {
// 指定的方法名称注册,那么需要使用错误提示
glog.Errorfln(`invalid route method: %s.%s.%s defined as "%s", but "func()" is required`,
glog.Errorfln(`invalid route method: %s.%s.%s defined as "%s", but "func()" is required for controller registry`,
pkgPath, ctlName, mname, v.Method(i).Type().String())
} else {
// 否则只是Debug提示
@ -108,7 +108,7 @@ func (s *Server)BindControllerMethod(pattern string, c Controller, method string
ctlName = fmt.Sprintf(`(%s)`, ctlName)
}
if _, ok := fval.Interface().(func()); !ok {
glog.Errorfln(`invalid route method: %s.%s.%s defined as "%s", but "func()" is required`,
glog.Errorfln(`invalid route method: %s.%s.%s defined as "%s", but "func()" is required for controller registry`,
pkgPath, ctlName, mname, fval.Type().String())
return
}
@ -147,7 +147,7 @@ func (s *Server)BindControllerRest(pattern string, c Controller) {
ctlName = fmt.Sprintf(`(%s)`, ctlName)
}
if _, ok := v.Method(i).Interface().(func()); !ok {
glog.Errorfln(`invalid route method: %s.%s.%s defined as "%s", but "func()" is required`,
glog.Errorfln(`invalid route method: %s.%s.%s defined as "%s", but "func()" is required for controller registry`,
pkgPath, ctlName, mname, v.Method(i).Type().String())
return
}

View File

@ -57,7 +57,7 @@ func (s *Server)BindObject(pattern string, obj interface{}, methods...string) {
if !ok {
if len(methodMap) > 0 {
// 指定的方法名称注册,那么需要使用错误提示
glog.Errorfln(`invalid route method: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" is required`,
glog.Errorfln(`invalid route method: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" is required for object registry`,
pkgPath, objName, mname, v.Method(i).Type().String())
} else {
// 否则只是Debug提示
@ -127,7 +127,7 @@ func (s *Server)BindObjectMethod(pattern string, obj interface{}, method string)
}
faddr, ok := fval.Interface().(func(*Request))
if !ok {
glog.Errorfln(`invalid route method: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" is required`,
glog.Errorfln(`invalid route method: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" is required for object registry`,
pkgPath, objName, mname, fval.Type().String())
return
}
@ -174,7 +174,7 @@ func (s *Server)BindObjectRest(pattern string, obj interface{}) {
}
faddr, ok := v.Method(i).Interface().(func(*Request))
if !ok {
glog.Errorfln(`invalid route method: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" is required`,
glog.Errorfln(`invalid route method: %s.%s.%s defined as "%s", but "func(*ghttp.Request)" is required for object registry`,
pkgPath, objName, mname, v.Method(i).Type().String())
continue
}

View File

@ -69,7 +69,7 @@ func (s *Session) Id() string {
}
// 获取当前session所有数据
func (s *Session) Data() map[string]interface{} {
func (s *Session) Map() map[string]interface{} {
if len(s.id) > 0 || s.request.Cookie.GetSessionId() != "" {
s.init()
return s.data.Map()

View File

@ -123,7 +123,7 @@ func Test_Router_Basic2(t *testing.T) {
obj := new(GroupObject)
ctl := new(GroupController)
// 分组路由批量注册
s.Group("/api").Bind("/api", []ghttp.GroupItem{
s.Group("/api").Bind([]ghttp.GroupItem{
{"ALL", "/handler", Handler},
{"ALL", "/ctl", ctl},
{"GET", "/ctl/my-show", ctl, "Show"},

View File

@ -440,10 +440,14 @@ func homeWindows() (string, error) {
// Available in develop environment.
//
// 获取入口函数文件所在目录(main包文件目录),
// **仅对源码开发环境有效(即仅对生成该可执行文件的系统下有效)**
// **仅对源码开发环境有效(即仅对生成该可执行文件的系统下有效)**
// 注意该方法被第一次调用时如果是在异步的goroutine中该方法可能无法获取到main包路径。
func MainPkgPath() string {
path := mainPkgPath.Val()
if path != "" {
if path == "-" {
return ""
}
return path
}
for i := 1; i < 10000; i++ {
@ -457,6 +461,8 @@ func MainPkgPath() string {
break
}
}
// 找不到,下次不用再检索了
mainPkgPath.Set("-")
return ""
}

View File

@ -7,142 +7,159 @@
package gtime
import (
"bytes"
"github.com/gogf/gf/g/text/gregex"
"bytes"
"github.com/gogf/gf/g/text/gregex"
"github.com/gogf/gf/g/text/gstr"
"strings"
)
var (
// 参考http://php.net/manual/zh/function.date.php
formats = map[byte]string {
// ================== 日 ==================
'd' : "02", // 月份中的第几天,有前导零的 2 位数字(01 到 31)
'D' : "Mon", // 星期中的第几天文本表示3 个字母(Mon 到 Sun)
'j' : "=j=02", // 月份中的第几天,没有前导零(1 到 31)
'l' : "Monday", // ("L"的小写字母)星期几,完整的文本格式(Sunday 到 Saturday)
// 参考http://php.net/manual/zh/function.date.php
formats = map[byte]string{
// ================== 日 ==================
'd': "02", // 月份中的第几天,有前导零的 2 位数字(01 到 31)
'D': "Mon", // 星期中的第几天文本表示3 个字母(Mon 到 Sun)
'w': "Monday", // 星期中的第几天,数字型式的文本表示 0为星期天 6为星期六
'j': "=j=02", // 月份中的第几天,没有前导零(1 到 31)
'l': "Monday", // ("L"的小写字母)星期几,完整的文本格式(Sunday 到 Saturday)
// ================== 月 ==================
'F' : "January", // 月份,完整的文本格式,例如 January 或者 March January 到 December
'm' : "01", // 数字表示的月份,有前导零(01 到 12)
'M' : "Jan", // 三个字母缩写表示的月份(Jan 到 Dec)
'n' : "1", // 数字表示的月份,没有前导零(1 到 12)
// ================== 月 ==================
'F': "January", // 月份,完整的文本格式,例如 January 或者 March January 到 December
'm': "01", // 数字表示的月份,有前导零(01 到 12)
'M': "Jan", // 三个字母缩写表示的月份(Jan 到 Dec)
'n': "1", // 数字表示的月份,没有前导零(1 到 12)
// ================== 年 ==================
'Y' : "2006", // 4 位数字完整表示的年份, 例如1999 或 2003
'y' : "06", // 2 位数字表示的年份, 例如99 或 03
// ================== 年 ==================
'Y': "2006", // 4 位数字完整表示的年份, 例如1999 或 2003
'y': "06", // 2 位数字表示的年份, 例如99 或 03
// ================== 时间 ==================
'a' : "pm", // 小写的上午和下午值 am 或 pm
'A' : "PM", // 大写的上午和下午值 AM 或 PM
'g' : "3", // 小时12 小时格式,没有前导零, 1 到 12
'G' : "=G=15", // 小时24 小时格式,没有前导零, 0 到 23
'h' : "03", // 小时12 小时格式,有前导零, 01 到 12
'H' : "15", // 小时24 小时格式,有前导零, 00 到 23
'i' : "04", // 有前导零的分钟数, 00 到 59
's' : "05", // 秒数,有前导零, 00 到 59
'u' : "=u=.000", // 毫秒(3位)
// ================== 时间 ==================
'a': "pm", // 小写的上午和下午值 am 或 pm
'A': "PM", // 大写的上午和下午值 AM 或 PM
'g': "3", // 小时12 小时格式,没有前导零, 1 到 12
'G': "=G=15", // 小时24 小时格式,没有前导零, 0 到 23
'h': "03", // 小时12 小时格式,有前导零, 01 到 12
'H': "15", // 小时24 小时格式,有前导零, 00 到 23
'i': "04", // 有前导零的分钟数, 00 到 59
's': "05", // 秒数,有前导零, 00 到 59
'u': "=u=.000", // 毫秒(3位)
// ================== 时区 ==================
'O' : "-0700", // 与UTC相差的小时数, 例如:+0200
'P' : "-07:00", // 与UTC的差别小时和分钟之间有冒号分隔, 例如:+02:00
'T' : "MST", // 时区缩写, 例如UTCGMTCST
// ================== 时区 ==================
'O': "-0700", // 与UTC相差的小时数, 例如:+0200
'P': "-07:00", // 与UTC的差别小时和分钟之间有冒号分隔, 例如:+02:00
'T': "MST", // 时区缩写, 例如UTCGMTCST
// ================== 完整的日期/时间 ==================
'c' : "2006-01-02T15:04:05-07:00", // ISO 8601 格式的日期例如2004-02-12T15:19:21+00:00
'r' : "Mon, 02 Jan 06 15:04 MST", // RFC 822 格式的日期例如Thu, 21 Dec 2000 16:01:07 +0200
}
// ================== 完整的日期/时间 ==================
'c': "2006-01-02T15:04:05-07:00", // ISO 8601 格式的日期例如2004-02-12T15:19:21+00:00
'r': "Mon, 02 Jan 06 15:04 MST", // RFC 822 格式的日期例如Thu, 21 Dec 2000 16:01:07 +0200
}
// 星期的英文值和数字值对应map
weekMap = map[string]string{
"Sunday": "0",
"Monday": "1",
"Tuesday": "2",
"Wednesday": "3",
"Thursday": "4",
"Friday": "5",
"Saturday": "6",
}
)
// 将自定义的格式转换为标准库时间格式
func formatToStdLayout(format string) string {
b := bytes.NewBuffer(nil)
for i := 0; i < len(format); {
switch format[i] {
case '\\':
if i < len(format) - 1 {
b.WriteByte(format[i + 1])
i += 2
continue
} else {
return b.String()
}
b := bytes.NewBuffer(nil)
for i := 0; i < len(format); {
switch format[i] {
case '\\':
if i < len(format)-1 {
b.WriteByte(format[i+1])
i += 2
continue
} else {
return b.String()
}
default:
if f, ok := formats[format[i]]; ok {
// 有几个转换的符号需要特殊处理
switch format[i] {
case 'j':
b.WriteString("02")
case 'G':
b.WriteString("15")
case 'u':
if i > 0 && format[i - 1] == '.' {
b.WriteString("000")
} else {
b.WriteString(".000")
}
default:
if f, ok := formats[format[i]]; ok {
// 有几个转换的符号需要特殊处理
switch format[i] {
case 'j':
b.WriteString("02")
case 'G':
b.WriteString("15")
case 'u':
if i > 0 && format[i-1] == '.' {
b.WriteString("000")
} else {
b.WriteString(".000")
}
default:
b.WriteString(f)
}
} else {
b.WriteByte(format[i])
}
i++
}
}
return b.String()
default:
b.WriteString(f)
}
} else {
b.WriteByte(format[i])
}
i++
}
}
return b.String()
}
// 将format格式转换为正则表达式规则
func formatToRegexPattern(format string) string {
s := gregex.Quote(formatToStdLayout(format))
s, _ = gregex.ReplaceString(`[0-9]`, `[0-9]`, s)
s, _ = gregex.ReplaceString(`[A-Za-z]`, `[A-Za-z]`, s)
return s
s := gregex.Quote(formatToStdLayout(format))
s, _ = gregex.ReplaceString(`[0-9]`, `[0-9]`, s)
s, _ = gregex.ReplaceString(`[A-Za-z]`, `[A-Za-z]`, s)
return s
}
// 格式化,使用自定义日期格式
func (t *Time) Format(format string) string {
runes := []rune(format)
buffer := bytes.NewBuffer(nil)
for i := 0; i < len(runes); {
switch runes[i] {
case '\\':
if i < len(runes) - 1 {
buffer.WriteRune(runes[i + 1])
i += 2
continue
} else {
return buffer.String()
}
runes := []rune(format)
buffer := bytes.NewBuffer(nil)
for i := 0; i < len(runes); {
switch runes[i] {
case '\\':
if i < len(runes)-1 {
buffer.WriteRune(runes[i+1])
i += 2
continue
} else {
return buffer.String()
}
default:
if runes[i] > 255 {
buffer.WriteRune(runes[i])
break
}
if f, ok := formats[byte(runes[i])]; ok {
result := t.Time.Format(f)
// 有几个转换的符号需要特殊处理
switch runes[i] {
case 'j': buffer.WriteString(gstr.ReplaceByArray(result, []string{"=j=0", "", "=j=", ""}))
case 'G': buffer.WriteString(gstr.ReplaceByArray(result, []string{"=G=0", "", "=G=", ""}))
case 'u': buffer.WriteString(strings.Replace(result, "=u=.", "", -1))
default:
buffer.WriteString(result)
}
} else {
buffer.WriteRune(runes[i])
}
}
i++
}
return buffer.String()
default:
if runes[i] > 255 {
buffer.WriteRune(runes[i])
break
}
if f, ok := formats[byte(runes[i])]; ok {
result := t.Time.Format(f)
// 有几个转换的符号需要特殊处理
switch runes[i] {
case 'j':
buffer.WriteString(gstr.ReplaceByArray(result, []string{"=j=0", "", "=j=", ""}))
case 'G':
buffer.WriteString(gstr.ReplaceByArray(result, []string{"=G=0", "", "=G=", ""}))
case 'u':
buffer.WriteString(strings.Replace(result, "=u=.", "", -1))
case 'w':
buffer.WriteString(weekMap[result])
default:
buffer.WriteString(result)
}
} else {
buffer.WriteRune(runes[i])
}
}
i++
}
return buffer.String()
}
// 格式化,使用标准库格式
func (t *Time) Layout(layout string) string {
return t.Time.Format(layout)
}
return t.Time.Format(layout)
}

View File

@ -1,10 +1,9 @@
package gtime_test
import (
"testing"
"github.com/gogf/gf/g/os/gtime"
"github.com/gogf/gf/g/test/gtest"
"testing"
)
func Test_Format(t *testing.T) {
@ -43,6 +42,20 @@ func Test_Format(t *testing.T) {
}
gtest.Assert(timeTemp2.Format("Y-n-j G:i:s"), "2006-1-2 3:04:05")
// 测试数字型的星期
times := []map[string]string{
{"k": "2019-04-22", "f": "w", "r": "1"},
{"k": "2019-04-27", "f": "w", "r": "6"},
{"k": "2019-03-10", "f": "w", "r": "0"},
{"k": "2019-03-10", "f": "Y-m-d 星期:w", "r": "2019-03-10 星期:0"},
}
for _, v := range times {
t1, err1 := gtime.StrToTime(v["k"], "Y-m-d")
gtest.Assert(err1, nil)
gtest.Assert(t1.Format(v["f"]), v["r"])
}
})
}

View File

@ -90,6 +90,12 @@ func New(path...string) *View {
"version" : gf.VERSION,
}
// default build-in functions.
view.BindFunc("eq", view.funcEq)
view.BindFunc("ne", view.funcNe)
view.BindFunc("lt", view.funcLt)
view.BindFunc("le", view.funcLe)
view.BindFunc("gt", view.funcGt)
view.BindFunc("ge", view.funcGe)
view.BindFunc("text", view.funcText)
view.BindFunc("html", view.funcHtmlEncode)
view.BindFunc("htmlencode", view.funcHtmlEncode)

View File

@ -16,6 +16,62 @@ import (
"strings"
)
// Build-in template function: eq
func (view *View) funcEq(value interface{}, others...interface{}) bool {
s := gconv.String(value)
for _, v := range others {
if strings.Compare(s, gconv.String(v)) != 0 {
return false
}
}
return true
}
// Build-in template function: ne
func (view *View) funcNe(value interface{}, other interface{}) bool {
return strings.Compare(gconv.String(value), gconv.String(other)) != 0
}
// Build-in template function: lt
func (view *View) funcLt(value interface{}, other interface{}) bool {
s1 := gconv.String(value)
s2 := gconv.String(other)
if gstr.IsNumeric(s1) && gstr.IsNumeric(s2) {
return gconv.Int64(value) < gconv.Int64(other)
}
return strings.Compare(s1, s2) < 0
}
// Build-in template function: le
func (view *View) funcLe(value interface{}, other interface{}) bool {
s1 := gconv.String(value)
s2 := gconv.String(other)
if gstr.IsNumeric(s1) && gstr.IsNumeric(s2) {
return gconv.Int64(value) <= gconv.Int64(other)
}
return strings.Compare(s1, s2) <= 0
}
// Build-in template function: gt
func (view *View) funcGt(value interface{}, other interface{}) bool {
s1 := gconv.String(value)
s2 := gconv.String(other)
if gstr.IsNumeric(s1) && gstr.IsNumeric(s2) {
return gconv.Int64(value) > gconv.Int64(other)
}
return strings.Compare(s1, s2) > 0
}
// Build-in template function: ge
func (view *View) funcGe(value interface{}, other interface{}) bool {
s1 := gconv.String(value)
s2 := gconv.String(other)
if gstr.IsNumeric(s1) && gstr.IsNumeric(s2) {
return gconv.Int64(value) >= gconv.Int64(other)
}
return strings.Compare(s1, s2) >= 0
}
// Build-in template function: include
func (view *View) funcInclude(file string, data...map[string]interface{}) string {
var m map[string]interface{} = nil

View File

@ -31,7 +31,8 @@ var (
// if the template files under <path> changes (recursively).
func (view *View) getTemplate(path string, pattern string) (tpl *template.Template, err error) {
r := templates.GetOrSetFuncLock(path, func() interface {} {
files, err := gfile.ScanDir(path, pattern, true)
files := ([]string)(nil)
files, err = gfile.ScanDir(path, pattern, true)
if err != nil {
return nil
}
@ -90,7 +91,7 @@ func (view *View) searchFile(file string) (path string, folder string, err error
// ParseContent parses given template file <file>
// with given template parameters <params> and function map <funcMap>
// and returns the parsed string content.
func (view *View) Parse(file string, params map[string]interface{}, funcMap...map[string]interface{}) (parsed string, err error) {
func (view *View) Parse(file string, params...Params) (parsed string, err error) {
view.mu.RLock()
defer view.mu.RUnlock()
path, folder, err := view.searchFile(file)
@ -101,9 +102,6 @@ func (view *View) Parse(file string, params map[string]interface{}, funcMap...ma
if err != nil {
return "", err
}
if len(funcMap) > 0 {
tpl = tpl.Funcs(funcMap[0])
}
tpl, err = tpl.Parse(gfcache.GetContents(path))
if err != nil {
return "", err
@ -112,10 +110,16 @@ func (view *View) Parse(file string, params map[string]interface{}, funcMap...ma
// of the existing <params> or view.data because both variables are pointers.
// It's need to merge the values of the two maps into a new map.
vars := (map[string]interface{})(nil)
length := len(view.data)
if len(params) > 0 {
length += len(params[0])
}
if length > 0 {
vars = make(map[string]interface{}, length)
}
if len(view.data) > 0 {
if len(params) > 0 {
vars = make(map[string]interface{}, len(view.data) + len(params))
for k, v := range params {
for k, v := range params[0] {
vars[k] = v
}
for k, v := range view.data {
@ -125,7 +129,9 @@ func (view *View) Parse(file string, params map[string]interface{}, funcMap...ma
vars = view.data
}
} else {
vars = params
if len(params) > 0 {
vars = params[0]
}
}
buffer := bytes.NewBuffer(nil)
if err := tpl.Execute(buffer, vars); err != nil {
@ -137,13 +143,10 @@ func (view *View) Parse(file string, params map[string]interface{}, funcMap...ma
// ParseContent parses given template content <content>
// with given template parameters <params> and function map <funcMap>
// and returns the parsed content in []byte.
func (view *View) ParseContent(content string, params Params, funcMap...map[string]interface{}) (string, error) {
func (view *View) ParseContent(content string, params...Params) (string, error) {
view.mu.RLock()
defer view.mu.RUnlock()
tpl := template.New("").Delims(view.delimiters[0], view.delimiters[1]).Funcs(view.funcMap)
if len(funcMap) > 0 {
tpl = tpl.Funcs(funcMap[0])
}
tpl := template.New("template content").Delims(view.delimiters[0], view.delimiters[1]).Funcs(view.funcMap)
tpl, err := tpl.Parse(content)
if err != nil {
return "", err
@ -152,10 +155,16 @@ func (view *View) ParseContent(content string, params Params, funcMap...map[stri
// of the existing <params> or view.data because both variables are pointers.
// It's need to merge the values of the two maps into a new map.
vars := (map[string]interface{})(nil)
length := len(view.data)
if len(params) > 0 {
length += len(params[0])
}
if length > 0 {
vars = make(map[string]interface{}, length)
}
if len(view.data) > 0 {
if len(params) > 0 {
vars = make(map[string]interface{}, len(view.data) + len(params))
for k, v := range params {
for k, v := range params[0] {
vars[k] = v
}
for k, v := range view.data {
@ -165,7 +174,9 @@ func (view *View) ParseContent(content string, params Params, funcMap...map[stri
vars = view.data
}
} else {
vars = params
if len(params) > 0 {
vars = params[0]
}
}
buffer := bytes.NewBuffer(nil)
if err := tpl.Execute(buffer, vars); err != nil {

View File

@ -111,10 +111,16 @@ func AssertGT(value, expect interface{}) {
}
}
// AssertGTE checks <value> is GREATER OR EQUAL THAN <expect>.
// See AssertGE.
// Deprecated.
func AssertGTE(value, expect interface{}) {
AssertGE(value, expect)
}
// AssertGE checks <value> is GREATER OR EQUAL THAN <expect>.
// Notice that, only string, integer and float types can be compared by AssertGTE,
// others are invalid.
func AssertGTE(value, expect interface{}) {
func AssertGE(value, expect interface{}) {
passed := false
switch reflect.ValueOf(expect).Kind() {
case reflect.String:
@ -157,10 +163,16 @@ func AssertLT(value, expect interface{}) {
}
}
// AssertLTE checks <value> is LESS OR EQUAL THAN <expect>.
// See AssertLE.
// Deprecated.
func AssertLTE(value, expect interface{}) {
AssertLE(value, expect)
}
// AssertLE checks <value> is LESS OR EQUAL THAN <expect>.
// Notice that, only string, integer and float types can be compared by AssertLTE,
// others are invalid.
func AssertLTE(value, expect interface{}) {
func AssertLE(value, expect interface{}) {
passed := false
switch reflect.ValueOf(expect).Kind() {
case reflect.String:

View File

@ -5,8 +5,6 @@
// You can obtain one at https://github.com/gogf/gf.
// Package gregex provides high performance API for regular expression functionality.
//
// 正则表达式.
package gregex
import (
@ -17,22 +15,18 @@ import (
// to match the rules of regular expression pattern.
// And returns the copy.
//
// 转移正则规则字符串,例如:Quote(`[foo]`) 返回 `\[foo\]`
// Eg: Quote(`[foo]`) returns `\[foo\]`.
func Quote(s string) string {
return regexp.QuoteMeta(s)
}
// Validate checks whether given regular expression pattern <pattern> valid.
//
// 校验所给定的正则表达式是否符合规范
func Validate(pattern string) error {
_, err := getRegexp(pattern)
return err
}
// IsMatch checks whether given bytes <src> matches <pattern>.
//
// 正则表达式是否匹配
func IsMatch(pattern string, src []byte) bool {
if r, err := getRegexp(pattern); err == nil {
return r.Match(src)
@ -41,15 +35,11 @@ func IsMatch(pattern string, src []byte) bool {
}
// IsMatchString checks whether given string <src> matches <pattern>.
//
// 判断给定的字符串<src>是否满足正则表达式<pattern>.
func IsMatchString(pattern string, src string) bool {
return IsMatch(pattern, []byte(src))
}
// MatchString return bytes slice that matched <pattern>.
//
// 正则匹配,并返回匹配的列表(参数[]byte)
func Match(pattern string, src []byte) ([][]byte, error) {
if r, err := getRegexp(pattern); err == nil {
return r.FindSubmatch(src), nil
@ -59,8 +49,6 @@ func Match(pattern string, src []byte) ([][]byte, error) {
}
// MatchString return strings that matched <pattern>.
//
// 正则匹配,并返回匹配的列表(参数[]string)
func MatchString(pattern string, src string) ([]string, error) {
if r, err := getRegexp(pattern); err == nil {
return r.FindStringSubmatch(src), nil
@ -70,8 +58,6 @@ func MatchString(pattern string, src string) ([]string, error) {
}
// MatchAll return all bytes slices that matched <pattern>.
//
// 正则匹配,并返回所有匹配的列表(参数[]string)
func MatchAll(pattern string, src []byte) ([][][]byte, error) {
if r, err := getRegexp(pattern); err == nil {
return r.FindAllSubmatch(src, -1), nil
@ -81,8 +67,6 @@ func MatchAll(pattern string, src []byte) ([][][]byte, error) {
}
// MatchAllString return all strings that matched <pattern>.
//
// 正则匹配,并返回所有匹配的列表(参数[][]string).
func MatchAllString(pattern string, src string) ([][]string, error) {
if r, err := getRegexp(pattern); err == nil {
return r.FindAllStringSubmatch(src, -1), nil
@ -92,8 +76,6 @@ func MatchAllString(pattern string, src string) ([][]string, error) {
}
// ReplaceString replace all matched <pattern> in bytes <src> with bytes <replace>.
//
// 正则替换(全部替换).
func Replace(pattern string, replace, src []byte) ([]byte, error) {
if r, err := getRegexp(pattern); err == nil {
return r.ReplaceAll(src, replace), nil
@ -103,8 +85,6 @@ func Replace(pattern string, replace, src []byte) ([]byte, error) {
}
// ReplaceString replace all matched <pattern> in string <src> with string <replace>.
//
// 正则替换(全部替换),字符串
func ReplaceString(pattern, replace, src string) (string, error) {
r, e := Replace(pattern, []byte(replace), []byte(src))
return string(r), e
@ -113,11 +93,26 @@ func ReplaceString(pattern, replace, src string) (string, error) {
// ReplaceFunc replace all matched <pattern> in bytes <src>
// with custom replacement function <replaceFunc>.
func ReplaceFunc(pattern string, src []byte, replaceFunc func(b []byte) []byte) ([]byte, error) {
if r, err := getRegexp(pattern); err == nil {
return r.ReplaceAllFunc(src, replaceFunc), nil
} else {
return nil, err
}
if r, err := getRegexp(pattern); err == nil {
return r.ReplaceAllFunc(src, replaceFunc), nil
} else {
return nil, err
}
}
// ReplaceFunc replace all matched <pattern> in bytes <src>
// with custom replacement function <replaceFunc>.
// The parameter <match> type for <replaceFunc> is [][]byte,
// which is the result contains all sub-patterns of <pattern> using Match function.
func ReplaceFuncMatch(pattern string, src []byte, replaceFunc func(match [][]byte) []byte) ([]byte, error) {
if r, err := getRegexp(pattern); err == nil {
return r.ReplaceAllFunc(src, func(bytes []byte) []byte {
match, _ := Match(pattern, src)
return replaceFunc(match)
}), nil
} else {
return nil, err
}
}
// ReplaceStringFunc replace all matched <pattern> in string <src>
@ -129,6 +124,21 @@ func ReplaceStringFunc(pattern string, src string, replaceFunc func(s string) st
return string(bytes), err
}
// ReplaceStringFuncMatch replace all matched <pattern> in string <src>
// with custom replacement function <replaceFunc>.
// The parameter <match> type for <replaceFunc> is []string,
// which is the result contains all sub-patterns of <pattern> using MatchString function.
func ReplaceStringFuncMatch(pattern string, src string, replaceFunc func(match []string) string) (string, error) {
if r, err := getRegexp(pattern); err == nil {
return string(r.ReplaceAllFunc([]byte(src), func(bytes []byte) []byte {
match, _ := MatchString(pattern, src)
return []byte(replaceFunc(match))
})), nil
} else {
return "", err
}
}
// Split slices <src> into substrings separated by the expression and returns a slice of
// the substrings between those expression matches.
func Split(pattern string, src string) []string {

View File

@ -11,13 +11,15 @@ import (
"sync"
)
// 缓存对象主要用于缓存底层regx对象
var (
regexMu = sync.RWMutex{}
regexMap = make(map[string]*regexp.Regexp)
)
// 根据pattern生成对应的regexp正则对象
// getRegexp returns *regexp.Regexp object with given <pattern>.
// It uses cache to enhance the performance for compiling regular expression pattern,
// which means, it will return the same *regexp.Regexp object with the same regular
// expression pattern.
func getRegexp(pattern string) (*regexp.Regexp, error) {
if r := getCache(pattern); r != nil {
return r, nil
@ -30,7 +32,7 @@ func getRegexp(pattern string) (*regexp.Regexp, error) {
}
}
// 获得正则缓存对象
// getCache returns *regexp.Regexp object from cache by given <pattern>, for internal usage.
func getCache(pattern string) (regex *regexp.Regexp) {
regexMu.RLock()
regex = regexMap[pattern]
@ -38,7 +40,7 @@ func getCache(pattern string) (regex *regexp.Regexp) {
return
}
// 设置正则缓存对象
// setCache stores *regexp.Regexp object into cache, for internal usage.
func setCache(pattern string, regex *regexp.Regexp) {
regexMu.Lock()
regexMap[pattern] = regex

View File

@ -185,6 +185,33 @@ func Test_ReplaceFun(t *testing.T) {
})
}
func Test_ReplaceFuncMatch(t *testing.T) {
gtest.Case(t, func() {
s := []byte("1234567890")
p := `(\d{3})(\d{3})(.+)`
s0, e0 := gregex.ReplaceFuncMatch(p, s, func(match [][]byte) []byte {
return match[0]
})
gtest.Assert(e0, nil)
gtest.Assert(s0, s)
s1, e1 := gregex.ReplaceFuncMatch(p, s, func(match [][]byte) []byte {
return match[1]
})
gtest.Assert(e1, nil)
gtest.Assert(s1, []byte("123"))
s2, e2 := gregex.ReplaceFuncMatch(p, s, func(match [][]byte) []byte {
return match[2]
})
gtest.Assert(e2, nil)
gtest.Assert(s2, []byte("456"))
s3, e3 := gregex.ReplaceFuncMatch(p, s, func(match [][]byte) []byte {
return match[3]
})
gtest.Assert(e3, nil)
gtest.Assert(s3, []byte("7890"))
})
}
func Test_ReplaceStringFunc(t *testing.T) {
gtest.Case(t, func() {
re := "a(a+b+)b"
@ -206,6 +233,33 @@ func Test_ReplaceStringFunc(t *testing.T) {
})
}
func Test_ReplaceStringFuncMatch(t *testing.T) {
gtest.Case(t, func() {
s := "1234567890"
p := `(\d{3})(\d{3})(.+)`
s0, e0 := gregex.ReplaceStringFuncMatch(p, s, func(match []string) string {
return match[0]
})
gtest.Assert(e0, nil)
gtest.Assert(s0, s)
s1, e1 := gregex.ReplaceStringFuncMatch(p, s, func(match []string) string {
return match[1]
})
gtest.Assert(e1, nil)
gtest.Assert(s1, "123")
s2, e2 := gregex.ReplaceStringFuncMatch(p, s, func(match []string) string {
return match[2]
})
gtest.Assert(e2, nil)
gtest.Assert(s2, "456")
s3, e3 := gregex.ReplaceStringFuncMatch(p, s, func(match []string) string {
return match[3]
})
gtest.Assert(e3, nil)
gtest.Assert(s3, "7890")
})
}
func Test_Split(t *testing.T) {
gtest.Case(t, func() {
re := "a(a+b+)b"

View File

@ -62,7 +62,7 @@ func Export(i...interface{}) string {
func PrintBacktrace() {
index := 1
buffer := bytes.NewBuffer(nil)
for i := 0; i < 10000; i++ {
for i := 1; i < 10000; i++ {
if _, path, line, ok := runtime.Caller(i); ok {
buffer.WriteString(fmt.Sprintf(`%d. %s:%d%s`, index, path, line, "\n"))
index++

View File

@ -7,13 +7,13 @@ import (
func main() {
// 创建一个非并发安全的集合对象
s := gset.New(false)
s := gset.New(true)
// 添加数据项
s.Add(1)
// 批量添加数据项
s.BatchAdd([]interface{}{1, 2, 3})
s.Add([]interface{}{1, 2, 3}...)
// 集合数据项大小
fmt.Println(s.Size())

View File

@ -0,0 +1,22 @@
package main
import (
"fmt"
"github.com/gogf/gf/g"
"github.com/gogf/gf/g/container/gset"
)
func main() {
s1 := gset.NewFrom(g.Slice{1, 2, 3})
s2 := gset.NewFrom(g.Slice{4, 5, 6})
s3 := gset.NewFrom(g.Slice{1, 2, 3, 4, 5, 6, 7})
// 交集
fmt.Println(s3.Intersect(s1).Slice())
// 差集
fmt.Println(s3.Diff(s1).Slice())
// 并集
fmt.Println(s1.Union(s2).Slice())
// 补集
fmt.Println(s1.Complement(s3).Slice())
}

View File

@ -6,13 +6,12 @@ import (
func main() {
s := ghttp.GetServer()
s.EnableAdmin()
s.BindHandler("/", func(r *ghttp.Request) {
r.Response.Writeln("您可以同时通过HTTP和HTTPS方式看到该内容")
})
s.EnableHTTPS("./server.crt", "./server.key")
s.SetHTTPSPort(8198, 8199)
s.SetPort(8200, 8300)
s.SetHTTPSPort(8100, 8200)
s.SetPort(8300, 8400)
s.EnableAdmin()
s.Run()
}

View File

@ -61,7 +61,7 @@ func main() {
//g.REST("/obj/rest", obj)
// 分组路由批量注册
s.Group("/api").Bind("/api", []ghttp.GroupItem{
s.Group("/api").Bind([]ghttp.GroupItem{
{"ALL", "/handler", Handler},
{"ALL", "/ctl", ctl},

View File

@ -0,0 +1,16 @@
package main
import (
"github.com/gogf/gf/g"
"github.com/gogf/gf/g/net/ghttp"
)
func main() {
s := g.Server()
s.BindHandler("/", func(r *ghttp.Request) {
content := `{{.Request.Get "name"}}`
r.Response.WriteTplContent(content)
})
s.SetPort(8199)
s.Run()
}

View File

@ -10,8 +10,13 @@ func main() {
s.BindHandler("/", func(r *ghttp.Request) {
r.Cookie.Set("theme", "default")
r.Session.Set("name", "john")
content := `Config:{{.Config.redis.cache}}, Cookie:{{.Cookie.theme}}, Session:{{.Session.name}}`
r.Response.WriteTplContent(content, nil)
content := `
Get: {{.Get.name}}
Post: {{.Post.name}}
Config: {{.Config.redis}}
Cookie: {{.Cookie.theme}},
Session: {{.Session.name}}`
r.Response.WriteTplContent(content)
})
s.SetPort(8199)
s.Run()

View File

@ -1,6 +1,7 @@
package main
import (
"github.com/gogf/gf/g"
"github.com/gogf/gf/g/frame/gmvc"
"github.com/gogf/gf/g/net/ghttp"
)
@ -11,7 +12,7 @@ type ControllerIndex struct {
func (c *ControllerIndex) Info() {
c.View.Assign("title", "Go Frame 第一个网站")
c.View.Assigns(map[string]interface{}{
c.View.Assigns(g.Map{
"name": "很开心1",
"score": 100,
})

View File

@ -14,9 +14,6 @@ func main() {
s.SetAccessLogEnabled(true)
s.SetPort(2333)
v := g.View()
v.AddPath("template")
s.BindHandler("/", func(r *ghttp.Request) {
content, _ := gins.View().Parse("test.html", nil)
r.Response.Write(content)

View File

@ -0,0 +1,45 @@
package main
import (
"fmt"
"github.com/gogf/gf/g"
)
func main() {
tplContent := `
eq:
eq "a" "a": {{eq "a" "a"}}
eq "1" "1": {{eq "1" "1"}}
eq 1 "1": {{eq 1 "1"}}
ne:
ne 1 "1": {{ne 1 "1"}}
ne "a" "a": {{ne "a" "a"}}
ne "a" "b": {{ne "a" "b"}}
lt:
lt 1 "2": {{lt 1 "2"}}
lt 2 2 : {{lt 2 2 }}
lt "a" "b": {{lt "a" "b"}}
le:
le 1 "2": {{le 1 "2"}}
le 2 1 : {{le 2 1 }}
le "a" "a": {{le "a" "a"}}
gt:
gt 1 "2": {{gt 1 "2"}}
gt 2 1 : {{gt 2 1 }}
gt "a" "a": {{gt "a" "a"}}
ge:
ge 1 "2": {{ge 1 "2"}}
ge 2 1 : {{ge 2 1 }}
ge "a" "a": {{ge "a" "a"}}
`
content, err := g.View().ParseContent(tplContent, nil)
if err != nil {
panic(err)
}
fmt.Println(content)
}

View File

@ -0,0 +1,21 @@
package main
import (
"github.com/gogf/gf/g"
"github.com/gogf/gf/g/frame/gmvc"
)
type Controller struct {
gmvc.Controller
}
func (c *Controller) Test() {
c.View.Display("layout.html")
}
func main() {
s := g.Server()
s.BindControllerMethod("/", new(Controller), "Test")
s.SetPort(8199)
s.Run()
}

View File

@ -0,0 +1,3 @@
{{define "container"}}
<h1>CONTAINER</h1>
{{end}}

View File

@ -0,0 +1,3 @@
{{define "footer"}}
<h1>FOOTER</h1>
{{end}}

View File

@ -0,0 +1,3 @@
{{define "header"}}
<h1>HEADER</h1>
{{end}}

View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<title>GoFrame Layout</title>
{{template "header"}}
</head>
<body>
<div class="container">
{{template "container"}}
</div>
<div class="footer">
{{template "footer"}}
</div>
</body>
</html>

View File

@ -0,0 +1,22 @@
package main
import (
"github.com/gogf/gf/g"
"github.com/gogf/gf/g/net/ghttp"
)
func main() {
s := g.Server()
s.BindHandler("/main1", func(r *ghttp.Request) {
r.Response.WriteTpl("layout.html", g.Map{
"mainTpl": "main/main1.html",
})
})
s.BindHandler("/main2", func(r *ghttp.Request) {
r.Response.WriteTpl("layout.html", g.Map{
"mainTpl": "main/main2.html",
})
})
s.SetPort(8199)
s.Run()
}

View File

@ -0,0 +1 @@
<h1>FOOTER</h1>

View File

@ -0,0 +1 @@
<h1>HEADER</h1>

View File

@ -0,0 +1,3 @@
{{include "header.html" .}}
{{include .mainTpl .}}
{{include "footer.html" .}}

View File

@ -0,0 +1 @@
<h1>MAIN1</h1>

View File

@ -0,0 +1 @@
<h1>MAIN2</h1>

View File

@ -2,44 +2,10 @@ package main
import (
"fmt"
"github.com/gogf/gf/g/crypto/gmd5"
"github.com/gogf/gf/g/encoding/gbase64"
"github.com/gogf/gf/g/text/gstr"
)
func main() {
//fmt.Println([]byte{152})
//fmt.Println(len([]byte{152}))
//fmt.Println(len(string([]byte{152})))
//fmt.Println(len(string(byte(152))))
//os.Exit(1)
//fmt.Println(gstr.Chr(152))
//fmt.Println(len(gstr.Chr(152)))
//os.Exit(1)
data := "abcdefg"
dict := "no"
key := gmd5.EncryptString(dict)
x := 0
lenb := len(data)
l := len(key)
char := ""
strb := ""
for i := 0; i < lenb; i++ {
if x == l {
x = 0
}
char += key[x : x+1]
x++
}
for i := 0; i < lenb; i++ {
fmt.Println((gstr.Ord(data[i:i+1]) + gstr.Ord(char[i:i+1]) % 256))
//fmt.Println(gstr.Chr((gstr.Ord(data[i:i+1]) + gstr.Ord(char[i:i+1]) % 256) ))
//fmt.Println(data[i:i+1], gstr.Ord(data[i:i+1]), gstr.Ord(char[i:i+1]))
strb += gstr.Chr((gstr.Ord(data[i:i+1]) + gstr.Ord(char[i:i+1]) % 256) )
fmt.Println(len(strb))
fmt.Println("=============")
}
fmt.Println(strb)
fmt.Println(len(strb))
result := gbase64.Encode(strb)
fmt.Println(result)
array := make([]interface{}, 0, 10)
array[8] = 1
fmt.Println(array)
}

View File

@ -1,4 +1,4 @@
package gf
const VERSION = "v1.6.3"
const VERSION = "v1.6.5"
const AUTHORS = "john<john@goframe.org>"