123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- #include "StringImpl.h"
- #include "StdLibExtras.h"
- #include "kmalloc.h"
- #include "HashTable.h"
- #ifdef DEBUG_STRINGIMPL
- unsigned g_stringimpl_count;
- static HashTable<StringImpl*>* g_all_live_stringimpls;
- void dump_all_stringimpls()
- {
- unsigned i = 0;
- for (auto& it : *g_all_live_stringimpls) {
- dbgprintf("%u: \"%s\"\n", i, (*it).characters());
- ++i;
- }
- }
- #endif
- namespace AK {
- static StringImpl* s_the_empty_stringimpl = nullptr;
- void StringImpl::initialize_globals()
- {
- s_the_empty_stringimpl = nullptr;
- #ifdef DEBUG_STRINGIMPL
- g_stringimpl_count = 0;
- g_all_live_stringimpls = new HashTable<StringImpl*>;
- #endif
- }
- StringImpl& StringImpl::the_empty_stringimpl()
- {
- if (!s_the_empty_stringimpl)
- s_the_empty_stringimpl = new StringImpl(ConstructTheEmptyStringImpl);;
- return *s_the_empty_stringimpl;
- }
- StringImpl::StringImpl(ConstructWithInlineBufferTag, size_t length)
- : m_length(length)
- , m_characters(m_inline_buffer)
- {
- #ifdef DEBUG_STRINGIMPL
- ++g_stringimpl_count;
- g_all_live_stringimpls->set(this);
- #endif
- }
- StringImpl::~StringImpl()
- {
- #ifdef DEBUG_STRINGIMPL
- --g_stringimpl_count;
- g_all_live_stringimpls->remove(this);
- #endif
- }
- static inline size_t allocationSizeForStringImpl(size_t length)
- {
- return sizeof(StringImpl) + (sizeof(char) * length) + sizeof(char);
- }
- RetainPtr<StringImpl> StringImpl::create_uninitialized(size_t length, char*& buffer)
- {
- ASSERT(length);
- void* slot = kmalloc(allocationSizeForStringImpl(length));
- if (!slot)
- return nullptr;
- auto newStringImpl = adopt(*new (slot) StringImpl(ConstructWithInlineBuffer, length));
- buffer = const_cast<char*>(newStringImpl->m_characters);
- buffer[length] = '\0';
- return newStringImpl;
- }
- RetainPtr<StringImpl> StringImpl::create(const char* cstring, size_t length, ShouldChomp shouldChomp)
- {
- if (!cstring)
- return nullptr;
- if (!*cstring)
- return the_empty_stringimpl();
- char* buffer;
- auto newStringImpl = create_uninitialized(length, buffer);
- if (!newStringImpl)
- return nullptr;
- memcpy(buffer, cstring, length * sizeof(char));
- if (shouldChomp && buffer[length - 1] == '\n') {
- buffer[length - 1] = '\0';
- --newStringImpl->m_length;
- }
- return newStringImpl;
- }
- RetainPtr<StringImpl> StringImpl::create(const char* cstring, ShouldChomp shouldChomp)
- {
- if (!cstring)
- return nullptr;
- return create(cstring, strlen(cstring), shouldChomp);
- }
- static inline bool isASCIILowercase(char c)
- {
- return c >= 'a' && c <= 'z';
- }
- static inline bool isASCIIUppercase(char c)
- {
- return c >= 'A' && c <= 'Z';
- }
- static inline char toASCIILowercase(char c)
- {
- if (isASCIIUppercase(c))
- return c | 0x20;
- return c;
- }
- static inline char toASCIIUppercase(char c)
- {
- if (isASCIILowercase(c))
- return c & ~0x20;
- return c;
- }
- RetainPtr<StringImpl> StringImpl::to_lowercase() const
- {
- if (!m_length)
- return const_cast<StringImpl*>(this);
- for (size_t i = 0; i < m_length; ++i) {
- if (!isASCIILowercase(m_characters[i]))
- goto slowPath;
- }
- return const_cast<StringImpl*>(this);
- slowPath:
- char* buffer;
- auto lowercased = create_uninitialized(m_length, buffer);
- if (!lowercased)
- return nullptr;
- for (size_t i = 0; i < m_length; ++i)
- buffer[i] = toASCIILowercase(m_characters[i]);
- return lowercased;
- }
- RetainPtr<StringImpl> StringImpl::to_uppercase() const
- {
- if (!m_length)
- return const_cast<StringImpl*>(this);
- for (size_t i = 0; i < m_length; ++i) {
- if (!isASCIIUppercase(m_characters[i]))
- goto slowPath;
- }
- return const_cast<StringImpl*>(this);
- slowPath:
- char* buffer;
- auto uppercased = create_uninitialized(m_length, buffer);
- if (!uppercased)
- return nullptr;
- for (size_t i = 0; i < m_length; ++i)
- buffer[i] = toASCIIUppercase(m_characters[i]);
- return uppercased;
- }
- void StringImpl::compute_hash() const
- {
- if (!length()) {
- m_hash = 0;
- } else {
- unsigned hash = 0;
- for (size_t i = 0; i < m_length; ++i) {
- hash += m_characters[i];
- hash += (hash << 10);
- hash ^= (hash >> 6);
- }
- hash += hash << 3;
- hash ^= hash >> 11;
- hash += hash << 15;
- m_hash = hash;
- }
- m_hasHash = true;
- }
- }
|