Serenity Operating System
at master 302 lines 8.9 kB view raw
1/* 2 * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/AnyOf.h> 8#include <AK/ByteBuffer.h> 9#include <AK/Find.h> 10#include <AK/Function.h> 11#include <AK/StringBuilder.h> 12#include <AK/StringView.h> 13#include <AK/Vector.h> 14 15#ifndef KERNEL 16# include <AK/DeprecatedFlyString.h> 17# include <AK/DeprecatedString.h> 18# include <AK/FlyString.h> 19# include <AK/String.h> 20#endif 21 22namespace AK { 23 24#ifndef KERNEL 25StringView::StringView(String const& string) 26 : m_characters(reinterpret_cast<char const*>(string.bytes().data())) 27 , m_length(string.bytes().size()) 28{ 29} 30 31StringView::StringView(FlyString const& string) 32 : m_characters(reinterpret_cast<char const*>(string.bytes().data())) 33 , m_length(string.bytes().size()) 34{ 35} 36 37StringView::StringView(DeprecatedString const& string) 38 : m_characters(string.characters()) 39 , m_length(string.length()) 40{ 41} 42 43StringView::StringView(DeprecatedFlyString const& string) 44 : m_characters(string.characters()) 45 , m_length(string.length()) 46{ 47} 48#endif 49 50StringView::StringView(ByteBuffer const& buffer) 51 : m_characters((char const*)buffer.data()) 52 , m_length(buffer.size()) 53{ 54} 55 56Vector<StringView> StringView::split_view(char const separator, SplitBehavior split_behavior) const 57{ 58 StringView seperator_view { &separator, 1 }; 59 return split_view(seperator_view, split_behavior); 60} 61 62Vector<StringView> StringView::split_view(StringView separator, SplitBehavior split_behavior) const 63{ 64 Vector<StringView> parts; 65 for_each_split_view(separator, split_behavior, [&](StringView view) { 66 parts.append(view); 67 }); 68 return parts; 69} 70 71Vector<StringView> StringView::lines(bool consider_cr) const 72{ 73 if (is_empty()) 74 return {}; 75 76 if (!consider_cr) 77 return split_view('\n', SplitBehavior::KeepEmpty); 78 79 Vector<StringView> v; 80 size_t substart = 0; 81 bool last_ch_was_cr = false; 82 bool split_view = false; 83 for (size_t i = 0; i < length(); ++i) { 84 char ch = characters_without_null_termination()[i]; 85 if (ch == '\n') { 86 split_view = true; 87 if (last_ch_was_cr) { 88 substart = i + 1; 89 split_view = false; 90 } 91 } 92 if (ch == '\r') { 93 split_view = true; 94 last_ch_was_cr = true; 95 } else { 96 last_ch_was_cr = false; 97 } 98 if (split_view) { 99 size_t sublen = i - substart; 100 v.append(substring_view(substart, sublen)); 101 substart = i + 1; 102 } 103 split_view = false; 104 } 105 size_t taillen = length() - substart; 106 if (taillen != 0) 107 v.append(substring_view(substart, taillen)); 108 return v; 109} 110 111bool StringView::starts_with(char ch) const 112{ 113 if (is_empty()) 114 return false; 115 return ch == characters_without_null_termination()[0]; 116} 117 118bool StringView::starts_with(StringView str, CaseSensitivity case_sensitivity) const 119{ 120 return StringUtils::starts_with(*this, str, case_sensitivity); 121} 122 123bool StringView::ends_with(char ch) const 124{ 125 if (is_empty()) 126 return false; 127 return ch == characters_without_null_termination()[length() - 1]; 128} 129 130bool StringView::ends_with(StringView str, CaseSensitivity case_sensitivity) const 131{ 132 return StringUtils::ends_with(*this, str, case_sensitivity); 133} 134 135bool StringView::matches(StringView mask, Vector<MaskSpan>& mask_spans, CaseSensitivity case_sensitivity) const 136{ 137 return StringUtils::matches(*this, mask, case_sensitivity, &mask_spans); 138} 139 140bool StringView::matches(StringView mask, CaseSensitivity case_sensitivity) const 141{ 142 return StringUtils::matches(*this, mask, case_sensitivity); 143} 144 145bool StringView::contains(char needle) const 146{ 147 for (char current : *this) { 148 if (current == needle) 149 return true; 150 } 151 return false; 152} 153 154bool StringView::contains(u32 needle) const 155{ 156 // A code point should be at most four UTF-8 bytes, which easily fits into StringBuilder's inline-buffer. 157 // Therefore, this will not allocate. 158 StringBuilder needle_builder; 159 auto result = needle_builder.try_append_code_point(needle); 160 if (result.is_error()) { 161 // The needle is invalid, therefore the string does not contain it. 162 return false; 163 } 164 165 return contains(needle_builder.string_view()); 166} 167 168bool StringView::contains(StringView needle, CaseSensitivity case_sensitivity) const 169{ 170 return StringUtils::contains(*this, needle, case_sensitivity); 171} 172 173bool StringView::equals_ignoring_ascii_case(StringView other) const 174{ 175 return StringUtils::equals_ignoring_ascii_case(*this, other); 176} 177 178#ifndef KERNEL 179DeprecatedString StringView::to_lowercase_string() const 180{ 181 return StringImpl::create_lowercased(characters_without_null_termination(), length()); 182} 183 184DeprecatedString StringView::to_uppercase_string() const 185{ 186 return StringImpl::create_uppercased(characters_without_null_termination(), length()); 187} 188 189DeprecatedString StringView::to_titlecase_string() const 190{ 191 return StringUtils::to_titlecase(*this); 192} 193#endif 194 195StringView StringView::substring_view_starting_from_substring(StringView substring) const 196{ 197 char const* remaining_characters = substring.characters_without_null_termination(); 198 VERIFY(remaining_characters >= m_characters); 199 VERIFY(remaining_characters <= m_characters + m_length); 200 size_t remaining_length = m_length - (remaining_characters - m_characters); 201 return { remaining_characters, remaining_length }; 202} 203 204StringView StringView::substring_view_starting_after_substring(StringView substring) const 205{ 206 char const* remaining_characters = substring.characters_without_null_termination() + substring.length(); 207 VERIFY(remaining_characters >= m_characters); 208 VERIFY(remaining_characters <= m_characters + m_length); 209 size_t remaining_length = m_length - (remaining_characters - m_characters); 210 return { remaining_characters, remaining_length }; 211} 212 213bool StringView::copy_characters_to_buffer(char* buffer, size_t buffer_size) const 214{ 215 // We must fit at least the NUL-terminator. 216 VERIFY(buffer_size > 0); 217 218 size_t characters_to_copy = min(m_length, buffer_size - 1); 219 __builtin_memcpy(buffer, m_characters, characters_to_copy); 220 buffer[characters_to_copy] = 0; 221 222 return characters_to_copy == m_length; 223} 224 225template<typename T> 226Optional<T> StringView::to_int() const 227{ 228 return StringUtils::convert_to_int<T>(*this); 229} 230 231template Optional<i8> StringView::to_int() const; 232template Optional<i16> StringView::to_int() const; 233template Optional<i32> StringView::to_int() const; 234template Optional<long> StringView::to_int() const; 235template Optional<long long> StringView::to_int() const; 236 237template<typename T> 238Optional<T> StringView::to_uint() const 239{ 240 return StringUtils::convert_to_uint<T>(*this); 241} 242 243template Optional<u8> StringView::to_uint() const; 244template Optional<u16> StringView::to_uint() const; 245template Optional<u32> StringView::to_uint() const; 246template Optional<unsigned long> StringView::to_uint() const; 247template Optional<unsigned long long> StringView::to_uint() const; 248 249#ifndef KERNEL 250Optional<double> StringView::to_double(TrimWhitespace trim_whitespace) const 251{ 252 return StringUtils::convert_to_floating_point<double>(*this, trim_whitespace); 253} 254 255Optional<float> StringView::to_float(TrimWhitespace trim_whitespace) const 256{ 257 return StringUtils::convert_to_floating_point<float>(*this, trim_whitespace); 258} 259 260bool StringView::operator==(DeprecatedString const& string) const 261{ 262 return *this == string.view(); 263} 264 265DeprecatedString StringView::to_deprecated_string() const { return DeprecatedString { *this }; } 266 267DeprecatedString StringView::replace(StringView needle, StringView replacement, ReplaceMode replace_mode) const 268{ 269 return StringUtils::replace(*this, needle, replacement, replace_mode); 270} 271#endif 272 273Vector<size_t> StringView::find_all(StringView needle) const 274{ 275 return StringUtils::find_all(*this, needle); 276} 277 278Vector<StringView> StringView::split_view_if(Function<bool(char)> const& predicate, SplitBehavior split_behavior) const 279{ 280 if (is_empty()) 281 return {}; 282 283 Vector<StringView> v; 284 size_t substart = 0; 285 bool keep_empty = has_flag(split_behavior, SplitBehavior::KeepEmpty); 286 bool keep_separator = has_flag(split_behavior, SplitBehavior::KeepTrailingSeparator); 287 for (size_t i = 0; i < length(); ++i) { 288 char ch = characters_without_null_termination()[i]; 289 if (predicate(ch)) { 290 size_t sublen = i - substart; 291 if (sublen != 0 || keep_empty) 292 v.append(substring_view(substart, keep_separator ? sublen + 1 : sublen)); 293 substart = i + 1; 294 } 295 } 296 size_t taillen = length() - substart; 297 if (taillen != 0 || keep_empty) 298 v.append(substring_view(substart, taillen)); 299 return v; 300} 301 302}