github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/gossip/util/misc.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package util 8 9 import ( 10 cryptorand "crypto/rand" 11 "fmt" 12 "io" 13 "math/big" 14 "math/rand" 15 "reflect" 16 "runtime" 17 "sync" 18 "time" 19 20 "github.com/spf13/viper" 21 ) 22 23 // Equals returns whether a and b are the same 24 type Equals func(a interface{}, b interface{}) bool 25 26 var viperLock sync.RWMutex 27 28 // IndexInSlice returns the index of given object o in array 29 func IndexInSlice(array interface{}, o interface{}, equals Equals) int { 30 arr := reflect.ValueOf(array) 31 for i := 0; i < arr.Len(); i++ { 32 if equals(arr.Index(i).Interface(), o) { 33 return i 34 } 35 } 36 return -1 37 } 38 39 func numbericEqual(a interface{}, b interface{}) bool { 40 return a.(int) == b.(int) 41 } 42 43 // GetRandomIndices returns a slice of random indices 44 // from 0 to given highestIndex 45 func GetRandomIndices(indiceCount, highestIndex int) []int { 46 if highestIndex+1 < indiceCount { 47 return nil 48 } 49 50 indices := make([]int, 0) 51 if highestIndex+1 == indiceCount { 52 for i := 0; i < indiceCount; i++ { 53 indices = append(indices, i) 54 } 55 return indices 56 } 57 58 for len(indices) < indiceCount { 59 n := RandomInt(highestIndex + 1) 60 if IndexInSlice(indices, n, numbericEqual) != -1 { 61 continue 62 } 63 indices = append(indices, n) 64 } 65 return indices 66 } 67 68 // Set is a generic and thread-safe 69 // set container 70 type Set struct { 71 items map[interface{}]struct{} 72 lock *sync.RWMutex 73 } 74 75 // NewSet returns a new set 76 func NewSet() *Set { 77 return &Set{lock: &sync.RWMutex{}, items: make(map[interface{}]struct{})} 78 } 79 80 // Add adds given item to the set 81 func (s *Set) Add(item interface{}) { 82 s.lock.Lock() 83 defer s.lock.Unlock() 84 s.items[item] = struct{}{} 85 } 86 87 // Exists returns true whether given item is in the set 88 func (s *Set) Exists(item interface{}) bool { 89 s.lock.RLock() 90 defer s.lock.RUnlock() 91 _, exists := s.items[item] 92 return exists 93 } 94 95 // Size returns the size of the set 96 func (s *Set) Size() int { 97 s.lock.RLock() 98 defer s.lock.RUnlock() 99 return len(s.items) 100 } 101 102 // ToArray returns a slice with items 103 // at the point in time the method was invoked 104 func (s *Set) ToArray() []interface{} { 105 s.lock.RLock() 106 defer s.lock.RUnlock() 107 a := make([]interface{}, len(s.items)) 108 i := 0 109 for item := range s.items { 110 a[i] = item 111 i++ 112 } 113 return a 114 } 115 116 // Clear removes all elements from set 117 func (s *Set) Clear() { 118 s.lock.Lock() 119 defer s.lock.Unlock() 120 s.items = make(map[interface{}]struct{}) 121 } 122 123 // Remove removes a given item from the set 124 func (s *Set) Remove(item interface{}) { 125 s.lock.Lock() 126 defer s.lock.Unlock() 127 delete(s.items, item) 128 } 129 130 // PrintStackTrace prints to stdout 131 // all goroutines 132 func PrintStackTrace() { 133 buf := make([]byte, 1<<16) 134 runtime.Stack(buf, true) 135 fmt.Printf("%s", buf) 136 } 137 138 // GetIntOrDefault returns the int value from config if present otherwise default value 139 func GetIntOrDefault(key string, defVal int) int { 140 viperLock.RLock() 141 defer viperLock.RUnlock() 142 143 if val := viper.GetInt(key); val != 0 { 144 return val 145 } 146 147 return defVal 148 } 149 150 // GetDurationOrDefault returns the Duration value from config if present otherwise default value 151 func GetDurationOrDefault(key string, defVal time.Duration) time.Duration { 152 viperLock.RLock() 153 defer viperLock.RUnlock() 154 155 if val := viper.GetDuration(key); val != 0 { 156 return val 157 } 158 159 return defVal 160 } 161 162 // SetDuration stores duration key value to viper 163 func SetDuration(key string, val time.Duration) { 164 viperLock.Lock() 165 defer viperLock.Unlock() 166 viper.Set(key, val) 167 } 168 169 // RandomInt returns, as an int, a non-negative pseudo-random integer in [0,n) 170 // It panics if n <= 0 171 func RandomInt(n int) int { 172 if n <= 0 { 173 panic(fmt.Sprintf("Got invalid (non positive) value: %d", n)) 174 } 175 m := int(RandomUInt64()) % n 176 if m < 0 { 177 return n + m 178 } 179 return m 180 } 181 182 // RandomUInt64 returns a random uint64 183 func RandomUInt64() uint64 { 184 b := make([]byte, 8) 185 _, err := io.ReadFull(cryptorand.Reader, b) 186 if err == nil { 187 n := new(big.Int) 188 return n.SetBytes(b).Uint64() 189 } 190 rand.Seed(rand.Int63()) 191 return uint64(rand.Int63()) 192 }