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