PrimitiveString.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. /*
  2. * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/CharacterTypes.h>
  7. #include <AK/Utf16View.h>
  8. #include <LibJS/Runtime/AbstractOperations.h>
  9. #include <LibJS/Runtime/GlobalObject.h>
  10. #include <LibJS/Runtime/PrimitiveString.h>
  11. #include <LibJS/Runtime/PropertyKey.h>
  12. #include <LibJS/Runtime/VM.h>
  13. #include <LibJS/Runtime/Value.h>
  14. namespace JS {
  15. PrimitiveString::PrimitiveString(String string)
  16. : m_utf8_string(move(string))
  17. , m_has_utf8_string(true)
  18. {
  19. }
  20. PrimitiveString::PrimitiveString(Utf16String string)
  21. : m_utf16_string(move(string))
  22. , m_has_utf16_string(true)
  23. {
  24. }
  25. PrimitiveString::~PrimitiveString()
  26. {
  27. vm().string_cache().remove(m_utf8_string);
  28. }
  29. bool PrimitiveString::is_empty() const
  30. {
  31. if (m_has_utf16_string)
  32. return m_utf16_string.is_empty();
  33. if (m_has_utf8_string)
  34. return m_utf8_string.is_empty();
  35. VERIFY_NOT_REACHED();
  36. }
  37. String const& PrimitiveString::string() const
  38. {
  39. if (!m_has_utf8_string) {
  40. m_utf8_string = m_utf16_string.to_utf8();
  41. m_has_utf8_string = true;
  42. }
  43. return m_utf8_string;
  44. }
  45. Utf16String const& PrimitiveString::utf16_string() const
  46. {
  47. if (!m_has_utf16_string) {
  48. m_utf16_string = Utf16String(m_utf8_string);
  49. m_has_utf16_string = true;
  50. }
  51. return m_utf16_string;
  52. }
  53. Utf16View PrimitiveString::utf16_string_view() const
  54. {
  55. return utf16_string().view();
  56. }
  57. Optional<Value> PrimitiveString::get(GlobalObject& global_object, PropertyKey const& property_key) const
  58. {
  59. if (property_key.is_symbol())
  60. return {};
  61. if (property_key.is_string()) {
  62. if (property_key.as_string() == global_object.vm().names.length.as_string()) {
  63. auto length = utf16_string().length_in_code_units();
  64. return Value(static_cast<double>(length));
  65. }
  66. }
  67. auto index = canonical_numeric_index_string(property_key, CanonicalIndexMode::IgnoreNumericRoundtrip);
  68. if (!index.is_index())
  69. return {};
  70. auto str = utf16_string_view();
  71. auto length = str.length_in_code_units();
  72. if (length <= index.as_index())
  73. return {};
  74. return js_string(vm(), str.substring_view(index.as_index(), 1));
  75. }
  76. PrimitiveString* js_string(Heap& heap, Utf16View const& view)
  77. {
  78. return js_string(heap, Utf16String(view));
  79. }
  80. PrimitiveString* js_string(VM& vm, Utf16View const& view)
  81. {
  82. return js_string(vm.heap(), view);
  83. }
  84. PrimitiveString* js_string(Heap& heap, Utf16String string)
  85. {
  86. if (string.is_empty())
  87. return &heap.vm().empty_string();
  88. if (string.length_in_code_units() == 1) {
  89. u16 code_unit = string.code_unit_at(0);
  90. if (is_ascii(code_unit))
  91. return &heap.vm().single_ascii_character_string(static_cast<u8>(code_unit));
  92. }
  93. return heap.allocate_without_global_object<PrimitiveString>(move(string));
  94. }
  95. PrimitiveString* js_string(VM& vm, Utf16String string)
  96. {
  97. return js_string(vm.heap(), move(string));
  98. }
  99. PrimitiveString* js_string(Heap& heap, String string)
  100. {
  101. if (string.is_empty())
  102. return &heap.vm().empty_string();
  103. if (string.length() == 1) {
  104. auto ch = static_cast<u8>(string.characters()[0]);
  105. if (is_ascii(ch))
  106. return &heap.vm().single_ascii_character_string(ch);
  107. }
  108. auto& string_cache = heap.vm().string_cache();
  109. auto it = string_cache.find(string);
  110. if (it == string_cache.end()) {
  111. auto* new_string = heap.allocate_without_global_object<PrimitiveString>(string);
  112. string_cache.set(move(string), new_string);
  113. return new_string;
  114. }
  115. return it->value;
  116. }
  117. PrimitiveString* js_string(VM& vm, String string)
  118. {
  119. return js_string(vm.heap(), move(string));
  120. }
  121. }