1// 2// Copyright 2017 The Abseil Authors. 3// 4// Licensed under the Apache License, Version 2.0 (the "License"); 5// you may not use this file except in compliance with the License. 6// You may obtain a copy of the License at 7// 8// https://www.apache.org/licenses/LICENSE-2.0 9// 10// Unless required by applicable law or agreed to in writing, software 11// distributed under the License is distributed on an "AS IS" BASIS, 12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13// See the License for the specific language governing permissions and 14// limitations under the License. 15 16// This file contains :int128 implementation details that depend on internal 17// representation when ABSL_HAVE_INTRINSIC_INT128 is *not* defined. This file 18// is included by int128.h and relies on ABSL_INTERNAL_WCHAR_T being defined. 19 20constexpr uint64_t Int128Low64(int128 v) { return v.lo_; } 21 22constexpr int64_t Int128High64(int128 v) { return v.hi_; } 23 24#if defined(ABSL_IS_LITTLE_ENDIAN) 25 26constexpr int128::int128(int64_t high, uint64_t low) : lo_(low), hi_(high) {} 27 28constexpr int128::int128(int v) 29 : lo_{static_cast<uint64_t>(v)}, hi_{v < 0 ? ~int64_t{0} : 0} {} 30constexpr int128::int128(long v) // NOLINT(runtime/int) 31 : lo_{static_cast<uint64_t>(v)}, hi_{v < 0 ? ~int64_t{0} : 0} {} 32constexpr int128::int128(long long v) // NOLINT(runtime/int) 33 : lo_{static_cast<uint64_t>(v)}, hi_{v < 0 ? ~int64_t{0} : 0} {} 34 35constexpr int128::int128(unsigned int v) : lo_{v}, hi_{0} {} 36// NOLINTNEXTLINE(runtime/int) 37constexpr int128::int128(unsigned long v) : lo_{v}, hi_{0} {} 38// NOLINTNEXTLINE(runtime/int) 39constexpr int128::int128(unsigned long long v) : lo_{v}, hi_{0} {} 40 41constexpr int128::int128(uint128 v) 42 : lo_{Uint128Low64(v)}, hi_{static_cast<int64_t>(Uint128High64(v))} {} 43 44#elif defined(ABSL_IS_BIG_ENDIAN) 45 46constexpr int128::int128(int64_t high, uint64_t low) : hi_{high}, lo_{low} {} 47 48constexpr int128::int128(int v) 49 : hi_{v < 0 ? ~int64_t{0} : 0}, lo_{static_cast<uint64_t>(v)} {} 50constexpr int128::int128(long v) // NOLINT(runtime/int) 51 : hi_{v < 0 ? ~int64_t{0} : 0}, lo_{static_cast<uint64_t>(v)} {} 52constexpr int128::int128(long long v) // NOLINT(runtime/int) 53 : hi_{v < 0 ? ~int64_t{0} : 0}, lo_{static_cast<uint64_t>(v)} {} 54 55constexpr int128::int128(unsigned int v) : hi_{0}, lo_{v} {} 56// NOLINTNEXTLINE(runtime/int) 57constexpr int128::int128(unsigned long v) : hi_{0}, lo_{v} {} 58// NOLINTNEXTLINE(runtime/int) 59constexpr int128::int128(unsigned long long v) : hi_{0}, lo_{v} {} 60 61constexpr int128::int128(uint128 v) 62 : hi_{static_cast<int64_t>(Uint128High64(v))}, lo_{Uint128Low64(v)} {} 63 64#else // byte order 65#error "Unsupported byte order: must be little-endian or big-endian." 66#endif // byte order 67 68constexpr int128::operator bool() const { return lo_ || hi_; } 69 70constexpr int128::operator char() const { 71 // NOLINTNEXTLINE(runtime/int) 72 return static_cast<char>(static_cast<long long>(*this)); 73} 74 75constexpr int128::operator signed char() const { 76 // NOLINTNEXTLINE(runtime/int) 77 return static_cast<signed char>(static_cast<long long>(*this)); 78} 79 80constexpr int128::operator unsigned char() const { 81 return static_cast<unsigned char>(lo_); 82} 83 84constexpr int128::operator char16_t() const { 85 return static_cast<char16_t>(lo_); 86} 87 88constexpr int128::operator char32_t() const { 89 return static_cast<char32_t>(lo_); 90} 91 92constexpr int128::operator ABSL_INTERNAL_WCHAR_T() const { 93 // NOLINTNEXTLINE(runtime/int) 94 return static_cast<ABSL_INTERNAL_WCHAR_T>(static_cast<long long>(*this)); 95} 96 97constexpr int128::operator short() const { // NOLINT(runtime/int) 98 // NOLINTNEXTLINE(runtime/int) 99 return static_cast<short>(static_cast<long long>(*this)); 100} 101 102constexpr int128::operator unsigned short() const { // NOLINT(runtime/int) 103 return static_cast<unsigned short>(lo_); // NOLINT(runtime/int) 104} 105 106constexpr int128::operator int() const { 107 // NOLINTNEXTLINE(runtime/int) 108 return static_cast<int>(static_cast<long long>(*this)); 109} 110 111constexpr int128::operator unsigned int() const { 112 return static_cast<unsigned int>(lo_); 113} 114 115constexpr int128::operator long() const { // NOLINT(runtime/int) 116 // NOLINTNEXTLINE(runtime/int) 117 return static_cast<long>(static_cast<long long>(*this)); 118} 119 120constexpr int128::operator unsigned long() const { // NOLINT(runtime/int) 121 return static_cast<unsigned long>(lo_); // NOLINT(runtime/int) 122} 123 124constexpr int128::operator long long() const { // NOLINT(runtime/int) 125 // We don't bother checking the value of hi_. If *this < 0, lo_'s high bit 126 // must be set in order for the value to fit into a long long. Conversely, if 127 // lo_'s high bit is set, *this must be < 0 for the value to fit. 128 return int128_internal::BitCastToSigned(lo_); 129} 130 131constexpr int128::operator unsigned long long() const { // NOLINT(runtime/int) 132 return static_cast<unsigned long long>(lo_); // NOLINT(runtime/int) 133} 134 135inline int128::operator float() const { 136 // We must convert the absolute value and then negate as needed, because 137 // floating point types are typically sign-magnitude. Otherwise, the 138 // difference between the high and low 64 bits when interpreted as two's 139 // complement overwhelms the precision of the mantissa. 140 // 141 // Also check to make sure we don't negate Int128Min() 142 return hi_ < 0 && *this != Int128Min() 143 ? -static_cast<float>(-*this) 144 : static_cast<float>(lo_) + 145 std::ldexp(static_cast<float>(hi_), 64); 146} 147 148inline int128::operator double() const { 149 // See comment in int128::operator float() above. 150 return hi_ < 0 && *this != Int128Min() 151 ? -static_cast<double>(-*this) 152 : static_cast<double>(lo_) + 153 std::ldexp(static_cast<double>(hi_), 64); 154} 155 156inline int128::operator long double() const { 157 // See comment in int128::operator float() above. 158 return hi_ < 0 && *this != Int128Min() 159 ? -static_cast<long double>(-*this) 160 : static_cast<long double>(lo_) + 161 std::ldexp(static_cast<long double>(hi_), 64); 162} 163 164// Comparison operators. 165 166constexpr bool operator==(int128 lhs, int128 rhs) { 167 return (Int128Low64(lhs) == Int128Low64(rhs) && 168 Int128High64(lhs) == Int128High64(rhs)); 169} 170 171constexpr bool operator!=(int128 lhs, int128 rhs) { return !(lhs == rhs); } 172 173constexpr bool operator<(int128 lhs, int128 rhs) { 174 return (Int128High64(lhs) == Int128High64(rhs)) 175 ? (Int128Low64(lhs) < Int128Low64(rhs)) 176 : (Int128High64(lhs) < Int128High64(rhs)); 177} 178 179constexpr bool operator>(int128 lhs, int128 rhs) { 180 return (Int128High64(lhs) == Int128High64(rhs)) 181 ? (Int128Low64(lhs) > Int128Low64(rhs)) 182 : (Int128High64(lhs) > Int128High64(rhs)); 183} 184 185constexpr bool operator<=(int128 lhs, int128 rhs) { return !(lhs > rhs); } 186 187constexpr bool operator>=(int128 lhs, int128 rhs) { return !(lhs < rhs); } 188 189// Unary operators. 190 191constexpr int128 operator-(int128 v) { 192 return MakeInt128(~Int128High64(v) + (Int128Low64(v) == 0), 193 ~Int128Low64(v) + 1); 194} 195 196constexpr bool operator!(int128 v) { 197 return !Int128Low64(v) && !Int128High64(v); 198} 199 200constexpr int128 operator~(int128 val) { 201 return MakeInt128(~Int128High64(val), ~Int128Low64(val)); 202} 203 204// Arithmetic operators. 205 206namespace int128_internal { 207constexpr int128 SignedAddResult(int128 result, int128 lhs) { 208 // check for carry 209 return (Int128Low64(result) < Int128Low64(lhs)) 210 ? MakeInt128(Int128High64(result) + 1, Int128Low64(result)) 211 : result; 212} 213} // namespace int128_internal 214constexpr int128 operator+(int128 lhs, int128 rhs) { 215 return int128_internal::SignedAddResult( 216 MakeInt128(Int128High64(lhs) + Int128High64(rhs), 217 Int128Low64(lhs) + Int128Low64(rhs)), 218 lhs); 219} 220 221namespace int128_internal { 222constexpr int128 SignedSubstructResult(int128 result, int128 lhs, int128 rhs) { 223 // check for carry 224 return (Int128Low64(lhs) < Int128Low64(rhs)) 225 ? MakeInt128(Int128High64(result) - 1, Int128Low64(result)) 226 : result; 227} 228} // namespace int128_internal 229constexpr int128 operator-(int128 lhs, int128 rhs) { 230 return int128_internal::SignedSubstructResult( 231 MakeInt128(Int128High64(lhs) - Int128High64(rhs), 232 Int128Low64(lhs) - Int128Low64(rhs)), 233 lhs, rhs); 234} 235 236inline int128 operator*(int128 lhs, int128 rhs) { 237 return MakeInt128( 238 int128_internal::BitCastToSigned(Uint128High64(uint128(lhs) * rhs)), 239 Uint128Low64(uint128(lhs) * rhs)); 240} 241 242inline int128 int128::operator++(int) { 243 int128 tmp(*this); 244 *this += 1; 245 return tmp; 246} 247 248inline int128 int128::operator--(int) { 249 int128 tmp(*this); 250 *this -= 1; 251 return tmp; 252} 253 254inline int128& int128::operator++() { 255 *this += 1; 256 return *this; 257} 258 259inline int128& int128::operator--() { 260 *this -= 1; 261 return *this; 262} 263 264constexpr int128 operator|(int128 lhs, int128 rhs) { 265 return MakeInt128(Int128High64(lhs) | Int128High64(rhs), 266 Int128Low64(lhs) | Int128Low64(rhs)); 267} 268 269constexpr int128 operator&(int128 lhs, int128 rhs) { 270 return MakeInt128(Int128High64(lhs) & Int128High64(rhs), 271 Int128Low64(lhs) & Int128Low64(rhs)); 272} 273 274constexpr int128 operator^(int128 lhs, int128 rhs) { 275 return MakeInt128(Int128High64(lhs) ^ Int128High64(rhs), 276 Int128Low64(lhs) ^ Int128Low64(rhs)); 277} 278 279constexpr int128 operator<<(int128 lhs, int amount) { 280 // int64_t shifts of >= 63 are undefined, so we need some special-casing. 281 assert(amount >= 0 && amount < 127); 282 if (amount <= 0) { 283 return lhs; 284 } else if (amount < 63) { 285 return MakeInt128( 286 (Int128High64(lhs) << amount) | 287 static_cast<int64_t>(Int128Low64(lhs) >> (64 - amount)), 288 Int128Low64(lhs) << amount); 289 } else if (amount == 63) { 290 return MakeInt128(((Int128High64(lhs) << 32) << 31) | 291 static_cast<int64_t>(Int128Low64(lhs) >> 1), 292 (Int128Low64(lhs) << 32) << 31); 293 } else if (amount == 127) { 294 return MakeInt128(static_cast<int64_t>(Int128Low64(lhs) << 63), 0); 295 } else if (amount > 127) { 296 return MakeInt128(0, 0); 297 } else { 298 // amount >= 64 && amount < 127 299 return MakeInt128(static_cast<int64_t>(Int128Low64(lhs) << (amount - 64)), 300 0); 301 } 302} 303 304constexpr int128 operator>>(int128 lhs, int amount) { 305 // int64_t shifts of >= 63 are undefined, so we need some special-casing. 306 assert(amount >= 0 && amount < 127); 307 if (amount <= 0) { 308 return lhs; 309 } else if (amount < 63) { 310 return MakeInt128( 311 Int128High64(lhs) >> amount, 312 Int128Low64(lhs) >> amount | static_cast<uint64_t>(Int128High64(lhs)) 313 << (64 - amount)); 314 } else if (amount == 63) { 315 return MakeInt128((Int128High64(lhs) >> 32) >> 31, 316 static_cast<uint64_t>(Int128High64(lhs) << 1) | 317 (Int128Low64(lhs) >> 32) >> 31); 318 319 } else if (amount >= 127) { 320 return MakeInt128((Int128High64(lhs) >> 32) >> 31, 321 static_cast<uint64_t>((Int128High64(lhs) >> 32) >> 31)); 322 } else { 323 // amount >= 64 && amount < 127 324 return MakeInt128( 325 (Int128High64(lhs) >> 32) >> 31, 326 static_cast<uint64_t>(Int128High64(lhs) >> (amount - 64))); 327 } 328} 329