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   // Note that in order to add new overloads for append & assign, we have to
44   // duplicate the inherited versions so as not to inadvertently hide them.
45 
46   /// @}
47   /// @name String Assignment
48   /// @{
49 
50   /// Assign from a repeated element.
assign(size_t NumElts,char Elt)51   void assign(size_t NumElts, char Elt) {
52     this->SmallVectorImpl<char>::assign(NumElts, Elt);
53   }
54 
55   /// Assign from an iterator pair.
56   template<typename in_iter>
assign(in_iter S,in_iter E)57   void assign(in_iter S, in_iter E) {
58     this->clear();
59     SmallVectorImpl<char>::append(S, E);
60   }
61 
62   /// Assign from a StringRef.
assign(StringRef RHS)63   void assign(StringRef RHS) {
64     this->clear();
65     SmallVectorImpl<char>::append(RHS.begin(), RHS.end());
66   }
67 
68   /// Assign from a SmallVector.
assign(const SmallVectorImpl<char> & RHS)69   void assign(const SmallVectorImpl<char> &RHS) {
70     this->clear();
71     SmallVectorImpl<char>::append(RHS.begin(), RHS.end());
72   }
73 
74   /// Assign from a list of StringRefs.
assign(std::initializer_list<StringRef> Refs)75   void assign(std::initializer_list<StringRef> Refs) {
76     this->clear();
77     append(Refs);
78   }
79 
80   /// @}
81   /// @name String Concatenation
82   /// @{
83 
84   /// Append from an iterator pair.
85   template<typename in_iter>
append(in_iter S,in_iter E)86   void append(in_iter S, in_iter E) {
87     SmallVectorImpl<char>::append(S, E);
88   }
89 
append(size_t NumInputs,char Elt)90   void append(size_t NumInputs, char Elt) {
91     SmallVectorImpl<char>::append(NumInputs, Elt);
92   }
93 
94   /// Append from a StringRef.
append(StringRef RHS)95   void append(StringRef RHS) {
96     SmallVectorImpl<char>::append(RHS.begin(), RHS.end());
97   }
98 
99   /// Append from a SmallVector.
append(const SmallVectorImpl<char> & RHS)100   void append(const SmallVectorImpl<char> &RHS) {
101     SmallVectorImpl<char>::append(RHS.begin(), RHS.end());
102   }
103 
104   /// Append from a list of StringRefs.
append(std::initializer_list<StringRef> Refs)105   void append(std::initializer_list<StringRef> Refs) {
106     size_t SizeNeeded = this->size();
107     for (const StringRef &Ref : Refs)
108       SizeNeeded += Ref.size();
109     this->reserve(SizeNeeded);
110     auto CurEnd = this->end();
111     for (const StringRef &Ref : Refs) {
112       this->uninitialized_copy(Ref.begin(), Ref.end(), CurEnd);
113       CurEnd += Ref.size();
114     }
115     this->set_size(SizeNeeded);
116   }
117 
118   /// @}
119   /// @name String Comparison
120   /// @{
121 
122   /// Check for string equality.  This is more efficient than compare() when
123   /// the relative ordering of inequal strings isn't needed.
equals(StringRef RHS)124   bool equals(StringRef RHS) const {
125     return str().equals(RHS);
126   }
127 
128   /// Check for string equality, ignoring case.
equals_lower(StringRef RHS)129   bool equals_lower(StringRef RHS) const {
130     return str().equals_lower(RHS);
131   }
132 
133   /// Compare two strings; the result is -1, 0, or 1 if this string is
134   /// lexicographically less than, equal to, or greater than the \p RHS.
compare(StringRef RHS)135   int compare(StringRef RHS) const {
136     return str().compare(RHS);
137   }
138 
139   /// compare_lower - Compare two strings, ignoring case.
compare_lower(StringRef RHS)140   int compare_lower(StringRef RHS) const {
141     return str().compare_lower(RHS);
142   }
143 
144   /// compare_numeric - Compare two strings, treating sequences of digits as
145   /// numbers.
compare_numeric(StringRef RHS)146   int compare_numeric(StringRef RHS) const {
147     return str().compare_numeric(RHS);
148   }
149 
150   /// @}
151   /// @name String Predicates
152   /// @{
153 
154   /// startswith - Check if this string starts with the given \p Prefix.
startswith(StringRef Prefix)155   bool startswith(StringRef Prefix) const {
156     return str().startswith(Prefix);
157   }
158 
159   /// endswith - Check if this string ends with the given \p Suffix.
endswith(StringRef Suffix)160   bool endswith(StringRef Suffix) const {
161     return str().endswith(Suffix);
162   }
163 
164   /// @}
165   /// @name String Searching
166   /// @{
167 
168   /// find - Search for the first character \p C in the string.
169   ///
170   /// \return - The index of the first occurrence of \p C, or npos if not
171   /// found.
172   size_t find(char C, size_t From = 0) const {
173     return str().find(C, From);
174   }
175 
176   /// Search for the first string \p Str in the string.
177   ///
178   /// \returns The index of the first occurrence of \p Str, or npos if not
179   /// found.
180   size_t find(StringRef Str, size_t From = 0) const {
181     return str().find(Str, From);
182   }
183 
184   /// Search for the last character \p C in the string.
185   ///
186   /// \returns The index of the last occurrence of \p C, or npos if not
187   /// found.
188   size_t rfind(char C, size_t From = StringRef::npos) const {
189     return str().rfind(C, From);
190   }
191 
192   /// Search for the last string \p Str in the string.
193   ///
194   /// \returns The index of the last occurrence of \p Str, or npos if not
195   /// found.
rfind(StringRef Str)196   size_t rfind(StringRef Str) const {
197     return str().rfind(Str);
198   }
199 
200   /// Find the first character in the string that is \p C, or npos if not
201   /// found. Same as find.
202   size_t find_first_of(char C, size_t From = 0) const {
203     return str().find_first_of(C, From);
204   }
205 
206   /// Find the first character in the string that is in \p Chars, or npos if
207   /// not found.
208   ///
209   /// Complexity: O(size() + Chars.size())
210   size_t find_first_of(StringRef Chars, size_t From = 0) const {
211     return str().find_first_of(Chars, From);
212   }
213 
214   /// Find the first character in the string that is not \p C or npos if not
215   /// found.
216   size_t find_first_not_of(char C, size_t From = 0) const {
217     return str().find_first_not_of(C, From);
218   }
219 
220   /// Find the first character in the string that is not in the string
221   /// \p Chars, or npos if not found.
222   ///
223   /// Complexity: O(size() + Chars.size())
224   size_t find_first_not_of(StringRef Chars, size_t From = 0) const {
225     return str().find_first_not_of(Chars, From);
226   }
227 
228   /// Find the last character in the string that is \p C, or npos if not
229   /// found.
230   size_t find_last_of(char C, size_t From = StringRef::npos) const {
231     return str().find_last_of(C, From);
232   }
233 
234   /// Find the last character in the string that is in \p C, or npos if not
235   /// found.
236   ///
237   /// Complexity: O(size() + Chars.size())
238   size_t find_last_of(
239       StringRef Chars, size_t From = StringRef::npos) const {
240     return str().find_last_of(Chars, From);
241   }
242 
243   /// @}
244   /// @name Helpful Algorithms
245   /// @{
246 
247   /// Return the number of occurrences of \p C in the string.
count(char C)248   size_t count(char C) const {
249     return str().count(C);
250   }
251 
252   /// Return the number of non-overlapped occurrences of \p Str in the
253   /// string.
count(StringRef Str)254   size_t count(StringRef Str) const {
255     return str().count(Str);
256   }
257 
258   /// @}
259   /// @name Substring Operations
260   /// @{
261 
262   /// Return a reference to the substring from [Start, Start + N).
263   ///
264   /// \param Start The index of the starting character in the substring; if
265   /// the index is npos or greater than the length of the string then the
266   /// empty substring will be returned.
267   ///
268   /// \param N The number of characters to included in the substring. If \p N
269   /// exceeds the number of characters remaining in the string, the string
270   /// suffix (starting with \p Start) will be returned.
271   StringRef substr(size_t Start, size_t N = StringRef::npos) const {
272     return str().substr(Start, N);
273   }
274 
275   /// Return a reference to the substring from [Start, End).
276   ///
277   /// \param Start The index of the starting character in the substring; if
278   /// the index is npos or greater than the length of the string then the
279   /// empty substring will be returned.
280   ///
281   /// \param End The index following the last character to include in the
282   /// substring. If this is npos, or less than \p Start, or exceeds the
283   /// number of characters remaining in the string, the string suffix
284   /// (starting with \p Start) will be returned.
slice(size_t Start,size_t End)285   StringRef slice(size_t Start, size_t End) const {
286     return str().slice(Start, End);
287   }
288 
289   // Extra methods.
290 
291   /// Explicit conversion to StringRef.
str()292   StringRef str() const { return StringRef(this->data(), this->size()); }
293 
294   // TODO: Make this const, if it's safe...
c_str()295   const char* c_str() {
296     this->push_back(0);
297     this->pop_back();
298     return this->data();
299   }
300 
301   /// Implicit conversion to StringRef.
StringRef()302   operator StringRef() const { return str(); }
303 
string()304   explicit operator std::string() const {
305     return std::string(this->data(), this->size());
306   }
307 
308   // Extra operators.
309   SmallString &operator=(StringRef RHS) {
310     this->assign(RHS);
311     return *this;
312   }
313 
314   SmallString &operator+=(StringRef RHS) {
315     this->append(RHS.begin(), RHS.end());
316     return *this;
317   }
318   SmallString &operator+=(char C) {
319     this->push_back(C);
320     return *this;
321   }
322 };
323 
324 } // end namespace llvm
325 
326 #endif // LLVM_ADT_SMALLSTRING_H
327