Prechádzať zdrojové kódy

LibJS: Allow PrimitiveString to be created with a UTF-16 string

PrimitiveString may currently only be created with a UTF-8 string, and
it transcodes on the fly when a UTF-16 string is needed. Allow creating
a PrimitiveString from a UTF-16 string to avoid unnecessary transcoding
when the caller only wants UTF-16.
Timothy Flynn 4 rokov pred
rodič
commit
b6ff7f4fcc

+ 49 - 10
Userland/Libraries/LibJS/Runtime/PrimitiveString.cpp

@@ -12,7 +12,14 @@
 namespace JS {
 
 PrimitiveString::PrimitiveString(String string)
-    : m_string(move(string))
+    : m_utf8_string(move(string))
+    , m_has_utf8_string(true)
+{
+}
+
+PrimitiveString::PrimitiveString(Vector<u16> string)
+    : m_utf16_string(move(string))
+    , m_has_utf16_string(true)
 {
 }
 
@@ -20,10 +27,21 @@ PrimitiveString::~PrimitiveString()
 {
 }
 
+String const& PrimitiveString::string() const
+{
+    if (!m_has_utf8_string) {
+        m_utf8_string = utf16_string_view().to_utf8(Utf16View::AllowInvalidCodeUnits::Yes);
+        m_has_utf8_string = true;
+    }
+    return m_utf8_string;
+}
+
 Vector<u16> const& PrimitiveString::utf16_string() const
 {
-    if (m_utf16_string.is_empty() && !m_string.is_empty())
-        m_utf16_string = AK::utf8_to_utf16(m_string);
+    if (!m_has_utf16_string) {
+        m_utf16_string = AK::utf8_to_utf16(m_utf8_string);
+        m_has_utf16_string = true;
+    }
     return m_utf16_string;
 }
 
@@ -32,24 +50,45 @@ Utf16View PrimitiveString::utf16_string_view() const
     return Utf16View { utf16_string() };
 }
 
-PrimitiveString* js_string(Heap& heap, Utf16View const& string)
+PrimitiveString* js_string(Heap& heap, Utf16View const& view)
+{
+    if (view.is_empty())
+        return &heap.vm().empty_string();
+
+    if (view.length_in_code_units() == 1) {
+        u16 code_unit = view.code_unit_at(0);
+        if (is_ascii(code_unit))
+            return &heap.vm().single_ascii_character_string(static_cast<u8>(code_unit));
+    }
+
+    Vector<u16> string;
+    string.ensure_capacity(view.length_in_code_units());
+    string.append(view.data(), view.length_in_code_units());
+    return js_string(heap, move(string));
+}
+
+PrimitiveString* js_string(VM& vm, Utf16View const& view)
+{
+    return js_string(vm.heap(), view);
+}
+
+PrimitiveString* js_string(Heap& heap, Vector<u16> string)
 {
     if (string.is_empty())
         return &heap.vm().empty_string();
 
-    if (string.length_in_code_units() == 1) {
-        u16 code_unit = string.code_unit_at(0);
+    if (string.size() == 1) {
+        u16 code_unit = string.at(0);
         if (is_ascii(code_unit))
             return &heap.vm().single_ascii_character_string(static_cast<u8>(code_unit));
     }
 
-    auto utf8_string = string.to_utf8(Utf16View::AllowInvalidCodeUnits::Yes);
-    return heap.allocate_without_global_object<PrimitiveString>(move(utf8_string));
+    return heap.allocate_without_global_object<PrimitiveString>(move(string));
 }
 
-PrimitiveString* js_string(VM& vm, Utf16View const& string)
+PrimitiveString* js_string(VM& vm, Vector<u16> string)
 {
-    return js_string(vm.heap(), string);
+    return js_string(vm.heap(), move(string));
 }
 
 PrimitiveString* js_string(Heap& heap, String string)

+ 12 - 2
Userland/Libraries/LibJS/Runtime/PrimitiveString.h

@@ -15,9 +15,13 @@ namespace JS {
 class PrimitiveString final : public Cell {
 public:
     explicit PrimitiveString(String);
+    explicit PrimitiveString(Vector<u16>);
     virtual ~PrimitiveString();
 
-    String const& string() const { return m_string; }
+    PrimitiveString(PrimitiveString const&) = delete;
+    PrimitiveString& operator=(PrimitiveString const&) = delete;
+
+    String const& string() const;
 
     Vector<u16> const& utf16_string() const;
     Utf16View utf16_string_view() const;
@@ -25,13 +29,19 @@ public:
 private:
     virtual const char* class_name() const override { return "PrimitiveString"; }
 
-    String m_string;
+    mutable String m_utf8_string;
+    mutable bool m_has_utf8_string { false };
+
     mutable Vector<u16> m_utf16_string;
+    mutable bool m_has_utf16_string { false };
 };
 
 PrimitiveString* js_string(Heap&, Utf16View const&);
 PrimitiveString* js_string(VM&, Utf16View const&);
 
+PrimitiveString* js_string(Heap&, Vector<u16>);
+PrimitiveString* js_string(VM&, Vector<u16>);
+
 PrimitiveString* js_string(Heap&, String);
 PrimitiveString* js_string(VM&, String);