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