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