StringImpl.cpp 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. #include "StringImpl.h"
  2. #include "HashTable.h"
  3. #include "StdLibExtras.h"
  4. #include "kmalloc.h"
  5. #ifndef __serenity__
  6. # include <new>
  7. #endif
  8. //#define DEBUG_STRINGIMPL
  9. #ifdef DEBUG_STRINGIMPL
  10. unsigned g_stringimpl_count;
  11. static HashTable<StringImpl*>* g_all_live_stringimpls;
  12. void dump_all_stringimpls()
  13. {
  14. unsigned i = 0;
  15. for (auto& it : *g_all_live_stringimpls) {
  16. dbgprintf("%u: \"%s\"\n", i, (*it).characters());
  17. ++i;
  18. }
  19. }
  20. #endif
  21. namespace AK {
  22. static StringImpl* s_the_empty_stringimpl = nullptr;
  23. StringImpl& StringImpl::the_empty_stringimpl()
  24. {
  25. if (!s_the_empty_stringimpl) {
  26. void* slot = kmalloc(sizeof(StringImpl) + sizeof(char));
  27. s_the_empty_stringimpl = new (slot) StringImpl(ConstructTheEmptyStringImpl);
  28. }
  29. return *s_the_empty_stringimpl;
  30. }
  31. StringImpl::StringImpl(ConstructWithInlineBufferTag, int length)
  32. : m_length(length)
  33. {
  34. #ifdef DEBUG_STRINGIMPL
  35. if (!g_all_live_stringimpls)
  36. g_all_live_stringimpls = new HashTable<StringImpl*>;
  37. ++g_stringimpl_count;
  38. g_all_live_stringimpls->set(this);
  39. #endif
  40. }
  41. StringImpl::~StringImpl()
  42. {
  43. #ifdef DEBUG_STRINGIMPL
  44. --g_stringimpl_count;
  45. g_all_live_stringimpls->remove(this);
  46. #endif
  47. }
  48. static inline int allocation_size_for_stringimpl(int length)
  49. {
  50. return sizeof(StringImpl) + (sizeof(char) * length) + sizeof(char);
  51. }
  52. NonnullRefPtr<StringImpl> StringImpl::create_uninitialized(int length, char*& buffer)
  53. {
  54. ASSERT(length);
  55. void* slot = kmalloc(allocation_size_for_stringimpl(length));
  56. ASSERT(slot);
  57. auto new_stringimpl = adopt(*new (slot) StringImpl(ConstructWithInlineBuffer, length));
  58. buffer = const_cast<char*>(new_stringimpl->characters());
  59. buffer[length] = '\0';
  60. return new_stringimpl;
  61. }
  62. RefPtr<StringImpl> StringImpl::create(const char* cstring, int length, ShouldChomp should_chomp)
  63. {
  64. if (!cstring)
  65. return nullptr;
  66. if (!length || !*cstring)
  67. return the_empty_stringimpl();
  68. if (should_chomp) {
  69. while (length) {
  70. char last_ch = cstring[length - 1];
  71. if (!last_ch || last_ch == '\n' || last_ch == '\r')
  72. --length;
  73. else
  74. break;
  75. }
  76. }
  77. if (!length)
  78. return the_empty_stringimpl();
  79. char* buffer;
  80. auto new_stringimpl = create_uninitialized(length, buffer);
  81. memcpy(buffer, cstring, length * sizeof(char));
  82. return new_stringimpl;
  83. }
  84. RefPtr<StringImpl> StringImpl::create(const char* cstring, ShouldChomp shouldChomp)
  85. {
  86. if (!cstring)
  87. return nullptr;
  88. return create(cstring, strlen(cstring), shouldChomp);
  89. }
  90. static inline bool is_ascii_lowercase(char c)
  91. {
  92. return c >= 'a' && c <= 'z';
  93. }
  94. static inline bool is_ascii_uppercase(char c)
  95. {
  96. return c >= 'A' && c <= 'Z';
  97. }
  98. static inline char to_ascii_lowercase(char c)
  99. {
  100. if (is_ascii_uppercase(c))
  101. return c | 0x20;
  102. return c;
  103. }
  104. static inline char to_ascii_uppercase(char c)
  105. {
  106. if (is_ascii_lowercase(c))
  107. return c & ~0x20;
  108. return c;
  109. }
  110. NonnullRefPtr<StringImpl> StringImpl::to_lowercase() const
  111. {
  112. for (int i = 0; i < m_length; ++i) {
  113. if (!is_ascii_lowercase(characters()[i]))
  114. goto slow_path;
  115. }
  116. return const_cast<StringImpl&>(*this);
  117. slow_path:
  118. char* buffer;
  119. auto lowercased = create_uninitialized(m_length, buffer);
  120. for (int i = 0; i < m_length; ++i)
  121. buffer[i] = to_ascii_lowercase(characters()[i]);
  122. return lowercased;
  123. }
  124. NonnullRefPtr<StringImpl> StringImpl::to_uppercase() const
  125. {
  126. for (int i = 0; i < m_length; ++i) {
  127. if (!is_ascii_uppercase(characters()[i]))
  128. goto slow_path;
  129. }
  130. return const_cast<StringImpl&>(*this);
  131. slow_path:
  132. char* buffer;
  133. auto uppercased = create_uninitialized(m_length, buffer);
  134. for (int i = 0; i < m_length; ++i)
  135. buffer[i] = to_ascii_uppercase(characters()[i]);
  136. return uppercased;
  137. }
  138. void StringImpl::compute_hash() const
  139. {
  140. if (!length())
  141. m_hash = 0;
  142. else
  143. m_hash = string_hash(characters(), m_length);
  144. m_has_hash = true;
  145. }
  146. NonnullRefPtr<StringImpl> StringImpl::reversed() const
  147. {
  148. if (m_length == 0)
  149. return the_empty_stringimpl();
  150. char* buffer;
  151. const char* pos = &m_inline_buffer[m_length - 1];
  152. auto new_impl = create_uninitialized(m_length, buffer);
  153. for (int i = 0; i < m_length; i++)
  154. buffer[i] = *pos--;
  155. return new_impl;
  156. }
  157. }