github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/p2p/discover/distance.go (about) 1 // Copyright 2015 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package discover 18 19 import ( 20 "sort" 21 22 "github.com/ethereumproject/go-ethereum/common" 23 ) 24 25 // node distance computation. 26 27 // Closest sorts a set on distance to Target. 28 type closest struct { 29 Nodes [bucketSize]*Node 30 Target common.Hash 31 } 32 33 func (c *closest) Slice() []*Node { 34 for i, n := range c.Nodes { 35 if n == nil { 36 return c.Nodes[:i] 37 } 38 } 39 return c.Nodes[:] 40 } 41 42 func (c *closest) Add(entry *Node) { 43 i := sort.Search(len(c.Nodes), func(i int) bool { 44 other := c.Nodes[i] 45 if other == nil { 46 return true 47 } 48 return distcmp(c.Target, other.sha, entry.sha) >= 0 49 }) 50 51 if i >= len(c.Nodes) { 52 return 53 } 54 if n := c.Nodes[i]; n != nil && n.ID == entry.ID { 55 return 56 } 57 58 copy(c.Nodes[i+1:], c.Nodes[i:]) 59 c.Nodes[i] = entry 60 } 61 62 // distcmp compares the distances a->target and b->target. 63 // Returns -1 if a is closer to target, 1 if b is closer to target 64 // and 0 if they are equal. 65 func distcmp(target, a, b common.Hash) int { 66 for i := range target { 67 da := a[i] ^ target[i] 68 db := b[i] ^ target[i] 69 if da > db { 70 return 1 71 } else if da < db { 72 return -1 73 } 74 } 75 return 0 76 } 77 78 // table of leading zero counts for bytes [0..255] 79 var lzcount = [256]int{ 80 8, 7, 6, 6, 5, 5, 5, 5, 81 4, 4, 4, 4, 4, 4, 4, 4, 82 3, 3, 3, 3, 3, 3, 3, 3, 83 3, 3, 3, 3, 3, 3, 3, 3, 84 2, 2, 2, 2, 2, 2, 2, 2, 85 2, 2, 2, 2, 2, 2, 2, 2, 86 2, 2, 2, 2, 2, 2, 2, 2, 87 2, 2, 2, 2, 2, 2, 2, 2, 88 1, 1, 1, 1, 1, 1, 1, 1, 89 1, 1, 1, 1, 1, 1, 1, 1, 90 1, 1, 1, 1, 1, 1, 1, 1, 91 1, 1, 1, 1, 1, 1, 1, 1, 92 1, 1, 1, 1, 1, 1, 1, 1, 93 1, 1, 1, 1, 1, 1, 1, 1, 94 1, 1, 1, 1, 1, 1, 1, 1, 95 1, 1, 1, 1, 1, 1, 1, 1, 96 0, 0, 0, 0, 0, 0, 0, 0, 97 0, 0, 0, 0, 0, 0, 0, 0, 98 0, 0, 0, 0, 0, 0, 0, 0, 99 0, 0, 0, 0, 0, 0, 0, 0, 100 0, 0, 0, 0, 0, 0, 0, 0, 101 0, 0, 0, 0, 0, 0, 0, 0, 102 0, 0, 0, 0, 0, 0, 0, 0, 103 0, 0, 0, 0, 0, 0, 0, 0, 104 0, 0, 0, 0, 0, 0, 0, 0, 105 0, 0, 0, 0, 0, 0, 0, 0, 106 0, 0, 0, 0, 0, 0, 0, 0, 107 0, 0, 0, 0, 0, 0, 0, 0, 108 0, 0, 0, 0, 0, 0, 0, 0, 109 0, 0, 0, 0, 0, 0, 0, 0, 110 0, 0, 0, 0, 0, 0, 0, 0, 111 0, 0, 0, 0, 0, 0, 0, 0, 112 } 113 114 // logdist returns the logarithmic distance between a and b, log2(a ^ b). 115 func logdist(a, b common.Hash) int { 116 lz := 0 117 for i := range a { 118 x := a[i] ^ b[i] 119 if x == 0 { 120 lz += 8 121 } else { 122 lz += lzcount[x] 123 break 124 } 125 } 126 return len(a)*8 - lz 127 }