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