1 // Copyright 2018 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef ASTC_CODEC_BASE_UINT128_H_ 16 #define ASTC_CODEC_BASE_UINT128_H_ 17 18 #include <cassert> 19 #include <cstdint> 20 21 namespace astc_codec { 22 namespace base { 23 24 class UInt128 { 25 public: 26 UInt128() = default; UInt128(uint64_t low)27 UInt128(uint64_t low) : low_(low) { } UInt128(uint64_t high,uint64_t low)28 UInt128(uint64_t high, uint64_t low) : low_(low), high_(high) { } UInt128(const UInt128 & other)29 UInt128(const UInt128& other) : low_(other.low_), high_(other.high_) { } 30 LowBits()31 uint64_t LowBits() const { return low_; } HighBits()32 uint64_t HighBits() const { return high_; } 33 34 // Allow explicit casts to uint64_t. uint64_t()35 explicit operator uint64_t() const { return low_; } 36 37 // Copy operators. 38 UInt128& operator=(const UInt128& other) { 39 high_ = other.high_; 40 low_ = other.low_; 41 return *this; 42 } 43 44 // Equality operators. 45 bool operator==(const UInt128& other) const { 46 return high_ == other.high_ && low_ == other.low_; 47 } 48 49 bool operator!=(const UInt128& other) const { 50 return high_ != other.high_ || low_ != other.low_; 51 } 52 53 // Shifting. 54 UInt128& operator<<=(int shift) { 55 high_ = shift >= 64 ? (shift >= 128 ? 0 : low_ << (shift - 64)) 56 : high_ << shift; 57 58 if (shift > 0 && shift < 64) { 59 const uint64_t overlappingBits = low_ >> (64 - shift); 60 high_ |= overlappingBits; 61 } 62 63 low_ = shift >= 64 ? 0 : low_ << shift; 64 return *this; 65 } 66 67 UInt128 operator<<(int shift) const { 68 UInt128 result = *this; 69 result <<= shift; 70 return result; 71 } 72 73 UInt128& operator>>=(int shift) { 74 low_ = shift >= 64 ? (shift >= 128 ? 0 : high_ >> (shift - 64)) 75 : low_ >> shift; 76 77 if (shift > 0 && shift < 64) { 78 const uint64_t overlappingBits = high_ << (64 - shift); 79 low_ |= overlappingBits; 80 } 81 82 high_ = shift >= 64 ? 0 : high_ >> shift; 83 84 return *this; 85 } 86 87 UInt128 operator>>(int shift) const { 88 UInt128 result = *this; 89 result >>= shift; 90 return result; 91 } 92 93 // Binary operations. 94 UInt128& operator|=(const UInt128& other) { 95 high_ |= other.high_; 96 low_ |= other.low_; 97 return *this; 98 } 99 100 UInt128 operator|(const UInt128& other) const { 101 UInt128 result = *this; 102 result |= other; 103 return result; 104 } 105 106 UInt128& operator&=(const UInt128& other) { 107 high_ &= other.high_; 108 low_ &= other.low_; 109 return *this; 110 } 111 112 UInt128 operator&(const UInt128& other) const { 113 UInt128 result = *this; 114 result &= other; 115 return result; 116 } 117 118 UInt128& operator^=(const UInt128& other) { 119 high_ ^= other.high_; 120 low_ ^= other.low_; 121 return *this; 122 } 123 124 UInt128 operator^(const UInt128& other) const { 125 UInt128 result = *this; 126 result ^= other; 127 return result; 128 } 129 130 UInt128 operator~() const { 131 UInt128 result = *this; 132 result.high_ = ~high_; 133 result.low_ = ~low_; 134 return result; 135 } 136 137 // Addition/subtraction. 138 UInt128& operator+=(const UInt128& other) { 139 const uint64_t carry = 140 (((low_ & other.low_) & 1) + (low_ >> 1) + (other.low_ >> 1)) >> 63; 141 high_ += other.high_ + carry; 142 low_ += other.low_; 143 return *this; 144 } 145 146 UInt128 operator+(const UInt128& other) const { 147 UInt128 result = *this; 148 result += other; 149 return result; 150 } 151 152 UInt128& operator-=(const UInt128& other) { 153 low_ -= other.low_; 154 const uint64_t carry = 155 (((low_ & other.low_) & 1) + (low_ >> 1) + (other.low_ >> 1)) >> 63; 156 high_ -= other.high_ + carry; 157 return *this; 158 } 159 160 UInt128 operator-(const UInt128& other) const { 161 UInt128 result = *this; 162 result -= other; 163 return result; 164 } 165 166 private: 167 // TODO(google): Different order for little endian. 168 uint64_t low_ = 0; 169 uint64_t high_ = 0; 170 }; 171 172 } // namespace base 173 } // namespace astc_codec 174 175 #endif // ASTC_CODEC_BASE_UINT128_H_ 176