github.com/wangyougui/gf/v2@v2.6.5/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/wangyougui/gf.
     6  
     7  package garray
     8  
     9  import (
    10  	"bytes"
    11  	"math"
    12  	"sort"
    13  	"strings"
    14  
    15  	"github.com/wangyougui/gf/v2/errors/gcode"
    16  	"github.com/wangyougui/gf/v2/errors/gerror"
    17  	"github.com/wangyougui/gf/v2/internal/json"
    18  	"github.com/wangyougui/gf/v2/internal/rwmutex"
    19  	"github.com/wangyougui/gf/v2/text/gstr"
    20  	"github.com/wangyougui/gf/v2/util/gconv"
    21  	"github.com/wangyougui/gf/v2/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 `values` to the front of `index`.
   159  func (a *StrArray) InsertBefore(index int, values ...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], values...)
   167  	a.array = append(a.array, rear...)
   168  	return nil
   169  }
   170  
   171  // InsertAfter inserts the `values` to the back of `index`.
   172  func (a *StrArray) InsertAfter(index int, values ...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], values...)
   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  // RemoveValues removes multiple items by `values`.
   226  func (a *StrArray) RemoveValues(values ...string) {
   227  	a.mu.Lock()
   228  	defer a.mu.Unlock()
   229  	for _, value := range values {
   230  		if i := a.doSearchWithoutLock(value); i != -1 {
   231  			a.doRemoveWithoutLock(i)
   232  		}
   233  	}
   234  }
   235  
   236  // PushLeft pushes one or multiple items to the beginning of array.
   237  func (a *StrArray) PushLeft(value ...string) *StrArray {
   238  	a.mu.Lock()
   239  	a.array = append(value, a.array...)
   240  	a.mu.Unlock()
   241  	return a
   242  }
   243  
   244  // PushRight pushes one or multiple items to the end of array.
   245  // It equals to Append.
   246  func (a *StrArray) PushRight(value ...string) *StrArray {
   247  	a.mu.Lock()
   248  	a.array = append(a.array, value...)
   249  	a.mu.Unlock()
   250  	return a
   251  }
   252  
   253  // PopLeft pops and returns an item from the beginning of array.
   254  // Note that if the array is empty, the `found` is false.
   255  func (a *StrArray) PopLeft() (value string, found bool) {
   256  	a.mu.Lock()
   257  	defer a.mu.Unlock()
   258  	if len(a.array) == 0 {
   259  		return "", false
   260  	}
   261  	value = a.array[0]
   262  	a.array = a.array[1:]
   263  	return value, true
   264  }
   265  
   266  // PopRight pops and returns an item from the end of array.
   267  // Note that if the array is empty, the `found` is false.
   268  func (a *StrArray) PopRight() (value string, found bool) {
   269  	a.mu.Lock()
   270  	defer a.mu.Unlock()
   271  	index := len(a.array) - 1
   272  	if index < 0 {
   273  		return "", false
   274  	}
   275  	value = a.array[index]
   276  	a.array = a.array[:index]
   277  	return value, true
   278  }
   279  
   280  // PopRand randomly pops and return an item out of array.
   281  // Note that if the array is empty, the `found` is false.
   282  func (a *StrArray) PopRand() (value string, found bool) {
   283  	a.mu.Lock()
   284  	defer a.mu.Unlock()
   285  	return a.doRemoveWithoutLock(grand.Intn(len(a.array)))
   286  }
   287  
   288  // PopRands randomly pops and returns `size` items out of array.
   289  // If the given `size` is greater than size of the array, it returns all elements of the array.
   290  // Note that if given `size` <= 0 or the array is empty, it returns nil.
   291  func (a *StrArray) PopRands(size int) []string {
   292  	a.mu.Lock()
   293  	defer a.mu.Unlock()
   294  	if size <= 0 || len(a.array) == 0 {
   295  		return nil
   296  	}
   297  	if size >= len(a.array) {
   298  		size = len(a.array)
   299  	}
   300  	array := make([]string, size)
   301  	for i := 0; i < size; i++ {
   302  		array[i], _ = a.doRemoveWithoutLock(grand.Intn(len(a.array)))
   303  	}
   304  	return array
   305  }
   306  
   307  // PopLefts pops and returns `size` items from the beginning of array.
   308  // If the given `size` is greater than size of the array, it returns all elements of the array.
   309  // Note that if given `size` <= 0 or the array is empty, it returns nil.
   310  func (a *StrArray) PopLefts(size int) []string {
   311  	a.mu.Lock()
   312  	defer a.mu.Unlock()
   313  	if size <= 0 || len(a.array) == 0 {
   314  		return nil
   315  	}
   316  	if size >= len(a.array) {
   317  		array := a.array
   318  		a.array = a.array[:0]
   319  		return array
   320  	}
   321  	value := a.array[0:size]
   322  	a.array = a.array[size:]
   323  	return value
   324  }
   325  
   326  // PopRights pops and returns `size` items from the end of array.
   327  // If the given `size` is greater than size of the array, it returns all elements of the array.
   328  // Note that if given `size` <= 0 or the array is empty, it returns nil.
   329  func (a *StrArray) PopRights(size int) []string {
   330  	a.mu.Lock()
   331  	defer a.mu.Unlock()
   332  	if size <= 0 || len(a.array) == 0 {
   333  		return nil
   334  	}
   335  	index := len(a.array) - size
   336  	if index <= 0 {
   337  		array := a.array
   338  		a.array = a.array[:0]
   339  		return array
   340  	}
   341  	value := a.array[index:]
   342  	a.array = a.array[:index]
   343  	return value
   344  }
   345  
   346  // Range picks and returns items by range, like array[start:end].
   347  // Notice, if in concurrent-safe usage, it returns a copy of slice;
   348  // else a pointer to the underlying data.
   349  //
   350  // If `end` is negative, then the offset will start from the end of array.
   351  // If `end` is omitted, then the sequence will have everything from start up
   352  // until the end of the array.
   353  func (a *StrArray) Range(start int, end ...int) []string {
   354  	a.mu.RLock()
   355  	defer a.mu.RUnlock()
   356  	offsetEnd := len(a.array)
   357  	if len(end) > 0 && end[0] < offsetEnd {
   358  		offsetEnd = end[0]
   359  	}
   360  	if start > offsetEnd {
   361  		return nil
   362  	}
   363  	if start < 0 {
   364  		start = 0
   365  	}
   366  	array := ([]string)(nil)
   367  	if a.mu.IsSafe() {
   368  		array = make([]string, offsetEnd-start)
   369  		copy(array, a.array[start:offsetEnd])
   370  	} else {
   371  		array = a.array[start:offsetEnd]
   372  	}
   373  	return array
   374  }
   375  
   376  // SubSlice returns a slice of elements from the array as specified
   377  // by the `offset` and `size` parameters.
   378  // If in concurrent safe usage, it returns a copy of the slice; else a pointer.
   379  //
   380  // If offset is non-negative, the sequence will start at that offset in the array.
   381  // If offset is negative, the sequence will start that far from the end of the array.
   382  //
   383  // If length is given and is positive, then the sequence will have up to that many elements in it.
   384  // If the array is shorter than the length, then only the available array elements will be present.
   385  // If length is given and is negative then the sequence will stop that many elements from the end of the array.
   386  // If it is omitted, then the sequence will have everything from offset up until the end of the array.
   387  //
   388  // Any possibility crossing the left border of array, it will fail.
   389  func (a *StrArray) SubSlice(offset int, length ...int) []string {
   390  	a.mu.RLock()
   391  	defer a.mu.RUnlock()
   392  	size := len(a.array)
   393  	if len(length) > 0 {
   394  		size = length[0]
   395  	}
   396  	if offset > len(a.array) {
   397  		return nil
   398  	}
   399  	if offset < 0 {
   400  		offset = len(a.array) + offset
   401  		if offset < 0 {
   402  			return nil
   403  		}
   404  	}
   405  	if size < 0 {
   406  		offset += size
   407  		size = -size
   408  		if offset < 0 {
   409  			return nil
   410  		}
   411  	}
   412  	end := offset + size
   413  	if end > len(a.array) {
   414  		end = len(a.array)
   415  		size = len(a.array) - offset
   416  	}
   417  	if a.mu.IsSafe() {
   418  		s := make([]string, size)
   419  		copy(s, a.array[offset:])
   420  		return s
   421  	}
   422  	return a.array[offset:end]
   423  }
   424  
   425  // Append is alias of PushRight,please See PushRight.
   426  func (a *StrArray) Append(value ...string) *StrArray {
   427  	a.mu.Lock()
   428  	a.array = append(a.array, value...)
   429  	a.mu.Unlock()
   430  	return a
   431  }
   432  
   433  // Len returns the length of array.
   434  func (a *StrArray) Len() int {
   435  	a.mu.RLock()
   436  	length := len(a.array)
   437  	a.mu.RUnlock()
   438  	return length
   439  }
   440  
   441  // Slice returns the underlying data of array.
   442  // Note that, if it's in concurrent-safe usage, it returns a copy of underlying data,
   443  // or else a pointer to the underlying data.
   444  func (a *StrArray) Slice() []string {
   445  	array := ([]string)(nil)
   446  	if a.mu.IsSafe() {
   447  		a.mu.RLock()
   448  		defer a.mu.RUnlock()
   449  		array = make([]string, len(a.array))
   450  		copy(array, a.array)
   451  	} else {
   452  		array = a.array
   453  	}
   454  	return array
   455  }
   456  
   457  // Interfaces returns current array as []interface{}.
   458  func (a *StrArray) Interfaces() []interface{} {
   459  	a.mu.RLock()
   460  	defer a.mu.RUnlock()
   461  	array := make([]interface{}, len(a.array))
   462  	for k, v := range a.array {
   463  		array[k] = v
   464  	}
   465  	return array
   466  }
   467  
   468  // Clone returns a new array, which is a copy of current array.
   469  func (a *StrArray) Clone() (newArray *StrArray) {
   470  	a.mu.RLock()
   471  	array := make([]string, len(a.array))
   472  	copy(array, a.array)
   473  	a.mu.RUnlock()
   474  	return NewStrArrayFrom(array, a.mu.IsSafe())
   475  }
   476  
   477  // Clear deletes all items of current array.
   478  func (a *StrArray) Clear() *StrArray {
   479  	a.mu.Lock()
   480  	if len(a.array) > 0 {
   481  		a.array = make([]string, 0)
   482  	}
   483  	a.mu.Unlock()
   484  	return a
   485  }
   486  
   487  // Contains checks whether a value exists in the array.
   488  func (a *StrArray) Contains(value string) bool {
   489  	return a.Search(value) != -1
   490  }
   491  
   492  // ContainsI checks whether a value exists in the array with case-insensitively.
   493  // Note that it internally iterates the whole array to do the comparison with case-insensitively.
   494  func (a *StrArray) ContainsI(value string) bool {
   495  	a.mu.RLock()
   496  	defer a.mu.RUnlock()
   497  	if len(a.array) == 0 {
   498  		return false
   499  	}
   500  	for _, v := range a.array {
   501  		if strings.EqualFold(v, value) {
   502  			return true
   503  		}
   504  	}
   505  	return false
   506  }
   507  
   508  // Search searches array by `value`, returns the index of `value`,
   509  // or returns -1 if not exists.
   510  func (a *StrArray) Search(value string) int {
   511  	a.mu.RLock()
   512  	defer a.mu.RUnlock()
   513  	return a.doSearchWithoutLock(value)
   514  }
   515  
   516  func (a *StrArray) doSearchWithoutLock(value string) int {
   517  	if len(a.array) == 0 {
   518  		return -1
   519  	}
   520  	result := -1
   521  	for index, v := range a.array {
   522  		if strings.Compare(v, value) == 0 {
   523  			result = index
   524  			break
   525  		}
   526  	}
   527  	return result
   528  }
   529  
   530  // Unique uniques the array, clear repeated items.
   531  // Example: [1,1,2,3,2] -> [1,2,3]
   532  func (a *StrArray) Unique() *StrArray {
   533  	a.mu.Lock()
   534  	defer a.mu.Unlock()
   535  	if len(a.array) == 0 {
   536  		return a
   537  	}
   538  	var (
   539  		ok          bool
   540  		temp        string
   541  		uniqueSet   = make(map[string]struct{})
   542  		uniqueArray = make([]string, 0, len(a.array))
   543  	)
   544  	for i := 0; i < len(a.array); i++ {
   545  		temp = a.array[i]
   546  		if _, ok = uniqueSet[temp]; ok {
   547  			continue
   548  		}
   549  		uniqueSet[temp] = struct{}{}
   550  		uniqueArray = append(uniqueArray, temp)
   551  	}
   552  	a.array = uniqueArray
   553  	return a
   554  }
   555  
   556  // LockFunc locks writing by callback function `f`.
   557  func (a *StrArray) LockFunc(f func(array []string)) *StrArray {
   558  	a.mu.Lock()
   559  	defer a.mu.Unlock()
   560  	f(a.array)
   561  	return a
   562  }
   563  
   564  // RLockFunc locks reading by callback function `f`.
   565  func (a *StrArray) RLockFunc(f func(array []string)) *StrArray {
   566  	a.mu.RLock()
   567  	defer a.mu.RUnlock()
   568  	f(a.array)
   569  	return a
   570  }
   571  
   572  // Merge merges `array` into current array.
   573  // The parameter `array` can be any garray or slice type.
   574  // The difference between Merge and Append is Append supports only specified slice type,
   575  // but Merge supports more parameter types.
   576  func (a *StrArray) Merge(array interface{}) *StrArray {
   577  	return a.Append(gconv.Strings(array)...)
   578  }
   579  
   580  // Fill fills an array with num entries of the value `value`,
   581  // keys starting at the `startIndex` parameter.
   582  func (a *StrArray) Fill(startIndex int, num int, value string) error {
   583  	a.mu.Lock()
   584  	defer a.mu.Unlock()
   585  	if startIndex < 0 || startIndex > len(a.array) {
   586  		return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", startIndex, len(a.array))
   587  	}
   588  	for i := startIndex; i < startIndex+num; i++ {
   589  		if i > len(a.array)-1 {
   590  			a.array = append(a.array, value)
   591  		} else {
   592  			a.array[i] = value
   593  		}
   594  	}
   595  	return nil
   596  }
   597  
   598  // Chunk splits an array into multiple arrays,
   599  // the size of each array is determined by `size`.
   600  // The last chunk may contain less than size elements.
   601  func (a *StrArray) Chunk(size int) [][]string {
   602  	if size < 1 {
   603  		return nil
   604  	}
   605  	a.mu.RLock()
   606  	defer a.mu.RUnlock()
   607  	length := len(a.array)
   608  	chunks := int(math.Ceil(float64(length) / float64(size)))
   609  	var n [][]string
   610  	for i, end := 0, 0; chunks > 0; chunks-- {
   611  		end = (i + 1) * size
   612  		if end > length {
   613  			end = length
   614  		}
   615  		n = append(n, a.array[i*size:end])
   616  		i++
   617  	}
   618  	return n
   619  }
   620  
   621  // Pad pads array to the specified length with `value`.
   622  // If size is positive then the array is padded on the right, or negative on the left.
   623  // If the absolute value of `size` is less than or equal to the length of the array
   624  // then no padding takes place.
   625  func (a *StrArray) Pad(size int, value string) *StrArray {
   626  	a.mu.Lock()
   627  	defer a.mu.Unlock()
   628  	if size == 0 || (size > 0 && size < len(a.array)) || (size < 0 && size > -len(a.array)) {
   629  		return a
   630  	}
   631  	n := size
   632  	if size < 0 {
   633  		n = -size
   634  	}
   635  	n -= len(a.array)
   636  	tmp := make([]string, n)
   637  	for i := 0; i < n; i++ {
   638  		tmp[i] = value
   639  	}
   640  	if size > 0 {
   641  		a.array = append(a.array, tmp...)
   642  	} else {
   643  		a.array = append(tmp, a.array...)
   644  	}
   645  	return a
   646  }
   647  
   648  // Rand randomly returns one item from array(no deleting).
   649  func (a *StrArray) Rand() (value string, found bool) {
   650  	a.mu.RLock()
   651  	defer a.mu.RUnlock()
   652  	if len(a.array) == 0 {
   653  		return "", false
   654  	}
   655  	return a.array[grand.Intn(len(a.array))], true
   656  }
   657  
   658  // Rands randomly returns `size` items from array(no deleting).
   659  func (a *StrArray) Rands(size int) []string {
   660  	a.mu.RLock()
   661  	defer a.mu.RUnlock()
   662  	if size <= 0 || len(a.array) == 0 {
   663  		return nil
   664  	}
   665  	array := make([]string, size)
   666  	for i := 0; i < size; i++ {
   667  		array[i] = a.array[grand.Intn(len(a.array))]
   668  	}
   669  	return array
   670  }
   671  
   672  // Shuffle randomly shuffles the array.
   673  func (a *StrArray) Shuffle() *StrArray {
   674  	a.mu.Lock()
   675  	defer a.mu.Unlock()
   676  	for i, v := range grand.Perm(len(a.array)) {
   677  		a.array[i], a.array[v] = a.array[v], a.array[i]
   678  	}
   679  	return a
   680  }
   681  
   682  // Reverse makes array with elements in reverse order.
   683  func (a *StrArray) Reverse() *StrArray {
   684  	a.mu.Lock()
   685  	defer a.mu.Unlock()
   686  	for i, j := 0, len(a.array)-1; i < j; i, j = i+1, j-1 {
   687  		a.array[i], a.array[j] = a.array[j], a.array[i]
   688  	}
   689  	return a
   690  }
   691  
   692  // Join joins array elements with a string `glue`.
   693  func (a *StrArray) Join(glue string) string {
   694  	a.mu.RLock()
   695  	defer a.mu.RUnlock()
   696  	if len(a.array) == 0 {
   697  		return ""
   698  	}
   699  	buffer := bytes.NewBuffer(nil)
   700  	for k, v := range a.array {
   701  		buffer.WriteString(v)
   702  		if k != len(a.array)-1 {
   703  			buffer.WriteString(glue)
   704  		}
   705  	}
   706  	return buffer.String()
   707  }
   708  
   709  // CountValues counts the number of occurrences of all values in the array.
   710  func (a *StrArray) CountValues() map[string]int {
   711  	m := make(map[string]int)
   712  	a.mu.RLock()
   713  	defer a.mu.RUnlock()
   714  	for _, v := range a.array {
   715  		m[v]++
   716  	}
   717  	return m
   718  }
   719  
   720  // Iterator is alias of IteratorAsc.
   721  func (a *StrArray) Iterator(f func(k int, v string) bool) {
   722  	a.IteratorAsc(f)
   723  }
   724  
   725  // IteratorAsc iterates the array readonly in ascending order with given callback function `f`.
   726  // If `f` returns true, then it continues iterating; or false to stop.
   727  func (a *StrArray) IteratorAsc(f func(k int, v string) bool) {
   728  	a.mu.RLock()
   729  	defer a.mu.RUnlock()
   730  	for k, v := range a.array {
   731  		if !f(k, v) {
   732  			break
   733  		}
   734  	}
   735  }
   736  
   737  // IteratorDesc iterates the array readonly in descending order with given callback function `f`.
   738  // If `f` returns true, then it continues iterating; or false to stop.
   739  func (a *StrArray) IteratorDesc(f func(k int, v string) bool) {
   740  	a.mu.RLock()
   741  	defer a.mu.RUnlock()
   742  	for i := len(a.array) - 1; i >= 0; i-- {
   743  		if !f(i, a.array[i]) {
   744  			break
   745  		}
   746  	}
   747  }
   748  
   749  // String returns current array as a string, which implements like json.Marshal does.
   750  func (a *StrArray) String() string {
   751  	if a == nil {
   752  		return ""
   753  	}
   754  	a.mu.RLock()
   755  	defer a.mu.RUnlock()
   756  	buffer := bytes.NewBuffer(nil)
   757  	buffer.WriteByte('[')
   758  	for k, v := range a.array {
   759  		buffer.WriteString(`"` + gstr.QuoteMeta(v, `"\`) + `"`)
   760  		if k != len(a.array)-1 {
   761  			buffer.WriteByte(',')
   762  		}
   763  	}
   764  	buffer.WriteByte(']')
   765  	return buffer.String()
   766  }
   767  
   768  // MarshalJSON implements the interface MarshalJSON for json.Marshal.
   769  // Note that do not use pointer as its receiver here.
   770  func (a StrArray) MarshalJSON() ([]byte, error) {
   771  	a.mu.RLock()
   772  	defer a.mu.RUnlock()
   773  	return json.Marshal(a.array)
   774  }
   775  
   776  // UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.
   777  func (a *StrArray) UnmarshalJSON(b []byte) error {
   778  	if a.array == nil {
   779  		a.array = make([]string, 0)
   780  	}
   781  	a.mu.Lock()
   782  	defer a.mu.Unlock()
   783  	if err := json.UnmarshalUseNumber(b, &a.array); err != nil {
   784  		return err
   785  	}
   786  	return nil
   787  }
   788  
   789  // UnmarshalValue is an interface implement which sets any type of value for array.
   790  func (a *StrArray) UnmarshalValue(value interface{}) error {
   791  	a.mu.Lock()
   792  	defer a.mu.Unlock()
   793  	switch value.(type) {
   794  	case string, []byte:
   795  		return json.UnmarshalUseNumber(gconv.Bytes(value), &a.array)
   796  	default:
   797  		a.array = gconv.SliceStr(value)
   798  	}
   799  	return nil
   800  }
   801  
   802  // Filter iterates array and filters elements using custom callback function.
   803  // It removes the element from array if callback function `filter` returns true,
   804  // it or else does nothing and continues iterating.
   805  func (a *StrArray) Filter(filter func(index int, value string) bool) *StrArray {
   806  	a.mu.Lock()
   807  	defer a.mu.Unlock()
   808  	for i := 0; i < len(a.array); {
   809  		if filter(i, a.array[i]) {
   810  			a.array = append(a.array[:i], a.array[i+1:]...)
   811  		} else {
   812  			i++
   813  		}
   814  	}
   815  	return a
   816  }
   817  
   818  // FilterEmpty removes all empty string value of the array.
   819  func (a *StrArray) FilterEmpty() *StrArray {
   820  	a.mu.Lock()
   821  	defer a.mu.Unlock()
   822  	for i := 0; i < len(a.array); {
   823  		if a.array[i] == "" {
   824  			a.array = append(a.array[:i], a.array[i+1:]...)
   825  		} else {
   826  			i++
   827  		}
   828  	}
   829  	return a
   830  }
   831  
   832  // Walk applies a user supplied function `f` to every item of array.
   833  func (a *StrArray) Walk(f func(value string) string) *StrArray {
   834  	a.mu.Lock()
   835  	defer a.mu.Unlock()
   836  	for i, v := range a.array {
   837  		a.array[i] = f(v)
   838  	}
   839  	return a
   840  }
   841  
   842  // IsEmpty checks whether the array is empty.
   843  func (a *StrArray) IsEmpty() bool {
   844  	return a.Len() == 0
   845  }
   846  
   847  // DeepCopy implements interface for deep copy of current type.
   848  func (a *StrArray) DeepCopy() interface{} {
   849  	if a == nil {
   850  		return nil
   851  	}
   852  	a.mu.RLock()
   853  	defer a.mu.RUnlock()
   854  	newSlice := make([]string, len(a.array))
   855  	copy(newSlice, a.array)
   856  	return NewStrArrayFrom(newSlice, a.mu.IsSafe())
   857  }