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#ifdef __cpp_impl_three_way_comparison 190constexpr absl::strong_ordering operator<=>(int128 lhs, int128 rhs) { 191 if (int64_t lhs_high = Int128High64(lhs), rhs_high = Int128High64(rhs); 192 lhs_high < rhs_high) { 193 return absl::strong_ordering::less; 194 } else if (lhs_high > rhs_high) { 195 return absl::strong_ordering::greater; 196 } else if (uint64_t lhs_low = Uint128Low64(lhs), rhs_low = Uint128Low64(rhs); 197 lhs_low < rhs_low) { 198 return absl::strong_ordering::less; 199 } else if (lhs_low > rhs_low) { 200 return absl::strong_ordering::greater; 201 } else { 202 return absl::strong_ordering::equal; 203 } 204} 205#endif 206 207// Unary operators. 208 209constexpr int128 operator-(int128 v) { 210 return MakeInt128(~Int128High64(v) + (Int128Low64(v) == 0), 211 ~Int128Low64(v) + 1); 212} 213 214constexpr bool operator!(int128 v) { 215 return !Int128Low64(v) && !Int128High64(v); 216} 217 218constexpr int128 operator~(int128 val) { 219 return MakeInt128(~Int128High64(val), ~Int128Low64(val)); 220} 221 222// Arithmetic operators. 223 224namespace int128_internal { 225constexpr int128 SignedAddResult(int128 result, int128 lhs) { 226 // check for carry 227 return (Int128Low64(result) < Int128Low64(lhs)) 228 ? MakeInt128(Int128High64(result) + 1, Int128Low64(result)) 229 : result; 230} 231} // namespace int128_internal 232constexpr int128 operator+(int128 lhs, int128 rhs) { 233 return int128_internal::SignedAddResult( 234 MakeInt128(Int128High64(lhs) + Int128High64(rhs), 235 Int128Low64(lhs) + Int128Low64(rhs)), 236 lhs); 237} 238 239namespace int128_internal { 240constexpr int128 SignedSubstructResult(int128 result, int128 lhs, int128 rhs) { 241 // check for carry 242 return (Int128Low64(lhs) < Int128Low64(rhs)) 243 ? MakeInt128(Int128High64(result) - 1, Int128Low64(result)) 244 : result; 245} 246} // namespace int128_internal 247constexpr int128 operator-(int128 lhs, int128 rhs) { 248 return int128_internal::SignedSubstructResult( 249 MakeInt128(Int128High64(lhs) - Int128High64(rhs), 250 Int128Low64(lhs) - Int128Low64(rhs)), 251 lhs, rhs); 252} 253 254inline int128 operator*(int128 lhs, int128 rhs) { 255 return MakeInt128( 256 int128_internal::BitCastToSigned(Uint128High64(uint128(lhs) * rhs)), 257 Uint128Low64(uint128(lhs) * rhs)); 258} 259 260inline int128 int128::operator++(int) { 261 int128 tmp(*this); 262 *this += 1; 263 return tmp; 264} 265 266inline int128 int128::operator--(int) { 267 int128 tmp(*this); 268 *this -= 1; 269 return tmp; 270} 271 272inline int128& int128::operator++() { 273 *this += 1; 274 return *this; 275} 276 277inline int128& int128::operator--() { 278 *this -= 1; 279 return *this; 280} 281 282constexpr int128 operator|(int128 lhs, int128 rhs) { 283 return MakeInt128(Int128High64(lhs) | Int128High64(rhs), 284 Int128Low64(lhs) | Int128Low64(rhs)); 285} 286 287constexpr int128 operator&(int128 lhs, int128 rhs) { 288 return MakeInt128(Int128High64(lhs) & Int128High64(rhs), 289 Int128Low64(lhs) & Int128Low64(rhs)); 290} 291 292constexpr int128 operator^(int128 lhs, int128 rhs) { 293 return MakeInt128(Int128High64(lhs) ^ Int128High64(rhs), 294 Int128Low64(lhs) ^ Int128Low64(rhs)); 295} 296 297constexpr int128 operator<<(int128 lhs, int amount) { 298 // int64_t shifts of >= 63 are undefined, so we need some special-casing. 299 assert(amount >= 0 && amount < 127); 300 if (amount <= 0) { 301 return lhs; 302 } else if (amount < 63) { 303 return MakeInt128( 304 (Int128High64(lhs) << amount) | 305 static_cast<int64_t>(Int128Low64(lhs) >> (64 - amount)), 306 Int128Low64(lhs) << amount); 307 } else if (amount == 63) { 308 return MakeInt128(((Int128High64(lhs) << 32) << 31) | 309 static_cast<int64_t>(Int128Low64(lhs) >> 1), 310 (Int128Low64(lhs) << 32) << 31); 311 } else if (amount == 127) { 312 return MakeInt128(static_cast<int64_t>(Int128Low64(lhs) << 63), 0); 313 } else if (amount > 127) { 314 return MakeInt128(0, 0); 315 } else { 316 // amount >= 64 && amount < 127 317 return MakeInt128(static_cast<int64_t>(Int128Low64(lhs) << (amount - 64)), 318 0); 319 } 320} 321 322constexpr int128 operator>>(int128 lhs, int amount) { 323 // int64_t shifts of >= 63 are undefined, so we need some special-casing. 324 assert(amount >= 0 && amount < 127); 325 if (amount <= 0) { 326 return lhs; 327 } else if (amount < 63) { 328 return MakeInt128( 329 Int128High64(lhs) >> amount, 330 Int128Low64(lhs) >> amount | static_cast<uint64_t>(Int128High64(lhs)) 331 << (64 - amount)); 332 } else if (amount == 63) { 333 return MakeInt128((Int128High64(lhs) >> 32) >> 31, 334 static_cast<uint64_t>(Int128High64(lhs) << 1) | 335 (Int128Low64(lhs) >> 32) >> 31); 336 337 } else if (amount >= 127) { 338 return MakeInt128((Int128High64(lhs) >> 32) >> 31, 339 static_cast<uint64_t>((Int128High64(lhs) >> 32) >> 31)); 340 } else { 341 // amount >= 64 && amount < 127 342 return MakeInt128( 343 (Int128High64(lhs) >> 32) >> 31, 344 static_cast<uint64_t>(Int128High64(lhs) >> (amount - 64))); 345 } 346} 347