1 /*
2  * Copyright (C) 2015 The Android Open Source Project
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  *      http://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 #ifndef BERBERIS_BASE_BIT_UTIL_H_
18 #define BERBERIS_BASE_BIT_UTIL_H_
19 
20 #include <climits>
21 #include <cstdint>
22 #include <cstring>
23 #include <limits>
24 #include <tuple>
25 #include <type_traits>
26 
27 #include "berberis/base/checks.h"
28 #include "berberis/base/dependent_false.h"
29 
30 namespace berberis {
31 
32 template <typename BaseType>
33 class Raw;
34 
35 template <typename BaseType>
36 class Saturating;
37 
38 template <typename BaseType>
39 class Wrapping;
40 
41 template <typename T>
IsPowerOf2(T x)42 constexpr bool IsPowerOf2(T x) {
43   static_assert(std::is_integral_v<T>, "IsPowerOf2: T must be integral");
44   DCHECK(x != 0);
45   return (x & (x - 1)) == 0;
46 }
47 
48 template <typename T>
IsPowerOf2(Raw<T> x)49 constexpr bool IsPowerOf2(Raw<T> x) {
50   return IsPowerOf2(x.value);
51 }
52 
53 template <typename T>
IsPowerOf2(Saturating<T> x)54 constexpr bool IsPowerOf2(Saturating<T> x) {
55   return IsPowerOf2(x.value);
56 }
57 
58 template <typename T>
IsPowerOf2(Wrapping<T> x)59 constexpr bool IsPowerOf2(Wrapping<T> x) {
60   return IsPowerOf2(x.value);
61 }
62 
63 template <size_t kAlign, typename T>
AlignDown(T x)64 constexpr T AlignDown(T x) {
65   static_assert(std::is_integral_v<T>);
66   static_assert(IsPowerOf2(kAlign));
67   static_assert(static_cast<T>(kAlign) > 0);
68   return x & ~(kAlign - 1);
69 }
70 
71 template <typename T>
AlignDown(T x,size_t align)72 constexpr T AlignDown(T x, size_t align) {
73   static_assert(std::is_integral_v<T>, "AlignDown: T must be integral");
74   DCHECK(IsPowerOf2(align));
75   return x & ~(align - 1);
76 }
77 
78 template <size_t kAlign, typename T>
AlignDown(Raw<T> x)79 constexpr Raw<T> AlignDown(Raw<T> x) {
80   return {AlignDown<kAlign>(x.value)};
81 }
82 
83 template <size_t kAlign, typename T>
AlignDown(Saturating<T> x)84 constexpr Saturating<T> AlignDown(Saturating<T> x) {
85   return {AlignDown<kAlign>(x.value)};
86 }
87 
88 template <size_t kAlign, typename T>
AlignDown(Wrapping<T> x)89 constexpr Wrapping<T> AlignDown(Wrapping<T> x) {
90   return {AlignDown<kAlign>(x.value)};
91 }
92 
93 // Helper to align pointers.
94 template <size_t kAlign, typename T>
AlignDown(T * p)95 constexpr T* AlignDown(T* p) {
96   return reinterpret_cast<T*>(AlignDown<kAlign>(reinterpret_cast<uintptr_t>(p)));
97 }
98 
99 template <typename T>
AlignDown(T * p,size_t align)100 constexpr T* AlignDown(T* p, size_t align) {
101   return reinterpret_cast<T*>(AlignDown(reinterpret_cast<uintptr_t>(p), align));
102 }
103 
104 template <size_t kAlign, typename T>
AlignUp(T x)105 constexpr T AlignUp(T x) {
106   return AlignDown<kAlign>(x + kAlign - 1);
107 }
108 
109 template <typename T>
AlignUp(T x,size_t align)110 constexpr T AlignUp(T x, size_t align) {
111   return AlignDown(x + align - 1, align);
112 }
113 
114 template <size_t kAlign, typename T>
AlignUp(Raw<T> x)115 constexpr Raw<T> AlignUp(Raw<T> x) {
116   return {AlignUp<kAlign>(x.value)};
117 }
118 
119 template <size_t kAlign, typename T>
AlignUp(Saturating<T> x)120 constexpr Saturating<T> AlignUp(Saturating<T> x) {
121   return {AlignUp<kAlign>(x.value)};
122 }
123 
124 template <size_t kAlign, typename T>
AlignUp(Wrapping<T> x)125 constexpr Wrapping<T> AlignUp(Wrapping<T> x) {
126   return {AlignUp<kAlign>(x.value)};
127 }
128 
129 // Helper to align pointers.
130 template <size_t kAlign, typename T>
AlignUp(T * p)131 constexpr T* AlignUp(T* p) {
132   return reinterpret_cast<T*>(AlignUp<kAlign>(reinterpret_cast<uintptr_t>(p)));
133 }
134 
135 template <typename T>
AlignUp(T * p,size_t align)136 constexpr T* AlignUp(T* p, size_t align) {
137   return reinterpret_cast<T*>(AlignUp(reinterpret_cast<uintptr_t>(p), align));
138 }
139 
140 template <size_t kAlign, typename T>
IsAligned(T x)141 constexpr bool IsAligned(T x) {
142   return AlignDown<kAlign>(x) == x;
143 }
144 
145 template <typename T>
IsAligned(T x,size_t align)146 constexpr bool IsAligned(T x, size_t align) {
147   return AlignDown(x, align) == x;
148 }
149 
150 template <size_t kAlign, typename T>
IsAligned(Raw<T> x)151 constexpr bool IsAligned(Raw<T> x) {
152   return IsAligned<kAlign>(x.value);
153 }
154 
155 template <size_t kAlign, typename T>
IsAligned(Saturating<T> x)156 constexpr bool IsAligned(Saturating<T> x) {
157   return IsAligned<kAlign>(x.value);
158 }
159 
160 template <size_t kAlign, typename T>
IsAligned(Wrapping<T> x)161 constexpr bool IsAligned(Wrapping<T> x) {
162   return IsAligned<kAlign>(x.value);
163 }
164 
165 // Helper to align pointers.
166 template <size_t kAlign, typename T>
IsAligned(T * p,size_t align)167 constexpr bool IsAligned(T* p, size_t align) {
168   return IsAligned<kAlign>(reinterpret_cast<uintptr_t>(p), align);
169 }
170 
171 template <typename T>
IsAligned(T * p,size_t align)172 constexpr bool IsAligned(T* p, size_t align) {
173   return IsAligned(reinterpret_cast<uintptr_t>(p), align);
174 }
175 
176 template <typename T>
BitUtilLog2(T x)177 constexpr T BitUtilLog2(T x) {
178   static_assert(std::is_integral_v<T>, "Log2: T must be integral");
179   CHECK(IsPowerOf2(x));
180   // TODO(b/260725458): Use std::countr_zero after C++20 becomes available
181   return __builtin_ctz(x);
182 }
183 
184 // Signextend bits from size to the corresponding signed type of sizeof(Type) size.
185 // If the result of this function is assigned to a wider signed type it'll automatically
186 // sign-extend.
187 template <unsigned size, typename Type>
SignExtend(const Type val)188 static auto SignExtend(const Type val) {
189   static_assert(std::is_integral_v<Type>, "Only integral types are supported");
190   static_assert(size > 0 && size < (sizeof(Type) * CHAR_BIT), "Invalid size value");
191   using SignedType = std::make_signed_t<Type>;
192   struct {
193     SignedType val : size;
194   } holder = {.val = static_cast<SignedType>(val)};
195   // Compiler takes care of sign-extension of the field with the specified bit-length.
196   return static_cast<SignedType>(holder.val);
197 }
198 
199 // Verify that argument value fits into a target.
200 template <typename ResultType, typename ArgumentType>
IsInRange(ArgumentType x)201 inline bool IsInRange(ArgumentType x) {
202   // Note: conversion from wider integer type into narrow integer type is always
203   // defined.  Conversion to unsigned produces well-defined result while conversion
204   // to signed type produces implementation-defined result but in both cases value
205   // is guaranteed to be unchanged if it can be represented in the destination type
206   // and is *some* valid value if it's unrepesentable.
207   //
208   // Quote from the standard (including "note" in the standard):
209   //   If the destination type is unsigned, the resulting value is the least unsigned
210   // integer congruent to the source integer (modulo 2ⁿ where n is the number of bits
211   // used to represent the unsigned type). [ Note: In a two’s complement representation,
212   // this conversion is conceptual and there is no change in the bit pattern (if there
213   // is no truncation). — end note ]
214   //   If the destination type is signed, the value is unchanged if it can be represented
215   // in the destination type; otherwise, the value is implementation-defined.
216 
217   return static_cast<ResultType>(x) == x;
218 }
219 
220 template <typename T>
CountRZero(T x)221 [[nodiscard]] constexpr T CountRZero(T x) {
222   // We couldn't use C++20 std::countr_zero yet ( http://b/318678905 ) for __uint128_t .
223   // Switch to std::popcount when/if that bug would be fixed.
224   static_assert(!std::is_signed_v<T>);
225   if constexpr (sizeof(T) == 16) {
226     if (static_cast<uint64_t>(x) == 0) {
227       return __builtin_ctzll(x >> 64) + 64;
228     }
229     return __builtin_ctzll(x);
230   } else if constexpr (sizeof(T) == sizeof(uint64_t)) {
231     return __builtin_ctzll(x);
232   } else if constexpr (sizeof(T) == sizeof(uint32_t)) {
233     return __builtin_ctz(x);
234   } else {
235     static_assert(kDependentTypeFalse<T>);
236   }
237 }
238 
239 template <typename T>
CountRZero(Raw<T> x)240 [[nodiscard]] constexpr Raw<T> CountRZero(Raw<T> x) {
241   return {CountRZero(x.value)};
242 }
243 
244 template <typename T>
CountRZero(Saturating<T> x)245 [[nodiscard]] constexpr Saturating<T> CountRZero(Saturating<T> x) {
246   return {CountRZero(x.value)};
247 }
248 
249 template <typename T>
CountRZero(Wrapping<T> x)250 [[nodiscard]] constexpr Wrapping<T> CountRZero(Wrapping<T> x) {
251   return {CountRZero(x.value)};
252 }
253 
254 template <typename T>
Popcount(T x)255 [[nodiscard]] constexpr T Popcount(T x) {
256   // We couldn't use C++20 std::popcount yet ( http://b/318678905 ) for __uint128_t .
257   // Switch to std::popcount when/if that bug would be fixed.
258   static_assert(!std::is_signed_v<T>);
259   if constexpr (sizeof(T) == 16) {
260     return __builtin_popcountll(x) + __builtin_popcountll(x >> 64);
261   } else if constexpr (sizeof(T) == sizeof(uint64_t)) {
262     return __builtin_popcountll(x);
263   } else if constexpr (sizeof(T) == sizeof(uint32_t)) {
264     return __builtin_popcount(x);
265   } else {
266     static_assert(kDependentTypeFalse<T>);
267   }
268 }
269 
270 template <typename T>
Popcount(Raw<T> x)271 [[nodiscard]] constexpr Raw<T> Popcount(Raw<T> x) {
272   return {Popcount(x.value)};
273 }
274 
275 template <typename T>
Popcount(Saturating<T> x)276 [[nodiscard]] constexpr Saturating<T> Popcount(Saturating<T> x) {
277   return {Popcount(x.value)};
278 }
279 
280 template <typename T>
Popcount(Wrapping<T> x)281 [[nodiscard]] constexpr Wrapping<T> Popcount(Wrapping<T> x) {
282   return {Popcount(x.value)};
283 }
284 
285 // bit_cast<Dest, Source> is a well-defined equivalent of address-casting:
286 //   *reinterpret_cast<Dest*>(&source)
287 // See chromium base/macros.h for details.
288 template <class Dest, class Source>
bit_cast(const Source & source)289 inline Dest bit_cast(const Source& source) {
290   static_assert(sizeof(Dest) == sizeof(Source),
291                 "bit_cast: source and destination must be of same size");
292   static_assert(std::is_trivially_copyable_v<Dest>,
293                 "bit_cast: destination must be trivially copyable");
294   static_assert(std::is_trivially_copyable_v<Source>,
295                 "bit_cast: source must be trivially copyable");
296   Dest dest;
297   memcpy(&dest, &source, sizeof(dest));
298   return dest;
299 }
300 
301 namespace intrinsics {
302 
303 template <typename BaseType>
304 class WrappedFloatType;
305 
306 }  // namespace intrinsics
307 
308 template <typename T>
309 struct TypeTraits;
310 
311 // Raw integers.  Used to carry payload, which may be be EXPLICITLY converted to Saturating
312 // integer, Wrapping integer, or WrappedFloatType.
313 //
314 // ����������'�� suppopt any actual operations, arithmetic, etc.
315 // Use bitcast or convert to one of three types listed above!
316 
317 template <typename Base>
318 class Raw {
319  public:
320   using BaseType = Base;
321 
322   static_assert(std::is_integral_v<BaseType>);
323   static_assert(!std::is_signed_v<BaseType>);
324 
325   template <typename IntType,
326             typename = std::enable_if_t<std::is_integral_v<IntType> &&
327                                         sizeof(IntType) == sizeof(BaseType)>>
IntType()328   [[nodiscard]] constexpr operator IntType() const {
329     return static_cast<IntType>(value);
330   }
331   template <typename IntType,
332             typename = std::enable_if_t<
333                 std::is_integral_v<IntType> && sizeof(BaseType) == sizeof(IntType) &&
334                 !std::is_signed_v<IntType> && !std::is_same_v<IntType, BaseType>>>
335   [[nodiscard]] constexpr operator Raw<IntType>() const {
336     return {static_cast<IntType>(value)};
337   }
338   template <typename IntType,
339             typename = std::enable_if_t<std::is_integral_v<IntType> &&
340                                         sizeof(BaseType) == sizeof(IntType)>>
341   [[nodiscard]] constexpr operator Saturating<IntType>() const {
342     return {static_cast<IntType>(value)};
343   }
344   template <typename FloatType,
345             typename = std::enable_if_t<!std::numeric_limits<FloatType>::is_exact &&
346                                         sizeof(BaseType) == sizeof(FloatType)>>
347   [[nodiscard]] constexpr operator intrinsics::WrappedFloatType<FloatType>() const {
348     // Can't use bit_cast here because of IA32 ABI!
349     intrinsics::WrappedFloatType<FloatType> result;
350     memcpy(&result, &value, sizeof(BaseType));
351     return result;
352   }
353   template <typename IntType,
354             typename = std::enable_if_t<std::is_integral_v<IntType> &&
355                                         sizeof(BaseType) == sizeof(IntType)>>
356   [[nodiscard]] constexpr operator Wrapping<IntType>() const {
357     return {static_cast<IntType>(value)};
358   }
359 
360   template <typename ResultType>
361   friend auto constexpr MaybeTruncateTo(Raw src)
362       -> std::enable_if_t<sizeof(typename ResultType::BaseType) <= sizeof(BaseType), ResultType> {
363     return ResultType{static_cast<ResultType::BaseType>(src.value)};
364   }
365   template <typename ResultType>
366   friend auto constexpr TruncateTo(Raw src)
367       -> std::enable_if_t<sizeof(typename ResultType::BaseType) < sizeof(BaseType), ResultType> {
368     return ResultType{static_cast<ResultType::BaseType>(src.value)};
369   }
370 
371   [[nodiscard]] friend constexpr bool operator==(Raw lhs, Raw rhs) {
372     return lhs.value == rhs.value;
373   }
374   [[nodiscard]] friend constexpr bool operator!=(Raw lhs, Raw rhs) {
375     return lhs.value != rhs.value;
376   }
377 
378   BaseType value = 0;
379 };
380 
381 // Saturating and wrapping integers.
382 //   1. Never trigger UB, even in case of overflow.
383 //   2. Only support mixed types when both are of the same type (e.g. SatInt8 and SatInt16 or
384 //      Int8 and Int64 are allowed, but SatInt8 and Int8 are forbidden and Int32 and Uint32
385 //      require explicit casting, too).
386 //   3. Results are performed after type expansion.
387 
388 template <typename Base>
389 class Saturating {
390  public:
391   using BaseType = Base;
392   using SignedType = Saturating<std::make_signed_t<BaseType>>;
393   using UnsignedType = Saturating<std::make_unsigned_t<BaseType>>;
394   static constexpr bool kIsSigned = std::is_signed_v<BaseType>;
395 
396   static_assert(std::is_integral_v<BaseType>);
397 
398   template <typename IntType,
399             typename = std::enable_if_t<std::is_integral_v<IntType> &&
400                                         ((sizeof(BaseType) < sizeof(IntType) &&
401                                           (std::is_signed_v<IntType> ||
402                                            kIsSigned == std::is_signed_v<IntType>)) ||
403                                          sizeof(IntType) == sizeof(BaseType))>>
IntType()404   [[nodiscard]] constexpr operator IntType() const {
405     return static_cast<IntType>(value);
406   }
407   template <typename IntType,
408             typename = std::enable_if_t<std::is_integral_v<IntType> &&
409                                         sizeof(BaseType) == sizeof(IntType)>>
410   [[nodiscard]] constexpr operator Raw<IntType>() const {
411     return {static_cast<IntType>(value)};
412   }
413   template <typename IntType,
414             typename = std::enable_if_t<
415                 std::is_integral_v<IntType> && sizeof(BaseType) <= sizeof(IntType) &&
416                 std::is_signed_v<IntType> == kIsSigned && !std::is_same_v<IntType, BaseType>>>
417   [[nodiscard]] constexpr operator Saturating<IntType>() const {
418     return {static_cast<IntType>(value)};
419   }
420   template <typename IntType,
421             typename = std::enable_if_t<std::is_integral_v<IntType> &&
422                                         sizeof(BaseType) == sizeof(IntType)>>
423   [[nodiscard]] constexpr operator Wrapping<IntType>() const {
424     return {static_cast<IntType>(value)};
425   }
426 
427   [[nodiscard]] friend constexpr bool operator==(Saturating lhs, Saturating rhs) {
428     return lhs.value == rhs.value;
429   }
430   [[nodiscard]] friend constexpr bool operator!=(Saturating lhs, Saturating rhs) {
431     return lhs.value != rhs.value;
432   }
433   [[nodiscard]] friend constexpr bool operator<(Saturating lhs, Saturating rhs) {
434     return lhs.value < rhs.value;
435   }
436   [[nodiscard]] friend constexpr bool operator<=(Saturating lhs, Saturating rhs) {
437     return lhs.value <= rhs.value;
438   }
439   [[nodiscard]] friend constexpr bool operator>(Saturating lhs, Saturating rhs) {
440     return lhs.value > rhs.value;
441   }
442   [[nodiscard]] friend constexpr bool operator>=(Saturating lhs, Saturating rhs) {
443     return lhs.value >= rhs.value;
444   }
445   friend constexpr Saturating& operator+=(Saturating& lhs, Saturating rhs) {
446     lhs = lhs + rhs;
447     return lhs;
448   }
Add(Saturating lhs,Saturating rhs)449   [[nodiscard]] friend constexpr std::tuple<Saturating, bool> Add(Saturating lhs, Saturating rhs) {
450     BaseType result;
451     bool overflow = __builtin_add_overflow(lhs.value, rhs.value, &result);
452     if (overflow) {
453       if constexpr (kIsSigned) {
454         if (result < 0) {
455           result = std::numeric_limits<BaseType>::max();
456         } else {
457           result = std::numeric_limits<BaseType>::min();
458         }
459       } else {
460         result = std::numeric_limits<BaseType>::max();
461       }
462     }
463     return {{result}, overflow};
464   }
465   [[nodiscard]] friend constexpr Saturating operator+(Saturating lhs, Saturating rhs) {
466     return std::get<0>(Add(lhs, rhs));
467   }
468   friend constexpr Saturating& operator-=(Saturating& lhs, Saturating rhs) {
469     lhs = lhs - rhs;
470     return lhs;
471   }
Neg(Saturating lhs)472   [[nodiscard]] friend constexpr std::tuple<Saturating, bool> Neg(Saturating lhs) {
473     if constexpr (kIsSigned) {
474       if (lhs.value == std::numeric_limits<BaseType>::min()) {
475         return {std::numeric_limits<BaseType>::max(), true};
476       }
477       return {{-lhs.value}, false};
478     }
479     return {{0}, lhs != 0};
480   }
481   [[nodiscard]] friend constexpr Saturating operator-(Saturating lhs) {
482     return std::get<0>(Neg(lhs));
483   }
Sub(Saturating lhs,Saturating rhs)484   [[nodiscard]] friend constexpr std::tuple<Saturating, bool> Sub(Saturating lhs, Saturating rhs) {
485     BaseType result;
486     bool overflow = __builtin_sub_overflow(lhs.value, rhs.value, &result);
487     if (overflow) {
488       if constexpr (kIsSigned) {
489         if (result < 0) {
490           result = std::numeric_limits<BaseType>::max();
491         } else {
492           result = std::numeric_limits<BaseType>::min();
493         }
494       } else {
495         result = 0;
496       }
497     }
498     return {{result}, overflow};
499   }
500   [[nodiscard]] friend constexpr Saturating operator-(Saturating lhs, Saturating rhs) {
501     return std::get<0>(Sub(lhs, rhs));
502   }
503   friend constexpr Saturating& operator*=(Saturating& lhs, Saturating rhs) {
504     lhs = lhs * rhs;
505     return lhs;
506   }
Mul(Saturating lhs,Saturating rhs)507   [[nodiscard]] friend constexpr std::tuple<Saturating, bool> Mul(Saturating lhs, Saturating rhs) {
508     BaseType result;
509     bool overflow = __builtin_mul_overflow(lhs.value, rhs.value, &result);
510     if (overflow) {
511       if constexpr (kIsSigned) {
512         if (lhs.value < 0 != rhs.value < 0) {
513           result = std::numeric_limits<BaseType>::min();
514         } else {
515           result = std::numeric_limits<BaseType>::max();
516         }
517       } else {
518         result = std::numeric_limits<BaseType>::max();
519       }
520     }
521     return {{result}, overflow};
522   }
523   [[nodiscard]] friend constexpr Saturating operator*(Saturating lhs, Saturating rhs) {
524     return std::get<0>(Mul(lhs, rhs));
525   }
526   friend constexpr Saturating& operator/=(Saturating& lhs, Saturating rhs) {
527     lhs = lhs / rhs;
528     return lhs;
529   }
Div(Saturating lhs,Saturating rhs)530   [[nodiscard]] friend constexpr std::tuple<Saturating, bool> Div(Saturating lhs, Saturating rhs) {
531     if constexpr (kIsSigned) {
532       if (lhs.value == std::numeric_limits<BaseType>::min() && rhs.value == -1) {
533         return {{std::numeric_limits<BaseType>::max()}, true};
534       }
535     }
536     return {{BaseType(lhs.value / rhs.value)}, false};
537   }
538   [[nodiscard]] friend constexpr Saturating operator/(Saturating lhs, Saturating rhs) {
539     return std::get<0>(Div(lhs, rhs));
540   }
541   friend constexpr Saturating& operator%=(Saturating& lhs, Saturating rhs) {
542     lhs = lhs % rhs;
543     return lhs;
544   }
Rem(Saturating lhs,Saturating rhs)545   [[nodiscard]] friend constexpr std::tuple<Saturating, bool> Rem(Saturating lhs, Saturating rhs) {
546     if constexpr (kIsSigned) {
547       if (lhs.value == std::numeric_limits<BaseType>::min() && rhs.value == -1) {
548         return {{1}, true};
549       }
550     }
551     return {{BaseType(lhs.value % rhs.value)}, false};
552   }
553   [[nodiscard]] friend constexpr Saturating operator%(Saturating lhs, Saturating rhs) {
554     return std::get<0>(Rem(lhs, rhs));
555   }
556   BaseType value = 0;
557 };
558 
559 template <typename Base>
560 class Wrapping {
561  public:
562   using BaseType = Base;
563   using SignedType = Wrapping<std::make_signed_t<BaseType>>;
564   using UnsignedType = Wrapping<std::make_unsigned_t<BaseType>>;
565   static constexpr bool kIsSigned = std::is_signed_v<BaseType>;
566 
567   static_assert(std::is_integral_v<BaseType>);
568 
569   template <typename IntType,
570             typename = std::enable_if_t<std::is_integral_v<IntType> &&
571                                         ((sizeof(BaseType) < sizeof(IntType) &&
572                                           (std::is_signed_v<IntType> ||
573                                            kIsSigned == std::is_signed_v<IntType>)) ||
574                                          sizeof(IntType) == sizeof(BaseType))>>
IntType()575   [[nodiscard]] constexpr operator IntType() const {
576     return static_cast<IntType>(value);
577   }
578   template <typename IntType,
579             typename = std::enable_if_t<std::is_integral_v<IntType> &&
580                                         sizeof(BaseType) == sizeof(IntType)>>
581   [[nodiscard]] constexpr operator Raw<IntType>() const {
582     return {static_cast<IntType>(value)};
583   }
584   template <typename IntType,
585             typename = std::enable_if_t<std::is_integral_v<IntType> &&
586                                         sizeof(BaseType) == sizeof(IntType)>>
587   [[nodiscard]] constexpr operator Saturating<IntType>() const {
588     return {static_cast<IntType>(value)};
589   }
590   template <typename IntType,
591             typename = std::enable_if_t<
592                 std::is_integral_v<IntType> && sizeof(BaseType) <= sizeof(IntType) &&
593                 std::is_signed_v<IntType> == kIsSigned && !std::is_same_v<IntType, BaseType>>>
594   [[nodiscard]] constexpr operator Wrapping<IntType>() const {
595     return {static_cast<IntType>(value)};
596   }
597 
598   [[nodiscard]] friend constexpr bool operator==(Wrapping lhs, Wrapping rhs) {
599     return lhs.value == rhs.value;
600   }
601   [[nodiscard]] friend constexpr bool operator!=(Wrapping lhs, Wrapping rhs) {
602     return lhs.value != rhs.value;
603   }
604   [[nodiscard]] friend constexpr bool operator<(Wrapping lhs, Wrapping rhs) {
605     return lhs.value < rhs.value;
606   }
607   [[nodiscard]] friend constexpr bool operator<=(Wrapping lhs, Wrapping rhs) {
608     return lhs.value <= rhs.value;
609   }
610   [[nodiscard]] friend constexpr bool operator>(Wrapping lhs, Wrapping rhs) {
611     return lhs.value > rhs.value;
612   }
613   [[nodiscard]] friend constexpr bool operator>=(Wrapping lhs, Wrapping rhs) {
614     return lhs.value >= rhs.value;
615   }
616   // Note:
617   //   1. We use __builtin_xxx_overflow instead of simple +, -, or * operators because
618   //      __builtin_xxx_overflow produces well-defined result in case of overflow while
619   //      +, -, * are triggering undefined behavior conditions.
620   //   2. All operator xxx= are implemented in terms of opernator xxx
621   friend constexpr Wrapping& operator+=(Wrapping& lhs, Wrapping rhs) {
622     lhs = lhs + rhs;
623     return lhs;
624   }
625   [[nodiscard]] friend constexpr Wrapping operator+(Wrapping lhs, Wrapping rhs) {
626     BaseType result;
627     __builtin_add_overflow(lhs.value, rhs.value, &result);
628     return {result};
629   }
630   friend constexpr Wrapping& operator-=(Wrapping& lhs, Wrapping rhs) {
631     lhs = lhs - rhs;
632     return lhs;
633   }
634   [[nodiscard]] friend constexpr Wrapping operator-(Wrapping lhs) {
635     BaseType result;
636     __builtin_sub_overflow(BaseType{0}, lhs.value, &result);
637     return {result};
638   }
639   [[nodiscard]] friend constexpr Wrapping operator-(Wrapping lhs, Wrapping rhs) {
640     BaseType result;
641     __builtin_sub_overflow(lhs.value, rhs.value, &result);
642     return {result};
643   }
644   friend constexpr Wrapping& operator*=(Wrapping& lhs, Wrapping rhs) {
645     lhs = lhs * rhs;
646     return lhs;
647   }
648   [[nodiscard]] friend constexpr Wrapping operator*(Wrapping lhs, Wrapping rhs) {
649     BaseType result;
650     __builtin_mul_overflow(lhs.value, rhs.value, &result);
651     return {result};
652   }
653   friend constexpr Wrapping& operator/=(Wrapping& lhs, Wrapping rhs) {
654     lhs = lhs / rhs;
655     return lhs;
656   }
657   [[nodiscard]] friend constexpr Wrapping operator/(Wrapping lhs, Wrapping rhs) {
658     if constexpr (kIsSigned) {
659       if (lhs.value == std::numeric_limits<BaseType>::min() && rhs.value == -1) {
660         return {std::numeric_limits<BaseType>::min()};
661       }
662     }
663     return {BaseType(lhs.value / rhs.value)};
664   }
665   friend constexpr Wrapping& operator%=(Wrapping& lhs, Wrapping rhs) {
666     lhs = lhs % rhs;
667     return lhs;
668   }
669   [[nodiscard]] friend constexpr Wrapping operator%(Wrapping lhs, Wrapping rhs) {
670     if constexpr (kIsSigned) {
671       if (lhs.value == std::numeric_limits<BaseType>::min() && rhs.value == -1) {
672         return {0};
673       }
674     }
675     return {BaseType(lhs.value % rhs.value)};
676   }
677   friend constexpr Wrapping& operator<<=(Wrapping& lhs, Wrapping rhs) {
678     lhs = lhs << rhs;
679     return lhs;
680   }
681   template <typename IntType>
682   [[nodiscard]] friend constexpr Wrapping operator<<(Wrapping lhs, Wrapping<IntType> rhs) {
683     return {BaseType(lhs.value << (rhs.value & (sizeof(BaseType) * CHAR_BIT - 1)))};
684   }
685   friend constexpr Wrapping& operator>>=(Wrapping& lhs, Wrapping rhs) {
686     lhs = lhs >> rhs;
687     return lhs;
688   }
689   template <typename IntType>
690   [[nodiscard]] friend constexpr Wrapping operator>>(Wrapping lhs, Wrapping<IntType> rhs) {
691     return {BaseType(lhs.value >> (rhs.value & (sizeof(BaseType) * CHAR_BIT - 1)))};
692   }
693   friend constexpr Wrapping& operator&=(Wrapping& lhs, Wrapping rhs) {
694     lhs = lhs & rhs;
695     return lhs;
696   }
697   [[nodiscard]] friend constexpr Wrapping operator&(Wrapping lhs, Wrapping rhs) {
698     return {BaseType(lhs.value & rhs.value)};
699   }
700   friend constexpr Wrapping& operator|=(Wrapping& lhs, Wrapping rhs) {
701     lhs = lhs | rhs;
702     return lhs;
703   }
704   [[nodiscard]] friend constexpr Wrapping operator|(Wrapping lhs, Wrapping rhs) {
705     return {BaseType(lhs.value | rhs.value)};
706   }
707   friend constexpr Wrapping& operator^=(Wrapping& lhs, Wrapping rhs) {
708     lhs = lhs ^ rhs;
709     return lhs;
710   }
711   [[nodiscard]] friend constexpr Wrapping operator^(Wrapping lhs, Wrapping rhs) {
712     return {BaseType(lhs.value ^ rhs.value)};
713   }
714   [[nodiscard]] friend constexpr Wrapping operator~(Wrapping lhs) { return {BaseType(~lhs.value)}; }
715   BaseType value = 0;
716 };
717 
718 using RawInt8 = Raw<uint8_t>;
719 using RawInt16 = Raw<uint16_t>;
720 using RawInt32 = Raw<uint32_t>;
721 using RawInt64 = Raw<uint64_t>;
722 #if defined(__LP64__)
723 using RawInt128 = Raw<unsigned __int128>;
724 #endif
725 
726 using SatInt8 = Saturating<int8_t>;
727 using SatUInt8 = Saturating<uint8_t>;
728 using SatInt16 = Saturating<int16_t>;
729 using SatUInt16 = Saturating<uint16_t>;
730 using SatInt32 = Saturating<int32_t>;
731 using SatUInt32 = Saturating<uint32_t>;
732 using SatInt64 = Saturating<int64_t>;
733 using SatUInt64 = Saturating<uint64_t>;
734 #if defined(__LP64__)
735 using SatInt128 = Saturating<__int128>;
736 using SatUInt128 = Saturating<unsigned __int128>;
737 #endif
738 
739 using Int8 = Wrapping<int8_t>;
740 using UInt8 = Wrapping<uint8_t>;
741 using Int16 = Wrapping<int16_t>;
742 using UInt16 = Wrapping<uint16_t>;
743 using Int32 = Wrapping<int32_t>;
744 using UInt32 = Wrapping<uint32_t>;
745 using Int64 = Wrapping<int64_t>;
746 using UInt64 = Wrapping<uint64_t>;
747 using IntPtr = Wrapping<intptr_t>;
748 using UIntPtr = Wrapping<uintptr_t>;
749 #if defined(__LP64__)
750 using Int128 = Wrapping<__int128>;
751 using UInt128 = Wrapping<unsigned __int128>;
752 #endif
753 
754 template <typename IntType>
755 [[nodiscard]] auto constexpr BitCastToSigned(Raw<IntType> src) ->
756     typename Wrapping<IntType>::SignedType {
757   return {static_cast<std::make_signed_t<IntType>>(src.value)};
758 }
759 
760 template <typename IntType>
761 [[nodiscard]] auto constexpr BitCastToSigned(Saturating<IntType> src) ->
762     typename Saturating<IntType>::SignedType {
763   return {static_cast<std::make_signed_t<IntType>>(src.value)};
764 }
765 
766 template <typename IntType>
767 [[nodiscard]] auto constexpr BitCastToSigned(Wrapping<IntType> src) ->
768     typename Wrapping<IntType>::SignedType {
769   return {static_cast<std::make_signed_t<IntType>>(src.value)};
770 }
771 
772 template <typename T>
773 using SignedType = decltype(BitCastToSigned(std::declval<T>()));
774 
775 template <typename IntType>
776 [[nodiscard]] auto constexpr BitCastToUnsigned(Raw<IntType> src) ->
777     typename Wrapping<IntType>::UnsignedType {
778   return {static_cast<std::make_unsigned_t<IntType>>(src.value)};
779 }
780 
781 template <typename IntType>
782 [[nodiscard]] auto constexpr BitCastToUnsigned(Saturating<IntType> src) ->
783     typename Saturating<IntType>::UnsignedType {
784   return {static_cast<std::make_unsigned_t<IntType>>(src.value)};
785 }
786 
787 template <typename IntType>
788 [[nodiscard]] auto constexpr BitCastToUnsigned(Wrapping<IntType> src) ->
789     typename Wrapping<IntType>::UnsignedType {
790   return {static_cast<std::make_unsigned_t<IntType>>(src.value)};
791 }
792 
793 template <typename T>
794 using UnsignedType = decltype(BitCastToUnsigned(std::declval<T>()));
795 
796 template <typename IntType>
797 [[nodiscard]] auto constexpr BitCastToSaturating(Saturating<IntType> src) -> Saturating<IntType> {
798   return src;
799 }
800 
801 template <typename IntType>
802 [[nodiscard]] auto constexpr BitCastToSaturating(Wrapping<IntType> src) -> Saturating<IntType> {
803   return {src.value};
804 }
805 
806 template <typename T>
807 using SaturatingType = decltype(BitCastToSaturating(std::declval<T>()));
808 
809 template <typename IntType>
810 [[nodiscard]] auto constexpr BitCastToWrapping(Saturating<IntType> src) -> Wrapping<IntType> {
811   return {src.value};
812 }
813 
814 template <typename IntType>
815 [[nodiscard]] auto constexpr BitCastToWrapping(Wrapping<IntType> src) -> Wrapping<IntType> {
816   return src;
817 }
818 
819 template <typename T>
820 using WrappingType = decltype(BitCastToWrapping(std::declval<T>()));
821 
822 template <typename IntType>
823 [[nodiscard]] auto constexpr BitCastToRaw(Raw<IntType> src) -> Raw<IntType> {
824   return src;
825 }
826 
827 template <typename IntType>
828 [[nodiscard]] auto constexpr BitCastToRaw(Saturating<IntType> src)
829     -> Raw<std::make_unsigned_t<IntType>> {
830   return {static_cast<std::make_unsigned_t<IntType>>(src.value)};
831 }
832 
833 template <typename IntType>
834 [[nodiscard]] auto constexpr BitCastToRaw(Wrapping<IntType> src)
835     -> Raw<std::make_unsigned_t<IntType>> {
836   return {static_cast<std::make_unsigned_t<IntType>>(src.value)};
837 }
838 
839 template <typename BaseType>
840 [[nodiscard]] constexpr auto BitCastToRaw(intrinsics::WrappedFloatType<BaseType> src)
841     -> Raw<std::make_unsigned_t<typename TypeTraits<intrinsics::WrappedFloatType<BaseType>>::Int>> {
842   return {bit_cast<
843       std::make_unsigned_t<typename TypeTraits<intrinsics::WrappedFloatType<BaseType>>::Int>>(src)};
844 }
845 
846 template <typename T>
847 using RawType = decltype(BitCastToRaw(std::declval<T>()));
848 
849 template <typename IntType>
850 [[nodiscard]] auto constexpr BitCastToFloat(Raw<IntType> src) ->
851     typename TypeTraits<IntType>::Float {
852   return bit_cast<typename TypeTraits<IntType>::Float>(src.value);
853 }
854 
855 template <typename IntType>
856 [[nodiscard]] auto constexpr BitCastToFloat(Saturating<IntType> src) ->
857     typename TypeTraits<IntType>::Float {
858   return bit_cast<typename TypeTraits<IntType>::Float>(src.value);
859 }
860 
861 template <typename IntType>
862 [[nodiscard]] auto constexpr BitCastToFloat(Wrapping<IntType> src) ->
863     typename TypeTraits<IntType>::Float {
864   return bit_cast<typename TypeTraits<IntType>::Float>(src.value);
865 }
866 
867 template <typename BaseType>
868 [[nodiscard]] constexpr auto BitCastToFloat(intrinsics::WrappedFloatType<BaseType> src)
869     -> intrinsics::WrappedFloatType<BaseType> {
870   return src;
871 }
872 
873 template <typename T>
874 using FloatType = decltype(BitCastToFloat(std::declval<T>()));
875 
876 template <typename ResultType, typename IntType>
877 [[nodiscard]] auto constexpr MaybeTruncateTo(IntType src)
878     -> std::enable_if_t<std::is_integral_v<IntType> &&
879                             sizeof(typename ResultType::BaseType) <= sizeof(IntType),
880                         ResultType> {
881   return ResultType{static_cast<ResultType::BaseType>(src)};
882 }
883 
884 template <typename ResultType, typename IntType>
885 [[nodiscard]] auto constexpr MaybeTruncateTo(Saturating<IntType> src)
886     -> std::enable_if_t<std::is_integral_v<IntType> &&
887                             sizeof(typename ResultType::BaseType) <= sizeof(IntType),
888                         ResultType> {
889   return ResultType{static_cast<ResultType::BaseType>(src.value)};
890 }
891 
892 template <typename ResultType, typename IntType>
893 [[nodiscard]] auto constexpr MaybeTruncateTo(Wrapping<IntType> src)
894     -> std::enable_if_t<std::is_integral_v<IntType> &&
895                             sizeof(typename ResultType::BaseType) <= sizeof(IntType),
896                         ResultType> {
897   return ResultType{static_cast<ResultType::BaseType>(src.value)};
898 }
899 
900 template <typename ResultType, typename IntType>
901 [[nodiscard]] auto constexpr TruncateTo(IntType src)
902     -> std::enable_if_t<std::is_integral_v<IntType> &&
903                             sizeof(typename ResultType::BaseType) < sizeof(IntType),
904                         ResultType> {
905   return ResultType{static_cast<ResultType::BaseType>(src)};
906 }
907 
908 template <typename ResultType, typename IntType>
909 [[nodiscard]] auto constexpr TruncateTo(Saturating<IntType> src)
910     -> std::enable_if_t<std::is_integral_v<IntType> &&
911                             sizeof(typename ResultType::BaseType) < sizeof(IntType),
912                         ResultType> {
913   return ResultType{static_cast<ResultType::BaseType>(src.value)};
914 }
915 
916 template <typename ResultType, typename IntType>
917 [[nodiscard]] auto constexpr TruncateTo(Wrapping<IntType> src)
918     -> std::enable_if_t<std::is_integral_v<IntType> &&
919                             sizeof(typename ResultType::BaseType) < sizeof(IntType),
920                         ResultType> {
921   return ResultType{static_cast<ResultType::BaseType>(src.value)};
922 }
923 
924 template <typename BaseType>
925 [[nodiscard]] constexpr auto Widen(Saturating<BaseType> source)
926     -> Saturating<typename TypeTraits<BaseType>::Wide> {
927   return {source.value};
928 }
929 
930 template <typename BaseType>
931 [[nodiscard]] constexpr auto Widen(Wrapping<BaseType> source)
932     -> Wrapping<typename TypeTraits<BaseType>::Wide> {
933   return {source.value};
934 }
935 
936 template <typename BaseType>
937 [[nodiscard]] constexpr auto Widen(intrinsics::WrappedFloatType<BaseType> source) ->
938     typename TypeTraits<intrinsics::WrappedFloatType<BaseType>>::Wide {
939   return {source};
940 }
941 
942 template <typename T>
943 using WideType = decltype(Widen(std::declval<T>()));
944 
945 template <typename BaseType>
946 [[nodiscard]] constexpr auto Narrow(Saturating<BaseType> source)
947     -> Saturating<typename TypeTraits<BaseType>::Narrow> {
948   if constexpr (Saturating<BaseType>::kIsSigned) {
949     if (source.value < std::numeric_limits<typename TypeTraits<BaseType>::Narrow>::min()) {
950       return {std::numeric_limits<typename TypeTraits<BaseType>::Narrow>::min()};
951     }
952   }
953   if (source.value > std::numeric_limits<typename TypeTraits<BaseType>::Narrow>::max()) {
954     return {std::numeric_limits<typename TypeTraits<BaseType>::Narrow>::max()};
955   }
956   return {static_cast<typename TypeTraits<BaseType>::Narrow>(source.value)};
957 }
958 
959 template <typename BaseType>
960 [[nodiscard]] constexpr auto Narrow(Wrapping<BaseType> source)
961     -> Wrapping<typename TypeTraits<BaseType>::Narrow> {
962   return {static_cast<typename TypeTraits<BaseType>::Narrow>(source.value)};
963 }
964 
965 template <typename BaseType>
966 [[nodiscard]] constexpr auto Narrow(intrinsics::WrappedFloatType<BaseType> source) ->
967     typename TypeTraits<intrinsics::WrappedFloatType<BaseType>>::Narrow {
968   return {source};
969 }
970 
971 template <typename T>
972 using NarrowType = decltype(Narrow(std::declval<T>()));
973 
974 // While `Narrow` returns value reduced to smaller data type there are centain algorithms
975 // which require the top half, too (most ofhen in the context of widening multiplication
976 // where top half of the product is produced).
977 // `NarrowTopHalf` returns top half of the value narrowed down to smaller type (overflow is not
978 // possible in that case).
979 template <typename BaseType>
980 [[nodiscard]] constexpr auto NarrowTopHalf(Wrapping<BaseType> source)
981     -> Wrapping<typename TypeTraits<BaseType>::Narrow> {
982   return {static_cast<typename TypeTraits<BaseType>::Narrow>(
983       source.value >> (sizeof(typename TypeTraits<BaseType>::Narrow) * CHAR_BIT))};
984 }
985 
986 }  // namespace berberis
987 
988 #endif  // BERBERIS_BASE_BIT_UTIL_H_
989