mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-07-20 12:34:30 -04:00
The goutil that OpenCloud currently uses is one version from the release that adds FreeBSD support, this now compiles successfully on FreeBSD.
310 lines
6.7 KiB
Go
310 lines
6.7 KiB
Go
package arrutil
|
|
|
|
import (
|
|
"errors"
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/gookit/goutil/comdef"
|
|
"github.com/gookit/goutil/mathutil"
|
|
"github.com/gookit/goutil/reflects"
|
|
"github.com/gookit/goutil/strutil"
|
|
)
|
|
|
|
// ErrInvalidType error
|
|
var ErrInvalidType = errors.New("the input param type is invalid")
|
|
|
|
/*************************************************************
|
|
* Join func for slice
|
|
*************************************************************/
|
|
|
|
// JoinStrings alias of strings.Join
|
|
func JoinStrings(sep string, ss ...string) string {
|
|
return strings.Join(ss, sep)
|
|
}
|
|
|
|
// StringsJoin alias of strings.Join
|
|
func StringsJoin(sep string, ss ...string) string {
|
|
return strings.Join(ss, sep)
|
|
}
|
|
|
|
// JoinTyped join typed []T slice to string.
|
|
//
|
|
// Usage:
|
|
//
|
|
// JoinTyped(",", 1,2,3) // "1,2,3"
|
|
// JoinTyped(",", "a","b","c") // "a,b,c"
|
|
// JoinTyped[any](",", "a",1,"c") // "a,1,c"
|
|
func JoinTyped[T any](sep string, arr ...T) string {
|
|
if arr == nil {
|
|
return ""
|
|
}
|
|
|
|
var sb strings.Builder
|
|
for i, v := range arr {
|
|
if i > 0 {
|
|
sb.WriteString(sep)
|
|
}
|
|
sb.WriteString(strutil.QuietString(v))
|
|
}
|
|
|
|
return sb.String()
|
|
}
|
|
|
|
// JoinSlice join []any slice to string.
|
|
func JoinSlice(sep string, arr ...any) string {
|
|
if arr == nil {
|
|
return ""
|
|
}
|
|
|
|
var sb strings.Builder
|
|
for i, v := range arr {
|
|
if i > 0 {
|
|
sb.WriteString(sep)
|
|
}
|
|
sb.WriteString(strutil.QuietString(v))
|
|
}
|
|
|
|
return sb.String()
|
|
}
|
|
|
|
/*************************************************************
|
|
* convert func for ints
|
|
*************************************************************/
|
|
|
|
// IntsToString convert []T to string
|
|
func IntsToString[T comdef.Integer](ints []T) string {
|
|
if len(ints) == 0 {
|
|
return "[]"
|
|
}
|
|
|
|
var sb strings.Builder
|
|
sb.WriteByte('[')
|
|
for i, v := range ints {
|
|
if i > 0 {
|
|
sb.WriteByte(',')
|
|
}
|
|
sb.WriteString(strconv.FormatInt(int64(v), 10))
|
|
}
|
|
sb.WriteByte(']')
|
|
return sb.String()
|
|
}
|
|
|
|
// ToInt64s convert any(allow: array,slice) to []int64
|
|
func ToInt64s(arr any) (ret []int64, err error) {
|
|
rv := reflect.ValueOf(arr)
|
|
if rv.Kind() != reflect.Slice && rv.Kind() != reflect.Array {
|
|
err = ErrInvalidType
|
|
return
|
|
}
|
|
|
|
for i := 0; i < rv.Len(); i++ {
|
|
i64, err := mathutil.Int64(rv.Index(i).Interface())
|
|
if err != nil {
|
|
return []int64{}, err
|
|
}
|
|
|
|
ret = append(ret, i64)
|
|
}
|
|
return
|
|
}
|
|
|
|
// MustToInt64s convert any(allow: array,slice) to []int64
|
|
func MustToInt64s(arr any) []int64 {
|
|
ret, _ := ToInt64s(arr)
|
|
return ret
|
|
}
|
|
|
|
// SliceToInt64s convert []any to []int64
|
|
func SliceToInt64s(arr []any) []int64 {
|
|
i64s := make([]int64, len(arr))
|
|
for i, v := range arr {
|
|
i64s[i] = mathutil.QuietInt64(v)
|
|
}
|
|
return i64s
|
|
}
|
|
|
|
// ToMap convert a list to new map.
|
|
//
|
|
// Example:
|
|
// type User struct {
|
|
// Name string
|
|
// Age int
|
|
// }
|
|
// users := []User{{"Tom", 18}, {"Jack", 20}}
|
|
// mp := arrutil.ToMap(users, func(u User) (string, int) {
|
|
// return u.Name, u.Age
|
|
// })
|
|
// // mp = map[string]int{"Tom":18, "Jack":20}
|
|
func ToMap[T any, K comdef.ScalarType, V any](list []T, mapFn func(T) (K, V)) map[K]V {
|
|
mp := make(map[K]V, len(list))
|
|
for _, item := range list {
|
|
k, v := mapFn(item)
|
|
mp[k] = v
|
|
}
|
|
return mp
|
|
}
|
|
|
|
/*************************************************************
|
|
* convert func for any-slice
|
|
*************************************************************/
|
|
|
|
// AnyToSlice convert any(allow: array,slice) to []any
|
|
func AnyToSlice(sl any) (ls []any, err error) {
|
|
rfKeys := reflect.ValueOf(sl)
|
|
if rfKeys.Kind() != reflect.Slice && rfKeys.Kind() != reflect.Array {
|
|
return nil, ErrInvalidType
|
|
}
|
|
|
|
for i := 0; i < rfKeys.Len(); i++ {
|
|
ls = append(ls, rfKeys.Index(i).Interface())
|
|
}
|
|
return
|
|
}
|
|
|
|
// AnyToStrings convert array or slice to []string
|
|
func AnyToStrings(arr any) []string {
|
|
ret, _ := ToStrings(arr)
|
|
return ret
|
|
}
|
|
|
|
// MustToStrings convert array or slice to []string
|
|
func MustToStrings(arr any) []string {
|
|
ret, err := ToStrings(arr)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return ret
|
|
}
|
|
|
|
// ToStrings convert any(allow: array,slice) to []string
|
|
func ToStrings(arr any) (ret []string, err error) {
|
|
// try direct convert
|
|
switch typVal := arr.(type) {
|
|
case string:
|
|
return []string{typVal}, nil
|
|
case []string:
|
|
return typVal, nil
|
|
case []any:
|
|
return SliceToStrings(typVal), nil
|
|
}
|
|
|
|
// try use reflect to convert
|
|
rv := reflect.ValueOf(arr)
|
|
if rv.Kind() != reflect.Slice && rv.Kind() != reflect.Array {
|
|
err = ErrInvalidType
|
|
return
|
|
}
|
|
|
|
for i := 0; i < rv.Len(); i++ {
|
|
str, err1 := strutil.ToString(rv.Index(i).Interface())
|
|
if err1 != nil {
|
|
return nil, err1
|
|
}
|
|
ret = append(ret, str)
|
|
}
|
|
return
|
|
}
|
|
|
|
// SliceToStrings safe convert []any to []string
|
|
func SliceToStrings(arr []any) []string {
|
|
ss := make([]string, len(arr))
|
|
for i, v := range arr {
|
|
ss[i] = strutil.SafeString(v)
|
|
}
|
|
return ss
|
|
}
|
|
|
|
// QuietStrings safe convert []any to []string
|
|
func QuietStrings(arr []any) []string { return SliceToStrings(arr) }
|
|
|
|
// ConvType convert type of slice elements to new type slice, by the given newElemTyp type.
|
|
//
|
|
// Supports conversion between []string, []intX, []uintX, []floatX.
|
|
//
|
|
// Usage:
|
|
//
|
|
// ints, _ := arrutil.ConvType([]string{"12", "23"}, 1) // []int{12, 23}
|
|
func ConvType[T any, R any](arr []T, newElemTyp R) ([]R, error) {
|
|
newArr := make([]R, len(arr))
|
|
elemTyp := reflect.TypeOf(newElemTyp)
|
|
|
|
for i, elem := range arr {
|
|
var anyElem any = elem
|
|
// type is same.
|
|
if _, ok := anyElem.(R); ok {
|
|
newArr[i] = anyElem.(R)
|
|
continue
|
|
}
|
|
|
|
// need conv type.
|
|
rfVal, err := reflects.ValueByType(elem, elemTyp)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
newArr[i] = rfVal.Interface().(R)
|
|
}
|
|
return newArr, nil
|
|
}
|
|
|
|
// AnyToString simple and quickly convert any array, slice to string
|
|
func AnyToString(arr any) string {
|
|
return NewFormatter(arr).Format()
|
|
}
|
|
|
|
// SliceToString convert []any to string
|
|
func SliceToString(arr ...any) string { return ToString(arr) }
|
|
|
|
// ToString simple and quickly convert []T to string
|
|
func ToString[T any](arr []T) string {
|
|
// like fmt.Println([]any(nil))
|
|
if arr == nil {
|
|
return "[]"
|
|
}
|
|
|
|
var sb strings.Builder
|
|
sb.WriteByte('[')
|
|
|
|
for i, v := range arr {
|
|
if i > 0 {
|
|
sb.WriteByte(',')
|
|
}
|
|
sb.WriteString(strutil.SafeString(v))
|
|
}
|
|
|
|
sb.WriteByte(']')
|
|
return sb.String()
|
|
}
|
|
|
|
// CombineToMap combine []K and []V slice to map[K]V.
|
|
//
|
|
// If keys length is greater than values, the extra keys will be ignored.
|
|
func CombineToMap[K comdef.SortedType, V any](keys []K, values []V) map[K]V {
|
|
ln := len(values)
|
|
mp := make(map[K]V, len(keys))
|
|
|
|
for i, key := range keys {
|
|
if i >= ln {
|
|
break
|
|
}
|
|
mp[key] = values[i]
|
|
}
|
|
return mp
|
|
}
|
|
|
|
// CombineToSMap combine two string-slice to map[string]string
|
|
func CombineToSMap(keys, values []string) map[string]string {
|
|
ln := len(values)
|
|
mp := make(map[string]string, len(keys))
|
|
|
|
for i, key := range keys {
|
|
if ln > i {
|
|
mp[key] = values[i]
|
|
} else {
|
|
mp[key] = ""
|
|
}
|
|
}
|
|
return mp
|
|
}
|