Skip to content

Commit 2b677fa

Browse files
authored
[libc][NFC] Simplify BigInt (#81992)
- Add a single `cmp` function to derive all comparison operators - Use the `friend` version of the member functions for symmetry - Add a `is_neg` function to factor sign extraction - Implement binary op through macro expansion
1 parent f55b79f commit 2b677fa

File tree

2 files changed

+74
-146
lines changed

2 files changed

+74
-146
lines changed

libc/src/__support/CPP/array.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,10 @@ template <class T, size_t N> struct array {
2828
LIBC_INLINE constexpr const T *data() const { return Data; }
2929

3030
LIBC_INLINE constexpr T &front() { return Data[0]; }
31-
LIBC_INLINE constexpr T &front() const { return Data[0]; }
31+
LIBC_INLINE constexpr const T &front() const { return Data[0]; }
3232

3333
LIBC_INLINE constexpr T &back() { return Data[N - 1]; }
34-
LIBC_INLINE constexpr T &back() const { return Data[N - 1]; }
34+
LIBC_INLINE constexpr const T &back() const { return Data[N - 1]; }
3535

3636
LIBC_INLINE constexpr T &operator[](size_t Index) { return Data[Index]; }
3737

libc/src/__support/UInt.h

Lines changed: 72 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,8 @@ struct BigInt {
6868
val[i] = other[i];
6969
WordType sign = 0;
7070
if constexpr (Signed && OtherSigned) {
71-
sign = static_cast<WordType>(-static_cast<make_signed_t<WordType>>(
72-
other[OtherBits / WORD_SIZE - 1] >> (WORD_SIZE - 1)));
71+
sign = static_cast<WordType>(
72+
-static_cast<make_signed_t<WordType>>(other.is_neg()));
7373
}
7474
for (; i < WORD_COUNT; ++i)
7575
val[i] = sign;
@@ -125,6 +125,11 @@ struct BigInt {
125125
val[i] = words[i];
126126
}
127127

128+
// TODO: Reuse the Sign type.
129+
LIBC_INLINE constexpr bool is_neg() const {
130+
return val.back() >> (WORD_SIZE - 1);
131+
}
132+
128133
template <typename T> LIBC_INLINE constexpr explicit operator T() const {
129134
return to<T>();
130135
}
@@ -148,7 +153,7 @@ struct BigInt {
148153
if constexpr (Signed && (T_BITS > Bits)) {
149154
// Extend sign for negative numbers.
150155
constexpr T MASK = (~T(0) << Bits);
151-
if (val[WORD_COUNT - 1] >> (WORD_SIZE - 1))
156+
if (is_neg())
152157
lo |= MASK;
153158
}
154159

@@ -267,8 +272,8 @@ struct BigInt {
267272
if constexpr (Signed) {
268273
BigInt<Bits, false, WordType> a(*this);
269274
BigInt<Bits, false, WordType> b(other);
270-
bool a_neg = (a.val[WORD_COUNT - 1] >> (WORD_SIZE - 1));
271-
bool b_neg = (b.val[WORD_COUNT - 1] >> (WORD_SIZE - 1));
275+
const bool a_neg = a.is_neg();
276+
const bool b_neg = b.is_neg();
272277
if (a_neg)
273278
a = -a;
274279
if (b_neg)
@@ -278,7 +283,6 @@ struct BigInt {
278283
prod = -prod;
279284
return static_cast<BigInt<Bits, true, WordType>>(prod);
280285
} else {
281-
282286
if constexpr (WORD_COUNT == 1) {
283287
return {val[0] * other.val[0]};
284288
} else {
@@ -383,10 +387,9 @@ struct BigInt {
383387
BigInt cur_power = *this;
384388

385389
while (power > 0) {
386-
if ((power % 2) > 0) {
387-
result = result * cur_power;
388-
}
389-
power = power >> 1;
390+
if ((power % 2) > 0)
391+
result *= cur_power;
392+
power >>= 1;
390393
cur_power *= cur_power;
391394
}
392395
*this = result;
@@ -709,7 +712,7 @@ struct BigInt {
709712
const size_t shift = s % WORD_SIZE; // Bit shift in the remaining words.
710713

711714
size_t i = 0;
712-
WordType sign = Signed ? (val[WORD_COUNT - 1] >> (WORD_SIZE - 1)) : 0;
715+
WordType sign = Signed ? is_neg() : 0;
713716

714717
if (drop < WORD_COUNT) {
715718
if (shift > 0) {
@@ -747,49 +750,31 @@ struct BigInt {
747750
return *this;
748751
}
749752

750-
LIBC_INLINE constexpr BigInt operator&(const BigInt &other) const {
751-
BigInt result;
752-
for (size_t i = 0; i < WORD_COUNT; ++i)
753-
result.val[i] = val[i] & other.val[i];
754-
return result;
753+
#define DEFINE_BINOP(OP) \
754+
LIBC_INLINE friend constexpr BigInt operator OP(const BigInt &lhs, \
755+
const BigInt &rhs) { \
756+
BigInt result; \
757+
for (size_t i = 0; i < WORD_COUNT; ++i) \
758+
result[i] = lhs[i] OP rhs[i]; \
759+
return result; \
760+
} \
761+
LIBC_INLINE friend constexpr BigInt operator OP##=(BigInt &lhs, \
762+
const BigInt &rhs) { \
763+
for (size_t i = 0; i < WORD_COUNT; ++i) \
764+
lhs[i] OP## = rhs[i]; \
765+
return lhs; \
755766
}
756767

757-
LIBC_INLINE constexpr BigInt &operator&=(const BigInt &other) {
758-
for (size_t i = 0; i < WORD_COUNT; ++i)
759-
val[i] &= other.val[i];
760-
return *this;
761-
}
768+
DEFINE_BINOP(&)
769+
DEFINE_BINOP(|)
770+
DEFINE_BINOP(^)
762771

763-
LIBC_INLINE constexpr BigInt operator|(const BigInt &other) const {
764-
BigInt result;
765-
for (size_t i = 0; i < WORD_COUNT; ++i)
766-
result.val[i] = val[i] | other.val[i];
767-
return result;
768-
}
769-
770-
LIBC_INLINE constexpr BigInt &operator|=(const BigInt &other) {
771-
for (size_t i = 0; i < WORD_COUNT; ++i)
772-
val[i] |= other.val[i];
773-
return *this;
774-
}
775-
776-
LIBC_INLINE constexpr BigInt operator^(const BigInt &other) const {
777-
BigInt result;
778-
for (size_t i = 0; i < WORD_COUNT; ++i)
779-
result.val[i] = val[i] ^ other.val[i];
780-
return result;
781-
}
782-
783-
LIBC_INLINE constexpr BigInt &operator^=(const BigInt &other) {
784-
for (size_t i = 0; i < WORD_COUNT; ++i)
785-
val[i] ^= other.val[i];
786-
return *this;
787-
}
772+
#undef DEFINE_BINOP
788773

789774
LIBC_INLINE constexpr BigInt operator~() const {
790775
BigInt result;
791776
for (size_t i = 0; i < WORD_COUNT; ++i)
792-
result.val[i] = ~val[i];
777+
result[i] = ~val[i];
793778
return result;
794779
}
795780

@@ -799,139 +784,82 @@ struct BigInt {
799784
return result;
800785
}
801786

802-
LIBC_INLINE constexpr bool operator==(const BigInt &other) const {
803-
for (size_t i = 0; i < WORD_COUNT; ++i) {
804-
if (val[i] != other.val[i])
787+
LIBC_INLINE friend constexpr bool operator==(const BigInt &lhs,
788+
const BigInt &rhs) {
789+
for (size_t i = 0; i < WORD_COUNT; ++i)
790+
if (lhs.val[i] != rhs.val[i])
805791
return false;
806-
}
807792
return true;
808793
}
809794

810-
LIBC_INLINE constexpr bool operator!=(const BigInt &other) const {
811-
for (size_t i = 0; i < WORD_COUNT; ++i) {
812-
if (val[i] != other.val[i])
813-
return true;
814-
}
815-
return false;
795+
LIBC_INLINE friend constexpr bool operator!=(const BigInt &lhs,
796+
const BigInt &rhs) {
797+
return !(lhs == rhs);
816798
}
817799

818-
LIBC_INLINE constexpr bool operator>(const BigInt &other) const {
800+
private:
801+
LIBC_INLINE friend constexpr int cmp(const BigInt &lhs, const BigInt &rhs) {
802+
const auto compare = [](WordType a, WordType b) {
803+
return a == b ? 0 : a > b ? 1 : -1;
804+
};
819805
if constexpr (Signed) {
820-
// Check for different signs;
821-
bool a_sign = val[WORD_COUNT - 1] >> (WORD_SIZE - 1);
822-
bool b_sign = other.val[WORD_COUNT - 1] >> (WORD_SIZE - 1);
823-
if (a_sign != b_sign) {
824-
return b_sign;
825-
}
826-
}
827-
for (size_t i = WORD_COUNT; i > 0; --i) {
828-
WordType word = val[i - 1];
829-
WordType other_word = other.val[i - 1];
830-
if (word > other_word)
831-
return true;
832-
else if (word < other_word)
833-
return false;
806+
const bool lhs_is_neg = lhs.is_neg();
807+
const bool rhs_is_neg = rhs.is_neg();
808+
if (lhs_is_neg != rhs_is_neg)
809+
return rhs_is_neg ? 1 : -1;
834810
}
835-
// Equal
836-
return false;
811+
for (size_t i = WORD_COUNT; i-- > 0;)
812+
if (auto cmp = compare(lhs[i], rhs[i]); cmp != 0)
813+
return cmp;
814+
return 0;
837815
}
838816

839-
LIBC_INLINE constexpr bool operator>=(const BigInt &other) const {
840-
if constexpr (Signed) {
841-
// Check for different signs;
842-
bool a_sign = val[WORD_COUNT - 1] >> (WORD_SIZE - 1);
843-
bool b_sign = other.val[WORD_COUNT - 1] >> (WORD_SIZE - 1);
844-
if (a_sign != b_sign) {
845-
return b_sign;
846-
}
847-
}
848-
for (size_t i = WORD_COUNT; i > 0; --i) {
849-
WordType word = val[i - 1];
850-
WordType other_word = other.val[i - 1];
851-
if (word > other_word)
852-
return true;
853-
else if (word < other_word)
854-
return false;
855-
}
856-
// Equal
857-
return true;
817+
public:
818+
LIBC_INLINE friend constexpr bool operator>(const BigInt &lhs,
819+
const BigInt &rhs) {
820+
return cmp(lhs, rhs) > 0;
858821
}
859-
860-
LIBC_INLINE constexpr bool operator<(const BigInt &other) const {
861-
if constexpr (Signed) {
862-
// Check for different signs;
863-
bool a_sign = val[WORD_COUNT - 1] >> (WORD_SIZE - 1);
864-
bool b_sign = other.val[WORD_COUNT - 1] >> (WORD_SIZE - 1);
865-
if (a_sign != b_sign) {
866-
return a_sign;
867-
}
868-
}
869-
870-
for (size_t i = WORD_COUNT; i > 0; --i) {
871-
WordType word = val[i - 1];
872-
WordType other_word = other.val[i - 1];
873-
if (word > other_word)
874-
return false;
875-
else if (word < other_word)
876-
return true;
877-
}
878-
// Equal
879-
return false;
822+
LIBC_INLINE friend constexpr bool operator>=(const BigInt &lhs,
823+
const BigInt &rhs) {
824+
return cmp(lhs, rhs) >= 0;
880825
}
881-
882-
LIBC_INLINE constexpr bool operator<=(const BigInt &other) const {
883-
if constexpr (Signed) {
884-
// Check for different signs;
885-
bool a_sign = val[WORD_COUNT - 1] >> (WORD_SIZE - 1);
886-
bool b_sign = other.val[WORD_COUNT - 1] >> (WORD_SIZE - 1);
887-
if (a_sign != b_sign) {
888-
return a_sign;
889-
}
890-
}
891-
for (size_t i = WORD_COUNT; i > 0; --i) {
892-
WordType word = val[i - 1];
893-
WordType other_word = other.val[i - 1];
894-
if (word > other_word)
895-
return false;
896-
else if (word < other_word)
897-
return true;
898-
}
899-
// Equal
900-
return true;
826+
LIBC_INLINE friend constexpr bool operator<(const BigInt &lhs,
827+
const BigInt &rhs) {
828+
return cmp(lhs, rhs) < 0;
829+
}
830+
LIBC_INLINE friend constexpr bool operator<=(const BigInt &lhs,
831+
const BigInt &rhs) {
832+
return cmp(lhs, rhs) <= 0;
901833
}
902834

903835
LIBC_INLINE constexpr BigInt &operator++() {
904-
BigInt one(1);
905-
add(one);
836+
add(BigInt(1));
906837
return *this;
907838
}
908839

909840
LIBC_INLINE constexpr BigInt operator++(int) {
910841
BigInt oldval(*this);
911-
BigInt one(1);
912-
add(one);
842+
add(BigInt(1));
913843
return oldval;
914844
}
915845

916846
LIBC_INLINE constexpr BigInt &operator--() {
917-
BigInt one(1);
918-
sub(one);
847+
sub(BigInt(1));
919848
return *this;
920849
}
921850

922851
LIBC_INLINE constexpr BigInt operator--(int) {
923852
BigInt oldval(*this);
924-
BigInt one(1);
925-
sub(one);
853+
sub(BigInt(1));
926854
return oldval;
927855
}
928856

929-
// Return the i-th 64-bit word of the number.
857+
// Return the i-th word of the number.
930858
LIBC_INLINE constexpr const WordType &operator[](size_t i) const {
931859
return val[i];
932860
}
933861

934-
// Return the i-th 64-bit word of the number.
862+
// Return the i-th word of the number.
935863
LIBC_INLINE constexpr WordType &operator[](size_t i) { return val[i]; }
936864

937865
LIBC_INLINE WordType *data() { return val; }

0 commit comments

Comments
 (0)