aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2026-08-06 23:12:01 +0200
committerEugen Wissner <belka@caraus.de>2026-08-06 23:12:01 +0200
commiteaf5934f81dcd8ce5705f13b651d7b93ca8c459f (patch)
tree890d2d69a3e80d1d3a64e69cb4af69a190986c5f /include
parentb2dee14873402ee3d13d59ae5579593796ea862f (diff)
downloadelna-eaf5934f81dcd8ce5705f13b651d7b93ca8c459f.tar.gz
Implement compile time castings for integers
Diffstat (limited to 'include')
-rw-r--r--include/elna/boot/evaluator.h3
-rw-r--r--include/elna/boot/result.h77
2 files changed, 58 insertions, 22 deletions
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<std::size_t> evaluate_traits_size(const type& subject);
std::optional<std::size_t> evaluate_traits_alignment(const type& subject);
+ static std::optional<constant_value> cast_to_int(const constant_value& source_expression);
+ static std::optional<constant_value> cast_to_word(const constant_value& source_expression);
+
public:
std::optional<std::size_t> evaluate_index(expression& subject);
std::optional<constant_value> 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<typename T>
- inline constexpr bool is_signed = std::is_same_v<T, std::int8_t>
+ inline constexpr bool is_signed_v = std::is_same_v<T, std::int8_t>
|| std::is_same_v<T, std::int16_t>
|| std::is_same_v<T, std::int32_t>
|| std::is_same_v<T, std::int64_t>;
@@ -239,10 +239,10 @@ namespace elna::boot
*
* \tparam T The examined type.
*
- * \see is_signed
+ * \see is_signed_v
*/
template<typename T>
- inline constexpr bool is_unsigned = std::is_same_v<T, std::uint8_t>
+ inline constexpr bool is_unsigned_v = std::is_same_v<T, std::uint8_t>
|| std::is_same_v<T, std::uint16_t>
|| std::is_same_v<T, std::uint32_t>
|| std::is_same_v<T, std::uint64_t>;
@@ -255,7 +255,7 @@ namespace elna::boot
* \tparam T The examined type.
*/
template<typename T>
- inline constexpr bool is_integral = is_signed<T> || is_unsigned<T>;
+ inline constexpr bool is_integral = is_signed_v<T> || is_unsigned_v<T>;
struct integer_literal
{
@@ -281,25 +281,25 @@ namespace elna::boot
std::weak_ordering operator<=>(const integer_literal& that) const;
template<typename U>
bool operator==(U that) const
- requires(is_unsigned<U> && sizeof(U) <= sizeof(unsigned long int))
+ requires(is_unsigned_v<U> && sizeof(U) <= sizeof(unsigned long int))
{
return mpz_cmp_ui(this->raw, that) == 0;
}
template<typename U>
bool operator==(U that) const
- requires(is_signed<U> && sizeof(U) <= sizeof(signed long int))
+ requires(is_signed_v<U> && sizeof(U) <= sizeof(signed long int))
{
return mpz_cmp_si(this->raw, that) == 0;
}
template<typename U>
std::weak_ordering operator<=>(U that) const
- requires(is_unsigned<U> && sizeof(U) <= sizeof(unsigned long int))
+ requires(is_unsigned_v<U> && sizeof(U) <= sizeof(unsigned long int))
{
return mpz_cmp_ui(this->raw, that) <=> 0;
}
template<typename U>
std::weak_ordering operator<=>(U that) const
- requires(is_signed<U> && sizeof(U) <= sizeof(signed long int))
+ requires(is_signed_v<U> && 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<std::ptrdiff_t> 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<std::size_t> to_unsigned() const;
+ template<typename T>
+ std::optional<T> try_to() const
+ requires is_integral<T>
+ {
+ if constexpr (is_signed_v<T>)
+ {
+ return to_signed<T>();
+ }
+ else if constexpr (is_unsigned_v<T>)
+ {
+ return to_unsigned<T>();
+ }
+ 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<integer_literal> 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<typename T = std::ptrdiff_t>
+ std::optional<T> to_signed() const
+ {
+ if (is_negative_minimum(sizeof(T) * CHAR_BIT))
+ {
+ return std::numeric_limits<T>::min();
+ }
+ auto [written, rop] = export_to_words<T>();
+
+ if (written > 1 || rop < 0)
+ {
+ return std::nullopt;
+ }
+ return is_negative() ? -rop : rop;
+ }
+
+ template<typename T = std::size_t>
+ std::optional<T> to_unsigned() const
+ {
+ auto [written, rop] = export_to_words<T>();
+
+ return written > 1 ? std::nullopt : std::make_optional(rop);
+ }
};
/**