Serenity Operating System
at hosted 244 lines 7.8 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#pragma once 28 29#include <AK/Forward.h> 30#include <AK/RefPtr.h> 31#include <AK/StringImpl.h> 32#include <AK/StringUtils.h> 33#include <AK/Traits.h> 34 35namespace AK { 36 37// String is a convenience wrapper around StringImpl, suitable for passing 38// around as a value type. It's basically the same as passing around a 39// RefPtr<StringImpl>, with a bit of syntactic sugar. 40// 41// Note that StringImpl is an immutable object that cannot shrink or grow. 42// Its allocation size is snugly tailored to the specific string it contains. 43// Copying a String is very efficient, since the internal StringImpl is 44// retainable and so copying only requires modifying the ref count. 45// 46// There are three main ways to construct a new String: 47// 48// s = String("some literal"); 49// 50// s = String::format("%d little piggies", m_piggies); 51// 52// StringBuilder builder; 53// builder.append("abc"); 54// builder.append("123"); 55// s = builder.to_string(); 56 57class String { 58public: 59 using ConstIterator = const char*; 60 61 ~String() {} 62 63 String() {} 64 String(const StringView&); 65 66 String(const String& other) 67 : m_impl(const_cast<String&>(other).m_impl) 68 { 69 } 70 71 String(String&& other) 72 : m_impl(move(other.m_impl)) 73 { 74 } 75 76 String(const char* cstring, ShouldChomp shouldChomp = NoChomp) 77 : m_impl(StringImpl::create(cstring, shouldChomp)) 78 { 79 } 80 81 String(const char* cstring, size_t length, ShouldChomp shouldChomp = NoChomp) 82 : m_impl(StringImpl::create(cstring, length, shouldChomp)) 83 { 84 } 85 86 String(const StringImpl& impl) 87 : m_impl(const_cast<StringImpl&>(impl)) 88 { 89 } 90 91 String(const StringImpl* impl) 92 : m_impl(const_cast<StringImpl*>(impl)) 93 { 94 } 95 96 String(RefPtr<StringImpl>&& impl) 97 : m_impl(move(impl)) 98 { 99 } 100 101 String(NonnullRefPtr<StringImpl>&& impl) 102 : m_impl(move(impl)) 103 { 104 } 105 106 String(const FlyString&); 107 108 static String repeated(char, size_t count); 109 bool matches(const StringView& mask, CaseSensitivity = CaseSensitivity::CaseInsensitive) const; 110 111 int to_int(bool& ok) const; 112 unsigned to_uint(bool& ok) const; 113 114 String to_lowercase() const; 115 String to_uppercase() const; 116 117 bool equals_ignoring_case(const StringView&) const; 118 119 bool contains(const String&) const; 120 121 Vector<String> split_limit(char separator, size_t limit, bool keep_empty = false) const; 122 Vector<String> split(char separator, bool keep_empty = false) const; 123 String substring(size_t start, size_t length) const; 124 125 Vector<StringView> split_view(char separator, bool keep_empty = false) const; 126 StringView substring_view(size_t start, size_t length) const; 127 128 bool is_null() const { return !m_impl; } 129 bool is_empty() const { return length() == 0; } 130 size_t length() const { return m_impl ? m_impl->length() : 0; } 131 const char* characters() const { return m_impl ? m_impl->characters() : nullptr; } 132 const char& operator[](size_t i) const 133 { 134 return (*m_impl)[i]; 135 } 136 137 ConstIterator begin() const { return characters(); } 138 ConstIterator end() const { return begin() + length(); } 139 140 bool starts_with(const StringView&) const; 141 bool ends_with(const StringView&) const; 142 bool starts_with(char) const; 143 bool ends_with(char) const; 144 145 bool operator==(const String&) const; 146 bool operator!=(const String& other) const { return !(*this == other); } 147 148 bool operator==(const StringView&) const; 149 bool operator!=(const StringView& other) const { return !(*this == other); } 150 151 bool operator==(const FlyString&) const; 152 bool operator!=(const FlyString& other) const { return !(*this == other); } 153 154 bool operator<(const String&) const; 155 bool operator<(const char*) const; 156 bool operator>=(const String& other) const { return !(*this < other); } 157 bool operator>=(const char* other) const { return !(*this < other); } 158 159 bool operator>(const String&) const; 160 bool operator>(const char*) const; 161 bool operator<=(const String& other) const { return !(*this > other); } 162 bool operator<=(const char* other) const { return !(*this > other); } 163 164 bool operator==(const char* cstring) const; 165 bool operator!=(const char* cstring) const { return !(*this == cstring); } 166 167 String isolated_copy() const; 168 169 static String empty(); 170 171 StringImpl* impl() { return m_impl.ptr(); } 172 const StringImpl* impl() const { return m_impl.ptr(); } 173 174 String& operator=(String&& other) 175 { 176 if (this != &other) 177 m_impl = move(other.m_impl); 178 return *this; 179 } 180 181 String& operator=(const String& other) 182 { 183 if (this != &other) 184 m_impl = const_cast<String&>(other).m_impl; 185 return *this; 186 } 187 188 u32 hash() const 189 { 190 if (!m_impl) 191 return 0; 192 return m_impl->hash(); 193 } 194 195 ByteBuffer to_byte_buffer() const; 196 197 template<typename BufferType> 198 static String copy(const BufferType& buffer, ShouldChomp should_chomp = NoChomp) 199 { 200 if (buffer.is_null()) 201 return {}; 202 if (buffer.is_empty()) 203 return empty(); 204 return String((const char*)buffer.data(), buffer.size(), should_chomp); 205 } 206 207 static String format(const char*, ...); 208 static String number(unsigned); 209 static String number(unsigned long); 210 static String number(unsigned long long); 211 static String number(int); 212 static String number(long); 213 static String number(long long); 214 215 StringView view() const; 216 217 int replace(const String& needle, const String& replacement, bool all_occurences = false); 218 219private: 220 RefPtr<StringImpl> m_impl; 221}; 222 223template<> 224struct Traits<String> : public GenericTraits<String> { 225 static unsigned hash(const String& s) { return s.impl() ? s.impl()->hash() : 0; } 226}; 227 228struct CaseInsensitiveStringTraits : public AK::Traits<String> { 229 static unsigned hash(const String& s) { return s.impl() ? s.to_lowercase().impl()->hash() : 0; } 230 static bool equals(const String& a, const String& b) { return a.to_lowercase() == b.to_lowercase(); } 231}; 232 233bool operator<(const char*, const String&); 234bool operator>=(const char*, const String&); 235bool operator>(const char*, const String&); 236bool operator<=(const char*, const String&); 237 238String escape_html_entities(const StringView& html); 239 240} 241 242using AK::CaseInsensitiveStringTraits; 243using AK::escape_html_entities; 244using AK::String;