From c995d195adaf07811cf35d81423a5a4afa7d60cf Mon Sep 17 00:00:00 2001 From: Chi Tsai Date: Thu, 9 Jan 2025 05:15:51 -0800 Subject: [PATCH] Add getStringData and getPropNameIdData implementation for Hermes Summary: Adds the Hermes implementation for `getStringData` and `getPropNameIdData`, which leverages the underlying UTF16 encoding Grafted from 32084e2498f2b03ade118f1483b374dea4d7e711 (D65648690) - Grafted path xplat/static_h to xplat/hermes Reviewed By: tmikov Differential Revision: D67412928 fbshipit-source-id: f9fa301e2fef49e7e77126aa65aa2303b8564497 --- API/hermes/hermes.cpp | 39 ++++++++++++++++++++ unittests/API/APITest.cpp | 76 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) diff --git a/API/hermes/hermes.cpp b/API/hermes/hermes.cpp index 300f7b9ae1a..22b3d4c3e6d 100644 --- a/API/hermes/hermes.cpp +++ b/API/hermes/hermes.cpp @@ -616,6 +616,16 @@ class HermesRuntimeImpl final : public HermesRuntime, std::u16string utf16(const jsi::String &str) override; std::u16string utf16(const jsi::PropNameID &sym) override; + void getStringData( + const jsi::String &str, + void *ctx, + void (*cb)(void *ctx, bool ascii, const void *data, size_t num)) override; + + void getPropNameIdData( + const jsi::PropNameID &sym, + void *ctx, + void (*cb)(void *ctx, bool ascii, const void *data, size_t num)) override; + jsi::Value createValueFromJsonUtf8(const uint8_t *json, size_t length) override; @@ -1805,6 +1815,35 @@ std::u16string HermesRuntimeImpl::utf16(const jsi::PropNameID &sym) { return std::u16string(arrayRef.data(), arrayRef.size()); } +void HermesRuntimeImpl::getStringData( + const jsi::String &str, + void *ctx, + void (*cb)(void *ctx, bool ascii, const void *data, size_t num)) { + auto *stringPrim = phv(str).getString(); + if (stringPrim->isASCII()) { + auto arrayRef = stringPrim->getStringRef(); + cb(ctx, true, arrayRef.data(), arrayRef.size()); + } else { + auto arrayRef = stringPrim->getStringRef(); + cb(ctx, false, arrayRef.data(), arrayRef.size()); + } +} + +void HermesRuntimeImpl::getPropNameIdData( + const jsi::PropNameID &sym, + void *ctx, + void (*cb)(void *ctx, bool ascii, const void *data, size_t num)) { + vm::SymbolID id = phv(sym).getSymbol(); + auto *stringPrim = runtime_.getStringPrimFromSymbolID(id); + if (stringPrim->isASCII()) { + auto arrayRef = stringPrim->getStringRef(); + cb(ctx, true, arrayRef.data(), arrayRef.size()); + } else { + auto arrayRef = stringPrim->getStringRef(); + cb(ctx, false, arrayRef.data(), arrayRef.size()); + } +} + jsi::Value HermesRuntimeImpl::createValueFromJsonUtf8( const uint8_t *json, size_t length) { diff --git a/unittests/API/APITest.cpp b/unittests/API/APITest.cpp index e4b91aef4c9..19cf3fb866a 100644 --- a/unittests/API/APITest.cpp +++ b/unittests/API/APITest.cpp @@ -1198,6 +1198,82 @@ TEST_P(HermesRuntimeTest, UTF16Test) { } } +TEST_P(HermesRuntimeTest, GetStringDataTest) { + std::u16string buf; + auto cb = [&buf](bool ascii, const void *data, size_t num) { + // this callback copies the string content, but removes every 'o' character + if (ascii) { + const char *begin = (const char *)data; + const char *end = (const char *)data + num; + while (begin < end) { + char curr = begin[0]; + if (curr != 'o') { + buf.push_back((char16_t)curr); + } + begin++; + } + } else { + const char16_t *begin = (const char16_t *)data; + const char16_t *end = (const char16_t *)data + num; + while (begin < end) { + char16_t curr = begin[0]; + if (curr != 'o') { + buf.push_back(curr); + } + begin++; + } + } + }; + + String asciiString = String::createFromUtf8(*rt, "foobar"); + asciiString.getStringData(*rt, cb); + EXPECT_EQ(buf, u"fbar"); + buf.clear(); + + String utf16Str = String::createFromUtf8(*rt, "👍foobar你好"); + utf16Str.getStringData(*rt, cb); + EXPECT_EQ(buf, u"👍fbar你好"); + buf.clear(); +} + +TEST_P(HermesRuntimeTest, GetPropNameIdDataTest) { + std::u16string buf; + auto cb = [&buf](bool ascii, const void *data, size_t num) { + // this callback copies the string content, but removes every 'o' character + if (ascii) { + const char *begin = (const char *)data; + const char *end = (const char *)data + num; + while (begin < end) { + char curr = begin[0]; + if (curr != 'o') { + buf.push_back((char16_t)curr); + } + begin++; + } + } else { + const char16_t *begin = (const char16_t *)data; + const char16_t *end = (const char16_t *)data + num; + while (begin < end) { + char16_t curr = begin[0]; + if (curr != 'o') { + buf.push_back(curr); + } + begin++; + } + } + }; + + PropNameID ascii = PropNameID::forAscii(*rt, "foobar"); + ascii.getPropNameIdData(*rt, cb); + EXPECT_EQ(buf, u"fbar"); + buf.clear(); + + PropNameID utf16 = PropNameID::forUtf8(*rt, "👍foobar你好"); + utf16.getPropNameIdData(*rt, cb); + EXPECT_EQ(buf, u"👍fbar你好"); + buf.clear(); +} + INSTANTIATE_TEST_CASE_P( Runtimes, HermesRuntimeTest,