github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/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 // AppendBytes appends big-endian byte representation to the 34 // buffer and returns the buffer. 35 func (u Uint128) AppendBytes(buf []byte) []byte { 36 buf = binary.BigEndian.AppendUint64(buf, u.Hi) 37 return binary.BigEndian.AppendUint64(buf, u.Lo) 38 } 39 40 // String returns a hexadecimal string representation. 41 func (u Uint128) String() string { 42 return hex.EncodeToString(u.GetBytes()) 43 } 44 45 // Equal returns whether or not the Uint128 are equivalent. 46 func (u Uint128) Equal(o Uint128) bool { 47 return u.Hi == o.Hi && u.Lo == o.Lo 48 } 49 50 // Compare compares the two Uint128. 51 func (u Uint128) Compare(o Uint128) int { 52 if u.Hi > o.Hi { 53 return 1 54 } else if u.Hi < o.Hi { 55 return -1 56 } else if u.Lo > o.Lo { 57 return 1 58 } else if u.Lo < o.Lo { 59 return -1 60 } 61 return 0 62 } 63 64 // Add returns a new Uint128 incremented by n. 65 func (u Uint128) Add(n uint64) Uint128 { 66 lo := u.Lo + n 67 hi := u.Hi 68 if u.Lo > lo { 69 hi++ 70 } 71 return Uint128{hi, lo} 72 } 73 74 // Sub returns a new Uint128 decremented by n. 75 func (u Uint128) Sub(n uint64) Uint128 { 76 lo := u.Lo - n 77 hi := u.Hi 78 if u.Lo < lo { 79 hi-- 80 } 81 return Uint128{hi, lo} 82 } 83 84 // And returns a new Uint128 that is the bitwise AND of two Uint128 values. 85 func (u Uint128) And(o Uint128) Uint128 { 86 return Uint128{u.Hi & o.Hi, u.Lo & o.Lo} 87 } 88 89 // Or returns a new Uint128 that is the bitwise OR of two Uint128 values. 90 func (u Uint128) Or(o Uint128) Uint128 { 91 return Uint128{u.Hi | o.Hi, u.Lo | o.Lo} 92 } 93 94 // Xor returns a new Uint128 that is the bitwise XOR of two Uint128 values. 95 func (u Uint128) Xor(o Uint128) Uint128 { 96 return Uint128{u.Hi ^ o.Hi, u.Lo ^ o.Lo} 97 } 98 99 // FromBytes parses the byte slice as a 128 bit big-endian unsigned integer. 100 // The caller is responsible for ensuring the byte slice contains 16 bytes. 101 func FromBytes(b []byte) Uint128 { 102 hi := binary.BigEndian.Uint64(b[:8]) 103 lo := binary.BigEndian.Uint64(b[8:]) 104 return Uint128{hi, lo} 105 } 106 107 // FromString parses a hexadecimal string as a 128-bit big-endian unsigned integer. 108 func FromString(s string) (Uint128, error) { 109 if len(s) > 32 { 110 return Uint128{}, errors.Errorf("input string %s too large for uint128", s) 111 } 112 bytes, err := hex.DecodeString(s) 113 if err != nil { 114 return Uint128{}, errors.Wrapf(err, "could not decode %s as hex", s) 115 } 116 117 // Grow the byte slice if it's smaller than 16 bytes, by prepending 0s 118 if len(bytes) < 16 { 119 bytesCopy := make([]byte, 16) 120 copy(bytesCopy[(16-len(bytes)):], bytes) 121 bytes = bytesCopy 122 } 123 124 return FromBytes(bytes), nil 125 } 126 127 // FromInts takes in two unsigned 64-bit integers and constructs a Uint128. 128 func FromInts(hi uint64, lo uint64) Uint128 { 129 return Uint128{hi, lo} 130 }