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>
|
template<typename WordType>
|
||||||
ALWAYS_INLINE constexpr WordType add_words(WordType word1, WordType word2, bool& carry)
|
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)
|
#if __has_builtin(__builtin_addc)
|
||||||
WordType ncarry, output;
|
WordType ncarry, output;
|
||||||
if constexpr (SameAs<WordType, unsigned int>)
|
if constexpr (SameAs<WordType, unsigned int>)
|
||||||
@@ -215,22 +226,23 @@ ALWAYS_INLINE constexpr WordType add_words(WordType word1, WordType word2, bool&
|
|||||||
}
|
}
|
||||||
#endif
|
#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>
|
template<typename WordType>
|
||||||
ALWAYS_INLINE constexpr WordType sub_words(WordType word1, WordType word2, bool& carry)
|
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)
|
#if __has_builtin(__builtin_subc)
|
||||||
WordType ncarry, output;
|
WordType ncarry, output;
|
||||||
if constexpr (SameAs<WordType, unsigned int>)
|
if constexpr (SameAs<WordType, unsigned int>)
|
||||||
@@ -257,16 +269,6 @@ ALWAYS_INLINE constexpr WordType sub_words(WordType word1, WordType word2, bool&
|
|||||||
}
|
}
|
||||||
#endif
|
#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>
|
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...) \
|
#define CONSTEXPR_STATE(function, args...) \
|
||||||
if (is_constant_evaluated()) { \
|
if consteval { \
|
||||||
if (IsSame<T, long double>) \
|
if constexpr (IsSame<T, long double>) \
|
||||||
return __builtin_##function##l(args); \
|
return __builtin_##function##l(args); \
|
||||||
if (IsSame<T, double>) \
|
if constexpr (IsSame<T, double>) \
|
||||||
return __builtin_##function(args); \
|
return __builtin_##function(args); \
|
||||||
if (IsSame<T, float>) \
|
if constexpr (IsSame<T, float>) \
|
||||||
return __builtin_##function##f(args); \
|
return __builtin_##function##f(args); \
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,7 +110,7 @@ template<FloatingPoint T>
|
|||||||
constexpr T ceil(T num)
|
constexpr T ceil(T num)
|
||||||
{
|
{
|
||||||
// FIXME: SSE4.1 rounds[sd] num, res, 0b110
|
// FIXME: SSE4.1 rounds[sd] num, res, 0b110
|
||||||
if (is_constant_evaluated()) {
|
if consteval {
|
||||||
if (num < NumericLimits<i64>::min() || num > NumericLimits<i64>::max())
|
if (num < NumericLimits<i64>::min() || num > NumericLimits<i64>::max())
|
||||||
return num;
|
return num;
|
||||||
return (static_cast<T>(static_cast<i64>(num)) == num)
|
return (static_cast<T>(static_cast<i64>(num)) == num)
|
||||||
@@ -133,7 +133,7 @@ template<FloatingPoint T>
|
|||||||
constexpr T floor(T num)
|
constexpr T floor(T num)
|
||||||
{
|
{
|
||||||
// FIXME: SSE4.1 rounds[sd] num, res, 0b101
|
// FIXME: SSE4.1 rounds[sd] num, res, 0b101
|
||||||
if (is_constant_evaluated()) {
|
if consteval {
|
||||||
if (num < NumericLimits<i64>::min() || num > NumericLimits<i64>::max())
|
if (num < NumericLimits<i64>::min() || num > NumericLimits<i64>::max())
|
||||||
return num;
|
return num;
|
||||||
return (static_cast<T>(static_cast<i64>(num)) == num)
|
return (static_cast<T>(static_cast<i64>(num)) == num)
|
||||||
@@ -156,7 +156,7 @@ template<FloatingPoint T>
|
|||||||
constexpr T trunc(T num)
|
constexpr T trunc(T num)
|
||||||
{
|
{
|
||||||
#if ARCH(AARCH64)
|
#if ARCH(AARCH64)
|
||||||
if (is_constant_evaluated()) {
|
if consteval {
|
||||||
if (num < NumericLimits<i64>::min() || num > NumericLimits<i64>::max())
|
if (num < NumericLimits<i64>::min() || num > NumericLimits<i64>::max())
|
||||||
return num;
|
return num;
|
||||||
return static_cast<T>(static_cast<i64>(num));
|
return static_cast<T>(static_cast<i64>(num));
|
||||||
@@ -601,7 +601,7 @@ constexpr T cos(T angle)
|
|||||||
template<FloatingPoint T>
|
template<FloatingPoint T>
|
||||||
constexpr void sincos(T angle, T& sin_val, T& cos_val)
|
constexpr void sincos(T angle, T& sin_val, T& cos_val)
|
||||||
{
|
{
|
||||||
if (is_constant_evaluated()) {
|
if consteval {
|
||||||
sin_val = sin(angle);
|
sin_val = sin(angle);
|
||||||
cos_val = cos(angle);
|
cos_val = cos(angle);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -376,22 +376,23 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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.
|
// OPTIMIZATION: Only construct the `m_null` member when we are constant-evaluating. Otherwise, this generates
|
||||||
// Otherwise, this generates an unnecessary zero-fill.
|
// an unnecessary zero-fill.
|
||||||
#if defined(AK_COMPILER_GCC)
|
#if defined(AK_COMPILER_GCC)
|
||||||
// NOTE: GCCs -Wuninitialized warning ends up checking this as well.
|
// GCC's -Wuninitialized warning ends up checking this as well.
|
||||||
should_construct = true;
|
construct_at(&m_null);
|
||||||
#endif
|
#else
|
||||||
if (should_construct)
|
if consteval {
|
||||||
construct_at(&m_null);
|
construct_at(&m_null);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
union {
|
union {
|
||||||
// FIXME: GCC seems to have an issue with uninitialized unions and non trivial types,
|
// FIXME: GCC seems to have an issue with uninitialized unions and non trivial types, which forces us to have an
|
||||||
// which forces us to have an equally sized trivial null member in the union
|
// equally sized trivial null member in the union to pseudo-initialize the union.
|
||||||
// to pseudo-initialize the union.
|
|
||||||
struct {
|
struct {
|
||||||
u8 _[sizeof(T)];
|
u8 _[sizeof(T)];
|
||||||
} m_null;
|
} m_null;
|
||||||
|
|||||||
@@ -122,20 +122,11 @@ requires(IsEnum<V>)
|
|||||||
return static_cast<UnderlyingType<V>>(value);
|
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>
|
template<typename T>
|
||||||
ALWAYS_INLINE constexpr void taint_for_optimizer(T& value)
|
ALWAYS_INLINE constexpr void taint_for_optimizer(T& value)
|
||||||
requires(IsIntegral<T>)
|
requires(IsIntegral<T>)
|
||||||
{
|
{
|
||||||
if (!is_constant_evaluated()) {
|
if !consteval {
|
||||||
asm volatile(""
|
asm volatile(""
|
||||||
: "+r"(value));
|
: "+r"(value));
|
||||||
}
|
}
|
||||||
@@ -145,7 +136,7 @@ template<typename T>
|
|||||||
ALWAYS_INLINE constexpr void taint_for_optimizer(T& value)
|
ALWAYS_INLINE constexpr void taint_for_optimizer(T& value)
|
||||||
requires(!IsIntegral<T>)
|
requires(!IsIntegral<T>)
|
||||||
{
|
{
|
||||||
if (!is_constant_evaluated()) {
|
if !consteval {
|
||||||
asm volatile(""
|
asm volatile(""
|
||||||
:
|
:
|
||||||
: "m"(value)
|
: "m"(value)
|
||||||
@@ -158,9 +149,11 @@ requires(!IsIntegral<T>)
|
|||||||
#define __DEFINE_GENERIC_ABS(type, zero, intrinsic) \
|
#define __DEFINE_GENERIC_ABS(type, zero, intrinsic) \
|
||||||
constexpr type abs(type num) \
|
constexpr type abs(type num) \
|
||||||
{ \
|
{ \
|
||||||
if (is_constant_evaluated()) \
|
if consteval { \
|
||||||
return num < (zero) ? -num : num; \
|
return num < (zero) ? -num : num; \
|
||||||
return __builtin_##intrinsic(num); \
|
} else { \
|
||||||
|
return __builtin_##intrinsic(num); \
|
||||||
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
__DEFINE_GENERIC_ABS(int, 0, abs);
|
__DEFINE_GENERIC_ABS(int, 0, abs);
|
||||||
@@ -180,7 +173,6 @@ using AK::ceil_div;
|
|||||||
using AK::clamp;
|
using AK::clamp;
|
||||||
using AK::exchange;
|
using AK::exchange;
|
||||||
using AK::forward;
|
using AK::forward;
|
||||||
using AK::is_constant_evaluated;
|
|
||||||
using AK::is_power_of_two;
|
using AK::is_power_of_two;
|
||||||
using AK::max;
|
using AK::max;
|
||||||
using AK::min;
|
using AK::min;
|
||||||
|
|||||||
@@ -59,16 +59,19 @@ public:
|
|||||||
|
|
||||||
constexpr ~StringBase()
|
constexpr ~StringBase()
|
||||||
{
|
{
|
||||||
if (!is_constant_evaluated())
|
if !consteval {
|
||||||
destroy_string();
|
destroy_string();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: This is primarily interesting to unit tests.
|
// NOTE: This is primarily interesting to unit tests.
|
||||||
[[nodiscard]] constexpr bool is_short_string() const
|
[[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;
|
return (m_impl.short_string.byte_count_and_short_string_flag & SHORT_STRING_FLAG) != 0;
|
||||||
return (short_string_without_union_member_assertion().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.
|
// Returns the underlying UTF-8 encoded bytes.
|
||||||
|
|||||||
@@ -27,8 +27,9 @@ public:
|
|||||||
: m_characters(characters)
|
: m_characters(characters)
|
||||||
, m_length(length)
|
, m_length(length)
|
||||||
{
|
{
|
||||||
if (!is_constant_evaluated())
|
if !consteval {
|
||||||
VERIFY(!Checked<uintptr_t>::addition_would_overflow(reinterpret_cast<uintptr_t>(characters), length));
|
VERIFY(!Checked<uintptr_t>::addition_would_overflow(reinterpret_cast<uintptr_t>(characters), length));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE StringView(unsigned char const* characters, size_t length)
|
ALWAYS_INLINE StringView(unsigned char const* characters, size_t length)
|
||||||
@@ -67,8 +68,9 @@ public:
|
|||||||
|
|
||||||
constexpr char const& operator[](size_t index) const
|
constexpr char const& operator[](size_t index) const
|
||||||
{
|
{
|
||||||
if (!is_constant_evaluated())
|
if !consteval {
|
||||||
VERIFY(index < m_length);
|
VERIFY(index < m_length);
|
||||||
|
}
|
||||||
return m_characters[index];
|
return m_characters[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,15 +118,17 @@ public:
|
|||||||
|
|
||||||
[[nodiscard]] constexpr StringView substring_view(size_t start, size_t length) const
|
[[nodiscard]] constexpr StringView substring_view(size_t start, size_t length) const
|
||||||
{
|
{
|
||||||
if (!is_constant_evaluated())
|
if !consteval {
|
||||||
VERIFY(start + length <= m_length);
|
VERIFY(start + length <= m_length);
|
||||||
|
}
|
||||||
return { m_characters + start, length };
|
return { m_characters + start, length };
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] constexpr StringView substring_view(size_t start) const
|
[[nodiscard]] constexpr StringView substring_view(size_t start) const
|
||||||
{
|
{
|
||||||
if (!is_constant_evaluated())
|
if !consteval {
|
||||||
VERIFY(start <= length());
|
VERIFY(start <= length());
|
||||||
|
}
|
||||||
return substring_view(start, length() - start);
|
return substring_view(start, length() - start);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,10 +60,12 @@ unsigned day_of_week(int year, unsigned month, int day);
|
|||||||
// can be negative.
|
// can be negative.
|
||||||
constexpr int day_of_year(int year, unsigned month, int day)
|
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.
|
VERIFY(month >= 1 && month <= 12); // Note that this prevents bad constexpr months, but never actually prints anything.
|
||||||
else if (!(month >= 1 && month <= 12))
|
} else {
|
||||||
return 0;
|
if (!(month >= 1 && month <= 12))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
constexpr Array seek_table = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
|
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;
|
int day_of_year = seek_table[month - 1] + day - 1;
|
||||||
|
|||||||
@@ -49,8 +49,9 @@ public:
|
|||||||
|
|
||||||
constexpr ~Utf16StringBase()
|
constexpr ~Utf16StringBase()
|
||||||
{
|
{
|
||||||
if (!is_constant_evaluated())
|
if !consteval {
|
||||||
destroy_string();
|
destroy_string();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE operator Utf16View() const& LIFETIME_BOUND { return utf16_view(); }
|
ALWAYS_INLINE operator Utf16View() const& LIFETIME_BOUND { return utf16_view(); }
|
||||||
@@ -278,9 +279,11 @@ public:
|
|||||||
// This is primarily interesting to unit tests.
|
// This is primarily interesting to unit tests.
|
||||||
[[nodiscard]] constexpr bool has_short_ascii_storage() const
|
[[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;
|
return (m_value.short_ascii_string.byte_count_and_short_string_flag & StringBase::SHORT_STRING_FLAG) != 0;
|
||||||
return (short_ascii_string_without_union_member_assertion().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.
|
// This is primarily interesting to unit tests.
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ public:
|
|||||||
constexpr Matrix& operator=(Matrix const& other)
|
constexpr Matrix& operator=(Matrix const& other)
|
||||||
{
|
{
|
||||||
#ifndef __clang__
|
#ifndef __clang__
|
||||||
if (is_constant_evaluated()) {
|
if consteval {
|
||||||
for (size_t i = 0; i < N; i++) {
|
for (size_t i = 0; i < N; i++) {
|
||||||
for (size_t j = 0; j < N; j++) {
|
for (size_t j = 0; j < N; j++) {
|
||||||
(*this)[i, j] = other[i, j];
|
(*this)[i, j] = other[i, j];
|
||||||
|
|||||||
Reference in New Issue
Block a user