/* * Copyright (c) 2018-2021, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include #include #include #include #include namespace AK { StringView::StringView(const String& string) : m_characters(string.characters()) , m_length(string.length()) { } StringView::StringView(const FlyString& string) : m_characters(string.characters()) , m_length(string.length()) { } StringView::StringView(const ByteBuffer& buffer) : m_characters((const char*)buffer.data()) , m_length(buffer.size()) { } Vector StringView::split_view(const char separator, bool keep_empty) const { StringView seperator_view { &separator, 1 }; return split_view(seperator_view, keep_empty); } Vector StringView::split_view(StringView separator, bool keep_empty) const { Vector parts; for_each_split_view(separator, keep_empty, [&](StringView view) { parts.append(view); }); return parts; } Vector StringView::lines(bool consider_cr) const { if (is_empty()) return {}; if (!consider_cr) return split_view('\n', true); Vector v; size_t substart = 0; bool last_ch_was_cr = false; bool split_view = false; for (size_t i = 0; i < length(); ++i) { char ch = characters_without_null_termination()[i]; if (ch == '\n') { split_view = true; if (last_ch_was_cr) { substart = i + 1; split_view = false; } } if (ch == '\r') { split_view = true; last_ch_was_cr = true; } else { last_ch_was_cr = false; } if (split_view) { size_t sublen = i - substart; v.append(substring_view(substart, sublen)); substart = i + 1; } split_view = false; } size_t taillen = length() - substart; if (taillen != 0) v.append(substring_view(substart, taillen)); return v; } bool StringView::starts_with(char ch) const { if (is_empty()) return false; return ch == characters_without_null_termination()[0]; } bool StringView::starts_with(StringView str, CaseSensitivity case_sensitivity) const { return StringUtils::starts_with(*this, str, case_sensitivity); } bool StringView::ends_with(char ch) const { if (is_empty()) return false; return ch == characters_without_null_termination()[length() - 1]; } bool StringView::ends_with(StringView str, CaseSensitivity case_sensitivity) const { return StringUtils::ends_with(*this, str, case_sensitivity); } bool StringView::matches(StringView mask, Vector& mask_spans, CaseSensitivity case_sensitivity) const { return StringUtils::matches(*this, mask, case_sensitivity, &mask_spans); } bool StringView::matches(StringView mask, CaseSensitivity case_sensitivity) const { return StringUtils::matches(*this, mask, case_sensitivity); } bool StringView::contains(char needle) const { for (char current : *this) { if (current == needle) return true; } return false; } bool StringView::contains(StringView needle, CaseSensitivity case_sensitivity) const { return StringUtils::contains(*this, needle, case_sensitivity); } bool StringView::equals_ignoring_case(StringView other) const { return StringUtils::equals_ignoring_case(*this, other); } String StringView::to_lowercase_string() const { return StringImpl::create_lowercased(characters_without_null_termination(), length()); } String StringView::to_uppercase_string() const { return StringImpl::create_uppercased(characters_without_null_termination(), length()); } String StringView::to_titlecase_string() const { return StringUtils::to_titlecase(*this); } StringView StringView::substring_view_starting_from_substring(StringView substring) const { const char* remaining_characters = substring.characters_without_null_termination(); VERIFY(remaining_characters >= m_characters); VERIFY(remaining_characters <= m_characters + m_length); size_t remaining_length = m_length - (remaining_characters - m_characters); return { remaining_characters, remaining_length }; } StringView StringView::substring_view_starting_after_substring(StringView substring) const { const char* remaining_characters = substring.characters_without_null_termination() + substring.length(); VERIFY(remaining_characters >= m_characters); VERIFY(remaining_characters <= m_characters + m_length); size_t remaining_length = m_length - (remaining_characters - m_characters); return { remaining_characters, remaining_length }; } template Optional StringView::to_int() const { return StringUtils::convert_to_int(*this); } template Optional StringView::to_int() const; template Optional StringView::to_int() const; template Optional StringView::to_int() const; template Optional StringView::to_int() const; template Optional StringView::to_int() const; template Optional StringView::to_uint() const { return StringUtils::convert_to_uint(*this); } template Optional StringView::to_uint() const; template Optional StringView::to_uint() const; template Optional StringView::to_uint() const; template Optional StringView::to_uint() const; template Optional StringView::to_uint() const; template Optional StringView::to_uint() const; template Optional StringView::to_uint() const; bool StringView::operator==(const String& string) const { if (string.is_null()) return !m_characters; if (!m_characters) return false; if (m_length != string.length()) return false; if (m_characters == string.characters()) return true; return !__builtin_memcmp(m_characters, string.characters(), m_length); } String StringView::to_string() const { return String { *this }; } String StringView::replace(StringView needle, StringView replacement, bool all_occurrences) const { return StringUtils::replace(*this, needle, replacement, all_occurrences); } Vector StringView::find_all(StringView needle) const { return StringUtils::find_all(*this, needle); } Vector StringView::split_view_if(Function const& predicate, bool keep_empty) const { if (is_empty()) return {}; Vector v; size_t substart = 0; for (size_t i = 0; i < length(); ++i) { char ch = characters_without_null_termination()[i]; if (predicate(ch)) { size_t sublen = i - substart; if (sublen != 0 || keep_empty) v.append(substring_view(substart, sublen)); substart = i + 1; } } size_t taillen = length() - substart; if (taillen != 0 || keep_empty) v.append(substring_view(substart, taillen)); return v; } }