Skip to content

Commit

Permalink
Add utf16 implementation for Hermes runtime
Browse files Browse the repository at this point in the history
Summary:
Adds the utf16 implementation for SH runtime. This makes use of the SH
StringView implementation which already stores the ASCII or UTF16 string
content.

Grafted from 9525c490fcad813f3973a0463d685d9419db844a (D65366621)
- Grafted path xplat/static_h to xplat/hermes

Reviewed By: tmikov

Differential Revision: D67412930

fbshipit-source-id: cdc31ec91cbf6e6befd342b6f9b9a14d57a40ea8
  • Loading branch information
tsaichien authored and facebook-github-bot committed Jan 9, 2025
1 parent a49b895 commit e08fb5f
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 0 deletions.
24 changes: 24 additions & 0 deletions API/hermes/hermes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,9 @@ class HermesRuntimeImpl final : public HermesRuntime,
jsi::String createStringFromUtf8(const uint8_t *utf8, size_t length) override;
std::string utf8(const jsi::String &) override;

std::u16string utf16(const jsi::String &str) override;
std::u16string utf16(const jsi::PropNameID &sym) override;

jsi::Value createValueFromJsonUtf8(const uint8_t *json, size_t length)
override;

Expand Down Expand Up @@ -1781,6 +1784,27 @@ std::string HermesRuntimeImpl::utf8(const jsi::String &str) {
vm::StringPrimitive::createStringView(runtime_, stringHandle(str)));
}

std::u16string HermesRuntimeImpl::utf16(const jsi::String &str) {
auto *stringPrim = phv(str).getString();
if (stringPrim->isASCII()) {
auto arrayRef = stringPrim->getStringRef<char>();
return std::u16string(arrayRef.begin(), arrayRef.end());
}
auto arrayRef = stringPrim->getStringRef<char16_t>();
return std::u16string(arrayRef.data(), arrayRef.size());
}

std::u16string HermesRuntimeImpl::utf16(const jsi::PropNameID &sym) {
vm::SymbolID id = phv(sym).getSymbol();
auto *stringPrim = runtime_.getStringPrimFromSymbolID(id);
if (stringPrim->isASCII()) {
auto arrayRef = stringPrim->getStringRef<char>();
return std::u16string(arrayRef.begin(), arrayRef.end());
}
auto arrayRef = stringPrim->getStringRef<char16_t>();
return std::u16string(arrayRef.data(), arrayRef.size());
}

jsi::Value HermesRuntimeImpl::createValueFromJsonUtf8(
const uint8_t *json,
size_t length) {
Expand Down
31 changes: 31 additions & 0 deletions unittests/API/APITest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1167,6 +1167,37 @@ TEST_P(HermesRuntimeTest, NativeExceptionDoesNotUseGlobalError) {
test.call(*rt).getString(*rt).utf8(*rt));
}

TEST_P(HermesRuntimeTest, UTF16Test) {
String ascii = String::createFromUtf8(*rt, "z");
EXPECT_EQ(ascii.utf16(*rt), u"z");

String foobar = String::createFromUtf8(*rt, "foobar");
EXPECT_EQ(foobar.utf16(*rt), u"foobar");

String chineseHello = String::createFromUtf8(*rt, "你好");
EXPECT_EQ(chineseHello.utf16(*rt), u"你好");

String thumbsUpEmoji = String::createFromUtf8(*rt, "👍");
EXPECT_EQ(thumbsUpEmoji.utf16(*rt), u"👍");

String combined = String::createFromUtf8(*rt, "foobar👍你好");
EXPECT_EQ(combined.utf16(*rt), u"foobar👍你好");

// We've only added specific implementations for HermesRuntime. The ABI
// runtime will convert to UTF8 first, causing the lone surrogates to be
// replaced with the Unicode replacement character. We will eventually add the
// UTF16-related APIs to the ABI Runtime and test these cases as well.
if (dynamic_cast<HermesRuntime *>(rt.get())) {
// Thumbs up emoji is encoded as 0xd83d 0xdc4d. These test UTF16 with lone
// high and low surrogates.
String loneHighSurrogate = eval("'\\ud83d'").getString(*rt);
EXPECT_EQ(loneHighSurrogate.utf16(*rt), std::u16string(u"\xd83d"));

String loneLowSurrogate = eval("'\\udc4d'").getString(*rt);
EXPECT_EQ(loneLowSurrogate.utf16(*rt), std::u16string(u"\xdc4d"));
}
}

INSTANTIATE_TEST_CASE_P(
Runtimes,
HermesRuntimeTest,
Expand Down

0 comments on commit e08fb5f

Please sign in to comment.