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
20namespace 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).
24template<unsigned InternalLen>
25class SmallString : public SmallVector<char, InternalLen> {
26public:
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