github.com/gopherd/gonum@v0.0.4/stat/card/card.go (about)

     1  // Copyright ©2019 The Gonum Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:generate ./generate_64bit.sh
     6  
     7  package card
     8  
     9  import (
    10  	"fmt"
    11  	"hash"
    12  	"math"
    13  	"reflect"
    14  	"sync"
    15  )
    16  
    17  const (
    18  	w32 = 32
    19  	w64 = 64
    20  )
    21  
    22  func alpha(m uint64) float64 {
    23  	if m < 128 {
    24  		return alphaValues[m]
    25  	}
    26  	return 0.7213 / (1 + 1.079/float64(m))
    27  }
    28  
    29  var alphaValues = [...]float64{
    30  	16: 0.673,
    31  	32: 0.697,
    32  	64: 0.709,
    33  }
    34  
    35  func linearCounting(m, v float64) float64 {
    36  	return m * (math.Log(m) - math.Log(v))
    37  }
    38  
    39  func max(a, b uint8) uint8 {
    40  	if a > b {
    41  		return a
    42  	}
    43  	return b
    44  }
    45  
    46  func min(a, b uint8) uint8 {
    47  	if a < b {
    48  		return a
    49  	}
    50  	return b
    51  }
    52  
    53  func typeNameOf(v interface{}) string {
    54  	t := reflect.TypeOf(v)
    55  	var prefix string
    56  	if t.Kind() == reflect.Ptr {
    57  		t = t.Elem()
    58  		prefix = "*"
    59  	}
    60  	if t.PkgPath() == "" {
    61  		return prefix + t.Name()
    62  	}
    63  	return prefix + t.PkgPath() + "." + t.Name()
    64  }
    65  
    66  // hashes holds registered hashes.
    67  var hashes sync.Map // map[string]userType
    68  
    69  type userType struct {
    70  	fn  reflect.Value // Holds a func() hash.Hash{32,64}.
    71  	typ reflect.Type  // Type of the returned hash implementation.
    72  }
    73  
    74  // RegisterHash registers a function that returns a new hash.Hash32 or hash.Hash64
    75  // to the name of the type implementing the interface. The value of fn must be a
    76  // func() hash.Hash32 or func() hash.Hash64, otherwise RegisterHash will panic.
    77  // RegisterHash will panic if there is not a unique mapping from the name to the
    78  // returned type.
    79  func RegisterHash(fn interface{}) {
    80  	const invalidType = "card: must register func() hash.Hash32 or func() hash.Hash64"
    81  
    82  	rf := reflect.ValueOf(fn)
    83  	rt := rf.Type()
    84  	if rf.Kind() != reflect.Func {
    85  		panic(invalidType)
    86  	}
    87  	if rt.NumIn() != 0 {
    88  		panic(invalidType)
    89  	}
    90  	if rt.NumOut() != 1 {
    91  		panic(invalidType)
    92  	}
    93  	h := rf.Call(nil)[0].Interface()
    94  	var name string
    95  	var h32 hash.Hash32
    96  	var h64 hash.Hash64
    97  	switch rf.Type().Out(0) {
    98  	case reflect.TypeOf(&h32).Elem(), reflect.TypeOf(&h64).Elem():
    99  		name = typeNameOf(h)
   100  	default:
   101  		panic(invalidType)
   102  	}
   103  	user := userType{fn: rf, typ: reflect.TypeOf(h)}
   104  	ut, dup := hashes.LoadOrStore(name, user)
   105  	stored := ut.(userType)
   106  	if dup && stored.typ != user.typ {
   107  		panic(fmt.Sprintf("card: registering duplicate types for %q: %s != %s", name, stored.typ, user.typ))
   108  	}
   109  }