github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/util/uint128/uint128.go (about) 1 // Copyright 2017 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package uint128 12 13 import ( 14 "encoding/binary" 15 "encoding/hex" 16 17 "github.com/cockroachdb/errors" 18 ) 19 20 // Uint128 is a big-endian 128 bit unsigned integer which wraps two uint64s. 21 type Uint128 struct { 22 Hi, Lo uint64 23 } 24 25 // GetBytes returns a big-endian byte representation. 26 func (u Uint128) GetBytes() []byte { 27 buf := make([]byte, 16) 28 binary.BigEndian.PutUint64(buf[:8], u.Hi) 29 binary.BigEndian.PutUint64(buf[8:], u.Lo) 30 return buf 31 } 32 33 // String returns a hexadecimal string representation. 34 func (u Uint128) String() string { 35 return hex.EncodeToString(u.GetBytes()) 36 } 37 38 // Equal returns whether or not the Uint128 are equivalent. 39 func (u Uint128) Equal(o Uint128) bool { 40 return u.Hi == o.Hi && u.Lo == o.Lo 41 } 42 43 // Compare compares the two Uint128. 44 func (u Uint128) Compare(o Uint128) int { 45 if u.Hi > o.Hi { 46 return 1 47 } else if u.Hi < o.Hi { 48 return -1 49 } else if u.Lo > o.Lo { 50 return 1 51 } else if u.Lo < o.Lo { 52 return -1 53 } 54 return 0 55 } 56 57 // Add returns a new Uint128 incremented by n. 58 func (u Uint128) Add(n uint64) Uint128 { 59 lo := u.Lo + n 60 hi := u.Hi 61 if u.Lo > lo { 62 hi++ 63 } 64 return Uint128{hi, lo} 65 } 66 67 // Sub returns a new Uint128 decremented by n. 68 func (u Uint128) Sub(n uint64) Uint128 { 69 lo := u.Lo - n 70 hi := u.Hi 71 if u.Lo < lo { 72 hi-- 73 } 74 return Uint128{hi, lo} 75 } 76 77 // And returns a new Uint128 that is the bitwise AND of two Uint128 values. 78 func (u Uint128) And(o Uint128) Uint128 { 79 return Uint128{u.Hi & o.Hi, u.Lo & o.Lo} 80 } 81 82 // Or returns a new Uint128 that is the bitwise OR of two Uint128 values. 83 func (u Uint128) Or(o Uint128) Uint128 { 84 return Uint128{u.Hi | o.Hi, u.Lo | o.Lo} 85 } 86 87 // Xor returns a new Uint128 that is the bitwise XOR of two Uint128 values. 88 func (u Uint128) Xor(o Uint128) Uint128 { 89 return Uint128{u.Hi ^ o.Hi, u.Lo ^ o.Lo} 90 } 91 92 // FromBytes parses the byte slice as a 128 bit big-endian unsigned integer. 93 // The caller is responsible for ensuring the byte slice contains 16 bytes. 94 func FromBytes(b []byte) Uint128 { 95 hi := binary.BigEndian.Uint64(b[:8]) 96 lo := binary.BigEndian.Uint64(b[8:]) 97 return Uint128{hi, lo} 98 } 99 100 // FromString parses a hexadecimal string as a 128-bit big-endian unsigned integer. 101 func FromString(s string) (Uint128, error) { 102 if len(s) > 32 { 103 return Uint128{}, errors.Errorf("input string %s too large for uint128", s) 104 } 105 bytes, err := hex.DecodeString(s) 106 if err != nil { 107 return Uint128{}, errors.Wrapf(err, "could not decode %s as hex", s) 108 } 109 110 // Grow the byte slice if it's smaller than 16 bytes, by prepending 0s 111 if len(bytes) < 16 { 112 bytesCopy := make([]byte, 16) 113 copy(bytesCopy[(16-len(bytes)):], bytes) 114 bytes = bytesCopy 115 } 116 117 return FromBytes(bytes), nil 118 } 119 120 // FromInts takes in two unsigned 64-bit integers and constructs a Uint128. 121 func FromInts(hi uint64, lo uint64) Uint128 { 122 return Uint128{hi, lo} 123 }