Updated with Xamarin copyrights
[mono.git] / mcs / class / corlib / System.Text / StringBuilder.cs
1 // -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2 //
3 // System.Text.StringBuilder
4 //
5 // Authors: 
6 //   Marcin Szczepanski (marcins@zipworld.com.au)
7 //   Paolo Molaro (lupus@ximian.com)
8 //   Patrik Torstensson
9 //
10 // NOTE: In the case the buffer is only filled by 50% a new string
11 //       will be returned by ToString() is cached in the '_cached_str'
12 //               cache_string will also control if a string has been handed out
13 //               to via ToString(). If you are chaning the code make sure that
14 //               if you modify the string data set the cache_string to null.
15 //
16
17 //
18 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
19 // Copyright 2011 Xamarin Inc
20 //
21 // Permission is hereby granted, free of charge, to any person obtaining
22 // a copy of this software and associated documentation files (the
23 // "Software"), to deal in the Software without restriction, including
24 // without limitation the rights to use, copy, modify, merge, publish,
25 // distribute, sublicense, and/or sell copies of the Software, and to
26 // permit persons to whom the Software is furnished to do so, subject to
27 // the following conditions:
28 // 
29 // The above copyright notice and this permission notice shall be
30 // included in all copies or substantial portions of the Software.
31 // 
32 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
33 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
34 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
35 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
36 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
37 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
38 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
39 //
40 using System.Runtime.Serialization;
41 using System.Runtime.CompilerServices;
42 using System.Runtime.InteropServices;
43
44 namespace System.Text {
45         
46         [Serializable]
47         [ComVisible (true)]
48         [MonoLimitation ("Serialization format not compatible with .NET")]
49         public sealed class StringBuilder : ISerializable
50         {
51                 private int _length;
52                 private string _str;
53                 private string _cached_str;
54                 
55                 private int _maxCapacity;
56                 private const int constDefaultCapacity = 16;
57
58                 public StringBuilder(string value, int startIndex, int length, int capacity) 
59                         : this (value, startIndex, length, capacity, Int32.MaxValue)
60                 {
61                 }
62
63                 private StringBuilder(string value, int startIndex, int length, int capacity, int maxCapacity)
64                 {
65                         // first, check the parameters and throw appropriate exceptions if needed
66                         if (null == value)
67                                 value = "";
68
69                         // make sure startIndex is zero or positive
70                         if (startIndex < 0)
71                                 throw new System.ArgumentOutOfRangeException ("startIndex", startIndex, "StartIndex cannot be less than zero.");
72
73                         // make sure length is zero or positive
74                         if(length < 0)
75                                 throw new System.ArgumentOutOfRangeException ("length", length, "Length cannot be less than zero.");
76
77                         if (capacity < 0)
78                                 throw new System.ArgumentOutOfRangeException ("capacity", capacity, "capacity must be greater than zero.");
79
80                         if (maxCapacity < 1)
81                                 throw new System.ArgumentOutOfRangeException ("maxCapacity", "maxCapacity is less than one.");
82                         if (capacity > maxCapacity)
83                                 throw new System.ArgumentOutOfRangeException ("capacity", "Capacity exceeds maximum capacity.");
84
85                         // make sure startIndex and length give a valid substring of value
86                         // re-ordered to avoid possible integer overflow
87                         if (startIndex > value.Length - length)
88                                 throw new System.ArgumentOutOfRangeException ("startIndex", startIndex, "StartIndex and length must refer to a location within the string.");
89
90                         if (capacity == 0) {
91                                 if (maxCapacity > constDefaultCapacity)
92                                         capacity = constDefaultCapacity;
93                                 else
94                                         _str = _cached_str = String.Empty;
95                         }
96                         _maxCapacity = maxCapacity;
97
98                         if (_str == null)
99                                 _str = String.InternalAllocateStr ((length > capacity) ? length : capacity);
100                         if (length > 0)
101                                 String.CharCopy (_str, 0, value, startIndex, length);
102                         
103                         _length = length;
104                 }
105
106                 public StringBuilder () : this (null) {}
107
108                 public StringBuilder(int capacity) : this (String.Empty, 0, 0, capacity) {}
109
110                 public StringBuilder(int capacity, int maxCapacity) : this (String.Empty, 0, 0, capacity, maxCapacity) { }
111
112                 public StringBuilder (string value)
113                 {
114                         /*
115                          * This is an optimization to avoid allocating the internal string
116                          * until the first Append () call.
117                          * The runtime pinvoke marshalling code needs to be aware of this.
118                          */
119                         if (null == value)
120                                 value = "";
121                         
122                         _length = value.Length;
123                         _str = _cached_str = value;
124                         _maxCapacity = Int32.MaxValue;
125                 }
126         
127                 public StringBuilder( string value, int capacity) : this(value == null ? "" : value, 0, value == null ? 0 : value.Length, capacity) {}
128         
129                 public int MaxCapacity {
130                         get {
131                                 return _maxCapacity;
132                         }
133                 }
134
135                 public int Capacity {
136                         get {
137                                 if (_str.Length == 0)
138                                         return Math.Min (_maxCapacity, constDefaultCapacity);
139                                 
140                                 return _str.Length;
141                         }
142
143                         set {
144                                 if (value < _length)
145                                         throw new ArgumentException( "Capacity must be larger than length" );
146
147                                 if (value > _maxCapacity)
148                                         throw new ArgumentOutOfRangeException ("value", "Should be less than or equal to MaxCapacity");
149
150                                 InternalEnsureCapacity(value);
151                         }
152                 }
153
154                 public int Length {
155                         get {
156                                 return _length;
157                         }
158
159                         set {
160                                 if( value < 0 || value > _maxCapacity)
161                                         throw new ArgumentOutOfRangeException();
162
163                                 if (value == _length)
164                                         return;
165
166                                 if (value < _length) {
167                                         // LAMESPEC:  The spec is unclear as to what to do
168                                         // with the capacity when truncating the string.
169
170                                         // Do as MS, keep the capacity
171                                         
172                                         // Make sure that we invalidate any cached string.
173                                         InternalEnsureCapacity (value);
174                                         _length = value;
175                                 } else {
176                                         // Expand the capacity to the new length and
177                                         // pad the string with NULL characters.
178                                         Append('\0', value - _length);
179                                 }
180                         }
181                 }
182
183                 [IndexerName("Chars")]
184                 public char this [int index] {
185                         get {
186                                 if (index >= _length || index < 0)
187                                         throw new IndexOutOfRangeException();
188
189                                 return _str [index];
190                         } 
191
192                         set {
193                                 if (index >= _length || index < 0)
194                                         throw new IndexOutOfRangeException();
195
196                                 if (null != _cached_str)
197                                         InternalEnsureCapacity (_length);
198                                 
199                                 _str.InternalSetChar (index, value);
200                         }
201                 }
202
203                 public override string ToString () 
204                 {
205                         if (_length == 0)
206                                 return String.Empty;
207
208                         if (null != _cached_str)
209                                 return _cached_str;
210
211                         // If we only have a half-full buffer we return a new string.
212                         if (_length < (_str.Length >> 1) || (_str.Length > string.LOS_limit && _length <= string.LOS_limit))
213                         {
214                                 // use String.SubstringUnchecked instead of String.Substring
215                                 // as the former is guaranteed to create a new string object
216                                 _cached_str = _str.SubstringUnchecked (0, _length);
217                                 return _cached_str;
218                         }
219
220                         _cached_str = _str;
221                         _str.InternalSetLength(_length);
222
223                         return _str;
224                 }
225
226                 public string ToString (int startIndex, int length) 
227                 {
228                         // re-ordered to avoid possible integer overflow
229                         if (startIndex < 0 || length < 0 || startIndex > _length - length)
230                                 throw new ArgumentOutOfRangeException();
231
232                         // use String.SubstringUnchecked instead of String.Substring
233                         // as the former is guaranteed to create a new string object
234                         if (startIndex == 0 && length == _length)
235                                 return ToString ();
236                         else
237                                 return _str.SubstringUnchecked (startIndex, length);
238                 }
239
240                 public int EnsureCapacity (int capacity) 
241                 {
242                         if (capacity < 0)
243                                 throw new ArgumentOutOfRangeException ("Capacity must be greater than 0." );
244
245                         if( capacity <= _str.Length )
246                                 return _str.Length;
247
248                         InternalEnsureCapacity (capacity);
249
250                         return _str.Length;
251                 }
252
253                 public bool Equals (StringBuilder sb) 
254                 {
255                         if (((object)sb) == null)
256                                 return false;
257                         
258                         if (_length == sb.Length && _str == sb._str )
259                                 return true;
260
261                         return false;
262                 }
263
264                 public StringBuilder Remove (int startIndex, int length)
265                 {
266                         // re-ordered to avoid possible integer overflow
267                         if (startIndex < 0 || length < 0 || startIndex > _length - length)
268                                 throw new ArgumentOutOfRangeException();
269                         
270                         if (null != _cached_str)
271                                 InternalEnsureCapacity (_length);
272                         
273                         // Copy everything after the 'removed' part to the start 
274                         // of the removed part and truncate the sLength
275                         if (_length - (startIndex + length) > 0)
276                                 String.CharCopy (_str, startIndex, _str, startIndex + length, _length - (startIndex + length));
277
278                         _length -= length;
279
280                         return this;
281                 }                              
282
283                 public StringBuilder Replace (char oldChar, char newChar) 
284                 {
285                         return Replace( oldChar, newChar, 0, _length);
286                 }
287
288                 public StringBuilder Replace (char oldChar, char newChar, int startIndex, int count) 
289                 {
290                         // re-ordered to avoid possible integer overflow
291                         if (startIndex > _length - count || startIndex < 0 || count < 0)
292                                 throw new ArgumentOutOfRangeException();
293
294                         if (null != _cached_str)
295                                 InternalEnsureCapacity (_str.Length);
296
297                         for (int replaceIterate = startIndex; replaceIterate < startIndex + count; replaceIterate++ ) {
298                                 if( _str [replaceIterate] == oldChar )
299                                         _str.InternalSetChar (replaceIterate, newChar);
300                         }
301
302                         return this;
303                 }
304
305                 public StringBuilder Replace( string oldValue, string newValue ) {
306                         return Replace (oldValue, newValue, 0, _length);
307                 }
308
309                 public StringBuilder Replace( string oldValue, string newValue, int startIndex, int count ) 
310                 {
311                         if (oldValue == null)
312                                 throw new ArgumentNullException ("The old value cannot be null.");
313
314                         if (startIndex < 0 || count < 0 || startIndex > _length - count)
315                                 throw new ArgumentOutOfRangeException ();
316
317                         if (oldValue.Length == 0)
318                                 throw new ArgumentException ("The old value cannot be zero length.");
319
320                         string substr = _str.Substring(startIndex, count);
321                         string replace = substr.Replace(oldValue, newValue);
322                         // return early if no oldValue was found
323                         if ((object) replace == (object) substr)
324                                 return this;
325
326                         InternalEnsureCapacity (replace.Length + (_length - count));
327
328                         // shift end part
329                         if (replace.Length < count)
330                                 String.CharCopy (_str, startIndex + replace.Length, _str, startIndex + count, _length - startIndex  - count);
331                         else if (replace.Length > count)
332                                 String.CharCopyReverse (_str, startIndex + replace.Length, _str, startIndex + count, _length - startIndex  - count);
333
334                         // copy middle part back into _str
335                         String.CharCopy (_str, startIndex, replace, 0, replace.Length);
336                         
337                         _length = replace.Length + (_length - count);
338
339                         return this;
340                 }
341
342                       
343                 /* The Append Methods */
344                 public StringBuilder Append (char[] value) 
345                 {
346                         if (value == null)
347                                 return this;
348
349                         int needed_cap = _length + value.Length;
350                         if (null != _cached_str || _str.Length < needed_cap)
351                                 InternalEnsureCapacity (needed_cap);
352                         
353                         String.CharCopy (_str, _length, value, 0, value.Length);
354                         _length = needed_cap;
355
356                         return this;
357                 } 
358                 
359                 public StringBuilder Append (string value) 
360                 {
361                         if (value == null)
362                                 return this;
363                         
364                         if (_length == 0 && value.Length < _maxCapacity && value.Length > _str.Length) {
365                                 _length = value.Length;
366                                 _str = _cached_str = value;
367                                 return this;
368                         }
369
370                         int needed_cap = _length + value.Length;
371                         if (null != _cached_str || _str.Length < needed_cap)
372                                 InternalEnsureCapacity (needed_cap);
373
374                         String.CharCopy (_str, _length, value, 0, value.Length);
375                         _length = needed_cap;
376                         return this;
377                 }
378
379                 public StringBuilder Append (bool value) {
380                         return Append (value.ToString());
381                 }
382                 
383                 public StringBuilder Append (byte value) {
384                         return Append (value.ToString());
385                 }
386
387                 public StringBuilder Append (decimal value) {
388                         return Append (value.ToString());
389                 }
390
391                 public StringBuilder Append (double value) {
392                         return Append (value.ToString());
393                 }
394
395                 public StringBuilder Append (short value) {
396                         return Append (value.ToString());
397                 }
398
399                 public StringBuilder Append (int value) {
400                         return Append (value.ToString());
401                 }
402
403                 public StringBuilder Append (long value) {
404                         return Append (value.ToString());
405                 }
406
407                 public StringBuilder Append (object value) {
408                         if (value == null)
409                                 return this;
410
411                         return Append (value.ToString());
412                 }
413
414                 [CLSCompliant(false)]
415                 public StringBuilder Append (sbyte value) {
416                         return Append (value.ToString());
417                 }
418
419                 public StringBuilder Append (float value) {
420                         return Append (value.ToString());
421                 }
422
423                 [CLSCompliant(false)]
424                 public StringBuilder Append (ushort value) {
425                         return Append (value.ToString());
426                 }       
427                 
428                 [CLSCompliant(false)]
429                 public StringBuilder Append (uint value) {
430                         return Append (value.ToString());
431                 }
432
433                 [CLSCompliant(false)]
434                 public StringBuilder Append (ulong value) {
435                         return Append (value.ToString());
436                 }
437
438                 public StringBuilder Append (char value) 
439                 {
440                         int needed_cap = _length + 1;
441                         if (null != _cached_str || _str.Length < needed_cap)
442                                 InternalEnsureCapacity (needed_cap);
443
444                         _str.InternalSetChar(_length, value);
445                         _length = needed_cap;
446
447                         return this;
448                 }
449
450                 public StringBuilder Append (char value, int repeatCount) 
451                 {
452                         if( repeatCount < 0 )
453                                 throw new ArgumentOutOfRangeException();
454
455                         InternalEnsureCapacity (_length + repeatCount);
456                         
457                         for (int i = 0; i < repeatCount; i++)
458                                 _str.InternalSetChar (_length++, value);
459
460                         return this;
461                 }
462
463                 public StringBuilder Append( char[] value, int startIndex, int charCount ) 
464                 {
465                         if (value == null) {
466                                 if (!(startIndex == 0 && charCount == 0))
467                                         throw new ArgumentNullException ("value");
468
469                                 return this;
470                         }
471
472                         if ((charCount < 0 || startIndex < 0) || (startIndex > value.Length - charCount)) 
473                                 throw new ArgumentOutOfRangeException();
474                         
475                         int needed_cap = _length + charCount;
476                         InternalEnsureCapacity (needed_cap);
477
478                         String.CharCopy (_str, _length, value, startIndex, charCount);
479                         _length = needed_cap;
480
481                         return this;
482                 }
483
484                 public StringBuilder Append (string value, int startIndex, int count) 
485                 {
486                         if (value == null) {
487                                 if (startIndex != 0 && count != 0)
488                                         throw new ArgumentNullException ("value");
489                                         
490                                 return this;
491                         }
492
493                         if ((count < 0 || startIndex < 0) || (startIndex > value.Length - count))
494                                 throw new ArgumentOutOfRangeException();
495                         
496                         int needed_cap = _length + count;
497                         if (null != _cached_str || _str.Length < needed_cap)
498                                 InternalEnsureCapacity (needed_cap);
499
500                         String.CharCopy (_str, _length, value, startIndex, count);
501                         
502                         _length = needed_cap;
503
504                         return this;
505                 }
506
507 #if NET_4_0 || MOONLIGHT || MOBILE
508                 public StringBuilder Clear ()
509                 {
510                         Length = 0;
511                         return this;
512                 }
513 #endif
514
515                 [ComVisible (false)]
516                 public StringBuilder AppendLine ()
517                 {
518                         return Append (System.Environment.NewLine);
519                 }
520
521                 [ComVisible (false)]
522                 public StringBuilder AppendLine (string value)
523                 {
524                         return Append (value).Append (System.Environment.NewLine);
525                 }
526
527                 public StringBuilder AppendFormat (string format, params object[] args)
528                 {
529                         return AppendFormat (null, format, args);
530                 }
531
532                 public StringBuilder AppendFormat (IFormatProvider provider,
533                                                    string format,
534                                                    params object[] args)
535                 {
536                         String.FormatHelper (this, provider, format, args);
537                         return this;
538                 }
539
540 #if MOONLIGHT
541                 internal
542 #else
543                 public
544 #endif
545                 StringBuilder AppendFormat (string format, object arg0)
546                 {
547                         return AppendFormat (null, format, new object [] { arg0 });
548                 }
549
550 #if MOONLIGHT
551                 internal
552 #else
553                 public
554 #endif
555                 StringBuilder AppendFormat (string format, object arg0, object arg1)
556                 {
557                         return AppendFormat (null, format, new object [] { arg0, arg1 });
558                 }
559
560 #if MOONLIGHT
561                 internal
562 #else
563                 public
564 #endif
565                 StringBuilder AppendFormat (string format, object arg0, object arg1, object arg2)
566                 {
567                         return AppendFormat (null, format, new object [] { arg0, arg1, arg2 });
568                 }
569
570                 /*  The Insert Functions */
571                 
572                 public StringBuilder Insert (int index, char[] value) 
573                 {
574                         return Insert (index, new string (value));
575                 }
576                                 
577                 public StringBuilder Insert (int index, string value) 
578                 {
579                         if( index > _length || index < 0)
580                                 throw new ArgumentOutOfRangeException();
581
582                         if (value == null || value.Length == 0)
583                                 return this;
584
585                         InternalEnsureCapacity (_length + value.Length);
586
587                         // Move everything to the right of the insert point across
588                         String.CharCopyReverse (_str, index + value.Length, _str, index, _length - index);
589                         
590                         // Copy in stuff from the insert buffer
591                         String.CharCopy (_str, index, value, 0, value.Length);
592                         
593                         _length += value.Length;
594
595                         return this;
596                 }
597
598                 public StringBuilder Insert( int index, bool value ) {
599                         return Insert (index, value.ToString());
600                 }
601                 
602                 public StringBuilder Insert( int index, byte value ) {
603                         return Insert (index, value.ToString());
604                 }
605
606                 public StringBuilder Insert( int index, char value) 
607                 {
608                         if (index > _length || index < 0)
609                                 throw new ArgumentOutOfRangeException ("index");
610
611                         InternalEnsureCapacity (_length + 1);
612                         
613                         // Move everything to the right of the insert point across
614                         String.CharCopyReverse (_str, index + 1, _str, index, _length - index);
615                         
616                         _str.InternalSetChar (index, value);
617                         _length++;
618
619                         return this;
620                 }
621
622                 public StringBuilder Insert( int index, decimal value ) {
623                         return Insert (index, value.ToString());
624                 }
625
626                 public StringBuilder Insert( int index, double value ) {
627                         return Insert (index, value.ToString());
628                 }
629                 
630                 public StringBuilder Insert( int index, short value ) {
631                         return Insert (index, value.ToString());
632                 }
633
634                 public StringBuilder Insert( int index, int value ) {
635                         return Insert (index, value.ToString());
636                 }
637
638                 public StringBuilder Insert( int index, long value ) {
639                         return Insert (index, value.ToString());
640                 }
641         
642                 public StringBuilder Insert( int index, object value ) {
643                         return Insert (index, value.ToString());
644                 }
645                 
646                 [CLSCompliant(false)]
647                 public StringBuilder Insert( int index, sbyte value ) {
648                         return Insert (index, value.ToString() );
649                 }
650
651                 public StringBuilder Insert (int index, float value) {
652                         return Insert (index, value.ToString() );
653                 }
654
655                 [CLSCompliant(false)]
656                 public StringBuilder Insert (int index, ushort value) {
657                         return Insert (index, value.ToString() );
658                 }
659
660                 [CLSCompliant(false)]
661                 public StringBuilder Insert (int index, uint value) {
662                         return Insert ( index, value.ToString() );
663                 }
664                 
665                 [CLSCompliant(false)]
666                 public StringBuilder Insert (int index, ulong value) {
667                         return Insert ( index, value.ToString() );
668                 }
669
670                 public StringBuilder Insert (int index, string value, int count) 
671                 {
672                         // LAMESPEC: The spec says to throw an exception if 
673                         // count < 0, while MS throws even for count < 1!
674                         if ( count < 0 )
675                                 throw new ArgumentOutOfRangeException();
676
677                         if (value != null && value != String.Empty)
678                                 for (int insertCount = 0; insertCount < count; insertCount++)
679                                         Insert( index, value );
680
681                         return this;
682                 }
683
684                 public StringBuilder Insert (int index, char [] value, int startIndex, int charCount)
685                 {
686                         if (value == null) {
687                                 if (startIndex == 0 && charCount == 0)
688                                         return this;
689
690                                 throw new ArgumentNullException ("value");
691                         }
692
693                         if (charCount < 0 || startIndex < 0 || startIndex > value.Length - charCount)
694                                 throw new ArgumentOutOfRangeException ();
695
696                         return Insert (index, new String (value, startIndex, charCount));
697                 }
698         
699                 private void InternalEnsureCapacity (int size) 
700                 {
701                         if (size > _str.Length || (object) _cached_str == (object) _str) {
702                                 int capacity = _str.Length;
703
704                                 // Try double buffer, if that doesn't work, set the length as capacity
705                                 if (size > capacity) {
706                                         
707                                         // The first time a string is appended, we just set _cached_str
708                                         // and _str to it. This allows us to do some optimizations.
709                                         // Below, we take this into account.
710                                         if ((object) _cached_str == (object) _str && capacity < constDefaultCapacity)
711                                                 capacity = constDefaultCapacity;
712                                         
713                                         capacity = capacity << 1;
714                                         if (size > capacity)
715                                                 capacity = size;
716
717                                         if (capacity >= Int32.MaxValue || capacity < 0)
718                                                 capacity = Int32.MaxValue;
719
720                                         if (capacity > _maxCapacity && size <= _maxCapacity)
721                                                 capacity = _maxCapacity;
722                                         
723                                         if (capacity > _maxCapacity)
724                                                 throw new ArgumentOutOfRangeException ("size", "capacity was less than the current size.");
725                                 }
726
727                                 string tmp = String.InternalAllocateStr (capacity);
728                                 if (_length > 0)
729                                         String.CharCopy (tmp, 0, _str, 0, _length);
730
731                                 _str = tmp;
732                         }
733
734                         _cached_str = null;
735                 }
736
737                 [ComVisible (false)]
738                 public void CopyTo (int sourceIndex, char [] destination, int destinationIndex, int count)
739                 {
740                         if (destination == null)
741                                 throw new ArgumentNullException ("destination");
742                         if ((Length - count < sourceIndex) ||
743                             (destination.Length -count < destinationIndex) ||
744                             (sourceIndex < 0 || destinationIndex < 0 || count < 0))
745                                 throw new ArgumentOutOfRangeException ();
746
747                         for (int i = 0; i < count; i++)
748                                 destination [destinationIndex+i] = _str [sourceIndex+i];
749                 }
750
751                 void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context)
752                 {
753                         info.AddValue ("m_MaxCapacity", _maxCapacity);
754                         info.AddValue ("Capacity", Capacity);
755                         info.AddValue ("m_StringValue", ToString ());
756                         info.AddValue ("m_currentThread", 0);
757                 }
758
759                 StringBuilder (SerializationInfo info, StreamingContext context)
760                 {
761                         string s = info.GetString ("m_StringValue");
762                         if (s == null)
763                                 s = "";
764                         _length = s.Length;
765                         _str = _cached_str = s;
766                         
767                         _maxCapacity = info.GetInt32 ("m_MaxCapacity");
768                         if (_maxCapacity < 0)
769                                 _maxCapacity = Int32.MaxValue;
770                         Capacity = info.GetInt32 ("Capacity");
771                 }
772         }
773 }