mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 08:32:43 +00:00 
			
		
		
		
	AK: Implement String::find_any_of() and StringView::find_any_of()
This implements StringUtils::find_any_of() and uses it in
String::find_any_of() and StringView::find_any_of(). All uses of
find_{first,last}_of have been replaced with find_any_of(), find() or
find_last(). find_{first,last}_of have subsequently been removed.
			
			
This commit is contained in:
		
							parent
							
								
									17eddf3ac4
								
							
						
					
					
						commit
						9cc35d1ba3
					
				
					 12 changed files with 44 additions and 52 deletions
				
			
		|  | @ -147,6 +147,8 @@ public: | ||||||
|     [[nodiscard]] Optional<size_t> find_last(char needle) const { return StringUtils::find_last(*this, needle); } |     [[nodiscard]] Optional<size_t> find_last(char needle) const { return StringUtils::find_last(*this, needle); } | ||||||
|     // FIXME: Implement find_last(StringView const&) for API symmetry.
 |     // FIXME: Implement find_last(StringView const&) for API symmetry.
 | ||||||
|     [[nodiscard]] Vector<size_t> find_all(StringView const& needle) const { return StringUtils::find_all(*this, needle); } |     [[nodiscard]] Vector<size_t> find_all(StringView const& needle) const { return StringUtils::find_all(*this, needle); } | ||||||
|  |     using SearchDirection = StringUtils::SearchDirection; | ||||||
|  |     [[nodiscard]] Optional<size_t> find_any_of(StringView const& needles, SearchDirection direction) const { return StringUtils::find_any_of(*this, needles, direction); } | ||||||
| 
 | 
 | ||||||
|     [[nodiscard]] String substring(size_t start, size_t length) const; |     [[nodiscard]] String substring(size_t start, size_t length) const; | ||||||
|     [[nodiscard]] String substring(size_t start) const; |     [[nodiscard]] String substring(size_t start) const; | ||||||
|  |  | ||||||
|  | @ -378,6 +378,24 @@ Vector<size_t> find_all(StringView const& haystack, StringView const& needle) | ||||||
|     return positions; |     return positions; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | Optional<size_t> find_any_of(StringView const& haystack, StringView const& needles, SearchDirection direction) | ||||||
|  | { | ||||||
|  |     if (haystack.is_empty() || needles.is_empty()) | ||||||
|  |         return {}; | ||||||
|  |     if (direction == SearchDirection::Forward) { | ||||||
|  |         for (size_t i = 0; i < haystack.length(); ++i) { | ||||||
|  |             if (needles.contains(haystack[i])) | ||||||
|  |                 return i; | ||||||
|  |         } | ||||||
|  |     } else if (direction == SearchDirection::Backward) { | ||||||
|  |         for (size_t i = haystack.length(); i > 0; --i) { | ||||||
|  |             if (needles.contains(haystack[i - 1])) | ||||||
|  |                 return i - 1; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return {}; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| String to_snakecase(const StringView& str) | String to_snakecase(const StringView& str) | ||||||
| { | { | ||||||
|     auto should_insert_underscore = [&](auto i, auto current_char) { |     auto should_insert_underscore = [&](auto i, auto current_char) { | ||||||
|  |  | ||||||
|  | @ -62,6 +62,11 @@ Optional<size_t> find(StringView const& haystack, char needle, size_t start = 0) | ||||||
| Optional<size_t> find(StringView const& haystack, StringView const& needle, size_t start = 0); | Optional<size_t> find(StringView const& haystack, StringView const& needle, size_t start = 0); | ||||||
| Optional<size_t> find_last(StringView const& haystack, char needle); | Optional<size_t> find_last(StringView const& haystack, char needle); | ||||||
| Vector<size_t> find_all(StringView const& haystack, StringView const& needle); | Vector<size_t> find_all(StringView const& haystack, StringView const& needle); | ||||||
|  | enum class SearchDirection { | ||||||
|  |     Forward, | ||||||
|  |     Backward | ||||||
|  | }; | ||||||
|  | Optional<size_t> find_any_of(StringView const& haystack, StringView const& needles, SearchDirection); | ||||||
| 
 | 
 | ||||||
| String to_snakecase(const StringView&); | String to_snakecase(const StringView&); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -238,33 +238,6 @@ bool StringView::operator==(const String& string) const | ||||||
|     return !__builtin_memcmp(m_characters, string.characters(), m_length); |     return !__builtin_memcmp(m_characters, string.characters(), m_length); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Optional<size_t> StringView::find_first_of(const StringView& view) const |  | ||||||
| { |  | ||||||
|     if (const auto location = AK::find_if(begin(), end(), |  | ||||||
|             [&](const auto c) { |  | ||||||
|                 return any_of(view.begin(), view.end(), |  | ||||||
|                     [&](const auto view_char) { |  | ||||||
|                         return c == view_char; |  | ||||||
|                     }); |  | ||||||
|             }); |  | ||||||
|         location != end()) { |  | ||||||
|         return location.index(); |  | ||||||
|     } |  | ||||||
|     return {}; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| Optional<size_t> StringView::find_last_of(const StringView& view) const |  | ||||||
| { |  | ||||||
|     for (size_t pos = m_length; pos != 0; --pos) { |  | ||||||
|         char c = m_characters[pos - 1]; |  | ||||||
|         for (char view_char : view) { |  | ||||||
|             if (c == view_char) |  | ||||||
|                 return pos - 1; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     return {}; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| String StringView::to_string() const { return String { *this }; } | String StringView::to_string() const { return String { *this }; } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -93,8 +93,8 @@ public: | ||||||
| 
 | 
 | ||||||
|     [[nodiscard]] Vector<size_t> find_all(StringView const& needle) const { return StringUtils::find_all(*this, needle); } |     [[nodiscard]] Vector<size_t> find_all(StringView const& needle) const { return StringUtils::find_all(*this, needle); } | ||||||
| 
 | 
 | ||||||
|     [[nodiscard]] Optional<size_t> find_first_of(StringView const&) const; |     using SearchDirection = StringUtils::SearchDirection; | ||||||
|     [[nodiscard]] Optional<size_t> find_last_of(StringView const&) const; |     [[nodiscard]] Optional<size_t> find_any_of(StringView const& needles, SearchDirection direction = SearchDirection::Forward) { return StringUtils::find_any_of(*this, needles, direction); } | ||||||
| 
 | 
 | ||||||
|     [[nodiscard]] constexpr StringView substring_view(size_t start, size_t length) const |     [[nodiscard]] constexpr StringView substring_view(size_t start, size_t length) const | ||||||
|     { |     { | ||||||
|  |  | ||||||
|  | @ -123,26 +123,19 @@ TEST_CASE(find_last) | ||||||
|     EXPECT_EQ(test_string_view.find_last('/'), 0U); |     EXPECT_EQ(test_string_view.find_last('/'), 0U); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| TEST_CASE(find_first_of) | TEST_CASE(find_any_of) | ||||||
| { | { | ||||||
|     auto test_string_view = "aabbcc_xy_ccbbaa"sv; |     auto test_string_view = "aabbcc_xy_ccbbaa"sv; | ||||||
|     EXPECT_EQ(test_string_view.find_first_of("bc"), 2U); |     EXPECT_EQ(test_string_view.find_any_of("bc", StringView::SearchDirection::Forward), 2U); | ||||||
|     EXPECT_EQ(test_string_view.find_first_of("yx"), 7U); |     EXPECT_EQ(test_string_view.find_any_of("yx", StringView::SearchDirection::Forward), 7U); | ||||||
|     EXPECT_EQ(test_string_view.find_first_of("defg").has_value(), false); |     EXPECT_EQ(test_string_view.find_any_of("defg", StringView::SearchDirection::Forward).has_value(), false); | ||||||
|  |     EXPECT_EQ(test_string_view.find_any_of("bc", StringView::SearchDirection::Backward), 13U); | ||||||
|  |     EXPECT_EQ(test_string_view.find_any_of("yx", StringView::SearchDirection::Backward), 8U); | ||||||
|  |     EXPECT_EQ(test_string_view.find_any_of("fghi", StringView::SearchDirection::Backward).has_value(), false); | ||||||
| 
 | 
 | ||||||
|     test_string_view = "/"sv; |     test_string_view = "/"sv; | ||||||
|     EXPECT_EQ(test_string_view.find_first_of("/"), 0U); |     EXPECT_EQ(test_string_view.find_any_of("/", StringView::SearchDirection::Forward), 0U); | ||||||
| } |     EXPECT_EQ(test_string_view.find_any_of("/", StringView::SearchDirection::Backward), 0U); | ||||||
| 
 |  | ||||||
| TEST_CASE(find_last_of) |  | ||||||
| { |  | ||||||
|     auto test_string_view = "aabbcc_xy_ccbbaa"sv; |  | ||||||
|     EXPECT_EQ(test_string_view.find_last_of("bc"), 13U); |  | ||||||
|     EXPECT_EQ(test_string_view.find_last_of("yx"), 8U); |  | ||||||
|     EXPECT_EQ(test_string_view.find_last_of("fghi").has_value(), false); |  | ||||||
| 
 |  | ||||||
|     test_string_view = "/"sv; |  | ||||||
|     EXPECT_EQ(test_string_view.find_last_of("/"), 0U); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| TEST_CASE(split_view) | TEST_CASE(split_view) | ||||||
|  |  | ||||||
|  | @ -637,7 +637,7 @@ Optional<Vector<GUI::AutocompleteProvider::Entry>> CppComprehensionEngine::try_a | ||||||
|     } else |     } else | ||||||
|         return {}; |         return {}; | ||||||
| 
 | 
 | ||||||
|     auto last_slash = partial_include.find_last_of("/"); |     auto last_slash = partial_include.find_last('/'); | ||||||
|     auto include_dir = String::empty(); |     auto include_dir = String::empty(); | ||||||
|     auto partial_basename = partial_include.substring_view((last_slash.has_value() ? last_slash.value() : 0) + 1); |     auto partial_basename = partial_include.substring_view((last_slash.has_value() ? last_slash.value() : 0) + 1); | ||||||
|     if (last_slash.has_value()) { |     if (last_slash.has_value()) { | ||||||
|  |  | ||||||
|  | @ -74,7 +74,7 @@ void LibraryMetadata::handle_mmap(FlatPtr base, size_t size, const String& name) | ||||||
|     else if (!name.contains(":")) |     else if (!name.contains(":")) | ||||||
|         return; |         return; | ||||||
|     else |     else | ||||||
|         path = name.substring(0, name.view().find_first_of(":").value()); |         path = name.substring(0, name.view().find(':').value()); | ||||||
| 
 | 
 | ||||||
|     String full_path; |     String full_path; | ||||||
|     if (name.contains(".so")) |     if (name.contains(".so")) | ||||||
|  |  | ||||||
|  | @ -60,9 +60,10 @@ struct [[gnu::packed]] MemoryRegionInfo { | ||||||
|         StringView memory_region_name { region_name }; |         StringView memory_region_name { region_name }; | ||||||
|         if (memory_region_name.contains("Loader.so")) |         if (memory_region_name.contains("Loader.so")) | ||||||
|             return "Loader.so"; |             return "Loader.so"; | ||||||
|         if (!memory_region_name.contains(":")) |         auto maybe_colon_index = memory_region_name.find(':'); | ||||||
|  |         if (!maybe_colon_index.has_value()) | ||||||
|             return {}; |             return {}; | ||||||
|         return memory_region_name.substring_view(0, memory_region_name.find_first_of(":").value()).to_string(); |         return memory_region_name.substring_view(0, *maybe_colon_index).to_string(); | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -73,7 +73,7 @@ Link::Link(String text, const Document& document) | ||||||
|     while (index < m_text.length() && (m_text[index] == ' ' || m_text[index] == '\t')) |     while (index < m_text.length() && (m_text[index] == ' ' || m_text[index] == '\t')) | ||||||
|         ++index; |         ++index; | ||||||
|     auto url_string = m_text.substring_view(index, m_text.length() - index); |     auto url_string = m_text.substring_view(index, m_text.length() - index); | ||||||
|     auto space_offset = url_string.find_first_of(" \t"); |     auto space_offset = url_string.find_any_of(" \t"); | ||||||
|     String url = url_string; |     String url = url_string; | ||||||
|     if (space_offset.has_value()) { |     if (space_offset.has_value()) { | ||||||
|         url = url_string.substring_view(0, space_offset.value()); |         url = url_string.substring_view(0, space_offset.value()); | ||||||
|  |  | ||||||
|  | @ -252,7 +252,7 @@ bool Editor::load_history(const String& path) | ||||||
|     auto data = history_file->read_all(); |     auto data = history_file->read_all(); | ||||||
|     auto hist = StringView { data.data(), data.size() }; |     auto hist = StringView { data.data(), data.size() }; | ||||||
|     for (auto& str : hist.split_view("\n\n")) { |     for (auto& str : hist.split_view("\n\n")) { | ||||||
|         auto it = str.find_first_of("::").value_or(0); |         auto it = str.find("::").value_or(0); | ||||||
|         auto time = str.substring_view(0, it).to_uint<time_t>().value_or(0); |         auto time = str.substring_view(0, it).to_uint<time_t>().value_or(0); | ||||||
|         auto string = str.substring_view(it == 0 ? it : it + 2); |         auto string = str.substring_view(it == 0 ? it : it + 2); | ||||||
|         m_history.append({ string, time }); |         m_history.append({ string, time }); | ||||||
|  |  | ||||||
|  | @ -222,7 +222,7 @@ static StringView parse_custom_property_name(const StringView& value) | ||||||
|     if (!value.starts_with("var(") || !value.ends_with(")")) |     if (!value.starts_with("var(") || !value.ends_with(")")) | ||||||
|         return {}; |         return {}; | ||||||
|     // FIXME: Allow for fallback
 |     // FIXME: Allow for fallback
 | ||||||
|     auto first_comma_index = value.find_first_of(","); |     auto first_comma_index = value.find(','); | ||||||
|     auto length = value.length(); |     auto length = value.length(); | ||||||
| 
 | 
 | ||||||
|     auto substring_length = first_comma_index.has_value() ? first_comma_index.value() - 4 - 1 : length - 4 - 1; |     auto substring_length = first_comma_index.has_value() ? first_comma_index.value() - 4 - 1 : length - 4 - 1; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Max Wipfli
						Max Wipfli