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
25namespace std
26{
27
28template<class T>
29class basic_string
30{
31public:
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
284private:
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
306typedef basic_string<char> string;
307
308//
309// Numeric conversions
310//
311
312// convert integer T to string
313template<class T> inline
314string _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
322inline string to_string(int _Val)
323{
324 return (_IntToString("%d", _Val));
325}
326
327inline string to_string(unsigned int _Val)
328{
329 return (_IntToString("%u", _Val));
330}
331
332inline string to_string(long _Val)
333{
334 return (_IntToString("%ld", _Val));
335}
336
337inline string to_string(unsigned long _Val)
338{
339 return (_IntToString("%lu", _Val));
340}
341
342inline string to_string(long long _Val)
343{
344 return (_IntToString("%lld", _Val));
345}
346
347inline string to_string(unsigned long long _Val)
348{
349 return (_IntToString("%llu", _Val));
350}
351
352//
353// Comparisons
354//
355
356template<class T> inline
357bool operator==(
358 const basic_string<T>& _Left,
359 const basic_string<T>& _Right)
360{
361 return (_Left.compare(_Right) == 0);
362}
363
364template<class T> inline
365bool operator!=(
366 const basic_string<T>& _Left,
367 const basic_string<T>& _Right)
368{
369 return (!(_Left == _Right));
370}
371
372template<class T> inline
373bool operator<(
374 const basic_string<T>& _Left,
375 const basic_string<T>& _Right)
376{
377 return (_Left.compare(_Right) < 0);
378}
379
380template<class T> inline
381bool operator>(
382 const basic_string<T>& _Left,
383 const basic_string<T>& _Right)
384{
385 return (_Right < _Left);
386}
387
388template<class T> inline
389bool operator<=(
390 const basic_string<T>& _Left,
391 const basic_string<T>& _Right)
392{
393 return (!(_Right < _Left));
394}
395
396template<class T> inline
397bool 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
408template<class T> inline
409basic_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