StringOrSymbol.h 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /*
  2. * Copyright (c) 2020, Matthew Olsson <mattco@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/DeprecatedFlyString.h>
  8. #include <LibJS/Runtime/PrimitiveString.h>
  9. #include <LibJS/Runtime/Symbol.h>
  10. #include <LibJS/Runtime/Value.h>
  11. namespace JS {
  12. class StringOrSymbol {
  13. public:
  14. StringOrSymbol()
  15. : m_bits(0)
  16. {
  17. }
  18. StringOrSymbol(char const* chars)
  19. : StringOrSymbol(DeprecatedFlyString(chars))
  20. {
  21. }
  22. StringOrSymbol(ByteString const& string)
  23. : StringOrSymbol(DeprecatedFlyString(string))
  24. {
  25. }
  26. StringOrSymbol(DeprecatedFlyString const& string)
  27. : m_string(string)
  28. {
  29. }
  30. ~StringOrSymbol()
  31. {
  32. if (is_string())
  33. m_string.~DeprecatedFlyString();
  34. }
  35. StringOrSymbol(Symbol const* symbol)
  36. : m_symbol_with_tag(symbol)
  37. {
  38. set_symbol_flag();
  39. }
  40. StringOrSymbol(StringOrSymbol const& other)
  41. {
  42. if (other.is_string())
  43. new (&m_string) DeprecatedFlyString(other.m_string);
  44. else
  45. m_bits = other.m_bits;
  46. }
  47. StringOrSymbol(StringOrSymbol&& other)
  48. {
  49. if (other.is_string())
  50. new (&m_string) DeprecatedFlyString(move(other.m_string));
  51. else
  52. m_bits = exchange(other.m_bits, 0);
  53. }
  54. ALWAYS_INLINE bool is_valid() const { return m_bits != 0; }
  55. ALWAYS_INLINE bool is_symbol() const { return is_valid() && (m_bits & 2); }
  56. ALWAYS_INLINE bool is_string() const { return is_valid() && !(m_bits & 2); }
  57. ALWAYS_INLINE DeprecatedFlyString as_string() const
  58. {
  59. VERIFY(is_string());
  60. return m_string;
  61. }
  62. ALWAYS_INLINE Symbol const* as_symbol() const
  63. {
  64. VERIFY(is_symbol());
  65. return reinterpret_cast<Symbol const*>(m_bits & ~2ULL);
  66. }
  67. ByteString to_display_string() const
  68. {
  69. if (is_string())
  70. return as_string();
  71. if (is_symbol())
  72. return as_symbol()->descriptive_string().release_value_but_fixme_should_propagate_errors().to_byte_string();
  73. VERIFY_NOT_REACHED();
  74. }
  75. Value to_value(VM& vm) const
  76. {
  77. if (is_string())
  78. return PrimitiveString::create(vm, as_string());
  79. if (is_symbol())
  80. return const_cast<Symbol*>(as_symbol());
  81. return {};
  82. }
  83. void visit_edges(Cell::Visitor& visitor)
  84. {
  85. if (is_symbol())
  86. visitor.visit(const_cast<Symbol*>(as_symbol()));
  87. }
  88. ALWAYS_INLINE bool operator==(StringOrSymbol const& other) const
  89. {
  90. if (is_string())
  91. return other.is_string() && m_string == other.m_string;
  92. if (is_symbol())
  93. return other.is_symbol() && as_symbol() == other.as_symbol();
  94. return true;
  95. }
  96. StringOrSymbol& operator=(StringOrSymbol const& other)
  97. {
  98. if (this != &other) {
  99. this->~StringOrSymbol();
  100. new (this) StringOrSymbol(other);
  101. }
  102. return *this;
  103. }
  104. StringOrSymbol& operator=(StringOrSymbol&& other)
  105. {
  106. if (this != &other) {
  107. this->~StringOrSymbol();
  108. new (this) StringOrSymbol(move(other));
  109. }
  110. return *this;
  111. }
  112. unsigned hash() const
  113. {
  114. if (is_string())
  115. return m_string.hash();
  116. return ptr_hash(as_symbol());
  117. }
  118. private:
  119. ALWAYS_INLINE void set_symbol_flag()
  120. {
  121. m_bits |= 2;
  122. }
  123. union {
  124. DeprecatedFlyString m_string;
  125. Symbol const* m_symbol_with_tag;
  126. uintptr_t m_bits;
  127. };
  128. };
  129. static_assert(sizeof(StringOrSymbol) == sizeof(uintptr_t));
  130. }
  131. template<>
  132. struct AK::Traits<JS::StringOrSymbol> : public DefaultTraits<JS::StringOrSymbol> {
  133. static unsigned hash(JS::StringOrSymbol const& key)
  134. {
  135. return key.hash();
  136. }
  137. };