mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-05-02 13:13:34 -04:00
The goutil that OpenCloud currently uses is one version from the release that adds FreeBSD support, this now compiles successfully on FreeBSD.
216 lines
4.6 KiB
Go
216 lines
4.6 KiB
Go
// Package maputil provide map data util functions. eg: convert, sub-value get, simple merge
|
|
package maputil
|
|
|
|
import (
|
|
"reflect"
|
|
"strings"
|
|
|
|
"github.com/gookit/goutil/arrutil"
|
|
)
|
|
|
|
// Key, value sep char consts
|
|
const (
|
|
ValSepStr = ","
|
|
ValSepChar = ','
|
|
KeySepStr = "."
|
|
KeySepChar = '.'
|
|
)
|
|
|
|
// Copy copies all key/value pairs in src adding them to dst.
|
|
// When a key in src is already present in dst,
|
|
// the value in dst will be overwritten by the value associated
|
|
// with the key in src.
|
|
func Copy[M1 ~map[K]V, M2 ~map[K]V, K comparable, V any](dst M1, src M2) {
|
|
for k, v := range src {
|
|
dst[k] = v
|
|
}
|
|
}
|
|
|
|
// DeleteFunc deletes any key/value pairs from m for which del returns true.
|
|
func DeleteFunc[M ~map[K]V, K comparable, V any](m M, del func(K, V) bool) {
|
|
for k, v := range m {
|
|
if del(k, v) {
|
|
delete(m, k)
|
|
}
|
|
}
|
|
}
|
|
|
|
// SimpleMerge simple merge two data map by string key. will merge the src to dst map
|
|
func SimpleMerge(src, dst map[string]any) map[string]any {
|
|
if len(src) == 0 {
|
|
return dst
|
|
}
|
|
if len(dst) == 0 {
|
|
return src
|
|
}
|
|
|
|
for key, val := range src {
|
|
if mp, ok := val.(map[string]any); ok {
|
|
if dmp, ok := dst[key].(map[string]any); ok {
|
|
dst[key] = SimpleMerge(mp, dmp)
|
|
continue
|
|
}
|
|
}
|
|
|
|
// simple merge
|
|
dst[key] = val
|
|
}
|
|
return dst
|
|
}
|
|
|
|
// Merge1level merge multi any map[string]any data. only merge one level data.
|
|
func Merge1level(mps ...map[string]any) map[string]any {
|
|
newMp := make(map[string]any)
|
|
for _, mp := range mps {
|
|
for k, v := range mp {
|
|
newMp[k] = v
|
|
}
|
|
}
|
|
return newMp
|
|
}
|
|
|
|
// func DeepMerge(src, dst map[string]any, deep int) map[string]any { TODO
|
|
// }
|
|
|
|
// MergeSMap simple merge two string map. merge src to dst map
|
|
func MergeSMap(src, dst map[string]string, ignoreCase bool) map[string]string {
|
|
return MergeStringMap(src, dst, ignoreCase)
|
|
}
|
|
|
|
// MergeStrMap simple merge two string map. merge src to dst map
|
|
func MergeStrMap(src, dst map[string]string) map[string]string {
|
|
return MergeStringMap(src, dst, false)
|
|
}
|
|
|
|
// AppendSMap append string map data to dst map.
|
|
func AppendSMap(dst, src map[string]string) map[string]string {
|
|
return MergeStringMap(src, dst, false)
|
|
}
|
|
|
|
// MergeStringMap simple merge two string map. merge src to dst map
|
|
func MergeStringMap(src, dst map[string]string, ignoreCase bool) map[string]string {
|
|
if len(src) == 0 {
|
|
return dst
|
|
}
|
|
if len(dst) == 0 {
|
|
return src
|
|
}
|
|
|
|
for k, v := range src {
|
|
if ignoreCase {
|
|
k = strings.ToLower(k)
|
|
}
|
|
dst[k] = v
|
|
}
|
|
return dst
|
|
}
|
|
|
|
// MergeMultiSMap quick merge multi string-map data.
|
|
func MergeMultiSMap(mps ...map[string]string) map[string]string {
|
|
newMp := make(map[string]string)
|
|
for _, mp := range mps {
|
|
for k, v := range mp {
|
|
newMp[k] = v
|
|
}
|
|
}
|
|
return newMp
|
|
}
|
|
|
|
// MergeL2StrMap merge multi level2 string-map data. The back map covers the front.
|
|
func MergeL2StrMap(mps ...map[string]map[string]string) map[string]map[string]string {
|
|
newMp := make(map[string]map[string]string)
|
|
for _, mp := range mps {
|
|
for k, v := range mp {
|
|
// merge level 2 value
|
|
if oldV, ok := newMp[k]; ok {
|
|
for k1, v1 := range v {
|
|
oldV[k1] = v1
|
|
}
|
|
newMp[k] = oldV
|
|
} else {
|
|
newMp[k] = v
|
|
}
|
|
}
|
|
}
|
|
return newMp
|
|
}
|
|
|
|
// FilterSMap filter empty elem for the string map.
|
|
func FilterSMap(sm map[string]string) map[string]string {
|
|
for key, val := range sm {
|
|
if val == "" {
|
|
delete(sm, key)
|
|
}
|
|
}
|
|
return sm
|
|
}
|
|
|
|
// MakeByPath build new value by key names
|
|
//
|
|
// Example:
|
|
//
|
|
// "site.info"
|
|
// ->
|
|
// map[string]any {
|
|
// site: {info: val}
|
|
// }
|
|
//
|
|
// // case 2, last key is slice:
|
|
// "site.tags[1]"
|
|
// ->
|
|
// map[string]any {
|
|
// site: {tags: [val]}
|
|
// }
|
|
func MakeByPath(path string, val any) (mp map[string]any) {
|
|
return MakeByKeys(strings.Split(path, KeySepStr), val)
|
|
}
|
|
|
|
// MakeByKeys build new value by key names
|
|
//
|
|
// Example:
|
|
//
|
|
// // case 1:
|
|
// []string{"site", "info"}
|
|
// ->
|
|
// map[string]any {
|
|
// site: {info: val}
|
|
// }
|
|
//
|
|
// // case 2, last key is slice:
|
|
// []string{"site", "tags[1]"}
|
|
// ->
|
|
// map[string]any {
|
|
// site: {tags: [val]}
|
|
// }
|
|
func MakeByKeys(keys []string, val any) (mp map[string]any) {
|
|
size := len(keys)
|
|
|
|
// if last key contains slice index, make slice wrap the val
|
|
lastKey := keys[size-1]
|
|
if newK, idx, ok := parseArrKeyIndex(lastKey); ok {
|
|
// valTyp := reflect.TypeOf(val)
|
|
sliTyp := reflect.SliceOf(reflect.TypeOf(val))
|
|
sliVal := reflect.MakeSlice(sliTyp, idx+1, idx+1)
|
|
sliVal.Index(idx).Set(reflect.ValueOf(val))
|
|
|
|
// update val and last key
|
|
val = sliVal.Interface()
|
|
keys[size-1] = newK
|
|
}
|
|
|
|
if size == 1 {
|
|
return map[string]any{keys[0]: val}
|
|
}
|
|
|
|
// multi nodes
|
|
arrutil.Reverse(keys)
|
|
for _, p := range keys {
|
|
if mp == nil {
|
|
mp = map[string]any{p: val}
|
|
} else {
|
|
mp = map[string]any{p: mp}
|
|
}
|
|
}
|
|
return
|
|
}
|