github.com/MetalBlockchain/metalgo@v1.11.9/ids/bits.go (about) 1 // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved. 2 // See the file LICENSE for licensing terms. 3 4 package ids 5 6 import ( 7 "bytes" 8 "math/bits" 9 ) 10 11 // NumBits is the number of bits this patricia tree manages 12 const NumBits = 256 13 14 // BitsPerByte is the number of bits per byte 15 const BitsPerByte = 8 16 17 // EqualSubset takes in two indices and two ids and returns if the ids are 18 // equal from bit start to bit end (non-inclusive). Bit indices are defined as: 19 // [7 6 5 4 3 2 1 0] [15 14 13 12 11 10 9 8] ... [255 254 253 252 251 250 249 248] 20 // Where index 7 is the MSB of byte 0. 21 func EqualSubset(start, stop int, id1, id2 ID) bool { 22 stop-- 23 if start > stop || stop < 0 { 24 return true 25 } 26 if stop >= NumBits { 27 return false 28 } 29 30 startIndex := start / BitsPerByte 31 stopIndex := stop / BitsPerByte 32 33 // If there is a series of bytes between the first byte and the last byte, they must be equal 34 if startIndex+1 < stopIndex && !bytes.Equal(id1[startIndex+1:stopIndex], id2[startIndex+1:stopIndex]) { 35 return false 36 } 37 38 startBit := uint(start % BitsPerByte) // Index in the byte that the first bit is at 39 stopBit := uint(stop % BitsPerByte) // Index in the byte that the last bit is at 40 41 startMask := -1 << startBit // 111...0... The number of 0s is equal to startBit 42 stopMask := (1 << (stopBit + 1)) - 1 // 000...1... The number of 1s is equal to stopBit+1 43 44 if startIndex == stopIndex { 45 // If we are looking at the same byte, both masks need to be applied 46 mask := startMask & stopMask 47 48 // The index here could be startIndex or stopIndex, as they are equal 49 b1 := mask & int(id1[startIndex]) 50 b2 := mask & int(id2[startIndex]) 51 52 return b1 == b2 53 } 54 55 start1 := startMask & int(id1[startIndex]) 56 start2 := startMask & int(id2[startIndex]) 57 58 stop1 := stopMask & int(id1[stopIndex]) 59 stop2 := stopMask & int(id2[stopIndex]) 60 61 return start1 == start2 && stop1 == stop2 62 } 63 64 // FirstDifferenceSubset takes in two indices and two ids and returns the index 65 // of the first difference between the ids inside bit start to bit end 66 // (non-inclusive). Bit indices are defined above 67 func FirstDifferenceSubset(start, stop int, id1, id2 ID) (int, bool) { 68 stop-- 69 if start > stop || stop < 0 || stop >= NumBits { 70 return 0, false 71 } 72 73 startIndex := start / BitsPerByte 74 stopIndex := stop / BitsPerByte 75 76 startBit := uint(start % BitsPerByte) // Index in the byte that the first bit is at 77 stopBit := uint(stop % BitsPerByte) // Index in the byte that the last bit is at 78 79 startMask := -1 << startBit // 111...0... The number of 0s is equal to startBit 80 stopMask := (1 << (stopBit + 1)) - 1 // 000...1... The number of 1s is equal to stopBit+1 81 82 if startIndex == stopIndex { 83 // If we are looking at the same byte, both masks need to be applied 84 mask := startMask & stopMask 85 86 // The index here could be startIndex or stopIndex, as they are equal 87 b1 := mask & int(id1[startIndex]) 88 b2 := mask & int(id2[startIndex]) 89 90 if b1 == b2 { 91 return 0, false 92 } 93 94 bd := b1 ^ b2 95 return bits.TrailingZeros8(uint8(bd)) + startIndex*BitsPerByte, true 96 } 97 98 // Check the first byte, may have some bits masked 99 start1 := startMask & int(id1[startIndex]) 100 start2 := startMask & int(id2[startIndex]) 101 102 if start1 != start2 { 103 bd := start1 ^ start2 104 return bits.TrailingZeros8(uint8(bd)) + startIndex*BitsPerByte, true 105 } 106 107 // Check all the interior bits 108 for i := startIndex + 1; i < stopIndex; i++ { 109 b1 := int(id1[i]) 110 b2 := int(id2[i]) 111 if b1 != b2 { 112 bd := b1 ^ b2 113 return bits.TrailingZeros8(uint8(bd)) + i*BitsPerByte, true 114 } 115 } 116 117 // Check the last byte, may have some bits masked 118 stop1 := stopMask & int(id1[stopIndex]) 119 stop2 := stopMask & int(id2[stopIndex]) 120 121 if stop1 != stop2 { 122 bd := stop1 ^ stop2 123 return bits.TrailingZeros8(uint8(bd)) + stopIndex*BitsPerByte, true 124 } 125 126 // No difference was found 127 return 0, false 128 }