Files
cgrates/utils/map.go
2020-07-20 12:58:41 +02:00

310 lines
6.8 KiB
Go

/*
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
Copyright (C) ITsysCOM GmbH
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
package utils
import (
"strconv"
"strings"
)
// Converts map[string]string into map[string]interface{}
func ConvertMapValStrIf(inMap map[string]string) map[string]interface{} {
outMap := make(map[string]interface{})
for field, val := range inMap {
outMap[field] = val
}
return outMap
}
// Mirrors key/val
func MirrorMap(mapIn map[string]string) map[string]string {
mapOut := make(map[string]string, len(mapIn))
for key, val := range mapIn {
mapOut[val] = key
}
return mapOut
}
// Returns mising keys in a map
func MissingMapKeys(inMap map[string]string, requiredKeys []string) []string {
missingKeys := []string{}
for _, reqKey := range requiredKeys {
if val, hasKey := inMap[reqKey]; !hasKey || val == EmptyString {
missingKeys = append(missingKeys, reqKey)
}
}
return missingKeys
}
// Return map keys
func MapKeys(m map[string]string) []string {
n := make([]string, len(m))
i := 0
for k := range m {
n[i] = k
i++
}
return n
}
type StringMap map[string]bool
func NewStringMap(s ...string) StringMap {
result := make(StringMap)
for _, v := range s {
v = strings.TrimSpace(v)
if v != EmptyString {
if strings.HasPrefix(v, NegativePrefix) {
result[v[1:]] = false
} else {
result[v] = true
}
}
}
return result
}
func ParseStringMap(s string) StringMap {
if s == ZERO {
return make(StringMap)
}
return StringMapFromSlice(strings.Split(s, INFIELD_SEP))
}
func (sm StringMap) Equal(om StringMap) bool {
if sm == nil && om != nil {
return false
}
if len(sm) != len(om) {
return false
}
for key := range sm {
if !om[key] {
return false
}
}
return true
}
func (sm StringMap) Includes(om StringMap) bool {
if len(sm) < len(om) {
return false
}
for key := range om {
if !sm[key] {
return false
}
}
return true
}
func (sm StringMap) Slice() []string {
result := make([]string, len(sm))
i := 0
for k := range sm {
result[i] = k
i++
}
return result
}
func (sm StringMap) IsEmpty() bool {
return sm == nil ||
len(sm) == 0 ||
sm[ANY] == true
}
func StringMapFromSlice(s []string) StringMap {
result := make(StringMap, len(s))
for _, v := range s {
v = strings.TrimSpace(v)
if v != EmptyString {
if strings.HasPrefix(v, NegativePrefix) {
result[v[1:]] = false
} else {
result[v] = true
}
}
}
return result
}
func (sm StringMap) Copy(o StringMap) {
for k, v := range o {
sm[k] = v
}
}
func (sm StringMap) Clone() StringMap {
result := make(StringMap, len(sm))
result.Copy(sm)
return result
}
func (sm StringMap) String() string {
return strings.Join(sm.Slice(), INFIELD_SEP)
}
func (sm StringMap) GetOne() string {
for key := range sm {
return key
}
return EmptyString
}
func (sm StringMap) Join(mps ...StringMap) {
for _, mp := range mps {
for k, v := range mp {
sm[k] = v
}
}
}
func (sm StringMap) HasKey(key string) (has bool) {
_, has = sm[key]
return
}
// Used to merge multiple maps (eg: output of struct having ExtraFields)
func MergeMapsStringIface(mps ...map[string]interface{}) (outMp map[string]interface{}) {
outMp = make(map[string]interface{})
for i, mp := range mps {
if i == 0 {
outMp = mp
continue
}
for k, v := range mp {
outMp[k] = v
}
}
return
}
// FieldMultiplyFactor defines multiply factors for different field values
// original defined for CDRE component
type FieldMultiplyFactor map[string]float64
func (fmp FieldMultiplyFactor) Clone() (cln FieldMultiplyFactor) {
cln = make(FieldMultiplyFactor, len(fmp))
for k, v := range fmp {
cln[k] = v
}
return
}
func MapStringToInt64(in map[string]string) (out map[string]int64, err error) {
mapout := make(map[string]int64, len(in))
for key, val := range in {
x, err := strconv.Atoi(val)
if err != nil {
return nil, err
}
mapout[key] = int64(x)
}
return mapout, nil
}
// FlagsWithParamsFromSlice construct a FlagsWithParams from the given slice
func FlagsWithParamsFromSlice(s []string) (flags FlagsWithParams) {
flags = make(FlagsWithParams)
for _, v := range s {
flag := strings.SplitN(v, InInFieldSep, 3)
if !flags.Has(flag[0]) {
flags[flag[0]] = make(FlagParams)
}
flags[flag[0]].Add(flag[1:])
}
return
}
// FlagParams stores the parameters for a flag
type FlagParams map[string][]string
// Has returns if the key was mentioned in flags
func (fWp FlagParams) Has(opt string) (has bool) {
_, has = fWp[opt]
return
}
// Add adds the options to the flag
func (fWp FlagParams) Add(opts []string) {
switch len(opts) {
case 0:
case 1:
fWp[opts[0]] = []string{}
default: // just in case we call this function with more elements than needed
fallthrough
case 2:
fWp[opts[0]] = InfieldSplit(opts[1])
}
return
}
// ParamsSlice returns the list of profiles for the subsystem
func (fWp FlagParams) ParamsSlice(opt string) (ps []string) {
return fWp[opt] // if it doesn't have the option it will return an empty slice
}
// FlagsWithParams should store a list of flags for each subsystem
type FlagsWithParams map[string]FlagParams
// Has returns if the key was mentioned in flags
func (fWp FlagsWithParams) Has(flag string) (has bool) {
_, has = fWp[flag]
return
}
// ParamsSlice returns the list of profiles for the subsystem
func (fWp FlagsWithParams) ParamsSlice(subs, opt string) (ps []string) {
if psIfc, has := fWp[subs]; has {
ps = psIfc.ParamsSlice(opt)
}
return
}
// SliceFlags converts from FlagsWithParams back to []string
func (fWp FlagsWithParams) SliceFlags() (sls []string) {
for key, sub := range fWp {
if len(sub) == 0 { // no option for these subsystem
sls = append(sls, key)
continue
}
for opt, values := range sub {
if len(values) == 0 { // it's an option without values(e.g *derivedreply)
sls = append(sls, ConcatenatedKey(key, opt))
continue
}
sls = append(sls, ConcatenatedKey(key, opt, strings.Join(values, INFIELD_SEP)))
}
}
return
}
// GetBool returns the flag as boolean
func (fWp FlagsWithParams) GetBool(key string) (b bool) {
var v FlagParams
if v, b = fWp[key]; !b {
return // not present means false
}
if v == nil || len(v) == 0 {
return true // empty map
}
return !v.Has("*disabled") // check if has *disable param
}