• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 defined(__x86_64__)
226   if constexpr (sizeof(T) == sizeof(unsigned __int128)) {
227     if (static_cast<uint64_t>(x) == 0) {
228       return __builtin_ctzll(x >> 64) + 64;
229     }
230     return __builtin_ctzll(x);
231   } else
232 #endif
233       if constexpr (sizeof(T) == sizeof(uint64_t)) {
234     return __builtin_ctzll(x);
235   } else if constexpr (sizeof(T) == sizeof(uint32_t)) {
236     return __builtin_ctz(x);
237   } else {
238     static_assert(kDependentTypeFalse<T>);
239   }
240 }
241 
242 template <typename T>
CountRZero(Raw<T> x)243 [[nodiscard]] constexpr Raw<T> CountRZero(Raw<T> x) {
244   return {CountRZero(x.value)};
245 }
246 
247 template <typename T>
CountRZero(Saturating<T> x)248 [[nodiscard]] constexpr Saturating<T> CountRZero(Saturating<T> x) {
249   return {CountRZero(x.value)};
250 }
251 
252 template <typename T>
CountRZero(Wrapping<T> x)253 [[nodiscard]] constexpr Wrapping<T> CountRZero(Wrapping<T> x) {
254   return {CountRZero(x.value)};
255 }
256 
257 template <typename T>
Popcount(T x)258 [[nodiscard]] constexpr T Popcount(T x) {
259   // We couldn't use C++20 std::popcount yet ( http://b/318678905 ) for __uint128_t .
260   // Switch to std::popcount when/if that bug would be fixed.
261   static_assert(!std::is_signed_v<T>);
262 #if defined(__x86_64__)
263   if constexpr (sizeof(T) == sizeof(unsigned __int128)) {
264     return __builtin_popcountll(x) + __builtin_popcountll(x >> 64);
265   } else
266 #endif
267       if constexpr (sizeof(T) == sizeof(uint64_t)) {
268     return __builtin_popcountll(x);
269   } else if constexpr (sizeof(T) == sizeof(uint32_t)) {
270     return __builtin_popcount(x);
271   } else {
272     static_assert(kDependentTypeFalse<T>);
273   }
274 }
275 
276 template <typename T>
Popcount(Raw<T> x)277 [[nodiscard]] constexpr Raw<T> Popcount(Raw<T> x) {
278   return {Popcount(x.value)};
279 }
280 
281 template <typename T>
Popcount(Saturating<T> x)282 [[nodiscard]] constexpr Saturating<T> Popcount(Saturating<T> x) {
283   return {Popcount(x.value)};
284 }
285 
286 template <typename T>
Popcount(Wrapping<T> x)287 [[nodiscard]] constexpr Wrapping<T> Popcount(Wrapping<T> x) {
288   return {Popcount(x.value)};
289 }
290 
291 // bit_cast<Dest, Source> is a well-defined equivalent of address-casting:
292 //   *reinterpret_cast<Dest*>(&source)
293 // See chromium base/macros.h for details.
294 template <class Dest, class Source>
bit_cast(const Source & source)295 inline Dest bit_cast(const Source& source) {
296   static_assert(sizeof(Dest) == sizeof(Source),
297                 "bit_cast: source and destination must be of same size");
298   static_assert(std::is_trivially_copyable_v<Dest>,
299                 "bit_cast: destination must be trivially copyable");
300   static_assert(std::is_trivially_copyable_v<Source>,
301                 "bit_cast: source must be trivially copyable");
302   Dest dest;
303   memcpy(&dest, &source, sizeof(dest));
304   return dest;
305 }
306 
307 namespace intrinsics {
308 
309 template <typename BaseType>
310 class WrappedFloatType;
311 
312 }  // namespace intrinsics
313 
314 template <typename T>
315 struct TypeTraits;
316 
317 // Raw integers.  Used to carry payload, which may be be EXPLICITLY converted to Saturating
318 // integer, Wrapping integer, or WrappedFloatType.
319 //
320 // ����������'�� suppopt any actual operations, arithmetic, etc.
321 // Use bitcast or convert to one of three types listed above!
322 
323 template <typename Base>
324 class Raw {
325  public:
326   using BaseType = Base;
327 
328   static_assert(std::is_integral_v<BaseType>);
329   static_assert(!std::is_signed_v<BaseType>);
330 
331   template <typename IntType,
332             typename = std::enable_if_t<std::is_integral_v<IntType> &&
333                                         sizeof(IntType) == sizeof(BaseType)>>
IntType()334   [[nodiscard]] constexpr operator IntType() const {
335     return static_cast<IntType>(value);
336   }
337   template <typename IntType,
338             typename = std::enable_if_t<
339                 std::is_integral_v<IntType> && sizeof(BaseType) == sizeof(IntType) &&
340                 !std::is_signed_v<IntType> && !std::is_same_v<IntType, BaseType>>>
341   [[nodiscard]] constexpr operator Raw<IntType>() const {
342     return {static_cast<IntType>(value)};
343   }
344   template <typename IntType,
345             typename = std::enable_if_t<std::is_integral_v<IntType> &&
346                                         sizeof(BaseType) == sizeof(IntType)>>
347   [[nodiscard]] constexpr operator Saturating<IntType>() const {
348     return {static_cast<IntType>(value)};
349   }
350   template <typename FloatType,
351             typename = std::enable_if_t<!std::numeric_limits<FloatType>::is_exact &&
352                                         sizeof(BaseType) == sizeof(FloatType)>>
353   [[nodiscard]] constexpr operator intrinsics::WrappedFloatType<FloatType>() const {
354     // Can't use bit_cast here because of IA32 ABI!
355     intrinsics::WrappedFloatType<FloatType> result;
356     memcpy(&result, &value, sizeof(BaseType));
357     return result;
358   }
359   template <typename IntType,
360             typename = std::enable_if_t<std::is_integral_v<IntType> &&
361                                         sizeof(BaseType) == sizeof(IntType)>>
362   [[nodiscard]] constexpr operator Wrapping<IntType>() const {
363     return {static_cast<IntType>(value)};
364   }
365 
366   template <typename ResultType>
367   friend auto constexpr MaybeTruncateTo(Raw src)
368       -> std::enable_if_t<sizeof(typename ResultType::BaseType) <= sizeof(BaseType), ResultType> {
369     return ResultType{static_cast<ResultType::BaseType>(src.value)};
370   }
371   template <typename ResultType>
372   friend auto constexpr TruncateTo(Raw src)
373       -> std::enable_if_t<sizeof(typename ResultType::BaseType) < sizeof(BaseType), ResultType> {
374     return ResultType{static_cast<ResultType::BaseType>(src.value)};
375   }
376 
377   [[nodiscard]] friend constexpr bool operator==(Raw lhs, Raw rhs) {
378     return lhs.value == rhs.value;
379   }
380   [[nodiscard]] friend constexpr bool operator!=(Raw lhs, Raw rhs) {
381     return lhs.value != rhs.value;
382   }
383 
384   BaseType value = 0;
385 };
386 
387 // Saturating and wrapping integers.
388 //   1. Never trigger UB, even in case of overflow.
389 //   2. Only support mixed types when both are of the same type (e.g. SatInt8 and SatInt16 or
390 //      Int8 and Int64 are allowed, but SatInt8 and Int8 are forbidden and Int32 and Uint32
391 //      require explicit casting, too).
392 //   3. Results are performed after type expansion.
393 
394 template <typename Base>
395 class Saturating {
396  public:
397   using BaseType = Base;
398   using SignedType = Saturating<std::make_signed_t<BaseType>>;
399   using UnsignedType = Saturating<std::make_unsigned_t<BaseType>>;
400   static constexpr bool kIsSigned = std::is_signed_v<BaseType>;
401 
402   static_assert(std::is_integral_v<BaseType>);
403 
404   template <typename IntType,
405             typename = std::enable_if_t<std::is_integral_v<IntType> &&
406                                         ((sizeof(BaseType) < sizeof(IntType) &&
407                                           (std::is_signed_v<IntType> ||
408                                            kIsSigned == std::is_signed_v<IntType>)) ||
409                                          sizeof(IntType) == sizeof(BaseType))>>
IntType()410   [[nodiscard]] constexpr operator IntType() const {
411     return static_cast<IntType>(value);
412   }
413   template <typename IntType,
414             typename = std::enable_if_t<std::is_integral_v<IntType> &&
415                                         sizeof(BaseType) == sizeof(IntType)>>
416   [[nodiscard]] constexpr operator Raw<IntType>() const {
417     return {static_cast<IntType>(value)};
418   }
419   template <typename IntType,
420             typename = std::enable_if_t<
421                 std::is_integral_v<IntType> && sizeof(BaseType) <= sizeof(IntType) &&
422                 std::is_signed_v<IntType> == kIsSigned && !std::is_same_v<IntType, BaseType>>>
423   [[nodiscard]] constexpr operator Saturating<IntType>() const {
424     return {static_cast<IntType>(value)};
425   }
426   template <typename IntType,
427             typename = std::enable_if_t<std::is_integral_v<IntType> &&
428                                         sizeof(BaseType) == sizeof(IntType)>>
429   [[nodiscard]] constexpr operator Wrapping<IntType>() const {
430     return {static_cast<IntType>(value)};
431   }
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   [[nodiscard]] friend constexpr bool operator>(Saturating lhs, Saturating rhs) {
446     return lhs.value > rhs.value;
447   }
448   [[nodiscard]] friend constexpr bool operator>=(Saturating lhs, Saturating rhs) {
449     return lhs.value >= rhs.value;
450   }
451   friend constexpr Saturating& operator+=(Saturating& lhs, Saturating rhs) {
452     lhs = lhs + rhs;
453     return lhs;
454   }
Add(Saturating lhs,Saturating rhs)455   [[nodiscard]] friend constexpr std::tuple<Saturating, bool> Add(Saturating lhs, Saturating rhs) {
456     BaseType result;
457     bool overflow = __builtin_add_overflow(lhs.value, rhs.value, &result);
458     if (overflow) {
459       if constexpr (kIsSigned) {
460         if (result < 0) {
461           result = std::numeric_limits<BaseType>::max();
462         } else {
463           result = std::numeric_limits<BaseType>::min();
464         }
465       } else {
466         result = std::numeric_limits<BaseType>::max();
467       }
468     }
469     return {{result}, overflow};
470   }
471   [[nodiscard]] friend constexpr Saturating operator+(Saturating lhs, Saturating rhs) {
472     return std::get<0>(Add(lhs, rhs));
473   }
474   friend constexpr Saturating& operator-=(Saturating& lhs, Saturating rhs) {
475     lhs = lhs - rhs;
476     return lhs;
477   }
Neg(Saturating lhs)478   [[nodiscard]] friend constexpr std::tuple<Saturating, bool> Neg(Saturating lhs) {
479     if constexpr (kIsSigned) {
480       if (lhs.value == std::numeric_limits<BaseType>::min()) {
481         return {std::numeric_limits<BaseType>::max(), true};
482       }
483       return {{-lhs.value}, false};
484     }
485     return {{0}, lhs != 0};
486   }
487   [[nodiscard]] friend constexpr Saturating operator-(Saturating lhs) {
488     return std::get<0>(Neg(lhs));
489   }
Sub(Saturating lhs,Saturating rhs)490   [[nodiscard]] friend constexpr std::tuple<Saturating, bool> Sub(Saturating lhs, Saturating rhs) {
491     BaseType result;
492     bool overflow = __builtin_sub_overflow(lhs.value, rhs.value, &result);
493     if (overflow) {
494       if constexpr (kIsSigned) {
495         if (result < 0) {
496           result = std::numeric_limits<BaseType>::max();
497         } else {
498           result = std::numeric_limits<BaseType>::min();
499         }
500       } else {
501         result = 0;
502       }
503     }
504     return {{result}, overflow};
505   }
506   [[nodiscard]] friend constexpr Saturating operator-(Saturating lhs, Saturating rhs) {
507     return std::get<0>(Sub(lhs, rhs));
508   }
509   friend constexpr Saturating& operator*=(Saturating& lhs, Saturating rhs) {
510     lhs = lhs * rhs;
511     return lhs;
512   }
Mul(Saturating lhs,Saturating rhs)513   [[nodiscard]] friend constexpr std::tuple<Saturating, bool> Mul(Saturating lhs, Saturating rhs) {
514     BaseType result;
515     bool overflow = __builtin_mul_overflow(lhs.value, rhs.value, &result);
516     if (overflow) {
517       if constexpr (kIsSigned) {
518         if (lhs.value < 0 != rhs.value < 0) {
519           result = std::numeric_limits<BaseType>::min();
520         } else {
521           result = std::numeric_limits<BaseType>::max();
522         }
523       } else {
524         result = std::numeric_limits<BaseType>::max();
525       }
526     }
527     return {{result}, overflow};
528   }
529   [[nodiscard]] friend constexpr Saturating operator*(Saturating lhs, Saturating rhs) {
530     return std::get<0>(Mul(lhs, rhs));
531   }
532   friend constexpr Saturating& operator/=(Saturating& lhs, Saturating rhs) {
533     lhs = lhs / rhs;
534     return lhs;
535   }
Div(Saturating lhs,Saturating rhs)536   [[nodiscard]] friend constexpr std::tuple<Saturating, bool> Div(Saturating lhs, Saturating rhs) {
537     if constexpr (kIsSigned) {
538       if (lhs.value == std::numeric_limits<BaseType>::min() && rhs.value == -1) {
539         return {{std::numeric_limits<BaseType>::max()}, true};
540       }
541     }
542     return {{BaseType(lhs.value / rhs.value)}, false};
543   }
544   [[nodiscard]] friend constexpr Saturating operator/(Saturating lhs, Saturating rhs) {
545     return std::get<0>(Div(lhs, rhs));
546   }
547   friend constexpr Saturating& operator%=(Saturating& lhs, Saturating rhs) {
548     lhs = lhs % rhs;
549     return lhs;
550   }
Rem(Saturating lhs,Saturating rhs)551   [[nodiscard]] friend constexpr std::tuple<Saturating, bool> Rem(Saturating lhs, Saturating rhs) {
552     if constexpr (kIsSigned) {
553       if (lhs.value == std::numeric_limits<BaseType>::min() && rhs.value == -1) {
554         return {{1}, true};
555       }
556     }
557     return {{BaseType(lhs.value % rhs.value)}, false};
558   }
559   [[nodiscard]] friend constexpr Saturating operator%(Saturating lhs, Saturating rhs) {
560     return std::get<0>(Rem(lhs, rhs));
561   }
562   BaseType value = 0;
563 };
564 
565 template <typename Base>
566 class Wrapping {
567  public:
568   using BaseType = Base;
569   using SignedType = Wrapping<std::make_signed_t<BaseType>>;
570   using UnsignedType = Wrapping<std::make_unsigned_t<BaseType>>;
571   static constexpr bool kIsSigned = std::is_signed_v<BaseType>;
572 
573   static_assert(std::is_integral_v<BaseType>);
574 
575   template <typename IntType,
576             typename = std::enable_if_t<std::is_integral_v<IntType> &&
577                                         ((sizeof(BaseType) < sizeof(IntType) &&
578                                           (std::is_signed_v<IntType> ||
579                                            kIsSigned == std::is_signed_v<IntType>)) ||
580                                          sizeof(IntType) == sizeof(BaseType))>>
IntType()581   [[nodiscard]] constexpr operator 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 Raw<IntType>() const {
588     return {static_cast<IntType>(value)};
589   }
590   template <typename IntType,
591             typename = std::enable_if_t<std::is_integral_v<IntType> &&
592                                         sizeof(BaseType) == sizeof(IntType)>>
593   [[nodiscard]] constexpr operator Saturating<IntType>() const {
594     return {static_cast<IntType>(value)};
595   }
596   template <typename IntType,
597             typename = std::enable_if_t<
598                 std::is_integral_v<IntType> && sizeof(BaseType) <= sizeof(IntType) &&
599                 std::is_signed_v<IntType> == kIsSigned && !std::is_same_v<IntType, BaseType>>>
600   [[nodiscard]] constexpr operator Wrapping<IntType>() const {
601     return {static_cast<IntType>(value)};
602   }
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   [[nodiscard]] friend constexpr bool operator>(Wrapping lhs, Wrapping rhs) {
617     return lhs.value > rhs.value;
618   }
619   [[nodiscard]] friend constexpr bool operator>=(Wrapping lhs, Wrapping rhs) {
620     return lhs.value >= rhs.value;
621   }
622   // Note:
623   //   1. We use __builtin_xxx_overflow instead of simple +, -, or * operators because
624   //      __builtin_xxx_overflow produces well-defined result in case of overflow while
625   //      +, -, * are triggering undefined behavior conditions.
626   //   2. All operator xxx= are implemented in terms of opernator xxx
627   friend constexpr Wrapping& operator+=(Wrapping& lhs, Wrapping rhs) {
628     lhs = lhs + rhs;
629     return lhs;
630   }
631   [[nodiscard]] friend constexpr Wrapping operator+(Wrapping lhs, Wrapping rhs) {
632     BaseType result;
633     __builtin_add_overflow(lhs.value, rhs.value, &result);
634     return {result};
635   }
636   friend constexpr Wrapping& operator-=(Wrapping& lhs, Wrapping rhs) {
637     lhs = lhs - rhs;
638     return lhs;
639   }
640   [[nodiscard]] friend constexpr Wrapping operator-(Wrapping lhs) {
641     BaseType result;
642     __builtin_sub_overflow(BaseType{0}, lhs.value, &result);
643     return {result};
644   }
645   [[nodiscard]] friend constexpr Wrapping operator-(Wrapping lhs, Wrapping rhs) {
646     BaseType result;
647     __builtin_sub_overflow(lhs.value, rhs.value, &result);
648     return {result};
649   }
650   friend constexpr Wrapping& operator*=(Wrapping& lhs, Wrapping rhs) {
651     lhs = lhs * rhs;
652     return lhs;
653   }
654   [[nodiscard]] friend constexpr Wrapping operator*(Wrapping lhs, Wrapping rhs) {
655     BaseType result;
656     __builtin_mul_overflow(lhs.value, rhs.value, &result);
657     return {result};
658   }
659   friend constexpr Wrapping& operator/=(Wrapping& lhs, Wrapping rhs) {
660     lhs = lhs / rhs;
661     return lhs;
662   }
663   [[nodiscard]] friend constexpr Wrapping operator/(Wrapping lhs, Wrapping rhs) {
664     if constexpr (kIsSigned) {
665       if (lhs.value == std::numeric_limits<BaseType>::min() && rhs.value == -1) {
666         return {std::numeric_limits<BaseType>::min()};
667       }
668     }
669     return {BaseType(lhs.value / rhs.value)};
670   }
671   friend constexpr Wrapping& operator%=(Wrapping& lhs, Wrapping rhs) {
672     lhs = lhs % rhs;
673     return lhs;
674   }
675   [[nodiscard]] friend constexpr Wrapping operator%(Wrapping lhs, Wrapping rhs) {
676     if constexpr (kIsSigned) {
677       if (lhs.value == std::numeric_limits<BaseType>::min() && rhs.value == -1) {
678         return {0};
679       }
680     }
681     return {BaseType(lhs.value % rhs.value)};
682   }
683   friend constexpr Wrapping& operator<<=(Wrapping& lhs, Wrapping rhs) {
684     lhs = lhs << rhs;
685     return lhs;
686   }
687   template <typename IntType>
688   [[nodiscard]] friend constexpr Wrapping operator<<(Wrapping lhs, Wrapping<IntType> rhs) {
689     return {BaseType(lhs.value << (rhs.value & (sizeof(BaseType) * CHAR_BIT - 1)))};
690   }
691   friend constexpr Wrapping& operator>>=(Wrapping& lhs, Wrapping rhs) {
692     lhs = lhs >> rhs;
693     return lhs;
694   }
695   template <typename IntType>
696   [[nodiscard]] friend constexpr Wrapping operator>>(Wrapping lhs, Wrapping<IntType> rhs) {
697     return {BaseType(lhs.value >> (rhs.value & (sizeof(BaseType) * CHAR_BIT - 1)))};
698   }
699   friend constexpr Wrapping& operator&=(Wrapping& lhs, Wrapping rhs) {
700     lhs = lhs & rhs;
701     return lhs;
702   }
703   [[nodiscard]] friend constexpr Wrapping operator&(Wrapping lhs, Wrapping rhs) {
704     return {BaseType(lhs.value & rhs.value)};
705   }
706   friend constexpr Wrapping& operator|=(Wrapping& lhs, Wrapping rhs) {
707     lhs = lhs | rhs;
708     return lhs;
709   }
710   [[nodiscard]] friend constexpr Wrapping operator|(Wrapping lhs, Wrapping rhs) {
711     return {BaseType(lhs.value | rhs.value)};
712   }
713   friend constexpr Wrapping& operator^=(Wrapping& lhs, Wrapping rhs) {
714     lhs = lhs ^ rhs;
715     return lhs;
716   }
717   [[nodiscard]] friend constexpr Wrapping operator^(Wrapping lhs, Wrapping rhs) {
718     return {BaseType(lhs.value ^ rhs.value)};
719   }
720   [[nodiscard]] friend constexpr Wrapping operator~(Wrapping lhs) { return {BaseType(~lhs.value)}; }
721   BaseType value = 0;
722 };
723 
724 using RawInt8 = Raw<uint8_t>;
725 using RawInt16 = Raw<uint16_t>;
726 using RawInt32 = Raw<uint32_t>;
727 using RawInt64 = Raw<uint64_t>;
728 #if defined(__x86_64__)
729 using RawInt128 = Raw<unsigned __int128>;
730 #endif
731 
732 using SatInt8 = Saturating<int8_t>;
733 using SatUInt8 = Saturating<uint8_t>;
734 using SatInt16 = Saturating<int16_t>;
735 using SatUInt16 = Saturating<uint16_t>;
736 using SatInt32 = Saturating<int32_t>;
737 using SatUInt32 = Saturating<uint32_t>;
738 using SatInt64 = Saturating<int64_t>;
739 using SatUInt64 = Saturating<uint64_t>;
740 #if defined(__x86_64__)
741 using SatInt128 = Saturating<__int128>;
742 using SatUInt128 = Saturating<unsigned __int128>;
743 #endif
744 
745 using Int8 = Wrapping<int8_t>;
746 using UInt8 = Wrapping<uint8_t>;
747 using Int16 = Wrapping<int16_t>;
748 using UInt16 = Wrapping<uint16_t>;
749 using Int32 = Wrapping<int32_t>;
750 using UInt32 = Wrapping<uint32_t>;
751 using Int64 = Wrapping<int64_t>;
752 using UInt64 = Wrapping<uint64_t>;
753 using IntPtr = Wrapping<intptr_t>;
754 using UIntPtr = Wrapping<uintptr_t>;
755 #if defined(__x86_64__)
756 using Int128 = Wrapping<__int128>;
757 using UInt128 = Wrapping<unsigned __int128>;
758 #endif
759 
760 template <typename IntType>
761 [[nodiscard]] auto constexpr BitCastToSigned(Raw<IntType> src) ->
762     typename Wrapping<IntType>::SignedType {
763   return {static_cast<std::make_signed_t<IntType>>(src.value)};
764 }
765 
766 template <typename IntType>
767 [[nodiscard]] auto constexpr BitCastToSigned(Saturating<IntType> src) ->
768     typename Saturating<IntType>::SignedType {
769   return {static_cast<std::make_signed_t<IntType>>(src.value)};
770 }
771 
772 template <typename IntType>
773 [[nodiscard]] auto constexpr BitCastToSigned(Wrapping<IntType> src) ->
774     typename Wrapping<IntType>::SignedType {
775   return {static_cast<std::make_signed_t<IntType>>(src.value)};
776 }
777 
778 template <typename T>
779 using SignedType = decltype(BitCastToSigned(std::declval<T>()));
780 
781 template <typename IntType>
782 [[nodiscard]] auto constexpr BitCastToUnsigned(Raw<IntType> src) ->
783     typename Wrapping<IntType>::UnsignedType {
784   return {static_cast<std::make_unsigned_t<IntType>>(src.value)};
785 }
786 
787 template <typename IntType>
788 [[nodiscard]] auto constexpr BitCastToUnsigned(Saturating<IntType> src) ->
789     typename Saturating<IntType>::UnsignedType {
790   return {static_cast<std::make_unsigned_t<IntType>>(src.value)};
791 }
792 
793 template <typename IntType>
794 [[nodiscard]] auto constexpr BitCastToUnsigned(Wrapping<IntType> src) ->
795     typename Wrapping<IntType>::UnsignedType {
796   return {static_cast<std::make_unsigned_t<IntType>>(src.value)};
797 }
798 
799 template <typename T>
800 using UnsignedType = decltype(BitCastToUnsigned(std::declval<T>()));
801 
802 template <typename IntType>
803 [[nodiscard]] auto constexpr BitCastToSaturating(Saturating<IntType> src) -> Saturating<IntType> {
804   return src;
805 }
806 
807 template <typename IntType>
808 [[nodiscard]] auto constexpr BitCastToSaturating(Wrapping<IntType> src) -> Saturating<IntType> {
809   return {src.value};
810 }
811 
812 template <typename T>
813 using SaturatingType = decltype(BitCastToSaturating(std::declval<T>()));
814 
815 template <typename IntType>
816 [[nodiscard]] auto constexpr BitCastToWrapping(Saturating<IntType> src) -> Wrapping<IntType> {
817   return {src.value};
818 }
819 
820 template <typename IntType>
821 [[nodiscard]] auto constexpr BitCastToWrapping(Wrapping<IntType> src) -> Wrapping<IntType> {
822   return src;
823 }
824 
825 template <typename T>
826 using WrappingType = decltype(BitCastToWrapping(std::declval<T>()));
827 
828 template <typename IntType>
829 [[nodiscard]] auto constexpr BitCastToRaw(Raw<IntType> src) -> Raw<IntType> {
830   return src;
831 }
832 
833 template <typename IntType>
834 [[nodiscard]] auto constexpr BitCastToRaw(Saturating<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 IntType>
840 [[nodiscard]] auto constexpr BitCastToRaw(Wrapping<IntType> src)
841     -> Raw<std::make_unsigned_t<IntType>> {
842   return {static_cast<std::make_unsigned_t<IntType>>(src.value)};
843 }
844 
845 template <typename BaseType>
846 [[nodiscard]] constexpr auto BitCastToRaw(intrinsics::WrappedFloatType<BaseType> src)
847     -> Raw<std::make_unsigned_t<typename TypeTraits<intrinsics::WrappedFloatType<BaseType>>::Int>> {
848   return {bit_cast<
849       std::make_unsigned_t<typename TypeTraits<intrinsics::WrappedFloatType<BaseType>>::Int>>(src)};
850 }
851 
852 template <typename T>
853 using RawType = decltype(BitCastToRaw(std::declval<T>()));
854 
855 template <typename IntType>
856 [[nodiscard]] auto constexpr BitCastToFloat(Raw<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(Saturating<IntType> src) ->
863     typename TypeTraits<IntType>::Float {
864   return bit_cast<typename TypeTraits<IntType>::Float>(src.value);
865 }
866 
867 template <typename IntType>
868 [[nodiscard]] auto constexpr BitCastToFloat(Wrapping<IntType> src) ->
869     typename TypeTraits<IntType>::Float {
870   return bit_cast<typename TypeTraits<IntType>::Float>(src.value);
871 }
872 
873 template <typename BaseType>
874 [[nodiscard]] constexpr auto BitCastToFloat(intrinsics::WrappedFloatType<BaseType> src)
875     -> intrinsics::WrappedFloatType<BaseType> {
876   return src;
877 }
878 
879 template <typename T>
880 using FloatType = decltype(BitCastToFloat(std::declval<T>()));
881 
882 template <typename ResultType, typename IntType>
883 [[nodiscard]] auto constexpr MaybeTruncateTo(IntType src)
884     -> std::enable_if_t<std::is_integral_v<IntType> &&
885                             sizeof(typename ResultType::BaseType) <= sizeof(IntType),
886                         ResultType> {
887   return ResultType{static_cast<ResultType::BaseType>(src)};
888 }
889 
890 template <typename ResultType, typename IntType>
891 [[nodiscard]] auto constexpr MaybeTruncateTo(Saturating<IntType> src)
892     -> std::enable_if_t<std::is_integral_v<IntType> &&
893                             sizeof(typename ResultType::BaseType) <= sizeof(IntType),
894                         ResultType> {
895   return ResultType{static_cast<ResultType::BaseType>(src.value)};
896 }
897 
898 template <typename ResultType, typename IntType>
899 [[nodiscard]] auto constexpr MaybeTruncateTo(Wrapping<IntType> src)
900     -> std::enable_if_t<std::is_integral_v<IntType> &&
901                             sizeof(typename ResultType::BaseType) <= sizeof(IntType),
902                         ResultType> {
903   return ResultType{static_cast<ResultType::BaseType>(src.value)};
904 }
905 
906 template <typename ResultType, typename IntType>
907 [[nodiscard]] auto constexpr TruncateTo(IntType src)
908     -> std::enable_if_t<std::is_integral_v<IntType> &&
909                             sizeof(typename ResultType::BaseType) < sizeof(IntType),
910                         ResultType> {
911   return ResultType{static_cast<ResultType::BaseType>(src)};
912 }
913 
914 template <typename ResultType, typename IntType>
915 [[nodiscard]] auto constexpr TruncateTo(Saturating<IntType> src)
916     -> std::enable_if_t<std::is_integral_v<IntType> &&
917                             sizeof(typename ResultType::BaseType) < sizeof(IntType),
918                         ResultType> {
919   return ResultType{static_cast<ResultType::BaseType>(src.value)};
920 }
921 
922 template <typename ResultType, typename IntType>
923 [[nodiscard]] auto constexpr TruncateTo(Wrapping<IntType> src)
924     -> std::enable_if_t<std::is_integral_v<IntType> &&
925                             sizeof(typename ResultType::BaseType) < sizeof(IntType),
926                         ResultType> {
927   return ResultType{static_cast<ResultType::BaseType>(src.value)};
928 }
929 
930 template <typename BaseType>
931 [[nodiscard]] constexpr auto Widen(Saturating<BaseType> source)
932     -> Saturating<typename TypeTraits<BaseType>::Wide> {
933   return {source.value};
934 }
935 
936 template <typename BaseType>
937 [[nodiscard]] constexpr auto Widen(Wrapping<BaseType> source)
938     -> Wrapping<typename TypeTraits<BaseType>::Wide> {
939   return {source.value};
940 }
941 
942 template <typename BaseType>
943 [[nodiscard]] constexpr auto Widen(intrinsics::WrappedFloatType<BaseType> source) ->
944     typename TypeTraits<intrinsics::WrappedFloatType<BaseType>>::Wide {
945   return {source};
946 }
947 
948 template <typename T>
949 using WideType = decltype(Widen(std::declval<T>()));
950 
951 template <typename BaseType>
952 [[nodiscard]] constexpr auto Narrow(Saturating<BaseType> source)
953     -> Saturating<typename TypeTraits<BaseType>::Narrow> {
954   if constexpr (Saturating<BaseType>::kIsSigned) {
955     if (source.value < std::numeric_limits<typename TypeTraits<BaseType>::Narrow>::min()) {
956       return {std::numeric_limits<typename TypeTraits<BaseType>::Narrow>::min()};
957     }
958   }
959   if (source.value > std::numeric_limits<typename TypeTraits<BaseType>::Narrow>::max()) {
960     return {std::numeric_limits<typename TypeTraits<BaseType>::Narrow>::max()};
961   }
962   return {static_cast<typename TypeTraits<BaseType>::Narrow>(source.value)};
963 }
964 
965 template <typename BaseType>
966 [[nodiscard]] constexpr auto Narrow(Wrapping<BaseType> source)
967     -> Wrapping<typename TypeTraits<BaseType>::Narrow> {
968   return {static_cast<typename TypeTraits<BaseType>::Narrow>(source.value)};
969 }
970 
971 template <typename BaseType>
972 [[nodiscard]] constexpr auto Narrow(intrinsics::WrappedFloatType<BaseType> source) ->
973     typename TypeTraits<intrinsics::WrappedFloatType<BaseType>>::Narrow {
974   return {source};
975 }
976 
977 template <typename T>
978 using NarrowType = decltype(Narrow(std::declval<T>()));
979 
980 // While `Narrow` returns value reduced to smaller data type there are centain algorithms
981 // which require the top half, too (most ofhen in the context of widening multiplication
982 // where top half of the product is produced).
983 // `NarrowTopHalf` returns top half of the value narrowed down to smaller type (overflow is not
984 // possible in that case).
985 template <typename BaseType>
986 [[nodiscard]] constexpr auto NarrowTopHalf(Wrapping<BaseType> source)
987     -> Wrapping<typename TypeTraits<BaseType>::Narrow> {
988   return {static_cast<typename TypeTraits<BaseType>::Narrow>(
989       source.value >> (sizeof(typename TypeTraits<BaseType>::Narrow) * CHAR_BIT))};
990 }
991 
992 }  // namespace berberis
993 
994 #endif  // BERBERIS_BASE_BIT_UTIL_H_
995