| 
									
										
										
										
											2020-01-18 09:38:21 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2021-04-22 01:24:48 -07:00
										 |  |  |  * SPDX-License-Identifier: BSD-2-Clause | 
					
						
							| 
									
										
										
										
											2020-01-18 09:38:21 +01:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-24 15:28:26 +01:00
										 |  |  | #include <AK/Debug.h>
 | 
					
						
							| 
									
										
										
										
											2020-03-22 10:12:55 +01:00
										 |  |  | #include <AK/FlyString.h>
 | 
					
						
							| 
									
										
										
										
											2020-03-08 12:34:33 +01:00
										 |  |  | #include <AK/HashTable.h>
 | 
					
						
							|  |  |  | #include <AK/Memory.h>
 | 
					
						
							|  |  |  | #include <AK/StdLibExtras.h>
 | 
					
						
							|  |  |  | #include <AK/StringImpl.h>
 | 
					
						
							|  |  |  | #include <AK/kmalloc.h>
 | 
					
						
							| 
									
										
										
										
											2018-12-28 03:09:45 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-24 15:28:26 +01:00
										 |  |  | #if STRINGIMPL_DEBUG
 | 
					
						
							| 
									
										
										
										
											2018-12-28 03:09:45 +01:00
										 |  |  | unsigned g_stringimpl_count; | 
					
						
							|  |  |  | static HashTable<StringImpl*>* g_all_live_stringimpls; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-30 10:47:48 +02:00
										 |  |  | void dump_all_stringimpls(); | 
					
						
							| 
									
										
										
										
											2018-12-28 03:09:45 +01:00
										 |  |  | void dump_all_stringimpls() | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned i = 0; | 
					
						
							|  |  |  |     for (auto& it : *g_all_live_stringimpls) { | 
					
						
							| 
									
										
										
										
											2020-10-07 14:02:42 +02:00
										 |  |  |         dbgln("{}: \"{}\"", i, *it); | 
					
						
							| 
									
										
										
										
											2018-12-28 03:09:45 +01:00
										 |  |  |         ++i; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace AK { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-21 02:10:45 +01:00
										 |  |  | static StringImpl* s_the_empty_stringimpl = nullptr; | 
					
						
							| 
									
										
										
										
											2018-10-22 13:10:08 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-21 02:10:45 +01:00
										 |  |  | StringImpl& StringImpl::the_empty_stringimpl() | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-06-20 13:21:56 +02:00
										 |  |  |     if (!s_the_empty_stringimpl) { | 
					
						
							|  |  |  |         void* slot = kmalloc(sizeof(StringImpl) + sizeof(char)); | 
					
						
							|  |  |  |         s_the_empty_stringimpl = new (slot) StringImpl(ConstructTheEmptyStringImpl); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-12-21 02:10:45 +01:00
										 |  |  |     return *s_the_empty_stringimpl; | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-09 17:45:40 +01:00
										 |  |  | StringImpl::StringImpl(ConstructWithInlineBufferTag, size_t length) | 
					
						
							| 
									
										
										
										
											2018-12-28 03:09:45 +01:00
										 |  |  |     : m_length(length) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2021-01-24 15:28:26 +01:00
										 |  |  | #if STRINGIMPL_DEBUG
 | 
					
						
							| 
									
										
										
										
											2019-02-17 10:35:48 +01:00
										 |  |  |     if (!g_all_live_stringimpls) | 
					
						
							|  |  |  |         g_all_live_stringimpls = new HashTable<StringImpl*>; | 
					
						
							| 
									
										
										
										
											2018-12-28 03:09:45 +01:00
										 |  |  |     ++g_stringimpl_count; | 
					
						
							|  |  |  |     g_all_live_stringimpls->set(this); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | StringImpl::~StringImpl() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-03-22 10:12:55 +01:00
										 |  |  |     if (m_fly) | 
					
						
							|  |  |  |         FlyString::did_destroy_impl({}, *this); | 
					
						
							| 
									
										
										
										
											2021-01-24 15:28:26 +01:00
										 |  |  | #if STRINGIMPL_DEBUG
 | 
					
						
							| 
									
										
										
										
											2018-12-28 03:09:45 +01:00
										 |  |  |     --g_stringimpl_count; | 
					
						
							|  |  |  |     g_all_live_stringimpls->remove(this); | 
					
						
							|  |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-09 17:45:40 +01:00
										 |  |  | static inline size_t allocation_size_for_stringimpl(size_t length) | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     return sizeof(StringImpl) + (sizeof(char) * length) + sizeof(char); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-09 17:45:40 +01:00
										 |  |  | NonnullRefPtr<StringImpl> StringImpl::create_uninitialized(size_t length, char*& buffer) | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-02-23 20:42:32 +01:00
										 |  |  |     VERIFY(length); | 
					
						
							| 
									
										
										
										
											2019-01-31 17:31:23 +01:00
										 |  |  |     void* slot = kmalloc(allocation_size_for_stringimpl(length)); | 
					
						
							| 
									
										
										
										
											2021-02-23 20:42:32 +01:00
										 |  |  |     VERIFY(slot); | 
					
						
							| 
									
										
										
										
											2021-04-23 16:46:57 +02:00
										 |  |  |     auto new_stringimpl = adopt_ref(*new (slot) StringImpl(ConstructWithInlineBuffer, length)); | 
					
						
							| 
									
										
										
										
											2019-06-20 13:21:56 +02:00
										 |  |  |     buffer = const_cast<char*>(new_stringimpl->characters()); | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  |     buffer[length] = '\0'; | 
					
						
							| 
									
										
										
										
											2019-01-31 17:31:23 +01:00
										 |  |  |     return new_stringimpl; | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-09 17:45:40 +01:00
										 |  |  | RefPtr<StringImpl> StringImpl::create(const char* cstring, size_t length, ShouldChomp should_chomp) | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     if (!cstring) | 
					
						
							|  |  |  |         return nullptr; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-07 20:19:16 +02:00
										 |  |  |     if (should_chomp) { | 
					
						
							|  |  |  |         while (length) { | 
					
						
							|  |  |  |             char last_ch = cstring[length - 1]; | 
					
						
							|  |  |  |             if (!last_ch || last_ch == '\n' || last_ch == '\r') | 
					
						
							|  |  |  |                 --length; | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-03 16:11:28 +01:00
										 |  |  |     if (!length) | 
					
						
							|  |  |  |         return the_empty_stringimpl(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  |     char* buffer; | 
					
						
							| 
									
										
										
										
											2019-01-31 17:31:23 +01:00
										 |  |  |     auto new_stringimpl = create_uninitialized(length, buffer); | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  |     memcpy(buffer, cstring, length * sizeof(char)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 17:31:23 +01:00
										 |  |  |     return new_stringimpl; | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-21 18:37:47 +02:00
										 |  |  | RefPtr<StringImpl> StringImpl::create(const char* cstring, ShouldChomp shouldChomp) | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     if (!cstring) | 
					
						
							|  |  |  |         return nullptr; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-07 00:19:35 +01:00
										 |  |  |     return create(cstring, strlen(cstring), shouldChomp); | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-05 10:37:34 +02:00
										 |  |  | RefPtr<StringImpl> StringImpl::create(ReadonlyBytes bytes, ShouldChomp shouldChomp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return StringImpl::create(reinterpret_cast<const char*>(bytes.data()), bytes.size(), shouldChomp); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 17:31:23 +01:00
										 |  |  | static inline bool is_ascii_lowercase(char c) | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     return c >= 'a' && c <= 'z'; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 17:31:23 +01:00
										 |  |  | static inline bool is_ascii_uppercase(char c) | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     return c >= 'A' && c <= 'Z'; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 17:31:23 +01:00
										 |  |  | static inline char to_ascii_lowercase(char c) | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-01-31 17:31:23 +01:00
										 |  |  |     if (is_ascii_uppercase(c)) | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  |         return c | 0x20; | 
					
						
							|  |  |  |     return c; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 17:31:23 +01:00
										 |  |  | static inline char to_ascii_uppercase(char c) | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-01-31 17:31:23 +01:00
										 |  |  |     if (is_ascii_lowercase(c)) | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  |         return c & ~0x20; | 
					
						
							|  |  |  |     return c; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-21 18:37:47 +02:00
										 |  |  | NonnullRefPtr<StringImpl> StringImpl::to_lowercase() const | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-12-09 17:45:40 +01:00
										 |  |  |     for (size_t i = 0; i < m_length; ++i) { | 
					
						
							| 
									
										
										
										
											2019-06-20 13:21:56 +02:00
										 |  |  |         if (!is_ascii_lowercase(characters()[i])) | 
					
						
							| 
									
										
										
										
											2019-01-31 17:31:23 +01:00
										 |  |  |             goto slow_path; | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-02-25 16:04:08 +01:00
										 |  |  |     return const_cast<StringImpl&>(*this); | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 17:31:23 +01:00
										 |  |  | slow_path: | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  |     char* buffer; | 
					
						
							| 
									
										
										
										
											2018-12-21 02:10:45 +01:00
										 |  |  |     auto lowercased = create_uninitialized(m_length, buffer); | 
					
						
							| 
									
										
										
										
											2019-12-09 17:45:40 +01:00
										 |  |  |     for (size_t i = 0; i < m_length; ++i) | 
					
						
							| 
									
										
										
										
											2019-06-20 13:21:56 +02:00
										 |  |  |         buffer[i] = to_ascii_lowercase(characters()[i]); | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  |     return lowercased; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-21 18:37:47 +02:00
										 |  |  | NonnullRefPtr<StringImpl> StringImpl::to_uppercase() const | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-12-09 17:45:40 +01:00
										 |  |  |     for (size_t i = 0; i < m_length; ++i) { | 
					
						
							| 
									
										
										
										
											2019-06-20 13:21:56 +02:00
										 |  |  |         if (!is_ascii_uppercase(characters()[i])) | 
					
						
							| 
									
										
										
										
											2019-01-31 17:31:23 +01:00
										 |  |  |             goto slow_path; | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-02-25 16:04:08 +01:00
										 |  |  |     return const_cast<StringImpl&>(*this); | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-31 17:31:23 +01:00
										 |  |  | slow_path: | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  |     char* buffer; | 
					
						
							| 
									
										
										
										
											2018-12-21 02:10:45 +01:00
										 |  |  |     auto uppercased = create_uninitialized(m_length, buffer); | 
					
						
							| 
									
										
										
										
											2019-12-09 17:45:40 +01:00
										 |  |  |     for (size_t i = 0; i < m_length; ++i) | 
					
						
							| 
									
										
										
										
											2019-06-20 13:21:56 +02:00
										 |  |  |         buffer[i] = to_ascii_uppercase(characters()[i]); | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  |     return uppercased; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-12-21 02:10:45 +01:00
										 |  |  | void StringImpl::compute_hash() const | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2019-03-12 00:56:33 +01:00
										 |  |  |     if (!length()) | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  |         m_hash = 0; | 
					
						
							| 
									
										
										
										
											2019-03-12 00:56:33 +01:00
										 |  |  |     else | 
					
						
							| 
									
										
										
										
											2019-06-20 13:21:56 +02:00
										 |  |  |         m_hash = string_hash(characters(), m_length); | 
					
						
							|  |  |  |     m_has_hash = true; | 
					
						
							| 
									
										
										
										
											2018-10-10 11:53:07 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } |