Serenity Operating System
at master 444 lines 13 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <AK/ByteBuffer.h> 8#include <AK/DeprecatedFlyString.h> 9#include <AK/DeprecatedString.h> 10#include <AK/Format.h> 11#include <AK/Function.h> 12#include <AK/StdLibExtras.h> 13#include <AK/StringView.h> 14#include <AK/Utf8View.h> 15#include <AK/Vector.h> 16 17namespace AK { 18 19bool DeprecatedString::operator==(DeprecatedFlyString const& fly_string) const 20{ 21 return m_impl == fly_string.impl() || view() == fly_string.view(); 22} 23 24bool DeprecatedString::operator==(DeprecatedString const& other) const 25{ 26 return m_impl == other.impl() || view() == other.view(); 27} 28 29bool DeprecatedString::operator==(StringView other) const 30{ 31 return view() == other; 32} 33 34bool DeprecatedString::operator<(DeprecatedString const& other) const 35{ 36 return view() < other.view(); 37} 38 39bool DeprecatedString::operator>(DeprecatedString const& other) const 40{ 41 return view() > other.view(); 42} 43 44bool DeprecatedString::copy_characters_to_buffer(char* buffer, size_t buffer_size) const 45{ 46 // We must fit at least the NUL-terminator. 47 VERIFY(buffer_size > 0); 48 49 size_t characters_to_copy = min(length(), buffer_size - 1); 50 __builtin_memcpy(buffer, characters(), characters_to_copy); 51 buffer[characters_to_copy] = 0; 52 53 return characters_to_copy == length(); 54} 55 56DeprecatedString DeprecatedString::isolated_copy() const 57{ 58 if (!m_impl) 59 return {}; 60 if (!m_impl->length()) 61 return empty(); 62 char* buffer; 63 auto impl = StringImpl::create_uninitialized(length(), buffer); 64 memcpy(buffer, m_impl->characters(), m_impl->length()); 65 return DeprecatedString(move(*impl)); 66} 67 68DeprecatedString DeprecatedString::substring(size_t start, size_t length) const 69{ 70 if (!length) 71 return DeprecatedString::empty(); 72 VERIFY(m_impl); 73 VERIFY(!Checked<size_t>::addition_would_overflow(start, length)); 74 VERIFY(start + length <= m_impl->length()); 75 return { characters() + start, length }; 76} 77 78DeprecatedString DeprecatedString::substring(size_t start) const 79{ 80 VERIFY(m_impl); 81 VERIFY(start <= length()); 82 return { characters() + start, length() - start }; 83} 84 85StringView DeprecatedString::substring_view(size_t start, size_t length) const 86{ 87 VERIFY(m_impl); 88 VERIFY(!Checked<size_t>::addition_would_overflow(start, length)); 89 VERIFY(start + length <= m_impl->length()); 90 return { characters() + start, length }; 91} 92 93StringView DeprecatedString::substring_view(size_t start) const 94{ 95 VERIFY(m_impl); 96 VERIFY(start <= length()); 97 return { characters() + start, length() - start }; 98} 99 100Vector<DeprecatedString> DeprecatedString::split(char separator, SplitBehavior split_behavior) const 101{ 102 return split_limit(separator, 0, split_behavior); 103} 104 105Vector<DeprecatedString> DeprecatedString::split_limit(char separator, size_t limit, SplitBehavior split_behavior) const 106{ 107 if (is_empty()) 108 return {}; 109 110 Vector<DeprecatedString> v; 111 size_t substart = 0; 112 bool keep_empty = has_flag(split_behavior, SplitBehavior::KeepEmpty); 113 bool keep_separator = has_flag(split_behavior, SplitBehavior::KeepTrailingSeparator); 114 for (size_t i = 0; i < length() && (v.size() + 1) != limit; ++i) { 115 char ch = characters()[i]; 116 if (ch == separator) { 117 size_t sublen = i - substart; 118 if (sublen != 0 || keep_empty) 119 v.append(substring(substart, keep_separator ? sublen + 1 : sublen)); 120 substart = i + 1; 121 } 122 } 123 size_t taillen = length() - substart; 124 if (taillen != 0 || keep_empty) 125 v.append(substring(substart, taillen)); 126 return v; 127} 128 129Vector<StringView> DeprecatedString::split_view(Function<bool(char)> separator, SplitBehavior split_behavior) const 130{ 131 if (is_empty()) 132 return {}; 133 134 Vector<StringView> v; 135 size_t substart = 0; 136 bool keep_empty = has_flag(split_behavior, SplitBehavior::KeepEmpty); 137 bool keep_separator = has_flag(split_behavior, SplitBehavior::KeepTrailingSeparator); 138 for (size_t i = 0; i < length(); ++i) { 139 char ch = characters()[i]; 140 if (separator(ch)) { 141 size_t sublen = i - substart; 142 if (sublen != 0 || keep_empty) 143 v.append(substring_view(substart, keep_separator ? sublen + 1 : sublen)); 144 substart = i + 1; 145 } 146 } 147 size_t taillen = length() - substart; 148 if (taillen != 0 || keep_empty) 149 v.append(substring_view(substart, taillen)); 150 return v; 151} 152 153Vector<StringView> DeprecatedString::split_view(char const separator, SplitBehavior split_behavior) const 154{ 155 return split_view([separator](char ch) { return ch == separator; }, split_behavior); 156} 157 158ByteBuffer DeprecatedString::to_byte_buffer() const 159{ 160 if (!m_impl) 161 return {}; 162 // FIXME: Handle OOM failure. 163 return ByteBuffer::copy(bytes()).release_value_but_fixme_should_propagate_errors(); 164} 165 166template<typename T> 167Optional<T> DeprecatedString::to_int(TrimWhitespace trim_whitespace) const 168{ 169 return StringUtils::convert_to_int<T>(view(), trim_whitespace); 170} 171 172template Optional<i8> DeprecatedString::to_int(TrimWhitespace) const; 173template Optional<i16> DeprecatedString::to_int(TrimWhitespace) const; 174template Optional<i32> DeprecatedString::to_int(TrimWhitespace) const; 175template Optional<long> DeprecatedString::to_int(TrimWhitespace) const; 176template Optional<long long> DeprecatedString::to_int(TrimWhitespace) const; 177 178template<typename T> 179Optional<T> DeprecatedString::to_uint(TrimWhitespace trim_whitespace) const 180{ 181 return StringUtils::convert_to_uint<T>(view(), trim_whitespace); 182} 183 184template Optional<u8> DeprecatedString::to_uint(TrimWhitespace) const; 185template Optional<u16> DeprecatedString::to_uint(TrimWhitespace) const; 186template Optional<u32> DeprecatedString::to_uint(TrimWhitespace) const; 187template Optional<unsigned long> DeprecatedString::to_uint(TrimWhitespace) const; 188template Optional<unsigned long long> DeprecatedString::to_uint(TrimWhitespace) const; 189 190#ifndef KERNEL 191Optional<double> DeprecatedString::to_double(TrimWhitespace trim_whitespace) const 192{ 193 return StringUtils::convert_to_floating_point<double>(*this, trim_whitespace); 194} 195 196Optional<float> DeprecatedString::to_float(TrimWhitespace trim_whitespace) const 197{ 198 return StringUtils::convert_to_floating_point<float>(*this, trim_whitespace); 199} 200#endif 201 202bool DeprecatedString::starts_with(StringView str, CaseSensitivity case_sensitivity) const 203{ 204 return StringUtils::starts_with(*this, str, case_sensitivity); 205} 206 207bool DeprecatedString::starts_with(char ch) const 208{ 209 if (is_empty()) 210 return false; 211 return characters()[0] == ch; 212} 213 214bool DeprecatedString::ends_with(StringView str, CaseSensitivity case_sensitivity) const 215{ 216 return StringUtils::ends_with(*this, str, case_sensitivity); 217} 218 219bool DeprecatedString::ends_with(char ch) const 220{ 221 if (is_empty()) 222 return false; 223 return characters()[length() - 1] == ch; 224} 225 226DeprecatedString DeprecatedString::repeated(char ch, size_t count) 227{ 228 if (!count) 229 return empty(); 230 char* buffer; 231 auto impl = StringImpl::create_uninitialized(count, buffer); 232 memset(buffer, ch, count); 233 return *impl; 234} 235 236DeprecatedString DeprecatedString::repeated(StringView string, size_t count) 237{ 238 if (!count || string.is_empty()) 239 return empty(); 240 char* buffer; 241 auto impl = StringImpl::create_uninitialized(count * string.length(), buffer); 242 for (size_t i = 0; i < count; i++) 243 __builtin_memcpy(buffer + i * string.length(), string.characters_without_null_termination(), string.length()); 244 return *impl; 245} 246 247DeprecatedString DeprecatedString::bijective_base_from(size_t value, unsigned base, StringView map) 248{ 249 value++; 250 if (map.is_null()) 251 map = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"sv; 252 253 VERIFY(base >= 2 && base <= map.length()); 254 255 // The '8 bits per byte' assumption may need to go? 256 Array<char, round_up_to_power_of_two(sizeof(size_t) * 8 + 1, 2)> buffer; 257 size_t i = 0; 258 do { 259 auto remainder = value % base; 260 auto new_value = value / base; 261 if (remainder == 0) { 262 new_value--; 263 remainder = map.length(); 264 } 265 266 buffer[i++] = map[remainder - 1]; 267 value = new_value; 268 } while (value > 0); 269 270 for (size_t j = 0; j < i / 2; ++j) 271 swap(buffer[j], buffer[i - j - 1]); 272 273 return DeprecatedString { ReadonlyBytes(buffer.data(), i) }; 274} 275 276DeprecatedString DeprecatedString::roman_number_from(size_t value) 277{ 278 if (value > 3999) 279 return DeprecatedString::number(value); 280 281 StringBuilder builder; 282 283 while (value > 0) { 284 if (value >= 1000) { 285 builder.append('M'); 286 value -= 1000; 287 } else if (value >= 900) { 288 builder.append("CM"sv); 289 value -= 900; 290 } else if (value >= 500) { 291 builder.append('D'); 292 value -= 500; 293 } else if (value >= 400) { 294 builder.append("CD"sv); 295 value -= 400; 296 } else if (value >= 100) { 297 builder.append('C'); 298 value -= 100; 299 } else if (value >= 90) { 300 builder.append("XC"sv); 301 value -= 90; 302 } else if (value >= 50) { 303 builder.append('L'); 304 value -= 50; 305 } else if (value >= 40) { 306 builder.append("XL"sv); 307 value -= 40; 308 } else if (value >= 10) { 309 builder.append('X'); 310 value -= 10; 311 } else if (value == 9) { 312 builder.append("IX"sv); 313 value -= 9; 314 } else if (value >= 5 && value <= 8) { 315 builder.append('V'); 316 value -= 5; 317 } else if (value == 4) { 318 builder.append("IV"sv); 319 value -= 4; 320 } else if (value <= 3) { 321 builder.append('I'); 322 value -= 1; 323 } 324 } 325 326 return builder.to_deprecated_string(); 327} 328 329bool DeprecatedString::matches(StringView mask, Vector<MaskSpan>& mask_spans, CaseSensitivity case_sensitivity) const 330{ 331 return StringUtils::matches(*this, mask, case_sensitivity, &mask_spans); 332} 333 334bool DeprecatedString::matches(StringView mask, CaseSensitivity case_sensitivity) const 335{ 336 return StringUtils::matches(*this, mask, case_sensitivity); 337} 338 339bool DeprecatedString::contains(StringView needle, CaseSensitivity case_sensitivity) const 340{ 341 return StringUtils::contains(*this, needle, case_sensitivity); 342} 343 344bool DeprecatedString::contains(char needle, CaseSensitivity case_sensitivity) const 345{ 346 return StringUtils::contains(*this, StringView(&needle, 1), case_sensitivity); 347} 348 349bool DeprecatedString::equals_ignoring_ascii_case(StringView other) const 350{ 351 return StringUtils::equals_ignoring_ascii_case(view(), other); 352} 353 354DeprecatedString DeprecatedString::reverse() const 355{ 356 StringBuilder reversed_string(length()); 357 for (size_t i = length(); i-- > 0;) { 358 reversed_string.append(characters()[i]); 359 } 360 return reversed_string.to_deprecated_string(); 361} 362 363DeprecatedString escape_html_entities(StringView html) 364{ 365 StringBuilder builder; 366 for (size_t i = 0; i < html.length(); ++i) { 367 if (html[i] == '<') 368 builder.append("&lt;"sv); 369 else if (html[i] == '>') 370 builder.append("&gt;"sv); 371 else if (html[i] == '&') 372 builder.append("&amp;"sv); 373 else if (html[i] == '"') 374 builder.append("&quot;"sv); 375 else 376 builder.append(html[i]); 377 } 378 return builder.to_deprecated_string(); 379} 380 381DeprecatedString::DeprecatedString(DeprecatedFlyString const& string) 382 : m_impl(string.impl()) 383{ 384} 385 386DeprecatedString DeprecatedString::to_lowercase() const 387{ 388 if (!m_impl) 389 return {}; 390 return m_impl->to_lowercase(); 391} 392 393DeprecatedString DeprecatedString::to_uppercase() const 394{ 395 if (!m_impl) 396 return {}; 397 return m_impl->to_uppercase(); 398} 399 400DeprecatedString DeprecatedString::to_snakecase() const 401{ 402 return StringUtils::to_snakecase(*this); 403} 404 405DeprecatedString DeprecatedString::to_titlecase() const 406{ 407 return StringUtils::to_titlecase(*this); 408} 409 410DeprecatedString DeprecatedString::invert_case() const 411{ 412 return StringUtils::invert_case(*this); 413} 414 415bool DeprecatedString::operator==(char const* cstring) const 416{ 417 return view() == cstring; 418} 419 420DeprecatedString DeprecatedString::vformatted(StringView fmtstr, TypeErasedFormatParams& params) 421{ 422 StringBuilder builder; 423 MUST(vformat(builder, fmtstr, params)); 424 return builder.to_deprecated_string(); 425} 426 427Vector<size_t> DeprecatedString::find_all(StringView needle) const 428{ 429 return StringUtils::find_all(*this, needle); 430} 431 432DeprecatedStringCodePointIterator DeprecatedString::code_points() const 433{ 434 return DeprecatedStringCodePointIterator(*this); 435} 436 437ErrorOr<DeprecatedString> DeprecatedString::from_utf8(ReadonlyBytes bytes) 438{ 439 if (!Utf8View(bytes).validate()) 440 return Error::from_string_literal("DeprecatedString::from_utf8: Input was not valid UTF-8"); 441 return DeprecatedString { StringImpl::create(bytes) }; 442} 443 444}