StringImpl.cpp 4.3 KB

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