From 12c8bc3e856300b7a42c2027df042ee22f21077f Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Sat, 21 Jan 2023 12:34:01 -0500 Subject: [PATCH] AK: Add a String factory to create a string from a single code point --- AK/String.h | 19 +++++++++++++++++++ Tests/AK/TestString.cpp | 25 ++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/AK/String.h b/AK/String.h index dc73fe7d55..7aca7b50dc 100644 --- a/AK/String.h +++ b/AK/String.h @@ -1,11 +1,13 @@ /* * Copyright (c) 2018-2022, Andreas Kling + * Copyright (c) 2023, Tim Flynn * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once +#include #include #include #include @@ -16,6 +18,7 @@ #include #include #include +#include #include namespace AK { @@ -74,6 +77,22 @@ public: return String { short_string }; } + // Creates a new String from a single code point. + static constexpr String from_code_point(u32 code_point) + { + VERIFY(is_unicode(code_point)); + + ShortString short_string; + size_t i = 0; + + auto length = UnicodeUtils::code_point_to_utf8(code_point, [&](auto byte) { + short_string.storage[i++] = static_cast(byte); + }); + short_string.byte_count_and_short_string_flag = (length << 1) | SHORT_STRING_FLAG; + + return String { short_string }; + } + // Creates a new String by case-transforming this String. Using these methods require linking LibUnicode into your application. ErrorOr to_lowercase(Optional const& locale = {}) const; ErrorOr to_uppercase(Optional const& locale = {}) const; diff --git a/Tests/AK/TestString.cpp b/Tests/AK/TestString.cpp index c5785c7dab..f90b7bf393 100644 --- a/Tests/AK/TestString.cpp +++ b/Tests/AK/TestString.cpp @@ -4,9 +4,12 @@ * SPDX-License-Identifier: BSD-2-Clause */ +// This is included first on purpose. We specifically do not want LibTest to override VERIFY here so +// that we can actually test that some String factory methods cause a crash with invalid input. +#include + #include -#include #include #include #include @@ -64,6 +67,26 @@ TEST_CASE(long_strings) EXPECT_EQ(string.bytes_as_string_view(), "abcdefgh"sv); } +TEST_CASE(from_code_points) +{ + for (u32 code_point = 0; code_point < 0x80; ++code_point) { + auto string = String::from_code_point(code_point); + + auto ch = static_cast(code_point); + StringView view { &ch, 1 }; + + EXPECT_EQ(string, view); + } + + auto string = String::from_code_point(0x10ffff); + EXPECT_EQ(string, "\xF4\x8F\xBF\xBF"sv); + + EXPECT_CRASH("Creating a string from an invalid code point", [] { + String::from_code_point(0xffffffff); + return Test::Crash::Failure::DidNotCrash; + }); +} + TEST_CASE(substring) { auto superstring = MUST(String::from_utf8("Hello I am a long string"sv));