| 
									
										
										
										
											2020-01-18 09:38:21 +01:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> | 
					
						
							|  |  |  |  * All rights reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Redistribution and use in source and binary forms, with or without | 
					
						
							|  |  |  |  * modification, are permitted provided that the following conditions are met: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 1. Redistributions of source code must retain the above copyright notice, this | 
					
						
							|  |  |  |  *    list of conditions and the following disclaimer. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 2. Redistributions in binary form must reproduce the above copyright notice, | 
					
						
							|  |  |  |  *    this list of conditions and the following disclaimer in the documentation | 
					
						
							|  |  |  |  *    and/or other materials provided with the distribution. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | 
					
						
							|  |  |  |  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
					
						
							|  |  |  |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 
					
						
							|  |  |  |  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | 
					
						
							|  |  |  |  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 
					
						
							|  |  |  |  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | 
					
						
							|  |  |  |  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | 
					
						
							|  |  |  |  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | 
					
						
							|  |  |  |  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
					
						
							|  |  |  |  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-14 21:41:10 +01:00
										 |  |  | #include <AK/ByteBuffer.h>
 | 
					
						
							| 
									
										
										
										
											2019-09-06 15:34:26 +02:00
										 |  |  | #include <AK/String.h>
 | 
					
						
							| 
									
										
										
										
											2019-05-28 11:53:16 +02:00
										 |  |  | #include <AK/StringView.h>
 | 
					
						
							| 
									
										
										
										
											2020-02-14 21:41:10 +01:00
										 |  |  | #include <AK/Vector.h>
 | 
					
						
							| 
									
										
										
										
											2019-04-16 02:39:16 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace AK { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-08 23:55:13 +02:00
										 |  |  | StringView::StringView(const String& string) | 
					
						
							|  |  |  |     : m_impl(string.impl()) | 
					
						
							| 
									
										
										
										
											2019-06-03 18:27:56 +02:00
										 |  |  |     , m_characters(string.characters()) | 
					
						
							| 
									
										
										
										
											2019-06-02 12:19:21 +02:00
										 |  |  |     , m_length(string.length()) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-29 12:03:28 +02:00
										 |  |  | StringView::StringView(const ByteBuffer& buffer) | 
					
						
							|  |  |  |     : m_characters((const char*)buffer.data()) | 
					
						
							| 
									
										
										
										
											2020-03-01 12:35:09 +01:00
										 |  |  |     , m_length(buffer.size()) | 
					
						
							| 
									
										
										
										
											2019-06-29 12:03:28 +02:00
										 |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-21 00:43:37 +03:00
										 |  |  | Vector<StringView> StringView::split_view(const char separator, bool keep_empty) const | 
					
						
							| 
									
										
										
										
											2019-04-16 02:39:16 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     if (is_empty()) | 
					
						
							| 
									
										
										
										
											2019-05-28 11:53:16 +02:00
										 |  |  |         return {}; | 
					
						
							| 
									
										
										
										
											2019-04-16 02:39:16 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     Vector<StringView> v; | 
					
						
							| 
									
										
										
										
											2019-12-09 17:45:40 +01:00
										 |  |  |     size_t substart = 0; | 
					
						
							|  |  |  |     for (size_t i = 0; i < length(); ++i) { | 
					
						
							| 
									
										
										
										
											2019-07-08 15:38:44 +02:00
										 |  |  |         char ch = characters_without_null_termination()[i]; | 
					
						
							| 
									
										
										
										
											2019-04-16 02:39:16 +02:00
										 |  |  |         if (ch == separator) { | 
					
						
							| 
									
										
										
										
											2019-12-09 17:45:40 +01:00
										 |  |  |             size_t sublen = i - substart; | 
					
						
							| 
									
										
										
										
											2019-09-21 00:43:37 +03:00
										 |  |  |             if (sublen != 0 || keep_empty) | 
					
						
							| 
									
										
										
										
											2019-04-16 02:39:16 +02:00
										 |  |  |                 v.append(substring_view(substart, sublen)); | 
					
						
							|  |  |  |             substart = i + 1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-12-09 17:45:40 +01:00
										 |  |  |     size_t taillen = length() - substart; | 
					
						
							| 
									
										
										
										
											2019-09-21 00:43:37 +03:00
										 |  |  |     if (taillen != 0 || keep_empty) | 
					
						
							| 
									
										
										
										
											2019-04-16 02:39:16 +02:00
										 |  |  |         v.append(substring_view(substart, taillen)); | 
					
						
							|  |  |  |     return v; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-02 07:42:33 -05:00
										 |  |  | Vector<StringView> StringView::lines(bool consider_cr) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (is_empty()) | 
					
						
							|  |  |  |         return {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!consider_cr) | 
					
						
							|  |  |  |         return split_view('\n', true); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Vector<StringView> v; | 
					
						
							| 
									
										
										
										
											2019-12-09 17:45:40 +01:00
										 |  |  |     size_t substart = 0; | 
					
						
							| 
									
										
										
										
											2019-12-02 07:42:33 -05:00
										 |  |  |     bool last_ch_was_cr = false; | 
					
						
							|  |  |  |     bool split_view = false; | 
					
						
							| 
									
										
										
										
											2019-12-09 17:45:40 +01:00
										 |  |  |     for (size_t i = 0; i < length(); ++i) { | 
					
						
							| 
									
										
										
										
											2019-12-02 07:42:33 -05:00
										 |  |  |         char ch = characters_without_null_termination()[i]; | 
					
						
							|  |  |  |         if (ch == '\n') { | 
					
						
							|  |  |  |             split_view = true; | 
					
						
							|  |  |  |             if (last_ch_was_cr) { | 
					
						
							|  |  |  |                 substart = i + 1; | 
					
						
							|  |  |  |                 split_view = false; | 
					
						
							|  |  |  |                 last_ch_was_cr = false; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (ch == '\r') { | 
					
						
							|  |  |  |             split_view = true; | 
					
						
							|  |  |  |             last_ch_was_cr = true; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (split_view) { | 
					
						
							| 
									
										
										
										
											2019-12-09 17:45:40 +01:00
										 |  |  |             size_t sublen = i - substart; | 
					
						
							| 
									
										
										
										
											2019-12-02 20:41:15 +01:00
										 |  |  |             v.append(substring_view(substart, sublen)); | 
					
						
							| 
									
										
										
										
											2019-12-02 07:42:33 -05:00
										 |  |  |             substart = i + 1; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         split_view = false; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-12-09 17:45:40 +01:00
										 |  |  |     size_t taillen = length() - substart; | 
					
						
							| 
									
										
										
										
											2019-12-02 07:42:33 -05:00
										 |  |  |     if (taillen != 0) | 
					
						
							|  |  |  |         v.append(substring_view(substart, taillen)); | 
					
						
							|  |  |  |     return v; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-15 10:14:22 +13:00
										 |  |  | bool StringView::starts_with(char ch) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (is_empty()) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     return ch == characters_without_null_termination()[0]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-12 06:13:07 -05:00
										 |  |  | bool StringView::starts_with(const StringView& str) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (str.is_empty()) | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     if (is_empty()) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     if (str.length() > length()) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     if (characters_without_null_termination() == str.characters_without_null_termination()) | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     return !memcmp(characters_without_null_termination(), str.characters_without_null_termination(), str.length()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-15 10:14:22 +13:00
										 |  |  | bool StringView::ends_with(char ch) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (is_empty()) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     return ch == characters_without_null_termination()[length() - 1]; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-30 01:44:30 +13:00
										 |  |  | bool StringView::ends_with(const StringView& str) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (str.is_empty()) | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     if (is_empty()) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     if (str.length() > length()) | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     return !memcmp(characters_without_null_termination() + length() - str.length(), str.characters_without_null_termination(), str.length()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-26 15:25:24 +08:00
										 |  |  | bool StringView::matches(const StringView& mask, CaseSensitivity case_sensitivity) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return StringUtils::matches(*this, mask, case_sensitivity); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-09 17:45:40 +01:00
										 |  |  | StringView StringView::substring_view(size_t start, size_t length) const | 
					
						
							| 
									
										
										
										
											2019-04-16 02:39:16 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     ASSERT(start + length <= m_length); | 
					
						
							|  |  |  |     return { m_characters + start, length }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-13 16:30:55 +03:00
										 |  |  | StringView StringView::substring_view_starting_from_substring(const StringView& substring) const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-07-08 15:38:44 +02:00
										 |  |  |     const char* remaining_characters = substring.characters_without_null_termination(); | 
					
						
							| 
									
										
										
										
											2019-06-13 16:30:55 +03:00
										 |  |  |     ASSERT(remaining_characters >= m_characters); | 
					
						
							|  |  |  |     ASSERT(remaining_characters <= m_characters + m_length); | 
					
						
							| 
									
										
										
										
											2019-12-09 17:45:40 +01:00
										 |  |  |     size_t remaining_length = m_length - (remaining_characters - m_characters); | 
					
						
							| 
									
										
										
										
											2019-06-13 16:30:55 +03:00
										 |  |  |     return { remaining_characters, remaining_length }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | StringView StringView::substring_view_starting_after_substring(const StringView& substring) const | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-07-08 15:38:44 +02:00
										 |  |  |     const char* remaining_characters = substring.characters_without_null_termination() + substring.length(); | 
					
						
							| 
									
										
										
										
											2019-06-13 16:30:55 +03:00
										 |  |  |     ASSERT(remaining_characters >= m_characters); | 
					
						
							|  |  |  |     ASSERT(remaining_characters <= m_characters + m_length); | 
					
						
							| 
									
										
										
										
											2019-12-09 17:45:40 +01:00
										 |  |  |     size_t remaining_length = m_length - (remaining_characters - m_characters); | 
					
						
							| 
									
										
										
										
											2019-06-13 16:30:55 +03:00
										 |  |  |     return { remaining_characters, remaining_length }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-04 11:44:20 +02:00
										 |  |  | int StringView::to_int(bool& ok) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     bool negative = false; | 
					
						
							|  |  |  |     int value = 0; | 
					
						
							| 
									
										
										
										
											2019-12-09 17:45:40 +01:00
										 |  |  |     size_t i = 0; | 
					
						
							| 
									
										
										
										
											2019-08-04 11:44:20 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (is_empty()) { | 
					
						
							|  |  |  |         ok = false; | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (characters_without_null_termination()[0] == '-') { | 
					
						
							|  |  |  |         i++; | 
					
						
							|  |  |  |         negative = true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     for (; i < length(); i++) { | 
					
						
							|  |  |  |         if (characters_without_null_termination()[i] < '0' || characters_without_null_termination()[i] > '9') { | 
					
						
							|  |  |  |             ok = false; | 
					
						
							|  |  |  |             return 0; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         value = value * 10; | 
					
						
							|  |  |  |         value += characters_without_null_termination()[i] - '0'; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ok = true; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return negative ? -value : value; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-16 02:39:16 +02:00
										 |  |  | unsigned StringView::to_uint(bool& ok) const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned value = 0; | 
					
						
							| 
									
										
										
										
											2019-12-09 17:45:40 +01:00
										 |  |  |     for (size_t i = 0; i < length(); ++i) { | 
					
						
							| 
									
										
										
										
											2019-07-08 15:38:44 +02:00
										 |  |  |         if (characters_without_null_termination()[i] < '0' || characters_without_null_termination()[i] > '9') { | 
					
						
							| 
									
										
										
										
											2019-04-16 02:39:16 +02:00
										 |  |  |             ok = false; | 
					
						
							|  |  |  |             return 0; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         value = value * 10; | 
					
						
							| 
									
										
										
										
											2019-07-08 15:38:44 +02:00
										 |  |  |         value += characters_without_null_termination()[i] - '0'; | 
					
						
							| 
									
										
										
										
											2019-04-16 02:39:16 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |     ok = true; | 
					
						
							|  |  |  |     return value; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-24 22:31:06 +02:00
										 |  |  | unsigned StringView::hash() const | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (is_empty()) | 
					
						
							|  |  |  |         return 0; | 
					
						
							|  |  |  |     if (m_impl) | 
					
						
							|  |  |  |         return m_impl->hash(); | 
					
						
							|  |  |  |     return string_hash(characters_without_null_termination(), length()); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-16 02:39:16 +02:00
										 |  |  | } |