mirror of
https://gitee.com/johng/gf
synced 2026-06-09 19:13:58 +08:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 66306464e1 | |||
| dd34ac1722 | |||
| 34cb222b33 | |||
| d39ef156de | |||
| f464dc7fb8 | |||
| d29b27a5df | |||
| aadc6aa504 | |||
| e8c3dfa13e | |||
| 9eea93cc6e | |||
| 308cb55b6b | |||
| 75ada78f8f | |||
| ecd86e3a12 | |||
| c1aa5eb717 | |||
| d2fed1198b | |||
| a9f9261dbd | |||
| 161e0d6e97 | |||
| 3efe511f42 | |||
| e6fb41504c | |||
| a800f731dd | |||
| f1a9fbb74e | |||
| cf81a73526 | |||
| 65036fffe8 | |||
| a69934a7e3 | |||
| 90e6f685b7 | |||
| 16a4a5ba46 | |||
| b489eed4ef |
@ -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)
|
||||
}
|
||||
@ -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()
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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 < v2;0: v1 == v2;1: 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)
|
||||
}
|
||||
@ -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 < v2;0: v1 == v2;1: 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)
|
||||
}
|
||||
@ -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 < v2;0: v1 == v2;1: 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)
|
||||
}
|
||||
@ -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()
|
||||
|
||||
@ -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 方法是深克隆
|
||||
|
||||
@ -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})
|
||||
|
||||
@ -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"})
|
||||
|
||||
@ -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"})
|
||||
|
||||
@ -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 方法是深克隆
|
||||
|
||||
@ -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})
|
||||
|
||||
@ -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 方法是深克隆
|
||||
|
||||
@ -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"})
|
||||
|
||||
@ -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"})
|
||||
|
||||
@ -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()
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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")
|
||||
})
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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...)
|
||||
}
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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"},
|
||||
|
||||
@ -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 ""
|
||||
}
|
||||
|
||||
|
||||
@ -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", // 时区缩写, 例如:UTC,GMT,CST
|
||||
// ================== 时区 ==================
|
||||
'O': "-0700", // 与UTC相差的小时数, 例如:+0200
|
||||
'P': "-07:00", // 与UTC的差别,小时和分钟之间有冒号分隔, 例如:+02:00
|
||||
'T': "MST", // 时区缩写, 例如:UTC,GMT,CST
|
||||
|
||||
// ================== 完整的日期/时间 ==================
|
||||
'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)
|
||||
}
|
||||
|
||||
@ -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"])
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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++
|
||||
|
||||
@ -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())
|
||||
22
geg/container/gset/gset2.go
Normal file
22
geg/container/gset/gset2.go
Normal 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())
|
||||
}
|
||||
@ -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()
|
||||
}
|
||||
|
||||
@ -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},
|
||||
|
||||
16
geg/net/ghttp/server/template/build-in/objects/objects.go
Normal file
16
geg/net/ghttp/server/template/build-in/objects/objects.go
Normal 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()
|
||||
}
|
||||
@ -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()
|
||||
@ -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,
|
||||
})
|
||||
|
||||
@ -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)
|
||||
|
||||
45
geg/os/gview/build_in_funcs/build_in_funcs2.go
Normal file
45
geg/os/gview/build_in_funcs/build_in_funcs2.go
Normal 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)
|
||||
}
|
||||
21
geg/os/gview/layout/layout1/main.go
Normal file
21
geg/os/gview/layout/layout1/main.go
Normal 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()
|
||||
}
|
||||
3
geg/os/gview/layout/layout1/template/container.html
Normal file
3
geg/os/gview/layout/layout1/template/container.html
Normal file
@ -0,0 +1,3 @@
|
||||
{{define "container"}}
|
||||
<h1>CONTAINER</h1>
|
||||
{{end}}
|
||||
3
geg/os/gview/layout/layout1/template/footer.html
Normal file
3
geg/os/gview/layout/layout1/template/footer.html
Normal file
@ -0,0 +1,3 @@
|
||||
{{define "footer"}}
|
||||
<h1>FOOTER</h1>
|
||||
{{end}}
|
||||
3
geg/os/gview/layout/layout1/template/header.html
Normal file
3
geg/os/gview/layout/layout1/template/header.html
Normal file
@ -0,0 +1,3 @@
|
||||
{{define "header"}}
|
||||
<h1>HEADER</h1>
|
||||
{{end}}
|
||||
15
geg/os/gview/layout/layout1/template/layout.html
Normal file
15
geg/os/gview/layout/layout1/template/layout.html
Normal 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>
|
||||
22
geg/os/gview/layout/layout2/main.go
Normal file
22
geg/os/gview/layout/layout2/main.go
Normal 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()
|
||||
}
|
||||
1
geg/os/gview/layout/layout2/template/footer.html
Normal file
1
geg/os/gview/layout/layout2/template/footer.html
Normal file
@ -0,0 +1 @@
|
||||
<h1>FOOTER</h1>
|
||||
1
geg/os/gview/layout/layout2/template/header.html
Normal file
1
geg/os/gview/layout/layout2/template/header.html
Normal file
@ -0,0 +1 @@
|
||||
<h1>HEADER</h1>
|
||||
3
geg/os/gview/layout/layout2/template/layout.html
Normal file
3
geg/os/gview/layout/layout2/template/layout.html
Normal file
@ -0,0 +1,3 @@
|
||||
{{include "header.html" .}}
|
||||
{{include .mainTpl .}}
|
||||
{{include "footer.html" .}}
|
||||
1
geg/os/gview/layout/layout2/template/main/main1.html
Normal file
1
geg/os/gview/layout/layout2/template/main/main1.html
Normal file
@ -0,0 +1 @@
|
||||
<h1>MAIN1</h1>
|
||||
1
geg/os/gview/layout/layout2/template/main/main2.html
Normal file
1
geg/os/gview/layout/layout2/template/main/main2.html
Normal file
@ -0,0 +1 @@
|
||||
<h1>MAIN2</h1>
|
||||
@ -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)
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package gf
|
||||
|
||||
const VERSION = "v1.6.3"
|
||||
const VERSION = "v1.6.5"
|
||||
const AUTHORS = "john<john@goframe.org>"
|
||||
|
||||
Reference in New Issue
Block a user