diff --git a/AK/StdLibExtras.h b/AK/StdLibExtras.h index 1ac5b1347d6..ac074bf72a7 100644 --- a/AK/StdLibExtras.h +++ b/AK/StdLibExtras.h @@ -116,6 +116,15 @@ constexpr decltype(auto) to_underlying(V value) requires(IsEnum) return static_cast>(value); } +constexpr bool is_constant_evaluated() +{ +#if __has_builtin(__builtin_is_constant_evaluated) + return __builtin_is_constant_evaluated(); +#else + return false; +#endif +} + } using AK::array_size; @@ -123,6 +132,7 @@ using AK::ceil_div; using AK::clamp; using AK::exchange; using AK::forward; +using AK::is_constant_evaluated; using AK::max; using AK::min; using AK::RawPtr; diff --git a/AK/StringView.h b/AK/StringView.h index 78dfa8494da..6cf0092ad45 100644 --- a/AK/StringView.h +++ b/AK/StringView.h @@ -24,7 +24,8 @@ public: : m_characters(characters) , m_length(length) { - VERIFY(!Checked::addition_would_overflow((uintptr_t)characters, length)); + if (!is_constant_evaluated()) + VERIFY(!Checked::addition_would_overflow((uintptr_t)characters, length)); } ALWAYS_INLINE StringView(const unsigned char* characters, size_t length) : m_characters((const char*)characters) @@ -93,7 +94,8 @@ public: [[nodiscard]] constexpr StringView substring_view(size_t start, size_t length) const { - VERIFY(start + length <= m_length); + if (!is_constant_evaluated()) + VERIFY(start + length <= m_length); return { m_characters + start, length }; } @@ -158,7 +160,7 @@ public: [[nodiscard]] StringView substring_view_starting_from_substring(const StringView& substring) const; [[nodiscard]] StringView substring_view_starting_after_substring(const StringView& substring) const; - bool operator==(const char* cstring) const + constexpr bool operator==(const char* cstring) const { if (is_null()) return !cstring; @@ -175,7 +177,7 @@ public: return !*cp; } - bool operator!=(const char* cstring) const + constexpr bool operator!=(const char* cstring) const { return !(*this == cstring); } diff --git a/Tests/AK/TestStringView.cpp b/Tests/AK/TestStringView.cpp index f9a786ec775..8f7785dce31 100644 --- a/Tests/AK/TestStringView.cpp +++ b/Tests/AK/TestStringView.cpp @@ -177,3 +177,28 @@ TEST_CASE(split_view) EXPECT_EQ(test_string_view.split_view_if(predicate), Vector({ "a", "b", "c", "d" })); EXPECT_EQ(test_string_view.split_view_if(predicate, true), Vector({ "a", "", "b", "c", "d" })); } + +TEST_CASE(constexpr_stuff) +{ +#define do_test() \ + static_assert(test_constexpr.length() == 3); \ + static_assert(!test_constexpr.is_empty()); \ + static_assert(test_constexpr.is_one_of("foo", "bar", "baz")); \ + static_assert(test_constexpr.is_one_of("foo"sv, "bar"sv, "baz"sv)); \ + static_assert(test_constexpr != "fob"sv); \ + static_assert(test_constexpr != "fob"); \ + static_assert(test_constexpr.substring_view(1).is_one_of("oo"sv)); + + { + // Can initialize from ""sv. + constexpr StringView test_constexpr { "foo"sv }; + do_test(); + } + + { + // Can initialize from char const*. + constexpr StringView test_constexpr { "foo" }; + do_test(); + } +#undef do_test +}