StringImpl.cpp 4.1 KB

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