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