github.com/gogf/gf@v1.16.9/container/garray/garray_normal_str.go (about)

     1  // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/gogf/gf.
     6  
     7  package garray
     8  
     9  import (
    10  	"bytes"
    11  	"github.com/gogf/gf/errors/gcode"
    12  	"github.com/gogf/gf/errors/gerror"
    13  	"github.com/gogf/gf/internal/json"
    14  	"github.com/gogf/gf/text/gstr"
    15  	"math"
    16  	"sort"
    17  	"strings"
    18  
    19  	"github.com/gogf/gf/internal/rwmutex"
    20  	"github.com/gogf/gf/util/gconv"
    21  	"github.com/gogf/gf/util/grand"
    22  )
    23  
    24  // StrArray is a golang string array with rich features.
    25  // It contains a concurrent-safe/unsafe switch, which should be set
    26  // when its initialization and cannot be changed then.
    27  type StrArray struct {
    28  	mu    rwmutex.RWMutex
    29  	array []string
    30  }
    31  
    32  // NewStrArray creates and returns an empty array.
    33  // The parameter `safe` is used to specify whether using array in concurrent-safety,
    34  // which is false in default.
    35  func NewStrArray(safe ...bool) *StrArray {
    36  	return NewStrArraySize(0, 0, safe...)
    37  }
    38  
    39  // NewStrArraySize create and returns an array with given size and cap.
    40  // The parameter `safe` is used to specify whether using array in concurrent-safety,
    41  // which is false in default.
    42  func NewStrArraySize(size int, cap int, safe ...bool) *StrArray {
    43  	return &StrArray{
    44  		mu:    rwmutex.Create(safe...),
    45  		array: make([]string, size, cap),
    46  	}
    47  }
    48  
    49  // NewStrArrayFrom creates and returns an array with given slice `array`.
    50  // The parameter `safe` is used to specify whether using array in concurrent-safety,
    51  // which is false in default.
    52  func NewStrArrayFrom(array []string, safe ...bool) *StrArray {
    53  	return &StrArray{
    54  		mu:    rwmutex.Create(safe...),
    55  		array: array,
    56  	}
    57  }
    58  
    59  // NewStrArrayFromCopy creates and returns an array from a copy of given slice `array`.
    60  // The parameter `safe` is used to specify whether using array in concurrent-safety,
    61  // which is false in default.
    62  func NewStrArrayFromCopy(array []string, safe ...bool) *StrArray {
    63  	newArray := make([]string, len(array))
    64  	copy(newArray, array)
    65  	return &StrArray{
    66  		mu:    rwmutex.Create(safe...),
    67  		array: newArray,
    68  	}
    69  }
    70  
    71  // At returns the value by the specified index.
    72  // If the given `index` is out of range of the array, it returns an empty string.
    73  func (a *StrArray) At(index int) (value string) {
    74  	value, _ = a.Get(index)
    75  	return
    76  }
    77  
    78  // Get returns the value by the specified index.
    79  // If the given `index` is out of range of the array, the `found` is false.
    80  func (a *StrArray) Get(index int) (value string, found bool) {
    81  	a.mu.RLock()
    82  	defer a.mu.RUnlock()
    83  	if index < 0 || index >= len(a.array) {
    84  		return "", false
    85  	}
    86  	return a.array[index], true
    87  }
    88  
    89  // Set sets value to specified index.
    90  func (a *StrArray) Set(index int, value string) error {
    91  	a.mu.Lock()
    92  	defer a.mu.Unlock()
    93  	if index < 0 || index >= len(a.array) {
    94  		return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
    95  	}
    96  	a.array[index] = value
    97  	return nil
    98  }
    99  
   100  // SetArray sets the underlying slice array with the given `array`.
   101  func (a *StrArray) SetArray(array []string) *StrArray {
   102  	a.mu.Lock()
   103  	defer a.mu.Unlock()
   104  	a.array = array
   105  	return a
   106  }
   107  
   108  // Replace replaces the array items by given `array` from the beginning of array.
   109  func (a *StrArray) Replace(array []string) *StrArray {
   110  	a.mu.Lock()
   111  	defer a.mu.Unlock()
   112  	max := len(array)
   113  	if max > len(a.array) {
   114  		max = len(a.array)
   115  	}
   116  	for i := 0; i < max; i++ {
   117  		a.array[i] = array[i]
   118  	}
   119  	return a
   120  }
   121  
   122  // Sum returns the sum of values in an array.
   123  func (a *StrArray) Sum() (sum int) {
   124  	a.mu.RLock()
   125  	defer a.mu.RUnlock()
   126  	for _, v := range a.array {
   127  		sum += gconv.Int(v)
   128  	}
   129  	return
   130  }
   131  
   132  // Sort sorts the array in increasing order.
   133  // The parameter `reverse` controls whether sort
   134  // in increasing order(default) or decreasing order
   135  func (a *StrArray) Sort(reverse ...bool) *StrArray {
   136  	a.mu.Lock()
   137  	defer a.mu.Unlock()
   138  	if len(reverse) > 0 && reverse[0] {
   139  		sort.Slice(a.array, func(i, j int) bool {
   140  			return strings.Compare(a.array[i], a.array[j]) >= 0
   141  		})
   142  	} else {
   143  		sort.Strings(a.array)
   144  	}
   145  	return a
   146  }
   147  
   148  // SortFunc sorts the array by custom function `less`.
   149  func (a *StrArray) SortFunc(less func(v1, v2 string) bool) *StrArray {
   150  	a.mu.Lock()
   151  	defer a.mu.Unlock()
   152  	sort.Slice(a.array, func(i, j int) bool {
   153  		return less(a.array[i], a.array[j])
   154  	})
   155  	return a
   156  }
   157  
   158  // InsertBefore inserts the `value` to the front of `index`.
   159  func (a *StrArray) InsertBefore(index int, value string) error {
   160  	a.mu.Lock()
   161  	defer a.mu.Unlock()
   162  	if index < 0 || index >= len(a.array) {
   163  		return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
   164  	}
   165  	rear := append([]string{}, a.array[index:]...)
   166  	a.array = append(a.array[0:index], value)
   167  	a.array = append(a.array, rear...)
   168  	return nil
   169  }
   170  
   171  // InsertAfter inserts the `value` to the back of `index`.
   172  func (a *StrArray) InsertAfter(index int, value string) error {
   173  	a.mu.Lock()
   174  	defer a.mu.Unlock()
   175  	if index < 0 || index >= len(a.array) {
   176  		return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
   177  	}
   178  	rear := append([]string{}, a.array[index+1:]...)
   179  	a.array = append(a.array[0:index+1], value)
   180  	a.array = append(a.array, rear...)
   181  	return nil
   182  }
   183  
   184  // Remove removes an item by index.
   185  // If the given `index` is out of range of the array, the `found` is false.
   186  func (a *StrArray) Remove(index int) (value string, found bool) {
   187  	a.mu.Lock()
   188  	defer a.mu.Unlock()
   189  	return a.doRemoveWithoutLock(index)
   190  }
   191  
   192  // doRemoveWithoutLock removes an item by index without lock.
   193  func (a *StrArray) doRemoveWithoutLock(index int) (value string, found bool) {
   194  	if index < 0 || index >= len(a.array) {
   195  		return "", false
   196  	}
   197  	// Determine array boundaries when deleting to improve deletion efficiency.
   198  	if index == 0 {
   199  		value := a.array[0]
   200  		a.array = a.array[1:]
   201  		return value, true
   202  	} else if index == len(a.array)-1 {
   203  		value := a.array[index]
   204  		a.array = a.array[:index]
   205  		return value, true
   206  	}
   207  	// If it is a non-boundary delete,
   208  	// it will involve the creation of an array,
   209  	// then the deletion is less efficient.
   210  	value = a.array[index]
   211  	a.array = append(a.array[:index], a.array[index+1:]...)
   212  	return value, true
   213  }
   214  
   215  // RemoveValue removes an item by value.
   216  // It returns true if value is found in the array, or else false if not found.
   217  func (a *StrArray) RemoveValue(value string) bool {
   218  	if i := a.Search(value); i != -1 {
   219  		_, found := a.Remove(i)
   220  		return found
   221  	}
   222  	return false
   223  }
   224  
   225  // PushLeft pushes one or multiple items to the beginning of array.
   226  func (a *StrArray) PushLeft(value ...string) *StrArray {
   227  	a.mu.Lock()
   228  	a.array = append(value, a.array...)
   229  	a.mu.Unlock()
   230  	return a
   231  }
   232  
   233  // PushRight pushes one or multiple items to the end of array.
   234  // It equals to Append.
   235  func (a *StrArray) PushRight(value ...string) *StrArray {
   236  	a.mu.Lock()
   237  	a.array = append(a.array, value...)
   238  	a.mu.Unlock()
   239  	return a
   240  }
   241  
   242  // PopLeft pops and returns an item from the beginning of array.
   243  // Note that if the array is empty, the `found` is false.
   244  func (a *StrArray) PopLeft() (value string, found bool) {
   245  	a.mu.Lock()
   246  	defer a.mu.Unlock()
   247  	if len(a.array) == 0 {
   248  		return "", false
   249  	}
   250  	value = a.array[0]
   251  	a.array = a.array[1:]
   252  	return value, true
   253  }
   254  
   255  // PopRight pops and returns an item from the end of array.
   256  // Note that if the array is empty, the `found` is false.
   257  func (a *StrArray) PopRight() (value string, found bool) {
   258  	a.mu.Lock()
   259  	defer a.mu.Unlock()
   260  	index := len(a.array) - 1
   261  	if index < 0 {
   262  		return "", false
   263  	}
   264  	value = a.array[index]
   265  	a.array = a.array[:index]
   266  	return value, true
   267  }
   268  
   269  // PopRand randomly pops and return an item out of array.
   270  // Note that if the array is empty, the `found` is false.
   271  func (a *StrArray) PopRand() (value string, found bool) {
   272  	a.mu.Lock()
   273  	defer a.mu.Unlock()
   274  	return a.doRemoveWithoutLock(grand.Intn(len(a.array)))
   275  }
   276  
   277  // PopRands randomly pops and returns `size` items out of array.
   278  // If the given `size` is greater than size of the array, it returns all elements of the array.
   279  // Note that if given `size` <= 0 or the array is empty, it returns nil.
   280  func (a *StrArray) PopRands(size int) []string {
   281  	a.mu.Lock()
   282  	defer a.mu.Unlock()
   283  	if size <= 0 || len(a.array) == 0 {
   284  		return nil
   285  	}
   286  	if size >= len(a.array) {
   287  		size = len(a.array)
   288  	}
   289  	array := make([]string, size)
   290  	for i := 0; i < size; i++ {
   291  		array[i], _ = a.doRemoveWithoutLock(grand.Intn(len(a.array)))
   292  	}
   293  	return array
   294  }
   295  
   296  // PopLefts pops and returns `size` items from the beginning of array.
   297  // If the given `size` is greater than size of the array, it returns all elements of the array.
   298  // Note that if given `size` <= 0 or the array is empty, it returns nil.
   299  func (a *StrArray) PopLefts(size int) []string {
   300  	a.mu.Lock()
   301  	defer a.mu.Unlock()
   302  	if size <= 0 || len(a.array) == 0 {
   303  		return nil
   304  	}
   305  	if size >= len(a.array) {
   306  		array := a.array
   307  		a.array = a.array[:0]
   308  		return array
   309  	}
   310  	value := a.array[0:size]
   311  	a.array = a.array[size:]
   312  	return value
   313  }
   314  
   315  // PopRights pops and returns `size` items from the end of array.
   316  // If the given `size` is greater than size of the array, it returns all elements of the array.
   317  // Note that if given `size` <= 0 or the array is empty, it returns nil.
   318  func (a *StrArray) PopRights(size int) []string {
   319  	a.mu.Lock()
   320  	defer a.mu.Unlock()
   321  	if size <= 0 || len(a.array) == 0 {
   322  		return nil
   323  	}
   324  	index := len(a.array) - size
   325  	if index <= 0 {
   326  		array := a.array
   327  		a.array = a.array[:0]
   328  		return array
   329  	}
   330  	value := a.array[index:]
   331  	a.array = a.array[:index]
   332  	return value
   333  }
   334  
   335  // Range picks and returns items by range, like array[start:end].
   336  // Notice, if in concurrent-safe usage, it returns a copy of slice;
   337  // else a pointer to the underlying data.
   338  //
   339  // If `end` is negative, then the offset will start from the end of array.
   340  // If `end` is omitted, then the sequence will have everything from start up
   341  // until the end of the array.
   342  func (a *StrArray) Range(start int, end ...int) []string {
   343  	a.mu.RLock()
   344  	defer a.mu.RUnlock()
   345  	offsetEnd := len(a.array)
   346  	if len(end) > 0 && end[0] < offsetEnd {
   347  		offsetEnd = end[0]
   348  	}
   349  	if start > offsetEnd {
   350  		return nil
   351  	}
   352  	if start < 0 {
   353  		start = 0
   354  	}
   355  	array := ([]string)(nil)
   356  	if a.mu.IsSafe() {
   357  		array = make([]string, offsetEnd-start)
   358  		copy(array, a.array[start:offsetEnd])
   359  	} else {
   360  		array = a.array[start:offsetEnd]
   361  	}
   362  	return array
   363  }
   364  
   365  // SubSlice returns a slice of elements from the array as specified
   366  // by the `offset` and `size` parameters.
   367  // If in concurrent safe usage, it returns a copy of the slice; else a pointer.
   368  //
   369  // If offset is non-negative, the sequence will start at that offset in the array.
   370  // If offset is negative, the sequence will start that far from the end of the array.
   371  //
   372  // If length is given and is positive, then the sequence will have up to that many elements in it.
   373  // If the array is shorter than the length, then only the available array elements will be present.
   374  // If length is given and is negative then the sequence will stop that many elements from the end of the array.
   375  // If it is omitted, then the sequence will have everything from offset up until the end of the array.
   376  //
   377  // Any possibility crossing the left border of array, it will fail.
   378  func (a *StrArray) SubSlice(offset int, length ...int) []string {
   379  	a.mu.RLock()
   380  	defer a.mu.RUnlock()
   381  	size := len(a.array)
   382  	if len(length) > 0 {
   383  		size = length[0]
   384  	}
   385  	if offset > len(a.array) {
   386  		return nil
   387  	}
   388  	if offset < 0 {
   389  		offset = len(a.array) + offset
   390  		if offset < 0 {
   391  			return nil
   392  		}
   393  	}
   394  	if size < 0 {
   395  		offset += size
   396  		size = -size
   397  		if offset < 0 {
   398  			return nil
   399  		}
   400  	}
   401  	end := offset + size
   402  	if end > len(a.array) {
   403  		end = len(a.array)
   404  		size = len(a.array) - offset
   405  	}
   406  	if a.mu.IsSafe() {
   407  		s := make([]string, size)
   408  		copy(s, a.array[offset:])
   409  		return s
   410  	} else {
   411  		return a.array[offset:end]
   412  	}
   413  }
   414  
   415  // Append is alias of PushRight,please See PushRight.
   416  func (a *StrArray) Append(value ...string) *StrArray {
   417  	a.mu.Lock()
   418  	a.array = append(a.array, value...)
   419  	a.mu.Unlock()
   420  	return a
   421  }
   422  
   423  // Len returns the length of array.
   424  func (a *StrArray) Len() int {
   425  	a.mu.RLock()
   426  	length := len(a.array)
   427  	a.mu.RUnlock()
   428  	return length
   429  }
   430  
   431  // Slice returns the underlying data of array.
   432  // Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,
   433  // or else a pointer to the underlying data.
   434  func (a *StrArray) Slice() []string {
   435  	array := ([]string)(nil)
   436  	if a.mu.IsSafe() {
   437  		a.mu.RLock()
   438  		defer a.mu.RUnlock()
   439  		array = make([]string, len(a.array))
   440  		copy(array, a.array)
   441  	} else {
   442  		array = a.array
   443  	}
   444  	return array
   445  }
   446  
   447  // Interfaces returns current array as []interface{}.
   448  func (a *StrArray) Interfaces() []interface{} {
   449  	a.mu.RLock()
   450  	defer a.mu.RUnlock()
   451  	array := make([]interface{}, len(a.array))
   452  	for k, v := range a.array {
   453  		array[k] = v
   454  	}
   455  	return array
   456  }
   457  
   458  // Clone returns a new array, which is a copy of current array.
   459  func (a *StrArray) Clone() (newArray *StrArray) {
   460  	a.mu.RLock()
   461  	array := make([]string, len(a.array))
   462  	copy(array, a.array)
   463  	a.mu.RUnlock()
   464  	return NewStrArrayFrom(array, a.mu.IsSafe())
   465  }
   466  
   467  // Clear deletes all items of current array.
   468  func (a *StrArray) Clear() *StrArray {
   469  	a.mu.Lock()
   470  	if len(a.array) > 0 {
   471  		a.array = make([]string, 0)
   472  	}
   473  	a.mu.Unlock()
   474  	return a
   475  }
   476  
   477  // Contains checks whether a value exists in the array.
   478  func (a *StrArray) Contains(value string) bool {
   479  	return a.Search(value) != -1
   480  }
   481  
   482  // ContainsI checks whether a value exists in the array with case-insensitively.
   483  // Note that it internally iterates the whole array to do the comparison with case-insensitively.
   484  func (a *StrArray) ContainsI(value string) bool {
   485  	a.mu.RLock()
   486  	defer a.mu.RUnlock()
   487  	if len(a.array) == 0 {
   488  		return false
   489  	}
   490  	for _, v := range a.array {
   491  		if strings.EqualFold(v, value) {
   492  			return true
   493  		}
   494  	}
   495  	return false
   496  }
   497  
   498  // Search searches array by `value`, returns the index of `value`,
   499  // or returns -1 if not exists.
   500  func (a *StrArray) Search(value string) int {
   501  	a.mu.RLock()
   502  	defer a.mu.RUnlock()
   503  	if len(a.array) == 0 {
   504  		return -1
   505  	}
   506  	result := -1
   507  	for index, v := range a.array {
   508  		if strings.Compare(v, value) == 0 {
   509  			result = index
   510  			break
   511  		}
   512  	}
   513  	return result
   514  }
   515  
   516  // Unique uniques the array, clear repeated items.
   517  // Example: [1,1,2,3,2] -> [1,2,3]
   518  func (a *StrArray) Unique() *StrArray {
   519  	a.mu.Lock()
   520  	for i := 0; i < len(a.array)-1; i++ {
   521  		for j := i + 1; j < len(a.array); {
   522  			if a.array[i] == a.array[j] {
   523  				a.array = append(a.array[:j], a.array[j+1:]...)
   524  			} else {
   525  				j++
   526  			}
   527  		}
   528  	}
   529  	a.mu.Unlock()
   530  	return a
   531  }
   532  
   533  // LockFunc locks writing by callback function `f`.
   534  func (a *StrArray) LockFunc(f func(array []string)) *StrArray {
   535  	a.mu.Lock()
   536  	defer a.mu.Unlock()
   537  	f(a.array)
   538  	return a
   539  }
   540  
   541  // RLockFunc locks reading by callback function `f`.
   542  func (a *StrArray) RLockFunc(f func(array []string)) *StrArray {
   543  	a.mu.RLock()
   544  	defer a.mu.RUnlock()
   545  	f(a.array)
   546  	return a
   547  }
   548  
   549  // Merge merges `array` into current array.
   550  // The parameter `array` can be any garray or slice type.
   551  // The difference between Merge and Append is Append supports only specified slice type,
   552  // but Merge supports more parameter types.
   553  func (a *StrArray) Merge(array interface{}) *StrArray {
   554  	return a.Append(gconv.Strings(array)...)
   555  }
   556  
   557  // Fill fills an array with num entries of the value `value`,
   558  // keys starting at the `startIndex` parameter.
   559  func (a *StrArray) Fill(startIndex int, num int, value string) error {
   560  	a.mu.Lock()
   561  	defer a.mu.Unlock()
   562  	if startIndex < 0 || startIndex > len(a.array) {
   563  		return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", startIndex, len(a.array))
   564  	}
   565  	for i := startIndex; i < startIndex+num; i++ {
   566  		if i > len(a.array)-1 {
   567  			a.array = append(a.array, value)
   568  		} else {
   569  			a.array[i] = value
   570  		}
   571  	}
   572  	return nil
   573  }
   574  
   575  // Chunk splits an array into multiple arrays,
   576  // the size of each array is determined by `size`.
   577  // The last chunk may contain less than size elements.
   578  func (a *StrArray) Chunk(size int) [][]string {
   579  	if size < 1 {
   580  		return nil
   581  	}
   582  	a.mu.RLock()
   583  	defer a.mu.RUnlock()
   584  	length := len(a.array)
   585  	chunks := int(math.Ceil(float64(length) / float64(size)))
   586  	var n [][]string
   587  	for i, end := 0, 0; chunks > 0; chunks-- {
   588  		end = (i + 1) * size
   589  		if end > length {
   590  			end = length
   591  		}
   592  		n = append(n, a.array[i*size:end])
   593  		i++
   594  	}
   595  	return n
   596  }
   597  
   598  // Pad pads array to the specified length with `value`.
   599  // If size is positive then the array is padded on the right, or negative on the left.
   600  // If the absolute value of `size` is less than or equal to the length of the array
   601  // then no padding takes place.
   602  func (a *StrArray) Pad(size int, value string) *StrArray {
   603  	a.mu.Lock()
   604  	defer a.mu.Unlock()
   605  	if size == 0 || (size > 0 && size < len(a.array)) || (size < 0 && size > -len(a.array)) {
   606  		return a
   607  	}
   608  	n := size
   609  	if size < 0 {
   610  		n = -size
   611  	}
   612  	n -= len(a.array)
   613  	tmp := make([]string, n)
   614  	for i := 0; i < n; i++ {
   615  		tmp[i] = value
   616  	}
   617  	if size > 0 {
   618  		a.array = append(a.array, tmp...)
   619  	} else {
   620  		a.array = append(tmp, a.array...)
   621  	}
   622  	return a
   623  }
   624  
   625  // Rand randomly returns one item from array(no deleting).
   626  func (a *StrArray) Rand() (value string, found bool) {
   627  	a.mu.RLock()
   628  	defer a.mu.RUnlock()
   629  	if len(a.array) == 0 {
   630  		return "", false
   631  	}
   632  	return a.array[grand.Intn(len(a.array))], true
   633  }
   634  
   635  // Rands randomly returns `size` items from array(no deleting).
   636  func (a *StrArray) Rands(size int) []string {
   637  	a.mu.RLock()
   638  	defer a.mu.RUnlock()
   639  	if size <= 0 || len(a.array) == 0 {
   640  		return nil
   641  	}
   642  	array := make([]string, size)
   643  	for i := 0; i < size; i++ {
   644  		array[i] = a.array[grand.Intn(len(a.array))]
   645  	}
   646  	return array
   647  }
   648  
   649  // Shuffle randomly shuffles the array.
   650  func (a *StrArray) Shuffle() *StrArray {
   651  	a.mu.Lock()
   652  	defer a.mu.Unlock()
   653  	for i, v := range grand.Perm(len(a.array)) {
   654  		a.array[i], a.array[v] = a.array[v], a.array[i]
   655  	}
   656  	return a
   657  }
   658  
   659  // Reverse makes array with elements in reverse order.
   660  func (a *StrArray) Reverse() *StrArray {
   661  	a.mu.Lock()
   662  	defer a.mu.Unlock()
   663  	for i, j := 0, len(a.array)-1; i < j; i, j = i+1, j-1 {
   664  		a.array[i], a.array[j] = a.array[j], a.array[i]
   665  	}
   666  	return a
   667  }
   668  
   669  // Join joins array elements with a string `glue`.
   670  func (a *StrArray) Join(glue string) string {
   671  	a.mu.RLock()
   672  	defer a.mu.RUnlock()
   673  	if len(a.array) == 0 {
   674  		return ""
   675  	}
   676  	buffer := bytes.NewBuffer(nil)
   677  	for k, v := range a.array {
   678  		buffer.WriteString(v)
   679  		if k != len(a.array)-1 {
   680  			buffer.WriteString(glue)
   681  		}
   682  	}
   683  	return buffer.String()
   684  }
   685  
   686  // CountValues counts the number of occurrences of all values in the array.
   687  func (a *StrArray) CountValues() map[string]int {
   688  	m := make(map[string]int)
   689  	a.mu.RLock()
   690  	defer a.mu.RUnlock()
   691  	for _, v := range a.array {
   692  		m[v]++
   693  	}
   694  	return m
   695  }
   696  
   697  // Iterator is alias of IteratorAsc.
   698  func (a *StrArray) Iterator(f func(k int, v string) bool) {
   699  	a.IteratorAsc(f)
   700  }
   701  
   702  // IteratorAsc iterates the array readonly in ascending order with given callback function `f`.
   703  // If `f` returns true, then it continues iterating; or false to stop.
   704  func (a *StrArray) IteratorAsc(f func(k int, v string) bool) {
   705  	a.mu.RLock()
   706  	defer a.mu.RUnlock()
   707  	for k, v := range a.array {
   708  		if !f(k, v) {
   709  			break
   710  		}
   711  	}
   712  }
   713  
   714  // IteratorDesc iterates the array readonly in descending order with given callback function `f`.
   715  // If `f` returns true, then it continues iterating; or false to stop.
   716  func (a *StrArray) IteratorDesc(f func(k int, v string) bool) {
   717  	a.mu.RLock()
   718  	defer a.mu.RUnlock()
   719  	for i := len(a.array) - 1; i >= 0; i-- {
   720  		if !f(i, a.array[i]) {
   721  			break
   722  		}
   723  	}
   724  }
   725  
   726  // String returns current array as a string, which implements like json.Marshal does.
   727  func (a *StrArray) String() string {
   728  	a.mu.RLock()
   729  	defer a.mu.RUnlock()
   730  	buffer := bytes.NewBuffer(nil)
   731  	buffer.WriteByte('[')
   732  	for k, v := range a.array {
   733  		buffer.WriteString(`"` + gstr.QuoteMeta(v, `"\`) + `"`)
   734  		if k != len(a.array)-1 {
   735  			buffer.WriteByte(',')
   736  		}
   737  	}
   738  	buffer.WriteByte(']')
   739  	return buffer.String()
   740  }
   741  
   742  // MarshalJSON implements the interface MarshalJSON for json.Marshal.
   743  // Note that do not use pointer as its receiver here.
   744  func (a StrArray) MarshalJSON() ([]byte, error) {
   745  	a.mu.RLock()
   746  	defer a.mu.RUnlock()
   747  	return json.Marshal(a.array)
   748  }
   749  
   750  // UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
   751  func (a *StrArray) UnmarshalJSON(b []byte) error {
   752  	if a.array == nil {
   753  		a.array = make([]string, 0)
   754  	}
   755  	a.mu.Lock()
   756  	defer a.mu.Unlock()
   757  	if err := json.UnmarshalUseNumber(b, &a.array); err != nil {
   758  		return err
   759  	}
   760  	return nil
   761  }
   762  
   763  // UnmarshalValue is an interface implement which sets any type of value for array.
   764  func (a *StrArray) UnmarshalValue(value interface{}) error {
   765  	a.mu.Lock()
   766  	defer a.mu.Unlock()
   767  	switch value.(type) {
   768  	case string, []byte:
   769  		return json.UnmarshalUseNumber(gconv.Bytes(value), &a.array)
   770  	default:
   771  		a.array = gconv.SliceStr(value)
   772  	}
   773  	return nil
   774  }
   775  
   776  // FilterEmpty removes all empty string value of the array.
   777  func (a *StrArray) FilterEmpty() *StrArray {
   778  	a.mu.Lock()
   779  	defer a.mu.Unlock()
   780  	for i := 0; i < len(a.array); {
   781  		if a.array[i] == "" {
   782  			a.array = append(a.array[:i], a.array[i+1:]...)
   783  		} else {
   784  			i++
   785  		}
   786  	}
   787  	return a
   788  }
   789  
   790  // Walk applies a user supplied function `f` to every item of array.
   791  func (a *StrArray) Walk(f func(value string) string) *StrArray {
   792  	a.mu.Lock()
   793  	defer a.mu.Unlock()
   794  	for i, v := range a.array {
   795  		a.array[i] = f(v)
   796  	}
   797  	return a
   798  }
   799  
   800  // IsEmpty checks whether the array is empty.
   801  func (a *StrArray) IsEmpty() bool {
   802  	return a.Len() == 0
   803  }