diff options
| author | Eugen Wissner <belka@caraus.de> | 2026-08-13 22:55:06 +0200 |
|---|---|---|
| committer | Eugen Wissner <belka@caraus.de> | 2026-08-13 22:55:06 +0200 |
| commit | bf7416a3ef9f0b787dcaebf816f3f3e6e385ff42 (patch) | |
| tree | 26359c705133dbd8e98f06483008a720d0dae9d7 /boot/result.cc | |
| parent | ae29de96c94e5c582f4424804464cdd29bf2a013 (diff) | |
| download | elna-bf7416a3ef9f0b787dcaebf816f3f3e6e385ff42.tar.gz | |
Implement fixed-size integers
Diffstat (limited to 'boot/result.cc')
| -rw-r--r-- | boot/result.cc | 86 |
1 files changed, 64 insertions, 22 deletions
diff --git a/boot/result.cc b/boot/result.cc index 30b4576..15fe8b4 100644 --- a/boot/result.cc +++ b/boot/result.cc @@ -226,7 +226,7 @@ namespace elna::boot std::optional<integer_literal> integer_literal::neg() const { - if (!is_signed() || is_negative_minimum()) + if (!is_signed() || is_negative_minimum(bits())) { return std::nullopt; } @@ -237,32 +237,44 @@ namespace elna::boot return result; } + std::optional<integer_literal> integer_literal::negate() const + { + integer_literal result{ true, this->m_size }; + + mpz_set(result.raw, this->raw); + mpz_neg(result.raw, result.raw); + + return std::move(result).check(); + } + std::optional<integer_literal> integer_literal::shl(const integer_literal& that) const { if (that >= bits()) { return std::nullopt; } - integer_literal result = *this; - - mpz_mul_2exp(result.raw, this->raw, static_cast<mp_bitcnt_t>(mpz_get_ui(that.raw))); + else + { + integer_literal result = *this; - return std::move(result).check(); + mpz_mul_2exp(result.raw, this->raw, static_cast<mp_bitcnt_t>(mpz_get_ui(that.raw))); + return std::make_optional(std::move(result).cast_to(is_signed(), size())); + } } std::optional<integer_literal> integer_literal::shr(const integer_literal& that) const { - integer_literal result = *this; - if (that >= bits()) { - mpz_set_si(result.raw, *this > 0 ? 0 : -1); + return std::nullopt; } else { + integer_literal result = *this; + mpz_fdiv_q_2exp(result.raw, this->raw, static_cast<mp_bitcnt_t>(mpz_get_ui(that.raw))); + return std::make_optional(std::move(result)); } - return std::make_optional(std::move(result)); } integer_literal integer_literal::operator|(const integer_literal& that) const @@ -298,7 +310,7 @@ namespace elna::boot mpz_com(result.raw, this->raw); - return result; + return std::move(result).cast_to(is_signed(), size()); } bool integer_literal::operator==(const integer_literal& that) const @@ -328,16 +340,49 @@ namespace elna::boot return *this; } - bool integer_literal::fit_into(const std::size_t target_size) + bool integer_literal::fit_into(bool target_signed, const std::size_t target_size) { - if (fits_in(target_size * CHAR_BIT)) + if (fits_in(target_signed, target_size * CHAR_BIT)) { + this->m_signed = target_signed; this->m_size = target_size; return true; } return false; } + bool integer_literal::fit_into(const std::size_t target_size) + { + return fit_into(is_signed(), target_size); + } + + integer_literal integer_literal::cast_to(bool target_signed, std::size_t target_size) const + { + integer_literal result{ target_signed, target_size }; + const std::size_t bits = target_size * CHAR_BIT; + + // Reduce to the unsigned residue in [0, 2^bits). This is the bit pattern + // resulting from truncating or zero-extending in two's complement, + // regardless of the source's sign. + mpz_fdiv_r_2exp(result.raw, this->raw, bits); + + // Since GMP doesn't store the value as 2's complement, if the value is + // signed it should be converted manually. + if (target_signed && mpz_tstbit(result.raw, bits - 1)) + { + mpz_t modulus; + + mpz_init(modulus); + mpz_set_ui(modulus, 1); + mpz_mul_2exp(modulus, modulus, bits); + + mpz_sub(result.raw, result.raw, modulus); + + mpz_clear(modulus); + } + return result; + } + bool integer_literal::is_signed() const { return this->m_signed; @@ -367,30 +412,27 @@ namespace elna::boot std::swap(lhs.m_size, rhs.m_size); } - bool integer_literal::fits_in(const std::size_t bits) const + bool integer_literal::fits_in(bool target_signed, const std::size_t bits) const { std::size_t required_bits = mpz_sizeinbase(this->raw, 2); - if (!is_negative() || !is_negative_minimum(bits)) + if (target_signed && !is_negative_minimum(bits)) { ++required_bits; // Add one bit for the sign. } - return required_bits <= bits && (!is_negative() || is_signed()); + return required_bits <= bits && (!is_negative() || target_signed); } std::optional<integer_literal> integer_literal::check() && { - return fits_in(bits()) ? std::make_optional(std::move(*this)) : std::nullopt; + return fits_in(is_signed(), bits()) + ? std::make_optional(std::move(*this)) + : std::nullopt; } bool integer_literal::is_negative_minimum(const std::size_t bits) const { - return mpz_scan1(this->raw, 0) == bits - 1; - } - - bool integer_literal::is_negative_minimum() const - { - return is_negative() && is_negative_minimum(bits()); + return is_negative() && mpz_scan1(this->raw, 0) == bits - 1; } std::size_t integer_literal::bits() const |
