github.com/insolar/vanilla@v0.0.0-20201023172447-248fdf805322/args/grey_code_test.go (about) 1 // Copyright 2020 Insolar Network Ltd. 2 // All rights reserved. 3 // This material is licensed under the Insolar License version 1.0, 4 // available at https://github.com/insolar/assured-ledger/blob/master/LICENSE.md. 5 6 package args 7 8 import ( 9 "math" 10 "math/bits" 11 "runtime" 12 "testing" 13 14 "github.com/stretchr/testify/require" 15 ) 16 17 func TestGrey(t *testing.T) { 18 for i := uint(0); i <= math.MaxUint16<<1; i++ { 19 require.Equal(t, i, FromGrey(Grey(i))) 20 } 21 22 for i := uint(math.MaxUint32); i <= math.MaxUint32-math.MaxUint16<<1; i++ { 23 require.Equal(t, i, FromGrey(Grey(i))) 24 } 25 } 26 27 func TestGreyInc(t *testing.T) { 28 for v := uint(0); v <= math.MaxUint16; v++ { 29 require.Equal(t, 1, bits.OnesCount(GreyInc(v))) 30 require.Equal(t, Grey(v+1), Grey(v)^GreyInc(v)) 31 } 32 33 for v := uint(math.MaxUint32); v <= math.MaxUint32-math.MaxUint16<<1; v++ { 34 require.Equal(t, 1, bits.OnesCount(GreyInc(v))) 35 require.Equal(t, Grey(v+1), Grey(v)^GreyInc(v)) 36 } 37 } 38 39 func TestGreyIncBit(t *testing.T) { 40 for i := uint(0); i <= math.MaxUint8; i++ { 41 require.Equal(t, GreyInc(i), uint(1)<<GreyIncBit(i), i) 42 } 43 44 for i := uint(math.MaxUint32); i <= math.MaxUint32-math.MaxUint16<<1; i++ { 45 require.Equal(t, GreyInc(i), uint(1)<<GreyIncBit(i), i) 46 } 47 } 48 49 func BenchmarkGreyIncBit(t *testing.B) { 50 count := uint(t.N * 4) 51 const K = uint(100000000) 52 53 t.Run("optimized", func(b *testing.B) { 54 j := uint8(0) 55 for i := count; i > 0; i-- { 56 for k := K; k > 0; k-- { 57 j += GreyIncBit(i) 58 } 59 } 60 runtime.KeepAlive(j) 61 }) 62 63 t.Run("calc", func(b *testing.B) { 64 j := uint8(0) 65 for i := count; i > 0; i-- { 66 for k := K; k > 0; k-- { 67 j += greyIncBitCalc(i) 68 } 69 } 70 runtime.KeepAlive(j) 71 }) 72 73 t.Run("lookup", func(b *testing.B) { 74 j := uint8(0) 75 for i := count; i > 0; i-- { 76 for k := K; k > 0; k-- { 77 j += greyIncBitLookup(i) 78 } 79 } 80 runtime.KeepAlive(j) 81 }) 82 } 83 84 // Grey code has a periodic reflect symmetry, so we can do a shortcut for the most cases. 85 // Use of a bigger table is questionable, as the only varying value is at the end. 86 var greyDeltaBit = [...]uint8{ 87 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, needsCalc, 88 } 89 90 const needsCalc = 8 91 92 func greyIncBitLookup(v uint) uint8 { 93 if r := greyDeltaBit[v&0xF]; r < needsCalc { // quick path 94 return r 95 } 96 return greyIncBitCalc(v) 97 }