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