mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Add createFromUtf16 JSI method (#48211)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/48211 Adding the default implementation for `createFromUtf16` method for JSI String and PropNameId. Changelog: [Internal] Reviewed By: tmikov Differential Revision: D67070206 fbshipit-source-id: 47297e6ae3028ee0e101628aab5bc076fcbbdebc
This commit is contained in:
committed by
Facebook GitHub Bot
parent
f89f191c26
commit
d9d824055e
@@ -182,6 +182,10 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation {
|
||||
PropNameID createPropNameIDFromString(const String& str) override {
|
||||
return plain_.createPropNameIDFromString(str);
|
||||
};
|
||||
PropNameID createPropNameIDFromUtf16(const char16_t* utf16, size_t length)
|
||||
override {
|
||||
return plain_.createPropNameIDFromUtf16(utf16, length);
|
||||
}
|
||||
PropNameID createPropNameIDFromSymbol(const Symbol& sym) override {
|
||||
return plain_.createPropNameIDFromSymbol(sym);
|
||||
};
|
||||
@@ -221,6 +225,9 @@ class RuntimeDecorator : public Base, private jsi::Instrumentation {
|
||||
String createStringFromUtf8(const uint8_t* utf8, size_t length) override {
|
||||
return plain_.createStringFromUtf8(utf8, length);
|
||||
};
|
||||
String createStringFromUtf16(const char16_t* utf16, size_t length) override {
|
||||
return plain_.createStringFromUtf16(utf16, length);
|
||||
}
|
||||
std::string utf8(const String& s) override {
|
||||
return plain_.utf8(s);
|
||||
}
|
||||
@@ -649,6 +656,11 @@ class WithRuntimeDecorator : public RuntimeDecorator<Plain, Base> {
|
||||
Around around{with_};
|
||||
return RD::createPropNameIDFromUtf8(utf8, length);
|
||||
};
|
||||
PropNameID createPropNameIDFromUtf16(const char16_t* utf16, size_t length)
|
||||
override {
|
||||
Around around{with_};
|
||||
return RD::createPropNameIDFromUtf16(utf16, length);
|
||||
}
|
||||
PropNameID createPropNameIDFromString(const String& str) override {
|
||||
Around around{with_};
|
||||
return RD::createPropNameIDFromString(str);
|
||||
@@ -704,6 +716,10 @@ class WithRuntimeDecorator : public RuntimeDecorator<Plain, Base> {
|
||||
Around around{with_};
|
||||
return RD::createStringFromUtf8(utf8, length);
|
||||
};
|
||||
String createStringFromUtf16(const char16_t* utf16, size_t length) override {
|
||||
Around around{with_};
|
||||
return RD::createStringFromUtf16(utf16, length);
|
||||
}
|
||||
std::string utf8(const String& s) override {
|
||||
Around around{with_};
|
||||
return RD::utf8(s);
|
||||
|
||||
@@ -163,6 +163,45 @@ std::u16string convertUTF8ToUTF16(const std::string& utf8) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Given a unsigned number, which is less than 16, return the hex character.
|
||||
inline char hexDigit(unsigned x) {
|
||||
return x < 10 ? '0' + x : 'A' + (x - 10);
|
||||
}
|
||||
|
||||
// Given a sequence of UTF 16 code units, return true if all code units are
|
||||
// ASCII characters
|
||||
bool isAllASCII(const char16_t* utf16, size_t length) {
|
||||
for (const char16_t* e = utf16 + length; utf16 != e; ++utf16) {
|
||||
if (*utf16 > 0x7F)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Given a sequences of UTF 16 code units, return a string that explicitly
|
||||
// expresses the code units
|
||||
std::string getUtf16CodeUnitString(const char16_t* utf16, size_t length) {
|
||||
// Every character will need 4 hex digits + the character escape "\u".
|
||||
// Plus 2 character for the opening and closing single quote.
|
||||
std::string s = std::string(6 * length + 2, 0);
|
||||
s.front() = '\'';
|
||||
|
||||
for (size_t i = 0; i != length; ++i) {
|
||||
char16_t ch = utf16[i];
|
||||
size_t start = (6 * i) + 1;
|
||||
|
||||
s[start] = '\\';
|
||||
s[start + 1] = 'u';
|
||||
|
||||
s[start + 2] = hexDigit((ch >> 12) & 0x000f);
|
||||
s[start + 3] = hexDigit((ch >> 8) & 0x000f);
|
||||
s[start + 4] = hexDigit((ch >> 4) & 0x000f);
|
||||
s[start + 5] = hexDigit(ch & 0x000f);
|
||||
}
|
||||
s.back() = '\'';
|
||||
return s;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Buffer::~Buffer() = default;
|
||||
@@ -248,6 +287,25 @@ Value Runtime::createValueFromJsonUtf8(const uint8_t* json, size_t length) {
|
||||
return parseJson.call(*this, String::createFromUtf8(*this, json, length));
|
||||
}
|
||||
|
||||
String Runtime::createStringFromUtf16(const char16_t* utf16, size_t length) {
|
||||
if (isAllASCII(utf16, length)) {
|
||||
std::string buffer(utf16, utf16 + length);
|
||||
return createStringFromAscii(buffer.data(), length);
|
||||
}
|
||||
auto s = getUtf16CodeUnitString(utf16, length);
|
||||
return global()
|
||||
.getPropertyAsFunction(*this, "eval")
|
||||
.call(*this, s)
|
||||
.getString(*this);
|
||||
}
|
||||
|
||||
PropNameID Runtime::createPropNameIDFromUtf16(
|
||||
const char16_t* utf16,
|
||||
size_t length) {
|
||||
auto jsString = createStringFromUtf16(utf16, length);
|
||||
return createPropNameIDFromString(jsString);
|
||||
}
|
||||
|
||||
std::u16string Runtime::utf16(const PropNameID& sym) {
|
||||
auto utf8Str = utf8(sym);
|
||||
return convertUTF8ToUTF16(utf8Str);
|
||||
|
||||
@@ -306,6 +306,9 @@ class JSI_EXPORT Runtime {
|
||||
virtual PropNameID createPropNameIDFromUtf8(
|
||||
const uint8_t* utf8,
|
||||
size_t length) = 0;
|
||||
virtual PropNameID createPropNameIDFromUtf16(
|
||||
const char16_t* utf16,
|
||||
size_t length);
|
||||
virtual PropNameID createPropNameIDFromString(const String& str) = 0;
|
||||
virtual PropNameID createPropNameIDFromSymbol(const Symbol& sym) = 0;
|
||||
virtual std::string utf8(const PropNameID&) = 0;
|
||||
@@ -322,6 +325,7 @@ class JSI_EXPORT Runtime {
|
||||
|
||||
virtual String createStringFromAscii(const char* str, size_t length) = 0;
|
||||
virtual String createStringFromUtf8(const uint8_t* utf8, size_t length) = 0;
|
||||
virtual String createStringFromUtf16(const char16_t* utf16, size_t length);
|
||||
virtual std::string utf8(const String&) = 0;
|
||||
|
||||
// \return a \c Value created from a utf8-encoded JSON string. The default
|
||||
@@ -515,6 +519,21 @@ class JSI_EXPORT PropNameID : public Pointer {
|
||||
reinterpret_cast<const uint8_t*>(utf8.data()), utf8.size());
|
||||
}
|
||||
|
||||
/// Given a series of UTF-16 encoded code units, create a PropNameId. The
|
||||
/// input may contain unpaired surrogates, which will be interpreted as a code
|
||||
/// point of the same value.
|
||||
static PropNameID
|
||||
forUtf16(Runtime& runtime, const char16_t* utf16, size_t length) {
|
||||
return runtime.createPropNameIDFromUtf16(utf16, length);
|
||||
}
|
||||
|
||||
/// Given a series of UTF-16 encoded code units stored inside std::u16string,
|
||||
/// create a PropNameId. The input may contain unpaired surrogates, which
|
||||
/// will be interpreted as a code point of the same value.
|
||||
static PropNameID forUtf16(Runtime& runtime, const std::u16string& str) {
|
||||
return runtime.createPropNameIDFromUtf16(str.data(), str.size());
|
||||
}
|
||||
|
||||
/// Create a PropNameID from a JS string.
|
||||
static PropNameID forString(Runtime& runtime, const jsi::String& str) {
|
||||
return runtime.createPropNameIDFromString(str);
|
||||
@@ -699,6 +718,21 @@ class JSI_EXPORT String : public Pointer {
|
||||
reinterpret_cast<const uint8_t*>(utf8.data()), utf8.length());
|
||||
}
|
||||
|
||||
/// Given a series of UTF-16 encoded code units, create a JS String. The input
|
||||
/// may contain unpaired surrogates, which will be interpreted as a code point
|
||||
/// of the same value.
|
||||
static String
|
||||
createFromUtf16(Runtime& runtime, const char16_t* utf16, size_t length) {
|
||||
return runtime.createStringFromUtf16(utf16, length);
|
||||
}
|
||||
|
||||
/// Given a series of UTF-16 encoded code units stored inside std::u16string,
|
||||
/// create a JS String. The input may contain unpaired surrogates, which will
|
||||
/// be interpreted as a code point of the same value.
|
||||
static String createFromUtf16(Runtime& runtime, const std::u16string& utf16) {
|
||||
return runtime.createStringFromUtf16(utf16.data(), utf16.length());
|
||||
}
|
||||
|
||||
/// \return whether a and b contain the same characters.
|
||||
static bool strictEquals(Runtime& runtime, const String& a, const String& b) {
|
||||
return runtime.strictEquals(a, b);
|
||||
|
||||
@@ -1576,7 +1576,7 @@ TEST_P(JSITest, UTF8ExceptionTest) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(JSITest, UTF16Test) {
|
||||
TEST_P(JSITest, UTF16ConversionTest) {
|
||||
// This Runtime Decorator is used to test the conversion from UTF-8 to UTF-16
|
||||
// in the default utf16 method for runtimes that do not provide their own
|
||||
// utf16 implementation.
|
||||
@@ -1640,6 +1640,50 @@ TEST_P(JSITest, UTF16Test) {
|
||||
EXPECT_EQ(str.utf16(rd), u"\uFFFD\u007A");
|
||||
}
|
||||
|
||||
TEST_P(JSITest, CreateFromUtf16Test) {
|
||||
// This Runtime Decorator is used to test the default createStringFromUtf16
|
||||
// and createPropNameIDFromUtf16 implementation for VMs that do not provide
|
||||
// their own implementation
|
||||
class RD : public RuntimeDecorator<Runtime, Runtime> {
|
||||
public:
|
||||
RD(Runtime& rt) : RuntimeDecorator(rt) {}
|
||||
|
||||
String createStringFromUtf16(const char16_t* utf16, size_t length)
|
||||
override {
|
||||
return Runtime::createStringFromUtf16(utf16, length);
|
||||
}
|
||||
|
||||
PropNameID createPropNameIDFromUtf16(const char16_t* utf16, size_t length)
|
||||
override {
|
||||
return Runtime::createPropNameIDFromUtf16(utf16, length);
|
||||
}
|
||||
};
|
||||
|
||||
RD rd = RD(rt);
|
||||
std::u16string utf16 = u"foobar";
|
||||
|
||||
auto jsString = String::createFromUtf16(rd, utf16);
|
||||
EXPECT_EQ(jsString.utf16(rd), utf16);
|
||||
auto prop = PropNameID::forUtf16(rd, utf16);
|
||||
EXPECT_EQ(prop.utf16(rd), utf16);
|
||||
|
||||
// 👋 in UTF-16 encoding is 0xd83d 0xdc4b
|
||||
utf16 = u"hello!\xd83d\xdc4b";
|
||||
jsString = String::createFromUtf16(rd, utf16.data(), utf16.length());
|
||||
EXPECT_EQ(jsString.utf16(rd), utf16);
|
||||
prop = PropNameID::forUtf16(rd, utf16);
|
||||
EXPECT_EQ(prop.utf16(rd), utf16);
|
||||
|
||||
utf16 = u"\xd83d";
|
||||
jsString = String::createFromUtf16(rd, utf16.data(), utf16.length());
|
||||
/// We need to use charCodeAt instead of UTF16 because the default
|
||||
/// implementation of UTF16 converts to UTF8, then to UTF16, so we will lose
|
||||
/// the lone surrogate value.
|
||||
rd.global().setProperty(rd, "loneSurrogate", jsString);
|
||||
auto cp = eval("loneSurrogate.charCodeAt(0)").getNumber();
|
||||
EXPECT_EQ(cp, 55357); // 0xD83D in decimal
|
||||
}
|
||||
|
||||
TEST_P(JSITest, GetStringDataTest) {
|
||||
// This Runtime Decorator is used to test the default getStringData
|
||||
// implementation for VMs that do not provide their own implementation
|
||||
|
||||
Reference in New Issue
Block a user