1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | |
5 | // |
6 | // clr_std/string |
7 | // |
8 | // Copy of some key Standard Template Library functionality |
9 | // |
10 | // This was created for use with SuperPMI. It has the minimal functionality needed by SuperPMI. It hasn't |
11 | // been tested elsewhere. |
12 | |
13 | #ifdef _MSC_VER |
14 | #pragma once |
15 | #endif |
16 | |
17 | #ifdef USE_STL |
18 | #include <string> |
19 | #else |
20 | #ifndef __clr_std_string_h__ |
21 | #define __clr_std_string_h__ |
22 | |
23 | #include "clr_std/vector" |
24 | |
25 | namespace std |
26 | { |
27 | |
28 | template<class T> |
29 | class basic_string |
30 | { |
31 | public: |
32 | typedef T value_type; |
33 | typedef size_t size_type; |
34 | typedef typename vector<T>::iterator iterator; |
35 | typedef typename vector<T>::const_iterator const_iterator; |
36 | |
37 | basic_string() |
38 | : m_string(1) // start with a string of length 1 for null terminator |
39 | { |
40 | m_string[0] = T(); |
41 | } |
42 | |
43 | basic_string(const basic_string<T>& _Right) |
44 | { |
45 | assign(_Right); |
46 | } |
47 | |
48 | // Initialize a string with _Count characters from the string pointed at by _Ptr. |
49 | // If you want to include the trailing null character, _Count needs to include that. |
50 | basic_string(const value_type* _Ptr, size_type _Count) |
51 | : m_string(_Count + 1) // add 1 for a null terminator |
52 | { |
53 | copy(_Ptr, _Count); |
54 | } |
55 | |
56 | basic_string(const value_type* _Ptr) |
57 | { |
58 | this->basic_string::basic_string(_Ptr, c_len(_Ptr)); |
59 | } |
60 | |
61 | void reserve(size_t newcapacity) |
62 | { |
63 | m_string.reserve(newcapacity + 1); // add 1 for the null terminator |
64 | } |
65 | |
66 | // |
67 | // Assignment |
68 | // |
69 | |
70 | basic_string<T>& operator=(const basic_string<T>& _Right) |
71 | { |
72 | if (this != &_Right) |
73 | { |
74 | assign(_Right); |
75 | } |
76 | return (*this); |
77 | } |
78 | |
79 | basic_string<T>& assign(const basic_string<T>& _Right) |
80 | { |
81 | m_string.resize(_Right.size() + 1); // +1 for null terminator |
82 | copy(_Right); |
83 | return (*this); |
84 | } |
85 | |
86 | // |
87 | // Basic data copying |
88 | // |
89 | |
90 | void copy(const basic_string<T>& _Right) |
91 | { |
92 | assert(size() >= _Right.size()); |
93 | size_type i; |
94 | for (i = 0; i < _Right.size(); i++) |
95 | { |
96 | m_string[i] = _Right.m_string[i]; |
97 | } |
98 | m_string[i] = T(); |
99 | } |
100 | |
101 | void copy(const value_type* _Ptr, size_type _Count) |
102 | { |
103 | assert(size() >= _Count); |
104 | size_type i; |
105 | for (i = 0; i < _Count; i++) |
106 | { |
107 | m_string[i] = _Ptr[i]; |
108 | } |
109 | m_string[i] = T(); |
110 | } |
111 | |
112 | // |
113 | // Appending |
114 | // |
115 | |
116 | // Append a C-style string to the string. |
117 | basic_string<T>& operator+=(const value_type* _Ptr) |
118 | { |
119 | size_type oldsize = size(); // doesn't include null terminator |
120 | size_type addsize = c_len(_Ptr); // doesn't include null terminator |
121 | size_type newsize = oldsize + addsize + 1; |
122 | m_string.resize(newsize); |
123 | size_type i; |
124 | for (i = oldsize; i < newsize - 1; i++) |
125 | { |
126 | m_string[i] = *_Ptr++; |
127 | } |
128 | m_string[i] = T(); |
129 | return (*this); |
130 | } |
131 | |
132 | basic_string<T>& operator+=(const basic_string<T>& _Right) |
133 | { |
134 | size_type oldsize = size(); // doesn't include null terminator |
135 | size_type addsize = _Right.size(); // doesn't include null terminator |
136 | size_type newsize = oldsize + addsize + 1; |
137 | m_string.resize(newsize); |
138 | size_type new_index = oldsize, right_index = 0; |
139 | while (right_index < addsize) |
140 | { |
141 | m_string[new_index] = _Right.m_string[right_index]; |
142 | ++new_index; |
143 | ++right_index; |
144 | } |
145 | m_string[new_index] = T(); |
146 | return (*this); |
147 | } |
148 | |
149 | basic_string<T>& operator+=(value_type _Ch) |
150 | { |
151 | size_type oldsize = size(); // doesn't include null terminator |
152 | m_string[oldsize] = _Ch; // Replace the null terminator with the new symbol. |
153 | m_string.push_back(T()); // Return the replaced terminator again. |
154 | return (*this); |
155 | } |
156 | |
157 | ~basic_string() |
158 | { |
159 | // vector destructor does all the work |
160 | } |
161 | |
162 | size_t size() const |
163 | { |
164 | assert(m_string.size() > 0); |
165 | return m_string.size() - 1; // Don't report the null terminator. |
166 | } |
167 | |
168 | size_t length() const |
169 | { |
170 | return size(); |
171 | } |
172 | |
173 | T& operator[](size_t iIndex) |
174 | { |
175 | assert(iIndex < size() + 1); // allow looking at the null terminator |
176 | return m_string[iIndex]; |
177 | } |
178 | |
179 | const T* c_str() const |
180 | { |
181 | return m_string.data(); |
182 | } |
183 | |
184 | iterator begin() |
185 | { |
186 | return m_string.begin(); |
187 | } |
188 | |
189 | iterator end() |
190 | { |
191 | return m_string.end(); |
192 | } |
193 | |
194 | const_iterator cbegin() const |
195 | { |
196 | return m_string.cbegin(); |
197 | } |
198 | |
199 | const_iterator cend() const |
200 | { |
201 | return m_string.cend(); |
202 | } |
203 | |
204 | basic_string<T> substr(size_type _Off = 0, size_type _Count = npos) const |
205 | { |
206 | size_type cursize = size(); |
207 | if (_Off >= cursize) |
208 | { |
209 | // result will be empty |
210 | return basic_string<T>(); |
211 | } |
212 | else |
213 | { |
214 | if ((_Count == npos) || // No count specified; take the whole string suffix |
215 | (_Off + _Count > cursize)) // Count specified is too many characters; just take the whole suffix |
216 | { |
217 | _Count = cursize - _Off; |
218 | } |
219 | return basic_string<T>(m_string.data() + _Off, _Count); |
220 | } |
221 | } |
222 | |
223 | size_type find_last_of(value_type _Ch) const |
224 | { |
225 | for (size_type _Off = size(); _Off != 0; _Off--) |
226 | { |
227 | if (m_string[_Off - 1] == _Ch) |
228 | { |
229 | return _Off - 1; |
230 | } |
231 | } |
232 | return npos; |
233 | } |
234 | |
235 | bool empty() const |
236 | { |
237 | return size() == 0; |
238 | } |
239 | |
240 | int compare(const basic_string<T>& _Str) const |
241 | { |
242 | size_type i; |
243 | size_type compareSize = size(); |
244 | if (_Str.size() < compareSize) |
245 | { |
246 | // This string is longer; compare character-by-character only as many characters as we have. |
247 | compareSize = _Str.size(); |
248 | } |
249 | for (i = 0; i < compareSize; i++) |
250 | { |
251 | if (m_string[i] != _Str.m_string[i]) |
252 | { |
253 | if (m_string[i] < _Str.m_string[i]) |
254 | { |
255 | return -1; |
256 | } |
257 | else |
258 | { |
259 | return 1; |
260 | } |
261 | } |
262 | } |
263 | |
264 | // All the characters we compared were identical, but one string might be longer than the other. |
265 | if (size() == _Str.size()) |
266 | { |
267 | // We compared everything. |
268 | return 0; |
269 | } |
270 | else if (size() < _Str.size()) |
271 | { |
272 | // _Str has more characters than this. |
273 | return -1; |
274 | } |
275 | else |
276 | { |
277 | // this has more characters than _Str |
278 | return 1; |
279 | } |
280 | } |
281 | |
282 | static const size_type npos = size_type(-1); |
283 | |
284 | private: |
285 | |
286 | // Compute the length in characters of a null-terminated C-style string, not including the trailing null character. |
287 | // _Ptr must not be nullptr. |
288 | size_type c_len(const value_type* _Ptr) |
289 | { |
290 | size_type count; |
291 | for (count = 0; *_Ptr != T(); _Ptr++) |
292 | { |
293 | count++; |
294 | } |
295 | return count; |
296 | } |
297 | |
298 | vector<T> m_string; // use a vector<> to represent the string, to avoid reimplementing similar functionality |
299 | |
300 | }; // class basic_string |
301 | |
302 | // |
303 | // String class instantiations |
304 | // |
305 | |
306 | typedef basic_string<char> string; |
307 | |
308 | // |
309 | // Numeric conversions |
310 | // |
311 | |
312 | // convert integer T to string |
313 | template<class T> inline |
314 | string _IntToString(const char *_Fmt, T _Val) |
315 | { |
316 | const size_t MaxIntBufSize = 21; /* can hold -2^63 and 2^64 - 1, plus NUL */ |
317 | char buf[MaxIntBufSize]; |
318 | int len = sprintf_s(buf, MaxIntBufSize, _Fmt, _Val); |
319 | return (string(buf, len)); |
320 | } |
321 | |
322 | inline string to_string(int _Val) |
323 | { |
324 | return (_IntToString("%d" , _Val)); |
325 | } |
326 | |
327 | inline string to_string(unsigned int _Val) |
328 | { |
329 | return (_IntToString("%u" , _Val)); |
330 | } |
331 | |
332 | inline string to_string(long _Val) |
333 | { |
334 | return (_IntToString("%ld" , _Val)); |
335 | } |
336 | |
337 | inline string to_string(unsigned long _Val) |
338 | { |
339 | return (_IntToString("%lu" , _Val)); |
340 | } |
341 | |
342 | inline string to_string(long long _Val) |
343 | { |
344 | return (_IntToString("%lld" , _Val)); |
345 | } |
346 | |
347 | inline string to_string(unsigned long long _Val) |
348 | { |
349 | return (_IntToString("%llu" , _Val)); |
350 | } |
351 | |
352 | // |
353 | // Comparisons |
354 | // |
355 | |
356 | template<class T> inline |
357 | bool operator==( |
358 | const basic_string<T>& _Left, |
359 | const basic_string<T>& _Right) |
360 | { |
361 | return (_Left.compare(_Right) == 0); |
362 | } |
363 | |
364 | template<class T> inline |
365 | bool operator!=( |
366 | const basic_string<T>& _Left, |
367 | const basic_string<T>& _Right) |
368 | { |
369 | return (!(_Left == _Right)); |
370 | } |
371 | |
372 | template<class T> inline |
373 | bool operator<( |
374 | const basic_string<T>& _Left, |
375 | const basic_string<T>& _Right) |
376 | { |
377 | return (_Left.compare(_Right) < 0); |
378 | } |
379 | |
380 | template<class T> inline |
381 | bool operator>( |
382 | const basic_string<T>& _Left, |
383 | const basic_string<T>& _Right) |
384 | { |
385 | return (_Right < _Left); |
386 | } |
387 | |
388 | template<class T> inline |
389 | bool operator<=( |
390 | const basic_string<T>& _Left, |
391 | const basic_string<T>& _Right) |
392 | { |
393 | return (!(_Right < _Left)); |
394 | } |
395 | |
396 | template<class T> inline |
397 | bool operator>=( |
398 | const basic_string<T>& _Left, |
399 | const basic_string<T>& _Right) |
400 | { |
401 | return (!(_Left < _Right)); |
402 | } |
403 | |
404 | // |
405 | // String concatenation and other string operations |
406 | // |
407 | |
408 | template<class T> inline |
409 | basic_string<T> operator+( |
410 | const basic_string<T>& _Left, |
411 | const basic_string<T>& _Right) |
412 | { |
413 | basic_string<T> ret; |
414 | ret.reserve(_Left.size() + _Right.size()); |
415 | ret += _Left; |
416 | ret += _Right; |
417 | return ret; |
418 | } |
419 | |
420 | }; // namespace std |
421 | |
422 | #endif /* __clr_std_string_h__ */ |
423 | |
424 | #endif // !USE_STL |
425 | |
426 | // Help the VIM editor figure out what kind of file this no-extension file is. |
427 | // vim: filetype=cpp |
428 | |