mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-25 17:25:08 +02:00
AK+LibGfx: Prefer if consteval over is_constant_evaluated
This is a new language construct in C++23, meant to generally replace is_constant_evaluated. See: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1938r3.html#problems-with-status-quo
This commit is contained in:
Notes:
github-actions[bot]
2026-02-22 18:57:04 +00:00
Author: https://github.com/trflynn89 Commit: https://github.com/LadybirdBrowser/ladybird/commit/6bc66fe7867 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/8088
@@ -188,7 +188,18 @@ ALWAYS_INLINE constexpr Word extend_sign(bool sign)
|
||||
template<typename WordType>
|
||||
ALWAYS_INLINE constexpr WordType add_words(WordType word1, WordType word2, bool& carry)
|
||||
{
|
||||
if (!is_constant_evaluated()) {
|
||||
if consteval {
|
||||
// Note: This is usually too confusing for both GCC and Clang.
|
||||
WordType output;
|
||||
bool ncarry = __builtin_add_overflow(word1, word2, &output);
|
||||
if (carry) {
|
||||
++output;
|
||||
if (output == 0)
|
||||
ncarry = true;
|
||||
}
|
||||
carry = ncarry;
|
||||
return output;
|
||||
} else {
|
||||
#if __has_builtin(__builtin_addc)
|
||||
WordType ncarry, output;
|
||||
if constexpr (SameAs<WordType, unsigned int>)
|
||||
@@ -215,22 +226,23 @@ ALWAYS_INLINE constexpr WordType add_words(WordType word1, WordType word2, bool&
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// Note: This is usually too confusing for both GCC and Clang.
|
||||
WordType output;
|
||||
bool ncarry = __builtin_add_overflow(word1, word2, &output);
|
||||
if (carry) {
|
||||
++output;
|
||||
if (output == 0)
|
||||
ncarry = true;
|
||||
}
|
||||
carry = ncarry;
|
||||
return output;
|
||||
}
|
||||
|
||||
template<typename WordType>
|
||||
ALWAYS_INLINE constexpr WordType sub_words(WordType word1, WordType word2, bool& carry)
|
||||
{
|
||||
if (!is_constant_evaluated()) {
|
||||
if consteval {
|
||||
// Note: This is usually too confusing for both GCC and Clang.
|
||||
WordType output;
|
||||
bool ncarry = __builtin_sub_overflow(word1, word2, &output);
|
||||
if (carry) {
|
||||
if (output == 0)
|
||||
ncarry = true;
|
||||
--output;
|
||||
}
|
||||
carry = ncarry;
|
||||
return output;
|
||||
} else {
|
||||
#if __has_builtin(__builtin_subc)
|
||||
WordType ncarry, output;
|
||||
if constexpr (SameAs<WordType, unsigned int>)
|
||||
@@ -257,16 +269,6 @@ ALWAYS_INLINE constexpr WordType sub_words(WordType word1, WordType word2, bool&
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// Note: This is usually too confusing for both GCC and Clang.
|
||||
WordType output;
|
||||
bool ncarry = __builtin_sub_overflow(word1, word2, &output);
|
||||
if (carry) {
|
||||
if (output == 0)
|
||||
ncarry = true;
|
||||
--output;
|
||||
}
|
||||
carry = ncarry;
|
||||
return output;
|
||||
}
|
||||
|
||||
template<typename WordType>
|
||||
|
||||
16
AK/Math.h
16
AK/Math.h
@@ -65,12 +65,12 @@ constexpr T to_degrees(T radians)
|
||||
}
|
||||
|
||||
#define CONSTEXPR_STATE(function, args...) \
|
||||
if (is_constant_evaluated()) { \
|
||||
if (IsSame<T, long double>) \
|
||||
if consteval { \
|
||||
if constexpr (IsSame<T, long double>) \
|
||||
return __builtin_##function##l(args); \
|
||||
if (IsSame<T, double>) \
|
||||
if constexpr (IsSame<T, double>) \
|
||||
return __builtin_##function(args); \
|
||||
if (IsSame<T, float>) \
|
||||
if constexpr (IsSame<T, float>) \
|
||||
return __builtin_##function##f(args); \
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ template<FloatingPoint T>
|
||||
constexpr T ceil(T num)
|
||||
{
|
||||
// FIXME: SSE4.1 rounds[sd] num, res, 0b110
|
||||
if (is_constant_evaluated()) {
|
||||
if consteval {
|
||||
if (num < NumericLimits<i64>::min() || num > NumericLimits<i64>::max())
|
||||
return num;
|
||||
return (static_cast<T>(static_cast<i64>(num)) == num)
|
||||
@@ -133,7 +133,7 @@ template<FloatingPoint T>
|
||||
constexpr T floor(T num)
|
||||
{
|
||||
// FIXME: SSE4.1 rounds[sd] num, res, 0b101
|
||||
if (is_constant_evaluated()) {
|
||||
if consteval {
|
||||
if (num < NumericLimits<i64>::min() || num > NumericLimits<i64>::max())
|
||||
return num;
|
||||
return (static_cast<T>(static_cast<i64>(num)) == num)
|
||||
@@ -156,7 +156,7 @@ template<FloatingPoint T>
|
||||
constexpr T trunc(T num)
|
||||
{
|
||||
#if ARCH(AARCH64)
|
||||
if (is_constant_evaluated()) {
|
||||
if consteval {
|
||||
if (num < NumericLimits<i64>::min() || num > NumericLimits<i64>::max())
|
||||
return num;
|
||||
return static_cast<T>(static_cast<i64>(num));
|
||||
@@ -601,7 +601,7 @@ constexpr T cos(T angle)
|
||||
template<FloatingPoint T>
|
||||
constexpr void sincos(T angle, T& sin_val, T& cos_val)
|
||||
{
|
||||
if (is_constant_evaluated()) {
|
||||
if consteval {
|
||||
sin_val = sin(angle);
|
||||
cos_val = cos(angle);
|
||||
return;
|
||||
|
||||
@@ -376,22 +376,23 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
ALWAYS_INLINE constexpr void construct_null_if_necessary(bool should_construct = is_constant_evaluated())
|
||||
ALWAYS_INLINE constexpr void construct_null_if_necessary()
|
||||
{
|
||||
// OPTIMIZATION: Only construct the `m_null` member when we are constant-evaluating.
|
||||
// Otherwise, this generates an unnecessary zero-fill.
|
||||
// OPTIMIZATION: Only construct the `m_null` member when we are constant-evaluating. Otherwise, this generates
|
||||
// an unnecessary zero-fill.
|
||||
#if defined(AK_COMPILER_GCC)
|
||||
// NOTE: GCCs -Wuninitialized warning ends up checking this as well.
|
||||
should_construct = true;
|
||||
#endif
|
||||
if (should_construct)
|
||||
// GCC's -Wuninitialized warning ends up checking this as well.
|
||||
construct_at(&m_null);
|
||||
#else
|
||||
if consteval {
|
||||
construct_at(&m_null);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
union {
|
||||
// FIXME: GCC seems to have an issue with uninitialized unions and non trivial types,
|
||||
// which forces us to have an equally sized trivial null member in the union
|
||||
// to pseudo-initialize the union.
|
||||
// FIXME: GCC seems to have an issue with uninitialized unions and non trivial types, which forces us to have an
|
||||
// equally sized trivial null member in the union to pseudo-initialize the union.
|
||||
struct {
|
||||
u8 _[sizeof(T)];
|
||||
} m_null;
|
||||
|
||||
@@ -122,20 +122,11 @@ requires(IsEnum<V>)
|
||||
return static_cast<UnderlyingType<V>>(value);
|
||||
}
|
||||
|
||||
constexpr bool is_constant_evaluated()
|
||||
{
|
||||
#if __has_builtin(__builtin_is_constant_evaluated)
|
||||
return __builtin_is_constant_evaluated();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
ALWAYS_INLINE constexpr void taint_for_optimizer(T& value)
|
||||
requires(IsIntegral<T>)
|
||||
{
|
||||
if (!is_constant_evaluated()) {
|
||||
if !consteval {
|
||||
asm volatile(""
|
||||
: "+r"(value));
|
||||
}
|
||||
@@ -145,7 +136,7 @@ template<typename T>
|
||||
ALWAYS_INLINE constexpr void taint_for_optimizer(T& value)
|
||||
requires(!IsIntegral<T>)
|
||||
{
|
||||
if (!is_constant_evaluated()) {
|
||||
if !consteval {
|
||||
asm volatile(""
|
||||
:
|
||||
: "m"(value)
|
||||
@@ -158,9 +149,11 @@ requires(!IsIntegral<T>)
|
||||
#define __DEFINE_GENERIC_ABS(type, zero, intrinsic) \
|
||||
constexpr type abs(type num) \
|
||||
{ \
|
||||
if (is_constant_evaluated()) \
|
||||
if consteval { \
|
||||
return num < (zero) ? -num : num; \
|
||||
} else { \
|
||||
return __builtin_##intrinsic(num); \
|
||||
} \
|
||||
}
|
||||
|
||||
__DEFINE_GENERIC_ABS(int, 0, abs);
|
||||
@@ -180,7 +173,6 @@ using AK::ceil_div;
|
||||
using AK::clamp;
|
||||
using AK::exchange;
|
||||
using AK::forward;
|
||||
using AK::is_constant_evaluated;
|
||||
using AK::is_power_of_two;
|
||||
using AK::max;
|
||||
using AK::min;
|
||||
|
||||
@@ -59,17 +59,20 @@ public:
|
||||
|
||||
constexpr ~StringBase()
|
||||
{
|
||||
if (!is_constant_evaluated())
|
||||
if !consteval {
|
||||
destroy_string();
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: This is primarily interesting to unit tests.
|
||||
[[nodiscard]] constexpr bool is_short_string() const
|
||||
{
|
||||
if (is_constant_evaluated())
|
||||
if consteval {
|
||||
return (m_impl.short_string.byte_count_and_short_string_flag & SHORT_STRING_FLAG) != 0;
|
||||
} else {
|
||||
return (short_string_without_union_member_assertion().byte_count_and_short_string_flag & SHORT_STRING_FLAG) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the underlying UTF-8 encoded bytes.
|
||||
// NOTE: There is no guarantee about null-termination.
|
||||
|
||||
@@ -27,9 +27,10 @@ public:
|
||||
: m_characters(characters)
|
||||
, m_length(length)
|
||||
{
|
||||
if (!is_constant_evaluated())
|
||||
if !consteval {
|
||||
VERIFY(!Checked<uintptr_t>::addition_would_overflow(reinterpret_cast<uintptr_t>(characters), length));
|
||||
}
|
||||
}
|
||||
|
||||
ALWAYS_INLINE StringView(unsigned char const* characters, size_t length)
|
||||
: m_characters(reinterpret_cast<char const*>(characters))
|
||||
@@ -67,8 +68,9 @@ public:
|
||||
|
||||
constexpr char const& operator[](size_t index) const
|
||||
{
|
||||
if (!is_constant_evaluated())
|
||||
if !consteval {
|
||||
VERIFY(index < m_length);
|
||||
}
|
||||
return m_characters[index];
|
||||
}
|
||||
|
||||
@@ -116,15 +118,17 @@ public:
|
||||
|
||||
[[nodiscard]] constexpr StringView substring_view(size_t start, size_t length) const
|
||||
{
|
||||
if (!is_constant_evaluated())
|
||||
if !consteval {
|
||||
VERIFY(start + length <= m_length);
|
||||
}
|
||||
return { m_characters + start, length };
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr StringView substring_view(size_t start) const
|
||||
{
|
||||
if (!is_constant_evaluated())
|
||||
if !consteval {
|
||||
VERIFY(start <= length());
|
||||
}
|
||||
return substring_view(start, length() - start);
|
||||
}
|
||||
|
||||
|
||||
@@ -60,10 +60,12 @@ unsigned day_of_week(int year, unsigned month, int day);
|
||||
// can be negative.
|
||||
constexpr int day_of_year(int year, unsigned month, int day)
|
||||
{
|
||||
if (is_constant_evaluated())
|
||||
if consteval {
|
||||
VERIFY(month >= 1 && month <= 12); // Note that this prevents bad constexpr months, but never actually prints anything.
|
||||
else if (!(month >= 1 && month <= 12))
|
||||
} else {
|
||||
if (!(month >= 1 && month <= 12))
|
||||
return 0;
|
||||
}
|
||||
|
||||
constexpr Array seek_table = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
|
||||
int day_of_year = seek_table[month - 1] + day - 1;
|
||||
|
||||
@@ -49,9 +49,10 @@ public:
|
||||
|
||||
constexpr ~Utf16StringBase()
|
||||
{
|
||||
if (!is_constant_evaluated())
|
||||
if !consteval {
|
||||
destroy_string();
|
||||
}
|
||||
}
|
||||
|
||||
ALWAYS_INLINE operator Utf16View() const& LIFETIME_BOUND { return utf16_view(); }
|
||||
explicit operator Utf16View() const&& = delete;
|
||||
@@ -278,10 +279,12 @@ public:
|
||||
// This is primarily interesting to unit tests.
|
||||
[[nodiscard]] constexpr bool has_short_ascii_storage() const
|
||||
{
|
||||
if (is_constant_evaluated())
|
||||
if consteval {
|
||||
return (m_value.short_ascii_string.byte_count_and_short_string_flag & StringBase::SHORT_STRING_FLAG) != 0;
|
||||
} else {
|
||||
return (short_ascii_string_without_union_member_assertion().byte_count_and_short_string_flag & StringBase::SHORT_STRING_FLAG) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
// This is primarily interesting to unit tests.
|
||||
[[nodiscard]] ALWAYS_INLINE bool has_long_ascii_storage() const
|
||||
|
||||
@@ -46,7 +46,7 @@ public:
|
||||
constexpr Matrix& operator=(Matrix const& other)
|
||||
{
|
||||
#ifndef __clang__
|
||||
if (is_constant_evaluated()) {
|
||||
if consteval {
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
for (size_t j = 0; j < N; j++) {
|
||||
(*this)[i, j] = other[i, j];
|
||||
|
||||
Reference in New Issue
Block a user