1 //===- llvm/ADT/SmallString.h - 'Normally small' strings --------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines the SmallString class. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLVM_ADT_SMALLSTRING_H 14 #define LLVM_ADT_SMALLSTRING_H 15 16 #include "llvm/ADT/SmallVector.h" 17 #include "llvm/ADT/StringRef.h" 18 #include <cstddef> 19 20 namespace llvm { 21 22 /// SmallString - A SmallString is just a SmallVector with methods and accessors 23 /// that make it work better as a string (e.g. operator+ etc). 24 template<unsigned InternalLen> 25 class SmallString : public SmallVector<char, InternalLen> { 26 public: 27 /// Default ctor - Initialize to empty. 28 SmallString() = default; 29 30 /// Initialize from a StringRef. 31 SmallString(StringRef S) : SmallVector<char, InternalLen>(S.begin(), S.end()) {} 32 33 /// Initialize by concatenating a list of StringRefs. 34 SmallString(std::initializer_list<StringRef> Refs) 35 : SmallVector<char, InternalLen>() { 36 this->append(Refs); 37 } 38 39 /// Initialize with a range. 40 template<typename ItTy> 41 SmallString(ItTy S, ItTy E) : SmallVector<char, InternalLen>(S, E) {} 42 43 /// @} 44 /// @name String Assignment 45 /// @{ 46 47 using SmallVector<char, InternalLen>::assign; 48 49 /// Assign from a StringRef. 50 void assign(StringRef RHS) { 51 SmallVectorImpl<char>::assign(RHS.begin(), RHS.end()); 52 } 53 54 /// Assign from a list of StringRefs. 55 void assign(std::initializer_list<StringRef> Refs) { 56 this->clear(); 57 append(Refs); 58 } 59 60 /// @} 61 /// @name String Concatenation 62 /// @{ 63 64 using SmallVector<char, InternalLen>::append; 65 66 /// Append from a StringRef. 67 void append(StringRef RHS) { 68 SmallVectorImpl<char>::append(RHS.begin(), RHS.end()); 69 } 70 71 /// Append from a list of StringRefs. 72 void append(std::initializer_list<StringRef> Refs) { 73 size_t SizeNeeded = this->size(); 74 for (const StringRef &Ref : Refs) 75 SizeNeeded += Ref.size(); 76 this->reserve(SizeNeeded); 77 auto CurEnd = this->end(); 78 for (const StringRef &Ref : Refs) { 79 this->uninitialized_copy(Ref.begin(), Ref.end(), CurEnd); 80 CurEnd += Ref.size(); 81 } 82 this->set_size(SizeNeeded); 83 } 84 85 /// @} 86 /// @name String Comparison 87 /// @{ 88 89 /// Check for string equality. This is more efficient than compare() when 90 /// the relative ordering of inequal strings isn't needed. 91 bool equals(StringRef RHS) const { 92 return str().equals(RHS); 93 } 94 95 /// Check for string equality, ignoring case. 96 bool equals_lower(StringRef RHS) const { 97 return str().equals_lower(RHS); 98 } 99 100 /// Compare two strings; the result is -1, 0, or 1 if this string is 101 /// lexicographically less than, equal to, or greater than the \p RHS. 102 int compare(StringRef RHS) const { 103 return str().compare(RHS); 104 } 105 106 /// compare_lower - Compare two strings, ignoring case. 107 int compare_lower(StringRef RHS) const { 108 return str().compare_lower(RHS); 109 } 110 111 /// compare_numeric - Compare two strings, treating sequences of digits as 112 /// numbers. 113 int compare_numeric(StringRef RHS) const { 114 return str().compare_numeric(RHS); 115 } 116 117 /// @} 118 /// @name String Predicates 119 /// @{ 120 121 /// startswith - Check if this string starts with the given \p Prefix. 122 bool startswith(StringRef Prefix) const { 123 return str().startswith(Prefix); 124 } 125 126 /// endswith - Check if this string ends with the given \p Suffix. 127 bool endswith(StringRef Suffix) const { 128 return str().endswith(Suffix); 129 } 130 131 /// @} 132 /// @name String Searching 133 /// @{ 134 135 /// find - Search for the first character \p C in the string. 136 /// 137 /// \return - The index of the first occurrence of \p C, or npos if not 138 /// found. 139 size_t find(char C, size_t From = 0) const { 140 return str().find(C, From); 141 } 142 143 /// Search for the first string \p Str in the string. 144 /// 145 /// \returns The index of the first occurrence of \p Str, or npos if not 146 /// found. 147 size_t find(StringRef Str, size_t From = 0) const { 148 return str().find(Str, From); 149 } 150 151 /// Search for the last character \p C in the string. 152 /// 153 /// \returns The index of the last occurrence of \p C, or npos if not 154 /// found. 155 size_t rfind(char C, size_t From = StringRef::npos) const { 156 return str().rfind(C, From); 157 } 158 159 /// Search for the last string \p Str in the string. 160 /// 161 /// \returns The index of the last occurrence of \p Str, or npos if not 162 /// found. 163 size_t rfind(StringRef Str) const { 164 return str().rfind(Str); 165 } 166 167 /// Find the first character in the string that is \p C, or npos if not 168 /// found. Same as find. 169 size_t find_first_of(char C, size_t From = 0) const { 170 return str().find_first_of(C, From); 171 } 172 173 /// Find the first character in the string that is in \p Chars, or npos if 174 /// not found. 175 /// 176 /// Complexity: O(size() + Chars.size()) 177 size_t find_first_of(StringRef Chars, size_t From = 0) const { 178 return str().find_first_of(Chars, From); 179 } 180 181 /// Find the first character in the string that is not \p C or npos if not 182 /// found. 183 size_t find_first_not_of(char C, size_t From = 0) const { 184 return str().find_first_not_of(C, From); 185 } 186 187 /// Find the first character in the string that is not in the string 188 /// \p Chars, or npos if not found. 189 /// 190 /// Complexity: O(size() + Chars.size()) 191 size_t find_first_not_of(StringRef Chars, size_t From = 0) const { 192 return str().find_first_not_of(Chars, From); 193 } 194 195 /// Find the last character in the string that is \p C, or npos if not 196 /// found. 197 size_t find_last_of(char C, size_t From = StringRef::npos) const { 198 return str().find_last_of(C, From); 199 } 200 201 /// Find the last character in the string that is in \p C, or npos if not 202 /// found. 203 /// 204 /// Complexity: O(size() + Chars.size()) 205 size_t find_last_of( 206 StringRef Chars, size_t From = StringRef::npos) const { 207 return str().find_last_of(Chars, From); 208 } 209 210 /// @} 211 /// @name Helpful Algorithms 212 /// @{ 213 214 /// Return the number of occurrences of \p C in the string. 215 size_t count(char C) const { 216 return str().count(C); 217 } 218 219 /// Return the number of non-overlapped occurrences of \p Str in the 220 /// string. 221 size_t count(StringRef Str) const { 222 return str().count(Str); 223 } 224 225 /// @} 226 /// @name Substring Operations 227 /// @{ 228 229 /// Return a reference to the substring from [Start, Start + N). 230 /// 231 /// \param Start The index of the starting character in the substring; if 232 /// the index is npos or greater than the length of the string then the 233 /// empty substring will be returned. 234 /// 235 /// \param N The number of characters to included in the substring. If \p N 236 /// exceeds the number of characters remaining in the string, the string 237 /// suffix (starting with \p Start) will be returned. 238 StringRef substr(size_t Start, size_t N = StringRef::npos) const { 239 return str().substr(Start, N); 240 } 241 242 /// Return a reference to the substring from [Start, End). 243 /// 244 /// \param Start The index of the starting character in the substring; if 245 /// the index is npos or greater than the length of the string then the 246 /// empty substring will be returned. 247 /// 248 /// \param End The index following the last character to include in the 249 /// substring. If this is npos, or less than \p Start, or exceeds the 250 /// number of characters remaining in the string, the string suffix 251 /// (starting with \p Start) will be returned. 252 StringRef slice(size_t Start, size_t End) const { 253 return str().slice(Start, End); 254 } 255 256 // Extra methods. 257 258 /// Explicit conversion to StringRef. 259 StringRef str() const { return StringRef(this->data(), this->size()); } 260 261 // TODO: Make this const, if it's safe... 262 const char* c_str() { 263 this->push_back(0); 264 this->pop_back(); 265 return this->data(); 266 } 267 268 /// Implicit conversion to StringRef. 269 operator StringRef() const { return str(); } 270 271 explicit operator std::string() const { 272 return std::string(this->data(), this->size()); 273 } 274 275 // Extra operators. 276 SmallString &operator=(StringRef RHS) { 277 this->assign(RHS); 278 return *this; 279 } 280 281 SmallString &operator+=(StringRef RHS) { 282 this->append(RHS.begin(), RHS.end()); 283 return *this; 284 } 285 SmallString &operator+=(char C) { 286 this->push_back(C); 287 return *this; 288 } 289 }; 290 291 } // end namespace llvm 292 293 #endif // LLVM_ADT_SMALLSTRING_H 294