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.
SmallString(StringRef S)31   SmallString(StringRef S) : SmallVector<char, InternalLen>(S.begin(), S.end()) {}
32 
33   /// Initialize by concatenating a list of StringRefs.
SmallString(std::initializer_list<StringRef> Refs)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>
SmallString(ItTy S,ItTy E)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.
assign(StringRef RHS)50   void assign(StringRef RHS) {
51     SmallVectorImpl<char>::assign(RHS.begin(), RHS.end());
52   }
53 
54   /// Assign from a list of StringRefs.
assign(std::initializer_list<StringRef> Refs)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.
append(StringRef RHS)67   void append(StringRef RHS) {
68     SmallVectorImpl<char>::append(RHS.begin(), RHS.end());
69   }
70 
71   /// Append from a list of StringRefs.
append(std::initializer_list<StringRef> Refs)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.
equals(StringRef RHS)91   bool equals(StringRef RHS) const {
92     return str().equals(RHS);
93   }
94 
95   /// Check for string equality, ignoring case.
equals_lower(StringRef RHS)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.
compare(StringRef RHS)102   int compare(StringRef RHS) const {
103     return str().compare(RHS);
104   }
105 
106   /// compare_lower - Compare two strings, ignoring case.
compare_lower(StringRef RHS)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.
compare_numeric(StringRef RHS)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.
startswith(StringRef 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.
endswith(StringRef 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.
rfind(StringRef Str)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.
count(char C)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.
count(StringRef Str)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.
slice(size_t Start,size_t End)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.
str()259   StringRef str() const { return StringRef(this->data(), this->size()); }
260 
261   // TODO: Make this const, if it's safe...
c_str()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.
StringRef()269   operator StringRef() const { return str(); }
270 
string()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