github.com/GuanceCloud/cliutils@v1.1.21/point/key.go (about)

     1  // Unless explicitly stated otherwise all files in this repository are licensed
     2  // under the MIT License.
     3  // This product includes software developed at Guance Cloud (https://www.guance.com/).
     4  // Copyright 2021-present Guance, Inc.
     5  
     6  package point
     7  
     8  import (
     9  	"fmt"
    10  	"hash/fnv"
    11  	"sort"
    12  	"strings"
    13  )
    14  
    15  // Key is the key-name and it's type composite.
    16  type Key struct {
    17  	key string // key-name + key-type
    18  	t   KeyType
    19  	def any
    20  }
    21  
    22  // NewKey create Key.
    23  func NewKey(k string, t KeyType, defaultVal ...any) *Key {
    24  	var def any
    25  	if len(defaultVal) > 0 {
    26  		def = defaultVal[0]
    27  	}
    28  
    29  	return &Key{
    30  		key: k,
    31  		t:   t,
    32  		def: def,
    33  	}
    34  }
    35  
    36  // NewTagKey create tag key with type string.
    37  func NewTagKey(k string, defaultVal string) *Key {
    38  	return NewKey(k, S, defaultVal)
    39  }
    40  
    41  // Key get key-name.
    42  func (k *Key) Key() string {
    43  	return k.key
    44  }
    45  
    46  // Type get key-type.
    47  func (k *Key) Type() KeyType {
    48  	switch len(k.key) {
    49  	case 0:
    50  		return X
    51  
    52  	case 1:
    53  		return KeyType(k.key[0])
    54  
    55  	default:
    56  		return KeyType(k.key[len(k.key)-1])
    57  	}
    58  }
    59  
    60  // Default get key's default value.
    61  func (k *Key) Default() any {
    62  	return k.def
    63  }
    64  
    65  // Keys is sorted Keys.
    66  type Keys struct {
    67  	hashed bool
    68  	hash   uint64
    69  	arr    []*Key
    70  }
    71  
    72  func (x *Keys) Len() int { return len(x.arr) }
    73  
    74  func (x *Keys) Swap(i, j int) {
    75  	arr := x.arr
    76  	arr[i], arr[j] = arr[j], arr[i]
    77  }
    78  
    79  func (x *Keys) Less(i, j int) bool {
    80  	return strings.Compare(x.arr[i].key, x.arr[j].key) < 0
    81  }
    82  
    83  // Has test if k exist.
    84  func (x *Keys) Has(k *Key) bool {
    85  	// TODO: should replaced by sort.Search()
    86  	for _, item := range x.arr {
    87  		if k.key == item.key {
    88  			return true
    89  		}
    90  	}
    91  
    92  	return false
    93  }
    94  
    95  // Add add specific k. if key & type exist, do nothing.
    96  func (x *Keys) Add(k *Key) {
    97  	if x.Has(k) {
    98  		return
    99  	}
   100  
   101  	x.arr = append(x.arr, k)
   102  	x.hashed = false
   103  }
   104  
   105  // Del remove specific k.
   106  func (x *Keys) Del(k *Key) {
   107  	i := 0
   108  	for _, key := range x.arr {
   109  		if key.key != k.key {
   110  			x.arr[i] = key
   111  			i++
   112  		}
   113  	}
   114  
   115  	if i != len(x.arr) {
   116  		x.hashed = false
   117  		x.arr = x.arr[:i]
   118  	}
   119  }
   120  
   121  // Pretty get pretty showing of all keys.
   122  func (x *Keys) Pretty() string {
   123  	arr := []string{}
   124  	for _, k := range x.arr {
   125  		arr = append(arr, fmt.Sprintf("% 4s: %q", KeyType(k.key[len(k.key)-1]), k.key[:len(k.key)-1]))
   126  	}
   127  
   128  	arr = append(arr, fmt.Sprintf("-----\nhashed: %v", x.hashed))
   129  
   130  	return strings.Join(arr, "\n")
   131  }
   132  
   133  // Hash calculate x's hash.
   134  func (x *Keys) Hash() uint64 {
   135  	if !x.hashed {
   136  		sort.Sort(x)
   137  		h := fnv.New64a()
   138  		if _, err := h.Write(func() []byte {
   139  			var arr []byte
   140  			for _, k := range x.arr {
   141  				arr = append(arr, k.key...)
   142  			}
   143  			return arr
   144  		}()); err == nil {
   145  			x.hash = h.Sum64()
   146  			x.hashed = true
   147  		}
   148  	}
   149  
   150  	return x.hash
   151  }