Some warning reduction:
[mono.git] / mcs / class / corlib / System.Text / StringBuilder.cs
1 // -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-\r
2 //\r
3 // System.Text.StringBuilder\r
4 //\r
5 // Author: Marcin Szczepanski (marcins@zipworld.com.au)\r
6 //\r
7 // TODO: Implement the AppendFormat methods.  Wasn't sure how\r
8 // best to do this at this early stage, might want to see\r
9 // how the String class and the IFormatProvide / IFormattable interfaces\r
10 // pan out first.\r
11 //  \r
12 // TODO: Make sure the coding complies to the ECMA draft, there's some\r
13 // variable names that probably don't (like sString)\r
14 //\r
15 \r
16 namespace System.Text {\r
17         public sealed class StringBuilder {\r
18 \r
19                 const int defaultCapacity = 16;\r
20 \r
21                 private int sCapacity;\r
22                 private int sLength;\r
23                 private char[] sString;\r
24 \r
25                 public StringBuilder() {\r
26 \r
27                         // The MS Implementation uses the default\r
28                         // capacity for a StringBuilder.  The spec\r
29                         // says it's up to the implementer, but \r
30                         // we'll do it the MS way just in case.\r
31                                 \r
32                         sString = new char[ defaultCapacity ];\r
33                         sCapacity = defaultCapacity;\r
34                         sLength = 0;\r
35                 }\r
36 \r
37                 public StringBuilder( int capacity ) {\r
38                         if( capacity < defaultCapacity ) {\r
39                                         // The spec says that the capacity\r
40                                         // has to be at least the default capacity\r
41                                 capacity = defaultCapacity;\r
42                         }\r
43 \r
44                         sString = new char[capacity];\r
45                         sCapacity = capacity;\r
46                         sLength = 0;\r
47                 }\r
48 \r
49                 public StringBuilder( string str ) {\r
50                 \r
51                         if( str.Length < defaultCapacity ) {    \r
52                                 char[] tString = str.ToCharArray();\r
53                                 sString = new char[ defaultCapacity ];\r
54                                 Array.Copy( tString, sString, str.Length );\r
55                                 sLength = str.Length;\r
56                                 sCapacity = defaultCapacity;\r
57                         } else {\r
58                                 sString = str.ToCharArray();\r
59                                 sCapacity = sString.Length;\r
60                                 sLength = sString.Length;\r
61                         }\r
62                 }\r
63         \r
64                 public int Capacity {\r
65                         get {\r
66                                 return sCapacity;\r
67                         }\r
68 \r
69                         set {\r
70                                 if( value < sLength ) {\r
71                                         throw new ArgumentException( "Capacity must be > length" );\r
72                                 } else {\r
73                                         char[] tString = new char[value];              \r
74                                         Array.Copy( sString, tString, sLength );\r
75                                         sString = tString;\r
76                                         sCapacity = sString.Length;\r
77                                 }\r
78                         }\r
79                 }\r
80 \r
81 \r
82                 public int Length {\r
83                         get {\r
84                                 return sLength;\r
85                         }\r
86 \r
87                         set {\r
88                                 if( value < 0 || value > Int32.MaxValue) {\r
89                                         throw new ArgumentOutOfRangeException();\r
90                                 } else {\r
91                                         if( value < sLength ) {\r
92                                                 // Truncate current string at value\r
93 \r
94                                                 // LAMESPEC:  The spec is unclear as to what to do\r
95                                                 // with the capacity when truncating the string.\r
96                                                 //\r
97                                                 // Don't change the capacity, as this is what\r
98                                                 // the MS implementation does.\r
99 \r
100                                                 sLength = value;\r
101                                         } else {\r
102                                                 // Expand the capacity to the new length and\r
103                                                 // pad the string with spaces.\r
104                                                 \r
105                                                 // LAMESPEC: The spec says to put the spaces on the\r
106                                                 // left of the string however the MS implementation\r
107                                                 // puts them on the right.  We'll do that for \r
108                                                 // compatibility (!)\r
109 \r
110                                                 char[] tString = new char[ value ];\r
111                                                 int padLength = value - sLength;\r
112                                                 \r
113                                                 string padding = new String( ' ', padLength );\r
114                                                 Array.Copy( sString, tString, sLength );\r
115                                                 Array.Copy( padding.ToCharArray(), 0, tString, sLength, padLength );\r
116                                                 sString = tString;\r
117                                                 sLength = sString.Length;\r
118                                                 sCapacity = value;\r
119                                         }\r
120                                 }\r
121                         }\r
122                 }\r
123 \r
124                 public char this[ int index ] {\r
125                         get {\r
126 \r
127                                 if( index >= sLength || index < 0 ) {\r
128                                         throw new IndexOutOfRangeException();\r
129                                 }\r
130                                 return sString[ index ];\r
131                         } \r
132 \r
133                         set {\r
134                                 if( index >= sLength || index < 0 ) {\r
135                                         throw new IndexOutOfRangeException();\r
136                                 }\r
137                                 sString[ index ] = value;\r
138                         }\r
139                 }\r
140 \r
141                 public override string ToString() {\r
142                         return ToString(0, sLength);\r
143                 }\r
144 \r
145                 public string ToString( int startIndex, int length ) {\r
146                         if( startIndex < 0 || length < 0 || startIndex + length > sLength ) {\r
147                                 throw new ArgumentOutOfRangeException();\r
148                         }\r
149         \r
150                         return new String( sString, startIndex, length );\r
151                 }\r
152 \r
153                 public int EnsureCapacity( int capacity ) {\r
154                         if( capacity < 0 ) {\r
155                                 throw new ArgumentOutOfRangeException( \r
156                                                                         "Capacity must be greater than 0." );\r
157                         }\r
158 \r
159                         if( capacity <= sCapacity ) {\r
160                                 return sCapacity;\r
161                         } else {\r
162                                 Capacity = capacity;\r
163                                 return sCapacity;\r
164                         }\r
165                 }\r
166 \r
167                 public bool Equals( StringBuilder sb ) {\r
168                         if( this.ToString() == sb.ToString() ) {\r
169                                 return true;\r
170                         } else {\r
171                                 return false;\r
172                         }\r
173                 }\r
174 \r
175                 public StringBuilder Remove( int startIndex, int length ) {\r
176                         if( startIndex < 0 || length < 0 || startIndex + length > sLength ) {\r
177                                 throw new ArgumentOutOfRangeException();\r
178                         }\r
179 \r
180                         // Copy everything after the 'removed' part to the start \r
181                                                 // of the removed part and truncate the sLength\r
182 \r
183                         Array.Copy( sString, startIndex + length, sString, \r
184                                                         startIndex, length );\r
185 \r
186                         sLength -= length;\r
187                         return this;\r
188                 }                              \r
189 \r
190                 public StringBuilder Replace( char oldChar, char newChar ) {\r
191                 \r
192                                 return Replace( oldChar, newChar, 0, sLength);\r
193                 }\r
194 \r
195                 public StringBuilder Replace( char oldChar, char newChar, int startIndex, int count ) {\r
196                         if( startIndex + count > sLength || startIndex < 0 || count < 0 ) {\r
197                                 throw new ArgumentOutOfRangeException();\r
198                         }\r
199 \r
200                         for( int replaceIterate = startIndex; replaceIterate < startIndex + count; replaceIterate++ ) {\r
201                                 if( this[replaceIterate] == oldChar ) {\r
202                                         this[replaceIterate] = newChar;\r
203                                 }\r
204                         }\r
205 \r
206                         return this;\r
207                 }\r
208 \r
209                 public StringBuilder Replace( string oldValue, string newValue ) {\r
210                         return Replace( oldValue, newValue, 0, sLength );\r
211                 }\r
212 \r
213                 public StringBuilder Replace( string oldValue, string newValue, int startIndex, int count ) {\r
214                         string startString = this.ToString();\r
215                         StringBuilder newStringB = new StringBuilder();\r
216                         string newString;\r
217 \r
218                         if( oldValue == null ) { \r
219                                 throw new ArgumentNullException(\r
220                                                                         "The old value cannot be null.");\r
221                         }\r
222 \r
223                         if( startIndex < 0 || count < 0 || startIndex + count > sLength ) {\r
224                                 throw new ArgumentOutOfRangeException();\r
225                         }\r
226 \r
227                         if( oldValue.Length == 0 ) {\r
228                                 throw new ArgumentException(\r
229                                                                         "The old value cannot be zero length.");\r
230                         }\r
231 \r
232                         int nextIndex = startIndex; // Where to start the next search\r
233                         int lastIndex = nextIndex;  // Where the last search finished\r
234 \r
235                         while( nextIndex != -1 ) {\r
236                                 nextIndex = startString.IndexOf( oldValue, lastIndex);                            \r
237                                 if( nextIndex != -1 ) {\r
238                                         // The MS implementation won't replace a substring \r
239                                                                                 // if that substring goes over the "count"\r
240                                                                                 // boundary, so we'll make sure the behaviour \r
241                                                                                 // here is the same.\r
242 \r
243                                         if( nextIndex + oldValue.Length <= startIndex + count ) {\r
244 \r
245                                                 // Add everything to the left of the old \r
246                                                                                                 // string\r
247                                                 newStringB.Append( startString.Substring( lastIndex, nextIndex - lastIndex ) );\r
248         \r
249                                                 // Add the replacement string\r
250                                                 newStringB.Append( newValue );\r
251                                                 \r
252                                                 // Set the next start point to the \r
253                                                                                                 // end of the last match\r
254                                                 lastIndex = nextIndex + oldValue.Length;\r
255                                         } else {\r
256                                                 // We're past the "count" we're supposed to replace within\r
257                                                 nextIndex = -1;\r
258                                                 newStringB.Append( \r
259                                                                                                         startString.Substring( lastIndex ) );\r
260                                         }\r
261 \r
262                                 } else {\r
263                                         // Append everything left over\r
264                                         newStringB.Append( startString.Substring( lastIndex ) );\r
265                                 }\r
266                         } \r
267 \r
268                         newString = newStringB.ToString();\r
269 \r
270                         EnsureCapacity( newString.Length );\r
271                         sString = newString.ToCharArray();\r
272                         sLength = newString.Length;\r
273                         return this;\r
274                 }\r
275 \r
276                       \r
277                     /* The Append Methods */\r
278 \r
279                 // TODO: Currently most of these methods convert the \r
280                 // parameter to a CharArray (via a String) and then pass\r
281                 // it to Append( char[] ).  There might be a faster way\r
282                 // of doing this, but it's probably adequate and anything else\r
283                 // would make it too messy.\r
284                 //\r
285                 // As an example, a sample test run of appending a 100 character\r
286                 // string to the StringBuilder, and loooping this 50,000 times\r
287                 // results in an elapsed time of 2.4s using the MS StringBuilder\r
288                 // and 2.7s using this StringBuilder.  Note that this results\r
289                 // in a 5 million character string.  I believe MS uses a lot\r
290                 // of "native" DLLs for the "meat" of the base classes.\r
291 \r
292 \r
293                 public StringBuilder Append( char[] value ) {\r
294                         if( sLength + value.Length > sCapacity ) {\r
295                                 // Need more capacity, double the capacity StringBuilder \r
296                                 // and make sure we have at least enough for the value \r
297                                 // if that's going to go over double. \r
298                                          \r
299                                 Capacity = value.Length + ( sCapacity + sCapacity);\r
300                         }\r
301 \r
302                         Array.Copy( value, 0, sString, sLength, value.Length );\r
303                         sLength += value.Length;\r
304 \r
305                         return this;\r
306                 } \r
307                 \r
308                 public StringBuilder Append( string value ) {\r
309                         if( value != null ) {\r
310                                 return Append( value.ToCharArray() );\r
311                         } else {\r
312                                 return null;\r
313                         }\r
314                 }\r
315 \r
316                 public StringBuilder Append( bool value ) {\r
317                         return Append( value.ToString().ToCharArray() );\r
318                 }\r
319                 \r
320                 public StringBuilder Append( byte value ) {\r
321                         return Append( value.ToString().ToCharArray() );\r
322                 }\r
323 \r
324                 public StringBuilder Append( int index, char value) {\r
325                         char[] appendChar = new char[1];\r
326                         \r
327                         appendChar[0] = value;\r
328                         return Append( appendChar );\r
329                 }\r
330 \r
331 \r
332                 public StringBuilder Append( decimal value ) {\r
333                         return Append( value.ToString().ToCharArray() );\r
334                 }\r
335 \r
336                 public StringBuilder Append( double value ) {\r
337                         return Append( value.ToString().ToCharArray() );\r
338                 }\r
339 \r
340                 public StringBuilder Append( short value ) {\r
341                         return Append( value.ToString().ToCharArray() );\r
342                 }\r
343 \r
344                 public StringBuilder Append( int value ) {\r
345                         return Append( value.ToString().ToCharArray() );\r
346                 }\r
347 \r
348                 public StringBuilder Append( long value ) {\r
349                         return Append( value.ToString().ToCharArray() );\r
350                 }\r
351 \r
352                 public StringBuilder Append( object value ) {\r
353                         return Append( value.ToString().ToCharArray() );\r
354                 }\r
355 \r
356                 public StringBuilder Append( sbyte value ) {\r
357                         return Append( value.ToString().ToCharArray() );\r
358                 }\r
359 \r
360                 public StringBuilder Append( float value ) {\r
361                         return Append( value.ToString().ToCharArray() );\r
362                 }\r
363 \r
364                 public StringBuilder Append( ushort value ) {\r
365                         return Append( value.ToString().ToCharArray() );\r
366                 }       \r
367                 \r
368                 public StringBuilder Append( uint value ) {\r
369                         return Append( value.ToString().ToCharArray() );\r
370                 }\r
371 \r
372                 public StringBuilder Append( ulong value ) {\r
373                         return Append( value.ToString().ToCharArray() );\r
374                 }\r
375 \r
376                 public StringBuilder Append( char value, int repeatCount ) {\r
377                         if( repeatCount < 0 ) {\r
378                                 throw new ArgumentOutOfRangeException();\r
379                         }\r
380 \r
381                         return Append( new String( value, repeatCount) );\r
382                 }\r
383 \r
384                 public StringBuilder Append( char[] value, int startIndex, int charCount ) {\r
385 \r
386                         if( (charCount < 0 || startIndex < 0) || \r
387                                         ( charCount + startIndex > value.Length ) ) {\r
388                                 throw new ArgumentOutOfRangeException();\r
389                         }\r
390                         \r
391                         if( value == null ) {\r
392                                 if( !(startIndex == 0 && charCount == 0) ) {\r
393                                         throw new ArgumentNullException();\r
394                                 } else {\r
395                                         return this;\r
396                                 }\r
397                         } else {\r
398                                 char[] appendChars = new char[ charCount ];\r
399                         \r
400                                 Array.Copy( value, startIndex, appendChars, 0, charCount );\r
401                                 return Append( appendChars );\r
402                         }\r
403                 }\r
404 \r
405                 public StringBuilder Append( string value, int startIndex, int count ) {\r
406                         if( (count < 0 || startIndex < 0) || \r
407                                                         ( startIndex + count > value.Length ) ) { \r
408                                 throw new ArgumentOutOfRangeException();\r
409                         }\r
410 \r
411                         return Append( value.Substring( startIndex, count ).ToCharArray() );\r
412                 }\r
413 \r
414                 public StringBuilder AppendFormat( string format, object arg0 ) {\r
415                         // TODO: Implement\r
416                         return this;\r
417                 }\r
418 \r
419                 public StringBuilder AppendFormat( string format, params object[] args ) {\r
420                         // TODO: Implement\r
421                         return this;\r
422                 }\r
423 \r
424                 public StringBuilder AppendFormat( IFormatProvider provider, string format,\r
425                                                                 params object[] args ) {\r
426                         // TODO: Implement\r
427                         return this;\r
428                 }\r
429 \r
430                 public StringBuilder AppendFormat( string format, object arg0, object arg1 ) {\r
431                         // TODO: Implement;\r
432                         return this;\r
433                 }\r
434 \r
435                 public StringBuilder AppendFormat( string format, object arg0, object arg1, object arg2 ) {\r
436                         // TODO Implement\r
437                         return this;\r
438                 }\r
439 \r
440                 /*  The Insert Functions */\r
441                 \r
442                 // Similarly to the Append functions, get everything down to a CharArray \r
443                 // and insert that.\r
444                 \r
445                 public StringBuilder Insert( int index, char[] value ) {\r
446                         if( index > sLength || index < 0) {\r
447                                 throw new ArgumentOutOfRangeException();\r
448                         }\r
449 \r
450                         if( value == null || value.Length == 0 ) {\r
451                                 return this;\r
452                         } else {\r
453                                 // Check we have the capacity to insert this array\r
454                                 if( sCapacity < sLength + value.Length ) {\r
455                                         Capacity = value.Length + ( sCapacity + sCapacity );\r
456                                 }\r
457 \r
458                                 // Move everything to the right of the insert point across\r
459                                 Array.Copy( sString, index, sString, index + value.Length, sLength - index);\r
460                                 \r
461                                 // Copy in stuff from the insert buffer\r
462                                 Array.Copy( value, 0, sString, index, value.Length );\r
463                                 \r
464                                 sLength += value.Length;\r
465                                 return this;\r
466                         }\r
467                 }\r
468                                 \r
469                 public StringBuilder Insert( int index, string value ) {\r
470                         return Insert( index, value.ToCharArray() );\r
471                 }\r
472 \r
473                 public StringBuilder Insert( int index, bool value ) {\r
474                         return Insert( index, value.ToString().ToCharArray() );\r
475                 }\r
476                 \r
477                 public StringBuilder Insert( int index, byte value ) {\r
478                         return Insert( index, value.ToString().ToCharArray() );\r
479                 }\r
480 \r
481                 public StringBuilder Insert( int index, char value) {\r
482                         char[] insertChar = new char[1];\r
483                         \r
484                         insertChar[0] = value;\r
485                         return Insert( index, insertChar );\r
486                 }\r
487 \r
488                 public StringBuilder Insert( int index, decimal value ) {\r
489                         return Insert( index, value.ToString().ToCharArray() );\r
490                 }\r
491 \r
492                 public StringBuilder Insert( int index, double value ) {\r
493                         return Insert( index, value.ToString().ToCharArray() );\r
494                 }\r
495                 \r
496                 public StringBuilder Insert( int index, short value ) {\r
497                         return Insert( index, value.ToString().ToCharArray() );\r
498                 }\r
499 \r
500                 public StringBuilder Insert( int index, int value ) {\r
501                         return Insert( index, value.ToString().ToCharArray() );\r
502                 }\r
503 \r
504                 public StringBuilder Insert( int index, long value ) {\r
505                         return Insert( index, value.ToString().ToCharArray() );\r
506                 }\r
507         \r
508                 public StringBuilder Insert( int index, object value ) {\r
509                         return Insert( index, value.ToString().ToCharArray() );\r
510                 }\r
511 \r
512                 public StringBuilder Insert( int index, sbyte value ) {\r
513                         return Insert( index, value.ToString().ToCharArray() );\r
514                 }\r
515 \r
516                 public StringBuilder Insert( int index, float value ) {\r
517                 return Insert( index, value.ToString().ToCharArray() );\r
518                 }\r
519 \r
520                 public StringBuilder Insert( int index, ushort value ) {\r
521                         return Insert( index, value.ToString().ToCharArray() );\r
522                 }\r
523 \r
524                 public StringBuilder Insert( int index, uint value ) {\r
525                         return Insert( index, value.ToString().ToCharArray() );\r
526                 }\r
527 \r
528                 public StringBuilder Insert( int index, ulong value ) {\r
529                         return Insert( index, value.ToString().ToCharArray() );\r
530                 }\r
531 \r
532                 public StringBuilder Insert( int index, string value, int count ) {\r
533                         if ( count < 0 ) {\r
534                                 throw new ArgumentOutOfRangeException();\r
535                         }\r
536 \r
537                         if( value != null ) {\r
538                                 if( value != "" ) {\r
539                                         for( int insertCount = 0; insertCount < count; \r
540                                                                                         insertCount++ ) {\r
541                                                 Insert( index, value.ToCharArray() );      \r
542                                         }\r
543                                 }\r
544                         }\r
545                         return this;\r
546                 }\r
547 \r
548                 public StringBuilder Insert( int index, char[] value, int startIndex, \r
549                                         int charCount ) {\r
550 \r
551                         if( value != null ) {\r
552                                 if( charCount < 0 || startIndex < 0 || startIndex + charCount > value.Length ) {\r
553                                         throw new ArgumentOutOfRangeException();\r
554                                 }\r
555                                         \r
556                                 char[] insertChars = new char[ charCount  ];\r
557                                 Array.Copy( value, startIndex, insertChars, 0, charCount );\r
558                                 return Insert( index, insertChars );\r
559                         } else {\r
560                                 return this;\r
561                         }\r
562                 }\r
563         }\r
564 }       \r