| 
									
										
										
										
											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. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-15 14:56:37 +02:00
										 |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-30 00:17:54 +03:00
										 |  |  | #include <AK/Assertions.h>
 | 
					
						
							|  |  |  | #include <AK/Checked.h>
 | 
					
						
							| 
									
										
										
										
											2020-02-14 21:41:10 +01:00
										 |  |  | #include <AK/Forward.h>
 | 
					
						
							| 
									
										
										
										
											2020-07-27 14:15:37 +02:00
										 |  |  | #include <AK/Span.h>
 | 
					
						
							| 
									
										
										
										
											2020-02-14 21:41:10 +01:00
										 |  |  | #include <AK/StdLibExtras.h>
 | 
					
						
							| 
									
										
										
										
											2020-02-26 15:25:24 +08:00
										 |  |  | #include <AK/StringUtils.h>
 | 
					
						
							| 
									
										
										
										
											2019-04-16 02:39:16 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | namespace AK { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-15 14:56:37 +02:00
										 |  |  | class StringView { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2021-01-10 16:29:28 -07:00
										 |  |  |     ALWAYS_INLINE constexpr StringView() = default; | 
					
						
							| 
									
										
										
										
											2020-05-30 16:06:30 +02:00
										 |  |  |     ALWAYS_INLINE constexpr StringView(const char* characters, size_t length) | 
					
						
							| 
									
										
										
										
											2019-05-28 11:53:16 +02:00
										 |  |  |         : m_characters(characters) | 
					
						
							|  |  |  |         , m_length(length) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-04-30 00:17:54 +03:00
										 |  |  |         ASSERT(!Checked<uintptr_t>::addition_would_overflow((uintptr_t)characters, length)); | 
					
						
							| 
									
										
										
										
											2019-05-28 11:53:16 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-04-30 11:43:25 +02:00
										 |  |  |     ALWAYS_INLINE StringView(const unsigned char* characters, size_t length) | 
					
						
							| 
									
										
										
										
											2019-05-28 11:53:16 +02:00
										 |  |  |         : m_characters((const char*)characters) | 
					
						
							|  |  |  |         , m_length(length) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-04-30 00:17:54 +03:00
										 |  |  |         ASSERT(!Checked<uintptr_t>::addition_would_overflow((uintptr_t)characters, length)); | 
					
						
							| 
									
										
										
										
											2019-05-28 11:53:16 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-05-30 16:06:30 +02:00
										 |  |  |     ALWAYS_INLINE constexpr StringView(const char* cstring) | 
					
						
							| 
									
										
										
										
											2019-04-15 14:56:37 +02:00
										 |  |  |         : m_characters(cstring) | 
					
						
							| 
									
										
										
										
											2020-03-08 12:34:33 +01:00
										 |  |  |         , m_length(cstring ? __builtin_strlen(cstring) : 0) | 
					
						
							| 
									
										
										
										
											2019-04-15 14:56:37 +02:00
										 |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-08-19 11:43:41 +02:00
										 |  |  |     ALWAYS_INLINE StringView(ReadonlyBytes bytes) | 
					
						
							|  |  |  |         : m_characters(reinterpret_cast<const char*>(bytes.data())) | 
					
						
							|  |  |  |         , m_length(bytes.size()) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-06-29 12:03:28 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     StringView(const ByteBuffer&); | 
					
						
							|  |  |  |     StringView(const String&); | 
					
						
							| 
									
										
										
										
											2020-03-22 10:12:55 +01:00
										 |  |  |     StringView(const FlyString&); | 
					
						
							| 
									
										
										
										
											2019-04-15 14:56:37 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-08 18:30:40 +02:00
										 |  |  |     bool is_null() const { return !m_characters; } | 
					
						
							| 
									
										
										
										
											2019-04-15 14:56:37 +02:00
										 |  |  |     bool is_empty() const { return m_length == 0; } | 
					
						
							| 
									
										
										
										
											2020-07-27 14:15:37 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-08 15:38:44 +02:00
										 |  |  |     const char* characters_without_null_termination() const { return m_characters; } | 
					
						
							| 
									
										
										
										
											2019-12-09 17:45:40 +01:00
										 |  |  |     size_t length() const { return m_length; } | 
					
						
							| 
									
										
										
										
											2020-07-27 14:15:37 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     ReadonlyBytes bytes() const { return { m_characters, m_length }; } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-10 16:13:29 +08:00
										 |  |  |     const char& operator[](size_t index) const { return m_characters[index]; } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-06 21:14:08 +02:00
										 |  |  |     using ConstIterator = SimpleIterator<const StringView, const char>; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     constexpr ConstIterator begin() const { return ConstIterator::begin(*this); } | 
					
						
							|  |  |  |     constexpr ConstIterator end() const { return ConstIterator::end(*this); } | 
					
						
							| 
									
										
										
										
											2019-04-15 14:56:37 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-24 22:31:06 +02:00
										 |  |  |     unsigned hash() const; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-18 17:59:38 +01:00
										 |  |  |     bool starts_with(const StringView&, CaseSensitivity = CaseSensitivity::CaseSensitive) const; | 
					
						
							| 
									
										
										
										
											2020-05-26 03:21:34 -07:00
										 |  |  |     bool ends_with(const StringView&, CaseSensitivity = CaseSensitivity::CaseSensitive) const; | 
					
						
							| 
									
										
										
										
											2020-02-15 10:14:22 +13:00
										 |  |  |     bool starts_with(char) const; | 
					
						
							|  |  |  |     bool ends_with(char) const; | 
					
						
							| 
									
										
										
										
											2020-02-26 15:25:24 +08:00
										 |  |  |     bool matches(const StringView& mask, CaseSensitivity = CaseSensitivity::CaseInsensitive) const; | 
					
						
							| 
									
										
										
										
											2020-10-25 09:04:39 +03:30
										 |  |  |     bool matches(const StringView& mask, Vector<MaskSpan>&, CaseSensitivity = CaseSensitivity::CaseInsensitive) const; | 
					
						
							| 
									
										
										
										
											2020-04-17 15:04:40 +02:00
										 |  |  |     bool contains(char) const; | 
					
						
							| 
									
										
										
										
											2020-10-20 15:07:03 -06:00
										 |  |  |     bool contains(const StringView&, CaseSensitivity = CaseSensitivity::CaseSensitive) const; | 
					
						
							| 
									
										
										
										
											2020-05-13 17:59:31 +01:00
										 |  |  |     bool equals_ignoring_case(const StringView& other) const; | 
					
						
							| 
									
										
										
										
											2019-09-12 06:13:07 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-20 18:05:04 +04:30
										 |  |  |     StringView trim_whitespace(TrimMode mode = TrimMode::Both) const { return StringUtils::trim_whitespace(*this, mode); } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-02 12:21:20 -06:00
										 |  |  |     Optional<size_t> find_first_of(char) const; | 
					
						
							|  |  |  |     Optional<size_t> find_first_of(const StringView&) const; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Optional<size_t> find_last_of(char) const; | 
					
						
							|  |  |  |     Optional<size_t> find_last_of(const StringView&) const; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-12 23:28:45 +03:30
										 |  |  |     Optional<size_t> find(const StringView&) const; | 
					
						
							|  |  |  |     Optional<size_t> find(char c) const; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-09 17:45:40 +01:00
										 |  |  |     StringView substring_view(size_t start, size_t length) const; | 
					
						
							| 
									
										
										
										
											2020-09-19 15:19:34 +02:00
										 |  |  |     StringView substring_view(size_t start) const; | 
					
						
							| 
									
										
										
										
											2019-09-21 00:43:37 +03:00
										 |  |  |     Vector<StringView> split_view(char, bool keep_empty = false) const; | 
					
						
							| 
									
										
										
										
											2020-05-28 00:51:43 +04:30
										 |  |  |     Vector<StringView> split_view(const StringView&, bool keep_empty = false) const; | 
					
						
							| 
									
										
										
										
											2019-08-04 11:44:20 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-02 07:42:33 -05:00
										 |  |  |     // Create a Vector of StringViews split by line endings. As of CommonMark
 | 
					
						
							|  |  |  |     // 0.29, the spec defines a line ending as "a newline (U+000A), a carriage
 | 
					
						
							|  |  |  |     // return (U+000D) not followed by a newline, or a carriage return and a
 | 
					
						
							|  |  |  |     // following newline.".
 | 
					
						
							|  |  |  |     Vector<StringView> lines(bool consider_cr = true) const; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-11 00:17:30 +11:00
										 |  |  |     template<typename T = int> | 
					
						
							|  |  |  |     Optional<T> to_int() const; | 
					
						
							|  |  |  |     template<typename T = unsigned> | 
					
						
							|  |  |  |     Optional<T> to_uint() const; | 
					
						
							| 
									
										
										
										
											2019-04-16 02:39:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-13 16:30:55 +03:00
										 |  |  |     // Create a new substring view of this string view, starting either at the beginning of
 | 
					
						
							|  |  |  |     // the given substring view, or after its end, and continuing until the end of this string
 | 
					
						
							|  |  |  |     // view (that is, for the remaining part of its length). For example,
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     //    StringView str { "foobar" };
 | 
					
						
							|  |  |  |     //    StringView substr = str.substring_view(1, 2);  // "oo"
 | 
					
						
							|  |  |  |     //    StringView substr_from = str.substring_view_starting_from_substring(subst);  // "oobar"
 | 
					
						
							|  |  |  |     //    StringView substr_after = str.substring_view_starting_after_substring(subst);  // "bar"
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // Note that this only works if the string view passed as an argument is indeed a substring
 | 
					
						
							|  |  |  |     // view of this string view, such as one created by substring_view() and split_view(). It
 | 
					
						
							|  |  |  |     // does not work for arbitrary strings; for example declaring substr in the example above as
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     //     StringView substr { "oo" };
 | 
					
						
							|  |  |  |     //
 | 
					
						
							|  |  |  |     // would not work.
 | 
					
						
							|  |  |  |     StringView substring_view_starting_from_substring(const StringView& substring) const; | 
					
						
							|  |  |  |     StringView substring_view_starting_after_substring(const StringView& substring) const; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 19:22:58 +02:00
										 |  |  |     bool operator==(const char* cstring) const | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-06-08 18:30:40 +02:00
										 |  |  |         if (is_null()) | 
					
						
							|  |  |  |             return !cstring; | 
					
						
							|  |  |  |         if (!cstring) | 
					
						
							|  |  |  |             return false; | 
					
						
							| 
									
										
										
										
											2021-02-23 14:13:57 +01:00
										 |  |  |         // NOTE: `m_characters` is not guaranteed to be null-terminated, but `cstring` is.
 | 
					
						
							|  |  |  |         const char* cp = cstring; | 
					
						
							|  |  |  |         for (size_t i = 0; i < m_length; ++i) { | 
					
						
							|  |  |  |             if (m_characters[i] != *(cp++)) | 
					
						
							|  |  |  |                 return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return !*cp; | 
					
						
							| 
									
										
										
										
											2019-06-07 19:22:58 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-02-23 14:13:57 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-07 19:22:58 +02:00
										 |  |  |     bool operator!=(const char* cstring) const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return !(*this == cstring); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-04-16 02:39:16 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     bool operator==(const String&) const; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-15 14:07:23 +02:00
										 |  |  |     bool operator==(const StringView& other) const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (is_null()) | 
					
						
							|  |  |  |             return other.is_null(); | 
					
						
							|  |  |  |         if (other.is_null()) | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         if (length() != other.length()) | 
					
						
							|  |  |  |             return false; | 
					
						
							| 
									
										
										
										
											2020-03-08 12:34:33 +01:00
										 |  |  |         return !__builtin_memcmp(m_characters, other.m_characters, m_length); | 
					
						
							| 
									
										
										
										
											2019-08-15 14:07:23 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     bool operator!=(const StringView& other) const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return !(*this == other); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-09 21:55:32 -04:00
										 |  |  |     bool operator<(const StringView& other) const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (int c = __builtin_memcmp(m_characters, other.m_characters, min(m_length, other.m_length))) | 
					
						
							|  |  |  |             return c < 0; | 
					
						
							|  |  |  |         return m_length < other.m_length; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-22 13:07:45 +01:00
										 |  |  |     const StringImpl* impl() const { return m_impl; } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-06 18:53:05 +02:00
										 |  |  |     String to_string() const; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-03 02:56:02 +03:30
										 |  |  |     bool is_whitespace() const { return StringUtils::is_whitespace(*this); } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-28 01:28:11 +03:30
										 |  |  |     template<typename T, typename... Rest> | 
					
						
							|  |  |  |     bool is_one_of(const T& string, Rest... rest) const | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (*this == string) | 
					
						
							|  |  |  |             return true; | 
					
						
							|  |  |  |         return is_one_of(rest...); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-15 14:56:37 +02:00
										 |  |  | private: | 
					
						
							| 
									
										
										
										
											2020-10-28 01:28:11 +03:30
										 |  |  |     bool is_one_of() const { return false; } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-06-03 18:27:56 +02:00
										 |  |  |     friend class String; | 
					
						
							| 
									
										
										
										
											2019-06-08 23:55:13 +02:00
										 |  |  |     const StringImpl* m_impl { nullptr }; | 
					
						
							| 
									
										
										
										
											2019-04-15 14:56:37 +02:00
										 |  |  |     const char* m_characters { nullptr }; | 
					
						
							| 
									
										
										
										
											2019-12-09 17:45:40 +01:00
										 |  |  |     size_t m_length { 0 }; | 
					
						
							| 
									
										
										
										
											2019-04-15 14:56:37 +02:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2019-04-16 02:39:16 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-08 10:48:56 -07:00
										 |  |  | template<> | 
					
						
							|  |  |  | struct Traits<StringView> : public GenericTraits<String> { | 
					
						
							|  |  |  |     static unsigned hash(const StringView& s) { return s.hash(); } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-04-16 02:39:16 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | using AK::StringView; |