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 | // ----------------------------------------------------------------------------- |
17 | // File: int128.h |
18 | // ----------------------------------------------------------------------------- |
19 | // |
20 | // This header file defines 128-bit integer types. |
21 | // |
22 | // Currently, this file defines `uint128`, an unsigned 128-bit integer; a signed |
23 | // 128-bit integer is forthcoming. |
24 | |
25 | #ifndef ABSL_NUMERIC_INT128_H_ |
26 | #define ABSL_NUMERIC_INT128_H_ |
27 | |
28 | #include <cassert> |
29 | #include <cmath> |
30 | #include <cstdint> |
31 | #include <cstring> |
32 | #include <iosfwd> |
33 | #include <limits> |
34 | #include <utility> |
35 | |
36 | #include "absl/base/config.h" |
37 | #include "absl/base/macros.h" |
38 | #include "absl/base/port.h" |
39 | |
40 | #if defined(_MSC_VER) |
41 | // In very old versions of MSVC and when the /Zc:wchar_t flag is off, wchar_t is |
42 | // a typedef for unsigned short. Otherwise wchar_t is mapped to the __wchar_t |
43 | // builtin type. We need to make sure not to define operator wchar_t() |
44 | // alongside operator unsigned short() in these instances. |
45 | #define ABSL_INTERNAL_WCHAR_T __wchar_t |
46 | #if defined(_M_X64) |
47 | #include <intrin.h> |
48 | #pragma intrinsic(_umul128) |
49 | #endif // defined(_M_X64) |
50 | #else // defined(_MSC_VER) |
51 | #define ABSL_INTERNAL_WCHAR_T wchar_t |
52 | #endif // defined(_MSC_VER) |
53 | |
54 | namespace absl { |
55 | |
56 | // uint128 |
57 | // |
58 | // An unsigned 128-bit integer type. The API is meant to mimic an intrinsic type |
59 | // as closely as is practical, including exhibiting undefined behavior in |
60 | // analogous cases (e.g. division by zero). This type is intended to be a |
61 | // drop-in replacement once C++ supports an intrinsic `uint128_t` type; when |
62 | // that occurs, existing well-behaved uses of `uint128` will continue to work |
63 | // using that new type. |
64 | // |
65 | // Note: code written with this type will continue to compile once `uint128_t` |
66 | // is introduced, provided the replacement helper functions |
67 | // `Uint128(Low|High)64()` and `MakeUint128()` are made. |
68 | // |
69 | // A `uint128` supports the following: |
70 | // |
71 | // * Implicit construction from integral types |
72 | // * Explicit conversion to integral types |
73 | // |
74 | // Additionally, if your compiler supports `__int128`, `uint128` is |
75 | // interoperable with that type. (Abseil checks for this compatibility through |
76 | // the `ABSL_HAVE_INTRINSIC_INT128` macro.) |
77 | // |
78 | // However, a `uint128` differs from intrinsic integral types in the following |
79 | // ways: |
80 | // |
81 | // * Errors on implicit conversions that do not preserve value (such as |
82 | // loss of precision when converting to float values). |
83 | // * Requires explicit construction from and conversion to floating point |
84 | // types. |
85 | // * Conversion to integral types requires an explicit static_cast() to |
86 | // mimic use of the `-Wnarrowing` compiler flag. |
87 | // * The alignment requirement of `uint128` may differ from that of an |
88 | // intrinsic 128-bit integer type depending on platform and build |
89 | // configuration. |
90 | // |
91 | // Example: |
92 | // |
93 | // float y = absl::Uint128Max(); // Error. uint128 cannot be implicitly |
94 | // // converted to float. |
95 | // |
96 | // absl::uint128 v; |
97 | // uint64_t i = v; // Error |
98 | // uint64_t i = static_cast<uint64_t>(v); // OK |
99 | // |
100 | class |
101 | #if defined(ABSL_HAVE_INTRINSIC_INT128) |
102 | alignas(unsigned __int128) |
103 | #endif // ABSL_HAVE_INTRINSIC_INT128 |
104 | uint128 { |
105 | public: |
106 | uint128() = default; |
107 | |
108 | // Constructors from arithmetic types |
109 | constexpr uint128(int v); // NOLINT(runtime/explicit) |
110 | constexpr uint128(unsigned int v); // NOLINT(runtime/explicit) |
111 | constexpr uint128(long v); // NOLINT(runtime/int) |
112 | constexpr uint128(unsigned long v); // NOLINT(runtime/int) |
113 | constexpr uint128(long long v); // NOLINT(runtime/int) |
114 | constexpr uint128(unsigned long long v); // NOLINT(runtime/int) |
115 | #ifdef ABSL_HAVE_INTRINSIC_INT128 |
116 | constexpr uint128(__int128 v); // NOLINT(runtime/explicit) |
117 | constexpr uint128(unsigned __int128 v); // NOLINT(runtime/explicit) |
118 | #endif // ABSL_HAVE_INTRINSIC_INT128 |
119 | explicit uint128(float v); |
120 | explicit uint128(double v); |
121 | explicit uint128(long double v); |
122 | |
123 | // Assignment operators from arithmetic types |
124 | uint128& operator=(int v); |
125 | uint128& operator=(unsigned int v); |
126 | uint128& operator=(long v); // NOLINT(runtime/int) |
127 | uint128& operator=(unsigned long v); // NOLINT(runtime/int) |
128 | uint128& operator=(long long v); // NOLINT(runtime/int) |
129 | uint128& operator=(unsigned long long v); // NOLINT(runtime/int) |
130 | #ifdef ABSL_HAVE_INTRINSIC_INT128 |
131 | uint128& operator=(__int128 v); |
132 | uint128& operator=(unsigned __int128 v); |
133 | #endif // ABSL_HAVE_INTRINSIC_INT128 |
134 | |
135 | // Conversion operators to other arithmetic types |
136 | constexpr explicit operator bool() const; |
137 | constexpr explicit operator char() const; |
138 | constexpr explicit operator signed char() const; |
139 | constexpr explicit operator unsigned char() const; |
140 | constexpr explicit operator char16_t() const; |
141 | constexpr explicit operator char32_t() const; |
142 | constexpr explicit operator ABSL_INTERNAL_WCHAR_T() const; |
143 | constexpr explicit operator short() const; // NOLINT(runtime/int) |
144 | // NOLINTNEXTLINE(runtime/int) |
145 | constexpr explicit operator unsigned short() const; |
146 | constexpr explicit operator int() const; |
147 | constexpr explicit operator unsigned int() const; |
148 | constexpr explicit operator long() const; // NOLINT(runtime/int) |
149 | // NOLINTNEXTLINE(runtime/int) |
150 | constexpr explicit operator unsigned long() const; |
151 | // NOLINTNEXTLINE(runtime/int) |
152 | constexpr explicit operator long long() const; |
153 | // NOLINTNEXTLINE(runtime/int) |
154 | constexpr explicit operator unsigned long long() const; |
155 | #ifdef ABSL_HAVE_INTRINSIC_INT128 |
156 | constexpr explicit operator __int128() const; |
157 | constexpr explicit operator unsigned __int128() const; |
158 | #endif // ABSL_HAVE_INTRINSIC_INT128 |
159 | explicit operator float() const; |
160 | explicit operator double() const; |
161 | explicit operator long double() const; |
162 | |
163 | // Trivial copy constructor, assignment operator and destructor. |
164 | |
165 | // Arithmetic operators. |
166 | uint128& operator+=(uint128 other); |
167 | uint128& operator-=(uint128 other); |
168 | uint128& operator*=(uint128 other); |
169 | // Long division/modulo for uint128. |
170 | uint128& operator/=(uint128 other); |
171 | uint128& operator%=(uint128 other); |
172 | uint128 operator++(int); |
173 | uint128 operator--(int); |
174 | uint128& operator<<=(int); |
175 | uint128& operator>>=(int); |
176 | uint128& operator&=(uint128 other); |
177 | uint128& operator|=(uint128 other); |
178 | uint128& operator^=(uint128 other); |
179 | uint128& operator++(); |
180 | uint128& operator--(); |
181 | |
182 | // Uint128Low64() |
183 | // |
184 | // Returns the lower 64-bit value of a `uint128` value. |
185 | friend constexpr uint64_t Uint128Low64(uint128 v); |
186 | |
187 | // Uint128High64() |
188 | // |
189 | // Returns the higher 64-bit value of a `uint128` value. |
190 | friend constexpr uint64_t Uint128High64(uint128 v); |
191 | |
192 | // MakeUInt128() |
193 | // |
194 | // Constructs a `uint128` numeric value from two 64-bit unsigned integers. |
195 | // Note that this factory function is the only way to construct a `uint128` |
196 | // from integer values greater than 2^64. |
197 | // |
198 | // Example: |
199 | // |
200 | // absl::uint128 big = absl::MakeUint128(1, 0); |
201 | friend constexpr uint128 MakeUint128(uint64_t high, uint64_t low); |
202 | |
203 | // Uint128Max() |
204 | // |
205 | // Returns the highest value for a 128-bit unsigned integer. |
206 | friend constexpr uint128 Uint128Max(); |
207 | |
208 | // Support for absl::Hash. |
209 | template <typename H> |
210 | friend H AbslHashValue(H h, uint128 v) { |
211 | return H::combine(std::move(h), Uint128High64(v), Uint128Low64(v)); |
212 | } |
213 | |
214 | private: |
215 | constexpr uint128(uint64_t high, uint64_t low); |
216 | |
217 | // TODO(strel) Update implementation to use __int128 once all users of |
218 | // uint128 are fixed to not depend on alignof(uint128) == 8. Also add |
219 | // alignas(16) to class definition to keep alignment consistent across |
220 | // platforms. |
221 | #if defined(ABSL_IS_LITTLE_ENDIAN) |
222 | uint64_t lo_; |
223 | uint64_t hi_; |
224 | #elif defined(ABSL_IS_BIG_ENDIAN) |
225 | uint64_t hi_; |
226 | uint64_t lo_; |
227 | #else // byte order |
228 | #error "Unsupported byte order: must be little-endian or big-endian." |
229 | #endif // byte order |
230 | }; |
231 | |
232 | // Prefer to use the constexpr `Uint128Max()`. |
233 | // |
234 | // TODO(absl-team) deprecate kuint128max once migration tool is released. |
235 | extern const uint128 kuint128max; |
236 | |
237 | // allow uint128 to be logged |
238 | std::ostream& operator<<(std::ostream& os, uint128 v); |
239 | |
240 | // TODO(strel) add operator>>(std::istream&, uint128) |
241 | |
242 | constexpr uint128 Uint128Max() { |
243 | return uint128((std::numeric_limits<uint64_t>::max)(), |
244 | (std::numeric_limits<uint64_t>::max)()); |
245 | } |
246 | |
247 | } // namespace absl |
248 | |
249 | // Specialized numeric_limits for uint128. |
250 | namespace std { |
251 | template <> |
252 | class numeric_limits<absl::uint128> { |
253 | public: |
254 | static constexpr bool is_specialized = true; |
255 | static constexpr bool is_signed = false; |
256 | static constexpr bool is_integer = true; |
257 | static constexpr bool is_exact = true; |
258 | static constexpr bool has_infinity = false; |
259 | static constexpr bool has_quiet_NaN = false; |
260 | static constexpr bool has_signaling_NaN = false; |
261 | static constexpr float_denorm_style has_denorm = denorm_absent; |
262 | static constexpr bool has_denorm_loss = false; |
263 | static constexpr float_round_style round_style = round_toward_zero; |
264 | static constexpr bool is_iec559 = false; |
265 | static constexpr bool is_bounded = true; |
266 | static constexpr bool is_modulo = true; |
267 | static constexpr int digits = 128; |
268 | static constexpr int digits10 = 38; |
269 | static constexpr int max_digits10 = 0; |
270 | static constexpr int radix = 2; |
271 | static constexpr int min_exponent = 0; |
272 | static constexpr int min_exponent10 = 0; |
273 | static constexpr int max_exponent = 0; |
274 | static constexpr int max_exponent10 = 0; |
275 | #ifdef ABSL_HAVE_INTRINSIC_INT128 |
276 | static constexpr bool traps = numeric_limits<unsigned __int128>::traps; |
277 | #else // ABSL_HAVE_INTRINSIC_INT128 |
278 | static constexpr bool traps = numeric_limits<uint64_t>::traps; |
279 | #endif // ABSL_HAVE_INTRINSIC_INT128 |
280 | static constexpr bool tinyness_before = false; |
281 | |
282 | static constexpr absl::uint128 (min)() { return 0; } |
283 | static constexpr absl::uint128 lowest() { return 0; } |
284 | static constexpr absl::uint128 (max)() { return absl::Uint128Max(); } |
285 | static constexpr absl::uint128 epsilon() { return 0; } |
286 | static constexpr absl::uint128 round_error() { return 0; } |
287 | static constexpr absl::uint128 infinity() { return 0; } |
288 | static constexpr absl::uint128 quiet_NaN() { return 0; } |
289 | static constexpr absl::uint128 signaling_NaN() { return 0; } |
290 | static constexpr absl::uint128 denorm_min() { return 0; } |
291 | }; |
292 | } // namespace std |
293 | |
294 | // TODO(absl-team): Implement signed 128-bit type |
295 | |
296 | // -------------------------------------------------------------------------- |
297 | // Implementation details follow |
298 | // -------------------------------------------------------------------------- |
299 | namespace absl { |
300 | |
301 | constexpr uint128 MakeUint128(uint64_t high, uint64_t low) { |
302 | return uint128(high, low); |
303 | } |
304 | |
305 | // Assignment from integer types. |
306 | |
307 | inline uint128& uint128::operator=(int v) { return *this = uint128(v); } |
308 | |
309 | inline uint128& uint128::operator=(unsigned int v) { |
310 | return *this = uint128(v); |
311 | } |
312 | |
313 | inline uint128& uint128::operator=(long v) { // NOLINT(runtime/int) |
314 | return *this = uint128(v); |
315 | } |
316 | |
317 | // NOLINTNEXTLINE(runtime/int) |
318 | inline uint128& uint128::operator=(unsigned long v) { |
319 | return *this = uint128(v); |
320 | } |
321 | |
322 | // NOLINTNEXTLINE(runtime/int) |
323 | inline uint128& uint128::operator=(long long v) { |
324 | return *this = uint128(v); |
325 | } |
326 | |
327 | // NOLINTNEXTLINE(runtime/int) |
328 | inline uint128& uint128::operator=(unsigned long long v) { |
329 | return *this = uint128(v); |
330 | } |
331 | |
332 | #ifdef ABSL_HAVE_INTRINSIC_INT128 |
333 | inline uint128& uint128::operator=(__int128 v) { |
334 | return *this = uint128(v); |
335 | } |
336 | |
337 | inline uint128& uint128::operator=(unsigned __int128 v) { |
338 | return *this = uint128(v); |
339 | } |
340 | #endif // ABSL_HAVE_INTRINSIC_INT128 |
341 | |
342 | // Arithmetic operators. |
343 | |
344 | uint128 operator<<(uint128 lhs, int amount); |
345 | uint128 operator>>(uint128 lhs, int amount); |
346 | uint128 operator+(uint128 lhs, uint128 rhs); |
347 | uint128 operator-(uint128 lhs, uint128 rhs); |
348 | uint128 operator*(uint128 lhs, uint128 rhs); |
349 | uint128 operator/(uint128 lhs, uint128 rhs); |
350 | uint128 operator%(uint128 lhs, uint128 rhs); |
351 | |
352 | inline uint128& uint128::operator<<=(int amount) { |
353 | *this = *this << amount; |
354 | return *this; |
355 | } |
356 | |
357 | inline uint128& uint128::operator>>=(int amount) { |
358 | *this = *this >> amount; |
359 | return *this; |
360 | } |
361 | |
362 | inline uint128& uint128::operator+=(uint128 other) { |
363 | *this = *this + other; |
364 | return *this; |
365 | } |
366 | |
367 | inline uint128& uint128::operator-=(uint128 other) { |
368 | *this = *this - other; |
369 | return *this; |
370 | } |
371 | |
372 | inline uint128& uint128::operator*=(uint128 other) { |
373 | *this = *this * other; |
374 | return *this; |
375 | } |
376 | |
377 | inline uint128& uint128::operator/=(uint128 other) { |
378 | *this = *this / other; |
379 | return *this; |
380 | } |
381 | |
382 | inline uint128& uint128::operator%=(uint128 other) { |
383 | *this = *this % other; |
384 | return *this; |
385 | } |
386 | |
387 | constexpr uint64_t Uint128Low64(uint128 v) { return v.lo_; } |
388 | |
389 | constexpr uint64_t Uint128High64(uint128 v) { return v.hi_; } |
390 | |
391 | // Constructors from integer types. |
392 | |
393 | #if defined(ABSL_IS_LITTLE_ENDIAN) |
394 | |
395 | constexpr uint128::uint128(uint64_t high, uint64_t low) |
396 | : lo_{low}, hi_{high} {} |
397 | |
398 | constexpr uint128::uint128(int v) |
399 | : lo_{static_cast<uint64_t>(v)}, |
400 | hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0} {} |
401 | constexpr uint128::uint128(long v) // NOLINT(runtime/int) |
402 | : lo_{static_cast<uint64_t>(v)}, |
403 | hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0} {} |
404 | constexpr uint128::uint128(long long v) // NOLINT(runtime/int) |
405 | : lo_{static_cast<uint64_t>(v)}, |
406 | hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0} {} |
407 | |
408 | constexpr uint128::uint128(unsigned int v) : lo_{v}, hi_{0} {} |
409 | // NOLINTNEXTLINE(runtime/int) |
410 | constexpr uint128::uint128(unsigned long v) : lo_{v}, hi_{0} {} |
411 | // NOLINTNEXTLINE(runtime/int) |
412 | constexpr uint128::uint128(unsigned long long v) : lo_{v}, hi_{0} {} |
413 | |
414 | #ifdef ABSL_HAVE_INTRINSIC_INT128 |
415 | constexpr uint128::uint128(__int128 v) |
416 | : lo_{static_cast<uint64_t>(v & ~uint64_t{0})}, |
417 | hi_{static_cast<uint64_t>(static_cast<unsigned __int128>(v) >> 64)} {} |
418 | constexpr uint128::uint128(unsigned __int128 v) |
419 | : lo_{static_cast<uint64_t>(v & ~uint64_t{0})}, |
420 | hi_{static_cast<uint64_t>(v >> 64)} {} |
421 | #endif // ABSL_HAVE_INTRINSIC_INT128 |
422 | |
423 | #elif defined(ABSL_IS_BIG_ENDIAN) |
424 | |
425 | constexpr uint128::uint128(uint64_t high, uint64_t low) |
426 | : hi_{high}, lo_{low} {} |
427 | |
428 | constexpr uint128::uint128(int v) |
429 | : hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0}, |
430 | lo_{static_cast<uint64_t>(v)} {} |
431 | constexpr uint128::uint128(long v) // NOLINT(runtime/int) |
432 | : hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0}, |
433 | lo_{static_cast<uint64_t>(v)} {} |
434 | constexpr uint128::uint128(long long v) // NOLINT(runtime/int) |
435 | : hi_{v < 0 ? (std::numeric_limits<uint64_t>::max)() : 0}, |
436 | lo_{static_cast<uint64_t>(v)} {} |
437 | |
438 | constexpr uint128::uint128(unsigned int v) : hi_{0}, lo_{v} {} |
439 | // NOLINTNEXTLINE(runtime/int) |
440 | constexpr uint128::uint128(unsigned long v) : hi_{0}, lo_{v} {} |
441 | // NOLINTNEXTLINE(runtime/int) |
442 | constexpr uint128::uint128(unsigned long long v) : hi_{0}, lo_{v} {} |
443 | |
444 | #ifdef ABSL_HAVE_INTRINSIC_INT128 |
445 | constexpr uint128::uint128(__int128 v) |
446 | : hi_{static_cast<uint64_t>(static_cast<unsigned __int128>(v) >> 64)}, |
447 | lo_{static_cast<uint64_t>(v & ~uint64_t{0})} {} |
448 | constexpr uint128::uint128(unsigned __int128 v) |
449 | : hi_{static_cast<uint64_t>(v >> 64)}, |
450 | lo_{static_cast<uint64_t>(v & ~uint64_t{0})} {} |
451 | #endif // ABSL_HAVE_INTRINSIC_INT128 |
452 | |
453 | #else // byte order |
454 | #error "Unsupported byte order: must be little-endian or big-endian." |
455 | #endif // byte order |
456 | |
457 | // Conversion operators to integer types. |
458 | |
459 | constexpr uint128::operator bool() const { return lo_ || hi_; } |
460 | |
461 | constexpr uint128::operator char() const { return static_cast<char>(lo_); } |
462 | |
463 | constexpr uint128::operator signed char() const { |
464 | return static_cast<signed char>(lo_); |
465 | } |
466 | |
467 | constexpr uint128::operator unsigned char() const { |
468 | return static_cast<unsigned char>(lo_); |
469 | } |
470 | |
471 | constexpr uint128::operator char16_t() const { |
472 | return static_cast<char16_t>(lo_); |
473 | } |
474 | |
475 | constexpr uint128::operator char32_t() const { |
476 | return static_cast<char32_t>(lo_); |
477 | } |
478 | |
479 | constexpr uint128::operator ABSL_INTERNAL_WCHAR_T() const { |
480 | return static_cast<ABSL_INTERNAL_WCHAR_T>(lo_); |
481 | } |
482 | |
483 | // NOLINTNEXTLINE(runtime/int) |
484 | constexpr uint128::operator short() const { return static_cast<short>(lo_); } |
485 | |
486 | constexpr uint128::operator unsigned short() const { // NOLINT(runtime/int) |
487 | return static_cast<unsigned short>(lo_); // NOLINT(runtime/int) |
488 | } |
489 | |
490 | constexpr uint128::operator int() const { return static_cast<int>(lo_); } |
491 | |
492 | constexpr uint128::operator unsigned int() const { |
493 | return static_cast<unsigned int>(lo_); |
494 | } |
495 | |
496 | // NOLINTNEXTLINE(runtime/int) |
497 | constexpr uint128::operator long() const { return static_cast<long>(lo_); } |
498 | |
499 | constexpr uint128::operator unsigned long() const { // NOLINT(runtime/int) |
500 | return static_cast<unsigned long>(lo_); // NOLINT(runtime/int) |
501 | } |
502 | |
503 | constexpr uint128::operator long long() const { // NOLINT(runtime/int) |
504 | return static_cast<long long>(lo_); // NOLINT(runtime/int) |
505 | } |
506 | |
507 | constexpr uint128::operator unsigned long long() const { // NOLINT(runtime/int) |
508 | return static_cast<unsigned long long>(lo_); // NOLINT(runtime/int) |
509 | } |
510 | |
511 | #ifdef ABSL_HAVE_INTRINSIC_INT128 |
512 | constexpr uint128::operator __int128() const { |
513 | return (static_cast<__int128>(hi_) << 64) + lo_; |
514 | } |
515 | |
516 | constexpr uint128::operator unsigned __int128() const { |
517 | return (static_cast<unsigned __int128>(hi_) << 64) + lo_; |
518 | } |
519 | #endif // ABSL_HAVE_INTRINSIC_INT128 |
520 | |
521 | // Conversion operators to floating point types. |
522 | |
523 | inline uint128::operator float() const { |
524 | return static_cast<float>(lo_) + std::ldexp(static_cast<float>(hi_), 64); |
525 | } |
526 | |
527 | inline uint128::operator double() const { |
528 | return static_cast<double>(lo_) + std::ldexp(static_cast<double>(hi_), 64); |
529 | } |
530 | |
531 | inline uint128::operator long double() const { |
532 | return static_cast<long double>(lo_) + |
533 | std::ldexp(static_cast<long double>(hi_), 64); |
534 | } |
535 | |
536 | // Comparison operators. |
537 | |
538 | inline bool operator==(uint128 lhs, uint128 rhs) { |
539 | return (Uint128Low64(lhs) == Uint128Low64(rhs) && |
540 | Uint128High64(lhs) == Uint128High64(rhs)); |
541 | } |
542 | |
543 | inline bool operator!=(uint128 lhs, uint128 rhs) { |
544 | return !(lhs == rhs); |
545 | } |
546 | |
547 | inline bool operator<(uint128 lhs, uint128 rhs) { |
548 | return (Uint128High64(lhs) == Uint128High64(rhs)) |
549 | ? (Uint128Low64(lhs) < Uint128Low64(rhs)) |
550 | : (Uint128High64(lhs) < Uint128High64(rhs)); |
551 | } |
552 | |
553 | inline bool operator>(uint128 lhs, uint128 rhs) { |
554 | return (Uint128High64(lhs) == Uint128High64(rhs)) |
555 | ? (Uint128Low64(lhs) > Uint128Low64(rhs)) |
556 | : (Uint128High64(lhs) > Uint128High64(rhs)); |
557 | } |
558 | |
559 | inline bool operator<=(uint128 lhs, uint128 rhs) { |
560 | return (Uint128High64(lhs) == Uint128High64(rhs)) |
561 | ? (Uint128Low64(lhs) <= Uint128Low64(rhs)) |
562 | : (Uint128High64(lhs) <= Uint128High64(rhs)); |
563 | } |
564 | |
565 | inline bool operator>=(uint128 lhs, uint128 rhs) { |
566 | return (Uint128High64(lhs) == Uint128High64(rhs)) |
567 | ? (Uint128Low64(lhs) >= Uint128Low64(rhs)) |
568 | : (Uint128High64(lhs) >= Uint128High64(rhs)); |
569 | } |
570 | |
571 | // Unary operators. |
572 | |
573 | inline uint128 operator-(uint128 val) { |
574 | uint64_t hi = ~Uint128High64(val); |
575 | uint64_t lo = ~Uint128Low64(val) + 1; |
576 | if (lo == 0) ++hi; // carry |
577 | return MakeUint128(hi, lo); |
578 | } |
579 | |
580 | inline bool operator!(uint128 val) { |
581 | return !Uint128High64(val) && !Uint128Low64(val); |
582 | } |
583 | |
584 | // Logical operators. |
585 | |
586 | inline uint128 operator~(uint128 val) { |
587 | return MakeUint128(~Uint128High64(val), ~Uint128Low64(val)); |
588 | } |
589 | |
590 | inline uint128 operator|(uint128 lhs, uint128 rhs) { |
591 | return MakeUint128(Uint128High64(lhs) | Uint128High64(rhs), |
592 | Uint128Low64(lhs) | Uint128Low64(rhs)); |
593 | } |
594 | |
595 | inline uint128 operator&(uint128 lhs, uint128 rhs) { |
596 | return MakeUint128(Uint128High64(lhs) & Uint128High64(rhs), |
597 | Uint128Low64(lhs) & Uint128Low64(rhs)); |
598 | } |
599 | |
600 | inline uint128 operator^(uint128 lhs, uint128 rhs) { |
601 | return MakeUint128(Uint128High64(lhs) ^ Uint128High64(rhs), |
602 | Uint128Low64(lhs) ^ Uint128Low64(rhs)); |
603 | } |
604 | |
605 | inline uint128& uint128::operator|=(uint128 other) { |
606 | hi_ |= other.hi_; |
607 | lo_ |= other.lo_; |
608 | return *this; |
609 | } |
610 | |
611 | inline uint128& uint128::operator&=(uint128 other) { |
612 | hi_ &= other.hi_; |
613 | lo_ &= other.lo_; |
614 | return *this; |
615 | } |
616 | |
617 | inline uint128& uint128::operator^=(uint128 other) { |
618 | hi_ ^= other.hi_; |
619 | lo_ ^= other.lo_; |
620 | return *this; |
621 | } |
622 | |
623 | // Arithmetic operators. |
624 | |
625 | inline uint128 operator<<(uint128 lhs, int amount) { |
626 | // uint64_t shifts of >= 64 are undefined, so we will need some |
627 | // special-casing. |
628 | if (amount < 64) { |
629 | if (amount != 0) { |
630 | return MakeUint128( |
631 | (Uint128High64(lhs) << amount) | (Uint128Low64(lhs) >> (64 - amount)), |
632 | Uint128Low64(lhs) << amount); |
633 | } |
634 | return lhs; |
635 | } |
636 | return MakeUint128(Uint128Low64(lhs) << (amount - 64), 0); |
637 | } |
638 | |
639 | inline uint128 operator>>(uint128 lhs, int amount) { |
640 | // uint64_t shifts of >= 64 are undefined, so we will need some |
641 | // special-casing. |
642 | if (amount < 64) { |
643 | if (amount != 0) { |
644 | return MakeUint128(Uint128High64(lhs) >> amount, |
645 | (Uint128Low64(lhs) >> amount) | |
646 | (Uint128High64(lhs) << (64 - amount))); |
647 | } |
648 | return lhs; |
649 | } |
650 | return MakeUint128(0, Uint128High64(lhs) >> (amount - 64)); |
651 | } |
652 | |
653 | inline uint128 operator+(uint128 lhs, uint128 rhs) { |
654 | uint128 result = MakeUint128(Uint128High64(lhs) + Uint128High64(rhs), |
655 | Uint128Low64(lhs) + Uint128Low64(rhs)); |
656 | if (Uint128Low64(result) < Uint128Low64(lhs)) { // check for carry |
657 | return MakeUint128(Uint128High64(result) + 1, Uint128Low64(result)); |
658 | } |
659 | return result; |
660 | } |
661 | |
662 | inline uint128 operator-(uint128 lhs, uint128 rhs) { |
663 | uint128 result = MakeUint128(Uint128High64(lhs) - Uint128High64(rhs), |
664 | Uint128Low64(lhs) - Uint128Low64(rhs)); |
665 | if (Uint128Low64(lhs) < Uint128Low64(rhs)) { // check for carry |
666 | return MakeUint128(Uint128High64(result) - 1, Uint128Low64(result)); |
667 | } |
668 | return result; |
669 | } |
670 | |
671 | inline uint128 operator*(uint128 lhs, uint128 rhs) { |
672 | #if defined(ABSL_HAVE_INTRINSIC_INT128) |
673 | // TODO(strel) Remove once alignment issues are resolved and unsigned __int128 |
674 | // can be used for uint128 storage. |
675 | return static_cast<unsigned __int128>(lhs) * |
676 | static_cast<unsigned __int128>(rhs); |
677 | #elif defined(_MSC_VER) && defined(_M_X64) |
678 | uint64_t carry; |
679 | uint64_t low = _umul128(Uint128Low64(lhs), Uint128Low64(rhs), &carry); |
680 | return MakeUint128(Uint128Low64(lhs) * Uint128High64(rhs) + |
681 | Uint128High64(lhs) * Uint128Low64(rhs) + carry, |
682 | low); |
683 | #else // ABSL_HAVE_INTRINSIC128 |
684 | uint64_t a32 = Uint128Low64(lhs) >> 32; |
685 | uint64_t a00 = Uint128Low64(lhs) & 0xffffffff; |
686 | uint64_t b32 = Uint128Low64(rhs) >> 32; |
687 | uint64_t b00 = Uint128Low64(rhs) & 0xffffffff; |
688 | uint128 result = |
689 | MakeUint128(Uint128High64(lhs) * Uint128Low64(rhs) + |
690 | Uint128Low64(lhs) * Uint128High64(rhs) + a32 * b32, |
691 | a00 * b00); |
692 | result += uint128(a32 * b00) << 32; |
693 | result += uint128(a00 * b32) << 32; |
694 | return result; |
695 | #endif // ABSL_HAVE_INTRINSIC128 |
696 | } |
697 | |
698 | // Increment/decrement operators. |
699 | |
700 | inline uint128 uint128::operator++(int) { |
701 | uint128 tmp(*this); |
702 | *this += 1; |
703 | return tmp; |
704 | } |
705 | |
706 | inline uint128 uint128::operator--(int) { |
707 | uint128 tmp(*this); |
708 | *this -= 1; |
709 | return tmp; |
710 | } |
711 | |
712 | inline uint128& uint128::operator++() { |
713 | *this += 1; |
714 | return *this; |
715 | } |
716 | |
717 | inline uint128& uint128::operator--() { |
718 | *this -= 1; |
719 | return *this; |
720 | } |
721 | |
722 | #if defined(ABSL_HAVE_INTRINSIC_INT128) |
723 | #include "absl/numeric/int128_have_intrinsic.inc" |
724 | #else // ABSL_HAVE_INTRINSIC_INT128 |
725 | #include "absl/numeric/int128_no_intrinsic.inc" |
726 | #endif // ABSL_HAVE_INTRINSIC_INT128 |
727 | |
728 | } // namespace absl |
729 | |
730 | #undef ABSL_INTERNAL_WCHAR_T |
731 | |
732 | #endif // ABSL_NUMERIC_INT128_H_ |
733 | |