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  }