From eaf5934f81dcd8ce5705f13b651d7b93ca8c459f Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Thu, 6 Aug 2026 23:12:01 +0200 Subject: Implement compile time castings for integers --- include/elna/boot/evaluator.h | 3 ++ include/elna/boot/result.h | 77 ++++++++++++++++++++++++++++++------------- 2 files changed, 58 insertions(+), 22 deletions(-) (limited to 'include') diff --git a/include/elna/boot/evaluator.h b/include/elna/boot/evaluator.h index 0d1a7c8..02db6ab 100644 --- a/include/elna/boot/evaluator.h +++ b/include/elna/boot/evaluator.h @@ -86,6 +86,9 @@ namespace elna::boot std::optional evaluate_traits_size(const type& subject); std::optional evaluate_traits_alignment(const type& subject); + static std::optional cast_to_int(const constant_value& source_expression); + static std::optional cast_to_word(const constant_value& source_expression); + public: std::optional evaluate_index(expression& subject); std::optional evaluate_traits(traits_expression& subject); diff --git a/include/elna/boot/result.h b/include/elna/boot/result.h index 3d01eb2..49e078e 100644 --- a/include/elna/boot/result.h +++ b/include/elna/boot/result.h @@ -226,10 +226,10 @@ namespace elna::boot * * \tparam T The examined type. * - * \see is_unsigned + * \see is_unsigned_v */ template - inline constexpr bool is_signed = std::is_same_v + inline constexpr bool is_signed_v = std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v; @@ -239,10 +239,10 @@ namespace elna::boot * * \tparam T The examined type. * - * \see is_signed + * \see is_signed_v */ template - inline constexpr bool is_unsigned = std::is_same_v + inline constexpr bool is_unsigned_v = std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v; @@ -255,7 +255,7 @@ namespace elna::boot * \tparam T The examined type. */ template - inline constexpr bool is_integral = is_signed || is_unsigned; + inline constexpr bool is_integral = is_signed_v || is_unsigned_v; struct integer_literal { @@ -281,25 +281,25 @@ namespace elna::boot std::weak_ordering operator<=>(const integer_literal& that) const; template bool operator==(U that) const - requires(is_unsigned && sizeof(U) <= sizeof(unsigned long int)) + requires(is_unsigned_v && sizeof(U) <= sizeof(unsigned long int)) { return mpz_cmp_ui(this->raw, that) == 0; } template bool operator==(U that) const - requires(is_signed && sizeof(U) <= sizeof(signed long int)) + requires(is_signed_v && sizeof(U) <= sizeof(signed long int)) { return mpz_cmp_si(this->raw, that) == 0; } template std::weak_ordering operator<=>(U that) const - requires(is_unsigned && sizeof(U) <= sizeof(unsigned long int)) + requires(is_unsigned_v && sizeof(U) <= sizeof(unsigned long int)) { return mpz_cmp_ui(this->raw, that) <=> 0; } template std::weak_ordering operator<=>(U that) const - requires(is_signed && sizeof(U) <= sizeof(signed long int)) + requires(is_signed_v && sizeof(U) <= sizeof(signed long int)) { return mpz_cmp_si(this->raw, that) <=> 0; } @@ -312,23 +312,31 @@ namespace elna::boot std::string to_string(const std::uint8_t base = 10U) const; /** - * \return Whether the stored value is a negative integer. - */ - bool is_negative() const; - - /** - * Exports the stored value as a host \c std::ptrdiff_t. + * Exports the stored value as a host \p T. * - * \return The converted value, or \c std::nullopt if out of range. - */ - std::optional to_signed() const; - - /** - * Exports the stored value as a host \c std::size_t. + * This function tries to shrink or extend the value to fit into the + * target type if possible. * + * \tparam Target type. * \return The converted value, or \c std::nullopt if out of range. */ - std::optional to_unsigned() const; + template + std::optional try_to() const + requires is_integral + { + if constexpr (is_signed_v) + { + return to_signed(); + } + else if constexpr (is_unsigned_v) + { + return to_unsigned(); + } + else + { + static_assert("integer_literal::to expected only integral types"); + } + } /** * Attempts to narrow this literal's internally stored size to @@ -366,6 +374,7 @@ namespace elna::boot integer_literal(bool is_signed, std::size_t size); bool fits_in(const std::size_t bits) const; std::optional check() &&; + bool is_negative() const; bool is_negative_minimum(const std::size_t bits) const; bool is_negative_minimum() const; std::size_t bits() const; @@ -381,6 +390,30 @@ namespace elna::boot return { written, rop[0] }; } + + template + std::optional to_signed() const + { + if (is_negative_minimum(sizeof(T) * CHAR_BIT)) + { + return std::numeric_limits::min(); + } + auto [written, rop] = export_to_words(); + + if (written > 1 || rop < 0) + { + return std::nullopt; + } + return is_negative() ? -rop : rop; + } + + template + std::optional to_unsigned() const + { + auto [written, rop] = export_to_words(); + + return written > 1 ? std::nullopt : std::make_optional(rop); + } }; /** -- cgit v1.2.3