mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 17:10:23 +00:00
5a6f0ef1bc
StringView::lines() supports line-separators “\n”, “\r”, and “\r\n”. The method will drop an entire line if it is surrounded by “\r” and “\n” separators on the left and right sides respectively.
287 lines
7.9 KiB
C++
287 lines
7.9 KiB
C++
/*
|
|
* Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <AK/AnyOf.h>
|
|
#include <AK/ByteBuffer.h>
|
|
#include <AK/Find.h>
|
|
#include <AK/FlyString.h>
|
|
#include <AK/Memory.h>
|
|
#include <AK/String.h>
|
|
#include <AK/StringView.h>
|
|
|
|
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> StringView::split_view(const char separator, bool keep_empty) const
|
|
{
|
|
if (is_empty())
|
|
return {};
|
|
|
|
Vector<StringView> v;
|
|
size_t substart = 0;
|
|
for (size_t i = 0; i < length(); ++i) {
|
|
char ch = characters_without_null_termination()[i];
|
|
if (ch == separator) {
|
|
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;
|
|
}
|
|
|
|
Vector<StringView> StringView::split_view(const StringView& separator, bool keep_empty) const
|
|
{
|
|
VERIFY(!separator.is_empty());
|
|
|
|
if (is_empty())
|
|
return {};
|
|
|
|
StringView view { *this };
|
|
|
|
Vector<StringView> parts;
|
|
|
|
auto maybe_separator_index = find(separator);
|
|
while (maybe_separator_index.has_value()) {
|
|
auto separator_index = maybe_separator_index.value();
|
|
auto part_with_separator = view.substring_view(0, separator_index + separator.length());
|
|
if (keep_empty || separator_index > 0)
|
|
parts.append(part_with_separator.substring_view(0, separator_index));
|
|
view = view.substring_view_starting_after_substring(part_with_separator);
|
|
maybe_separator_index = view.find(separator);
|
|
}
|
|
if (keep_empty || !view.is_empty())
|
|
parts.append(view);
|
|
|
|
return parts;
|
|
}
|
|
|
|
Vector<StringView> StringView::lines(bool consider_cr) const
|
|
{
|
|
if (is_empty())
|
|
return {};
|
|
|
|
if (!consider_cr)
|
|
return split_view('\n', true);
|
|
|
|
Vector<StringView> 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(const 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(const StringView& str, CaseSensitivity case_sensitivity) const
|
|
{
|
|
return StringUtils::ends_with(*this, str, case_sensitivity);
|
|
}
|
|
|
|
bool StringView::matches(const StringView& mask, Vector<MaskSpan>& mask_spans, CaseSensitivity case_sensitivity) const
|
|
{
|
|
return StringUtils::matches(*this, mask, case_sensitivity, &mask_spans);
|
|
}
|
|
|
|
bool StringView::matches(const 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(const StringView& needle, CaseSensitivity case_sensitivity) const
|
|
{
|
|
return StringUtils::contains(*this, needle, case_sensitivity);
|
|
}
|
|
|
|
bool StringView::equals_ignoring_case(const StringView& other) const
|
|
{
|
|
return StringUtils::equals_ignoring_case(*this, other);
|
|
}
|
|
|
|
StringView StringView::substring_view_starting_from_substring(const 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(const 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<typename T>
|
|
Optional<T> StringView::to_int() const
|
|
{
|
|
return StringUtils::convert_to_int<T>(*this);
|
|
}
|
|
|
|
template Optional<i8> StringView::to_int() const;
|
|
template Optional<i16> StringView::to_int() const;
|
|
template Optional<i32> StringView::to_int() const;
|
|
template Optional<i64> StringView::to_int() const;
|
|
|
|
template<typename T>
|
|
Optional<T> StringView::to_uint() const
|
|
{
|
|
return StringUtils::convert_to_uint<T>(*this);
|
|
}
|
|
|
|
template Optional<u8> StringView::to_uint() const;
|
|
template Optional<u16> StringView::to_uint() const;
|
|
template Optional<u32> StringView::to_uint() const;
|
|
template Optional<u64> StringView::to_uint() const;
|
|
template Optional<long> StringView::to_uint() const;
|
|
template Optional<long long> 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);
|
|
}
|
|
|
|
Optional<size_t> StringView::find_first_of(char c) const
|
|
{
|
|
if (const auto location = AK::find(begin(), end(), c); location != end()) {
|
|
return location.index();
|
|
}
|
|
return {};
|
|
}
|
|
|
|
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(char c) const
|
|
{
|
|
for (size_t pos = m_length; pos != 0; --pos) {
|
|
if (m_characters[pos - 1] == c)
|
|
return pos - 1;
|
|
}
|
|
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 {};
|
|
}
|
|
|
|
Optional<size_t> StringView::find(char c) const
|
|
{
|
|
return find(StringView { &c, 1 });
|
|
}
|
|
|
|
Optional<size_t> StringView::find(const StringView& view) const
|
|
{
|
|
return StringUtils::find(*this, view);
|
|
}
|
|
|
|
String StringView::to_string() const { return String { *this }; }
|
|
|
|
}
|