Merge pull request #1631 from alexanderkyte/stringbuilder-referencesource
authorRodrigo Kumpera <kumpera@gmail.com>
Mon, 23 Mar 2015 21:18:59 +0000 (17:18 -0400)
committerRodrigo Kumpera <kumpera@gmail.com>
Mon, 23 Mar 2015 21:18:59 +0000 (17:18 -0400)
Switch to using referencesource StringBuilder, with runtime fixes and tests

mcs/class/corlib/System.Text/StringBuilder.cs [deleted file]
mcs/class/corlib/System/String.cs
mcs/class/corlib/corlib.dll.sources
mono/metadata/marshal.c
mono/metadata/marshal.h
mono/metadata/object-internals.h
mono/metadata/remoting.c
mono/tests/cross-domain.cs
mono/tests/libtest.c
mono/tests/pinvoke2.cs

diff --git a/mcs/class/corlib/System.Text/StringBuilder.cs b/mcs/class/corlib/System.Text/StringBuilder.cs
deleted file mode 100644 (file)
index 629f52c..0000000
+++ /dev/null
@@ -1,773 +0,0 @@
-// -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
-//
-// System.Text.StringBuilder
-//
-// Authors: 
-//   Marcin Szczepanski (marcins@zipworld.com.au)
-//   Paolo Molaro (lupus@ximian.com)
-//   Patrik Torstensson
-//
-// NOTE: In the case the buffer is only filled by 50% a new string
-//       will be returned by ToString() is cached in the '_cached_str'
-//              cache_string will also control if a string has been handed out
-//              to via ToString(). If you are chaning the code make sure that
-//              if you modify the string data set the cache_string to null.
-//
-
-//
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
-// Copyright 2011 Xamarin Inc
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-// 
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-// 
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-using System.Runtime.Serialization;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-namespace System.Text {
-       
-       [Serializable]
-       [ComVisible (true)]
-        [MonoLimitation ("Serialization format not compatible with .NET")]
-       [StructLayout (LayoutKind.Sequential)]
-       public sealed class StringBuilder : ISerializable
-       {
-               private int _length;
-               private string _str;
-               private string _cached_str;
-               
-               private int _maxCapacity;
-               internal const int DefaultCapacity = 16;
-
-               public StringBuilder(string value, int startIndex, int length, int capacity) 
-                       : this (value, startIndex, length, capacity, Int32.MaxValue)
-               {
-               }
-
-               private StringBuilder(string value, int startIndex, int length, int capacity, int maxCapacity)
-               {
-                       // first, check the parameters and throw appropriate exceptions if needed
-                       if (null == value)
-                               value = "";
-
-                       // make sure startIndex is zero or positive
-                       if (startIndex < 0)
-                               throw new System.ArgumentOutOfRangeException ("startIndex", startIndex, "StartIndex cannot be less than zero.");
-
-                       // make sure length is zero or positive
-                       if(length < 0)
-                               throw new System.ArgumentOutOfRangeException ("length", length, "Length cannot be less than zero.");
-
-                       if (capacity < 0)
-                               throw new System.ArgumentOutOfRangeException ("capacity", capacity, "capacity must be greater than zero.");
-
-                       if (maxCapacity < 1)
-                               throw new System.ArgumentOutOfRangeException ("maxCapacity", "maxCapacity is less than one.");
-                       if (capacity > maxCapacity)
-                               throw new System.ArgumentOutOfRangeException ("capacity", "Capacity exceeds maximum capacity.");
-
-                       // make sure startIndex and length give a valid substring of value
-                       // re-ordered to avoid possible integer overflow
-                       if (startIndex > value.Length - length)
-                               throw new System.ArgumentOutOfRangeException ("startIndex", startIndex, "StartIndex and length must refer to a location within the string.");
-
-                       if (capacity == 0) {
-                               if (maxCapacity > DefaultCapacity)
-                                       capacity = DefaultCapacity;
-                               else
-                                       _str = _cached_str = String.Empty;
-                       }
-                       _maxCapacity = maxCapacity;
-
-                       if (_str == null)
-                               _str = String.InternalAllocateStr ((length > capacity) ? length : capacity);
-                       if (length > 0)
-                               String.CharCopy (_str, 0, value, startIndex, length);
-                       
-                       _length = length;
-               }
-
-               public StringBuilder () : this (null) {}
-
-               public StringBuilder(int capacity) : this (String.Empty, 0, 0, capacity) {}
-
-               public StringBuilder(int capacity, int maxCapacity) : this (String.Empty, 0, 0, capacity, maxCapacity) { }
-
-               public StringBuilder (string value)
-               {
-                       /*
-                        * This is an optimization to avoid allocating the internal string
-                        * until the first Append () call.
-                        * The runtime pinvoke marshalling code needs to be aware of this.
-                        */
-                       if (null == value)
-                               value = "";
-                       
-                       _length = value.Length;
-                       _str = _cached_str = value;
-                       _maxCapacity = Int32.MaxValue;
-               }
-       
-               public StringBuilder( string value, int capacity) : this(value == null ? "" : value, 0, value == null ? 0 : value.Length, capacity) {}
-       
-               public int MaxCapacity {
-                       get {
-                               return _maxCapacity;
-                       }
-               }
-
-               public int Capacity {
-                       get {
-                               if (_str.Length == 0)
-                                       return Math.Min (_maxCapacity, DefaultCapacity);
-                               
-                               return _str.Length;
-                       }
-
-                       set {
-                               if (value < _length)
-                                       throw new ArgumentException( "Capacity must be larger than length" );
-
-                               if (value > _maxCapacity)
-                                       throw new ArgumentOutOfRangeException ("value", "Should be less than or equal to MaxCapacity");
-
-                               InternalEnsureCapacity(value);
-                       }
-               }
-
-               public int Length {
-                       get {
-                               return _length;
-                       }
-
-                       set {
-                               if( value < 0 || value > _maxCapacity)
-                                       throw new ArgumentOutOfRangeException();
-
-                               if (value == _length)
-                                       return;
-
-                               if (value < _length) {
-                                       // LAMESPEC:  The spec is unclear as to what to do
-                                       // with the capacity when truncating the string.
-
-                                       // Do as MS, keep the capacity
-                                       
-                                       // Make sure that we invalidate any cached string.
-                                       InternalEnsureCapacity (value);
-                                       _length = value;
-                               } else {
-                                       // Expand the capacity to the new length and
-                                       // pad the string with NULL characters.
-                                       Append('\0', value - _length);
-                               }
-                       }
-               }
-
-               [IndexerName("Chars")]
-               public char this [int index] {
-                       get {
-                               if (index >= _length || index < 0)
-                                       throw new IndexOutOfRangeException();
-
-                               return _str [index];
-                       } 
-
-                       set {
-                               if (index >= _length || index < 0)
-                                       throw new IndexOutOfRangeException();
-
-                               if (null != _cached_str)
-                                       InternalEnsureCapacity (_length);
-                               
-                               _str.InternalSetChar (index, value);
-                       }
-               }
-
-               public override string ToString () 
-               {
-                       if (_length == 0)
-                               return String.Empty;
-
-                       if (null != _cached_str)
-                               return _cached_str;
-
-                       // If we only have a half-full buffer we return a new string.
-                       if (_length < (_str.Length >> 1) || (_str.Length > string.LOS_limit && _length <= string.LOS_limit))
-                       {
-                               // use String.SubstringUnchecked instead of String.Substring
-                               // as the former is guaranteed to create a new string object
-                               _cached_str = _str.SubstringUnchecked (0, _length);
-                               return _cached_str;
-                       }
-
-                       _cached_str = _str;
-                       _str.InternalSetLength(_length);
-
-                       return _str;
-               }
-
-               public string ToString (int startIndex, int length) 
-               {
-                       // re-ordered to avoid possible integer overflow
-                       if (startIndex < 0 || length < 0 || startIndex > _length - length)
-                               throw new ArgumentOutOfRangeException();
-
-                       // use String.SubstringUnchecked instead of String.Substring
-                       // as the former is guaranteed to create a new string object
-                       if (startIndex == 0 && length == _length)
-                               return ToString ();
-                       else
-                               return _str.SubstringUnchecked (startIndex, length);
-               }
-
-               public int EnsureCapacity (int capacity) 
-               {
-                       if (capacity < 0)
-                               throw new ArgumentOutOfRangeException ("Capacity must be greater than 0." );
-
-                       if( capacity <= _str.Length )
-                               return _str.Length;
-
-                       InternalEnsureCapacity (capacity);
-
-                       return _str.Length;
-               }
-
-               public bool Equals (StringBuilder sb) 
-               {
-                       if (((object)sb) == null)
-                               return false;
-                       
-                       if (_length == sb.Length && _str == sb._str )
-                               return true;
-
-                       return false;
-               }
-
-               public StringBuilder Remove (int startIndex, int length)
-               {
-                       // re-ordered to avoid possible integer overflow
-                       if (startIndex < 0 || length < 0 || startIndex > _length - length)
-                               throw new ArgumentOutOfRangeException();
-                       
-                       if (null != _cached_str)
-                               InternalEnsureCapacity (_length);
-                       
-                       // Copy everything after the 'removed' part to the start 
-                       // of the removed part and truncate the sLength
-                       if (_length - (startIndex + length) > 0)
-                               String.CharCopy (_str, startIndex, _str, startIndex + length, _length - (startIndex + length));
-
-                       _length -= length;
-
-                       return this;
-               }                              
-
-               public StringBuilder Replace (char oldChar, char newChar) 
-               {
-                       return Replace( oldChar, newChar, 0, _length);
-               }
-
-               public StringBuilder Replace (char oldChar, char newChar, int startIndex, int count) 
-               {
-                       // re-ordered to avoid possible integer overflow
-                       if (startIndex > _length - count || startIndex < 0 || count < 0)
-                               throw new ArgumentOutOfRangeException();
-
-                       if (null != _cached_str)
-                               InternalEnsureCapacity (_str.Length);
-
-                       for (int replaceIterate = startIndex; replaceIterate < startIndex + count; replaceIterate++ ) {
-                               if( _str [replaceIterate] == oldChar )
-                                       _str.InternalSetChar (replaceIterate, newChar);
-                       }
-
-                       return this;
-               }
-
-               public StringBuilder Replace( string oldValue, string newValue ) {
-                       return Replace (oldValue, newValue, 0, _length);
-               }
-
-               public StringBuilder Replace( string oldValue, string newValue, int startIndex, int count ) 
-               {
-                       if (oldValue == null)
-                               throw new ArgumentNullException ("The old value cannot be null.");
-
-                       if (startIndex < 0 || count < 0 || startIndex > _length - count)
-                               throw new ArgumentOutOfRangeException ();
-
-                       if (oldValue.Length == 0)
-                               throw new ArgumentException ("The old value cannot be zero length.");
-
-                       string substr = _str.Substring(startIndex, count);
-                       string replace = substr.Replace(oldValue, newValue);
-                       // return early if no oldValue was found
-                       if ((object) replace == (object) substr)
-                               return this;
-
-                       InternalEnsureCapacity (replace.Length + (_length - count));
-
-                       // shift end part
-                       if (replace.Length < count)
-                               String.CharCopy (_str, startIndex + replace.Length, _str, startIndex + count, _length - startIndex  - count);
-                       else if (replace.Length > count)
-                               String.CharCopyReverse (_str, startIndex + replace.Length, _str, startIndex + count, _length - startIndex  - count);
-
-                       // copy middle part back into _str
-                       String.CharCopy (_str, startIndex, replace, 0, replace.Length);
-                       
-                       _length = replace.Length + (_length - count);
-
-                       return this;
-               }
-
-                     
-               /* The Append Methods */
-               public StringBuilder Append (char[] value) 
-               {
-                       if (value == null)
-                               return this;
-
-                       int needed_cap = _length + value.Length;
-                       if (null != _cached_str || _str.Length < needed_cap)
-                               InternalEnsureCapacity (needed_cap);
-                       
-                       String.CharCopy (_str, _length, value, 0, value.Length);
-                       _length = needed_cap;
-
-                       return this;
-               } 
-               
-               public StringBuilder Append (string value) 
-               {
-                       if (value == null)
-                               return this;
-                       
-                       if (_length == 0 && value.Length < _maxCapacity && value.Length > _str.Length) {
-                               _length = value.Length;
-                               _str = _cached_str = value;
-                               return this;
-                       }
-
-                       int needed_cap = _length + value.Length;
-                       if (null != _cached_str || _str.Length < needed_cap)
-                               InternalEnsureCapacity (needed_cap);
-
-                       String.CharCopy (_str, _length, value, 0, value.Length);
-                       _length = needed_cap;
-                       return this;
-               }
-
-               public StringBuilder Append (bool value) {
-                       return Append (value.ToString());
-               }
-               
-               public StringBuilder Append (byte value) {
-                       return Append (value.ToString());
-               }
-
-               public StringBuilder Append (decimal value) {
-                       return Append (value.ToString());
-               }
-
-               public StringBuilder Append (double value) {
-                       return Append (value.ToString());
-               }
-
-               public StringBuilder Append (short value) {
-                       return Append (value.ToString());
-               }
-
-               public StringBuilder Append (int value) {
-                       return Append (value.ToString());
-               }
-
-               public StringBuilder Append (long value) {
-                       return Append (value.ToString());
-               }
-
-               public StringBuilder Append (object value) {
-                       if (value == null)
-                               return this;
-
-                       return Append (value.ToString());
-               }
-
-               [CLSCompliant(false)]
-               public StringBuilder Append (sbyte value) {
-                       return Append (value.ToString());
-               }
-
-               public StringBuilder Append (float value) {
-                       return Append (value.ToString());
-               }
-
-               [CLSCompliant(false)]
-               public StringBuilder Append (ushort value) {
-                       return Append (value.ToString());
-               }       
-               
-               [CLSCompliant(false)]
-               public StringBuilder Append (uint value) {
-                       return Append (value.ToString());
-               }
-
-               [CLSCompliant(false)]
-               public StringBuilder Append (ulong value) {
-                       return Append (value.ToString());
-               }
-
-               public StringBuilder Append (char value) 
-               {
-                       int needed_cap = _length + 1;
-                       if (null != _cached_str || _str.Length < needed_cap)
-                               InternalEnsureCapacity (needed_cap);
-
-                       _str.InternalSetChar(_length, value);
-                       _length = needed_cap;
-
-                       return this;
-               }
-
-               public StringBuilder Append (char value, int repeatCount) 
-               {
-                       if( repeatCount < 0 )
-                               throw new ArgumentOutOfRangeException();
-
-                       InternalEnsureCapacity (_length + repeatCount);
-                       
-                       for (int i = 0; i < repeatCount; i++)
-                               _str.InternalSetChar (_length++, value);
-
-                       return this;
-               }
-
-               public StringBuilder Append( char[] value, int startIndex, int charCount ) 
-               {
-                       if (value == null) {
-                               if (!(startIndex == 0 && charCount == 0))
-                                       throw new ArgumentNullException ("value");
-
-                               return this;
-                       }
-
-                       if ((charCount < 0 || startIndex < 0) || (startIndex > value.Length - charCount)) 
-                               throw new ArgumentOutOfRangeException();
-                       
-                       int needed_cap = _length + charCount;
-                       InternalEnsureCapacity (needed_cap);
-
-                       String.CharCopy (_str, _length, value, startIndex, charCount);
-                       _length = needed_cap;
-
-                       return this;
-               }
-
-               public StringBuilder Append (string value, int startIndex, int count) 
-               {
-                       if (value == null) {
-                               if (startIndex != 0 && count != 0)
-                                       throw new ArgumentNullException ("value");
-                                       
-                               return this;
-                       }
-
-                       if ((count < 0 || startIndex < 0) || (startIndex > value.Length - count))
-                               throw new ArgumentOutOfRangeException();
-                       
-                       int needed_cap = _length + count;
-                       if (null != _cached_str || _str.Length < needed_cap)
-                               InternalEnsureCapacity (needed_cap);
-
-                       String.CharCopy (_str, _length, value, startIndex, count);
-                       
-                       _length = needed_cap;
-
-                       return this;
-               }
-
-               internal unsafe StringBuilder Append (char* value, int valueCount)
-               {
-                       int needed_cap = _length + valueCount;
-                       InternalEnsureCapacity (needed_cap);
-
-                       fixed (char* src = _str) {
-                               String.CharCopy (src + _length, value, valueCount);
-                       }
-                       _length = needed_cap;
-
-                       return this;
-               }
-
-               public StringBuilder Clear ()
-               {
-                       Length = 0;
-                       return this;
-               }
-
-               [ComVisible (false)]
-               public StringBuilder AppendLine ()
-               {
-                       return Append (System.Environment.NewLine);
-               }
-
-               [ComVisible (false)]
-               public StringBuilder AppendLine (string value)
-               {
-                       return Append (value).Append (System.Environment.NewLine);
-               }
-
-               public StringBuilder AppendFormat (string format, params object[] args)
-               {
-                       return AppendFormat (null, format, args);
-               }
-
-               public StringBuilder AppendFormat (IFormatProvider provider,
-                                                  string format,
-                                                  params object[] args)
-               {
-                       String.FormatHelper (this, provider, format, args);
-                       return this;
-               }
-
-               public
-               StringBuilder AppendFormat (string format, object arg0)
-               {
-                       return AppendFormat (null, format, new object [] { arg0 });
-               }
-
-               public
-               StringBuilder AppendFormat (string format, object arg0, object arg1)
-               {
-                       return AppendFormat (null, format, new object [] { arg0, arg1 });
-               }
-
-               public
-               StringBuilder AppendFormat (string format, object arg0, object arg1, object arg2)
-               {
-                       return AppendFormat (null, format, new object [] { arg0, arg1, arg2 });
-               }
-
-               /*  The Insert Functions */
-               
-               public StringBuilder Insert (int index, char[] value) 
-               {
-                       return Insert (index, new string (value));
-               }
-                               
-               public StringBuilder Insert (int index, string value) 
-               {
-                       if( index > _length || index < 0)
-                               throw new ArgumentOutOfRangeException();
-
-                       if (value == null || value.Length == 0)
-                               return this;
-
-                       InternalEnsureCapacity (_length + value.Length);
-
-                       // Move everything to the right of the insert point across
-                       String.CharCopyReverse (_str, index + value.Length, _str, index, _length - index);
-                       
-                       // Copy in stuff from the insert buffer
-                       String.CharCopy (_str, index, value, 0, value.Length);
-                       
-                       _length += value.Length;
-
-                       return this;
-               }
-
-               public StringBuilder Insert( int index, bool value ) {
-                       return Insert (index, value.ToString());
-               }
-               
-               public StringBuilder Insert( int index, byte value ) {
-                       return Insert (index, value.ToString());
-               }
-
-               public StringBuilder Insert( int index, char value) 
-               {
-                       if (index > _length || index < 0)
-                               throw new ArgumentOutOfRangeException ("index");
-
-                       InternalEnsureCapacity (_length + 1);
-                       
-                       // Move everything to the right of the insert point across
-                       String.CharCopyReverse (_str, index + 1, _str, index, _length - index);
-                       
-                       _str.InternalSetChar (index, value);
-                       _length++;
-
-                       return this;
-               }
-
-               public StringBuilder Insert( int index, decimal value ) {
-                       return Insert (index, value.ToString());
-               }
-
-               public StringBuilder Insert( int index, double value ) {
-                       return Insert (index, value.ToString());
-               }
-               
-               public StringBuilder Insert( int index, short value ) {
-                       return Insert (index, value.ToString());
-               }
-
-               public StringBuilder Insert( int index, int value ) {
-                       return Insert (index, value.ToString());
-               }
-
-               public StringBuilder Insert( int index, long value ) {
-                       return Insert (index, value.ToString());
-               }
-       
-               public StringBuilder Insert( int index, object value ) {
-                       return Insert (index, value.ToString());
-               }
-               
-               [CLSCompliant(false)]
-               public StringBuilder Insert( int index, sbyte value ) {
-                       return Insert (index, value.ToString() );
-               }
-
-               public StringBuilder Insert (int index, float value) {
-                       return Insert (index, value.ToString() );
-               }
-
-               [CLSCompliant(false)]
-               public StringBuilder Insert (int index, ushort value) {
-                       return Insert (index, value.ToString() );
-               }
-
-               [CLSCompliant(false)]
-               public StringBuilder Insert (int index, uint value) {
-                       return Insert ( index, value.ToString() );
-               }
-               
-               [CLSCompliant(false)]
-               public StringBuilder Insert (int index, ulong value) {
-                       return Insert ( index, value.ToString() );
-               }
-
-               public StringBuilder Insert (int index, string value, int count) 
-               {
-                       // LAMESPEC: The spec says to throw an exception if 
-                       // count < 0, while MS throws even for count < 1!
-                       if ( count < 0 )
-                               throw new ArgumentOutOfRangeException();
-
-                       if (value != null && value != String.Empty)
-                               for (int insertCount = 0; insertCount < count; insertCount++)
-                                       Insert( index, value );
-
-                       return this;
-               }
-
-               public StringBuilder Insert (int index, char [] value, int startIndex, int charCount)
-               {
-                       if (value == null) {
-                               if (startIndex == 0 && charCount == 0)
-                                       return this;
-
-                               throw new ArgumentNullException ("value");
-                       }
-
-                       if (charCount < 0 || startIndex < 0 || startIndex > value.Length - charCount)
-                               throw new ArgumentOutOfRangeException ();
-
-                       return Insert (index, new String (value, startIndex, charCount));
-               }
-       
-               private void InternalEnsureCapacity (int size) 
-               {
-                       if (size > _str.Length || (object) _cached_str == (object) _str) {
-                               int capacity = _str.Length;
-
-                               // Try double buffer, if that doesn't work, set the length as capacity
-                               if (size > capacity) {
-                                       
-                                       // The first time a string is appended, we just set _cached_str
-                                       // and _str to it. This allows us to do some optimizations.
-                                       // Below, we take this into account.
-                                       if ((object) _cached_str == (object) _str && capacity < DefaultCapacity)
-                                               capacity = DefaultCapacity;
-                                       
-                                       capacity = capacity << 1;
-                                       if (size > capacity)
-                                               capacity = size;
-
-                                       if (capacity >= Int32.MaxValue || capacity < 0)
-                                               capacity = Int32.MaxValue;
-
-                                       if (capacity > _maxCapacity && size <= _maxCapacity)
-                                               capacity = _maxCapacity;
-                                       
-                                       if (capacity > _maxCapacity)
-                                               throw new ArgumentOutOfRangeException ("size", "capacity was less than the current size.");
-                               }
-
-                               string tmp = String.InternalAllocateStr (capacity);
-                               if (_length > 0)
-                                       String.CharCopy (tmp, 0, _str, 0, _length);
-
-                               _str = tmp;
-                       }
-
-                       _cached_str = null;
-               }
-
-               [ComVisible (false)]
-               public void CopyTo (int sourceIndex, char [] destination, int destinationIndex, int count)
-               {
-                       if (destination == null)
-                               throw new ArgumentNullException ("destination");
-                       if ((Length - count < sourceIndex) ||
-                           (destination.Length -count < destinationIndex) ||
-                           (sourceIndex < 0 || destinationIndex < 0 || count < 0))
-                               throw new ArgumentOutOfRangeException ();
-
-                       for (int i = 0; i < count; i++)
-                               destination [destinationIndex+i] = _str [sourceIndex+i];
-               }
-
-               void ISerializable.GetObjectData (SerializationInfo info, StreamingContext context)
-               {
-                       info.AddValue ("m_MaxCapacity", _maxCapacity);
-                       info.AddValue ("Capacity", Capacity);
-                       info.AddValue ("m_StringValue", ToString ());
-                       info.AddValue ("m_currentThread", 0);
-               }
-
-               StringBuilder (SerializationInfo info, StreamingContext context)
-               {
-                       string s = info.GetString ("m_StringValue");
-                       if (s == null)
-                               s = "";
-                       _length = s.Length;
-                       _str = _cached_str = s;
-                       
-                       _maxCapacity = info.GetInt32 ("m_MaxCapacity");
-                       if (_maxCapacity < 0)
-                               _maxCapacity = Int32.MaxValue;
-                       Capacity = info.GetInt32 ("Capacity");
-               }
-       }
-}       
index fcef4169705e4ffa0a64bf24a6b516780e70b0f6..ca183385132f872af210c1d7c521b292c80d9680 100644 (file)
@@ -3153,6 +3153,11 @@ namespace System
                        memcpy4 ((byte*)dest, (byte*)src, count * 2);
                }
 
+               internal static unsafe void wstrcpy (char *dmem, char *smem, int charCount)
+               {
+                       CharCopy (dmem, smem, charCount);
+               }
+
                internal static unsafe void CharCopyReverse (char *dest, char *src, int count)
                {
                        dest += count;
index bdd3e4b7069c2ca030671ebaf77a311baf72d814..a10e3300d6f904f4001fcb93fd11af168e18e920 100644 (file)
@@ -1200,7 +1200,6 @@ System.Security.Principal/WindowsImpersonationContext.cs
 System.Security.Principal/WindowsPrincipal.cs
 System.Text/EncodingHelper.cs
 System.Text/NormalizationForm.cs
-System.Text/StringBuilder.cs
 System.Text/Latin1Encoding.cs
 System.Threading/AsyncFlowControl.cs
 System.Threading/CompressedStack.cs
@@ -1577,6 +1576,7 @@ ReferenceSources/RuntimeHandles.cs
 ../../../external/referencesource/mscorlib/system/text/utf7encoding.cs
 ../../../external/referencesource/mscorlib/system/text/utf8encoding.cs
 
+../../../external/referencesource/mscorlib/system/text/stringbuilder.cs
 ../../../external/referencesource/mscorlib/system/text/stringbuildercache.cs
 
 ../../../external/referencesource/mscorlib/system/runtime/serialization/deserializationeventhandler.cs
index 902d2cfab12abf4a836ed8a110ca91572b6ac709..db333b21334d7b869291f04e5b7ec76f6f5feef3 100644 (file)
@@ -694,49 +694,13 @@ mono_array_to_byte_byvalarray (gpointer native_arr, MonoArray *arr, guint32 elnu
        mono_array_to_byvalarray (native_arr, arr, mono_defaults.byte_class, elnum);
 }
 
-void
-mono_string_utf8_to_builder (MonoStringBuilder *sb, char *text)
-{
-       GError *error = NULL;
-       guint16 *ut;
-       glong items_written;
-       int l;
-
-       if (!sb || !text)
-               return;
-
-       l = strlen (text);
-
-       ut = g_utf8_to_utf16 (text, l, NULL, &items_written, &error);
-       
-       if (items_written > mono_stringbuilder_capacity (sb))
-               items_written = mono_stringbuilder_capacity (sb);
-       
-       if (!error) {
-               if (! sb->str || sb->str == sb->cached_str)
-                       MONO_OBJECT_SETREF (sb, str, mono_string_new_size (mono_domain_get (), items_written));
-               
-               memcpy (mono_string_chars (sb->str), ut, items_written * 2);
-               sb->length = items_written;
-               sb->cached_str = NULL;
-       } else 
-               g_error_free (error);
-
-       g_free (ut);
-}
-
-MonoStringBuilder *
-mono_string_utf8_to_builder2 (char *text)
+static MonoStringBuilder *
+mono_string_builder_new (void)
 {
-       int l;
-       MonoStringBuilder *sb;
        static MonoClass *string_builder_class;
        static MonoMethod *sb_ctor;
-       void *args [1];
-       MonoObject *exc;
-
-       if (!text)
-               return NULL;
+       static void *args [1];
+       static int initial_len;
 
        if (!string_builder_class) {
                MonoMethodDesc *desc;
@@ -747,78 +711,99 @@ mono_string_utf8_to_builder2 (char *text)
                sb_ctor = mono_method_desc_search_in_class (desc, string_builder_class);
                g_assert (sb_ctor);
                mono_method_desc_free (desc);
-       }
 
-       l = strlen (text);
+               // We make a new array in the _to_builder function, so this
+               // array will always be garbage collected.
+               initial_len = 1;
+               args [0] = &initial_len;
+       }
 
-       sb = (MonoStringBuilder*)mono_object_new (mono_domain_get (), string_builder_class);
+       MonoStringBuilder *sb = (MonoStringBuilder*)mono_object_new (mono_domain_get (), string_builder_class);
+       MonoObject *exc;
        g_assert (sb);
-       args [0] = &l;
+
        mono_runtime_invoke (sb_ctor, sb, args, &exc);
+
+       g_assert (sb->chunkChars->max_length == initial_len);
        g_assert (!exc);
 
-       mono_string_utf8_to_builder (sb, text);
+       return sb;
+}
+
+static void
+mono_string_utf16_to_builder_copy (MonoStringBuilder *sb, gunichar2 *text, size_t len)
+{
+       MonoClass *ac = mono_array_class_get (mono_defaults.char_class, 1);
+       g_assert (ac);
+
+       MonoArray* newArray = mono_array_new (mono_domain_get (), mono_defaults.char_class, len);
+
+       gunichar2 *charDst = (gunichar2 *)newArray->vector;
+       gunichar2 *charSrc = (gunichar2 *)text;
+       memcpy (charDst, charSrc, sizeof (gunichar2) * len);
+
+       MONO_OBJECT_SETREF (sb, chunkChars, newArray);
+       sb->chunkOffset = 0;
+       sb->chunkLength = len;
+
+       return;
+}
+
+MonoStringBuilder *
+mono_string_utf16_to_builder2 (gunichar2 *text)
+{
+       if (!text)
+               return NULL;
+
+       MonoStringBuilder *sb = mono_string_builder_new ();
+       mono_string_utf16_to_builder (sb, text);
 
        return sb;
 }
 
-/*
- * FIXME: This routine does not seem to do what it seems to do
- * the @text is never copied into the string builder
- */
 void
-mono_string_utf16_to_builder (MonoStringBuilder *sb, gunichar2 *text)
+mono_string_utf8_to_builder (MonoStringBuilder *sb, char *text)
 {
-       guint32 len;
 
        if (!sb || !text)
                return;
 
-       g_assert (mono_string_chars (sb->str) == text);
+       int len = strlen (text);
+       GError *error = NULL;
+       gunichar2* ut = g_utf8_to_utf16 (text, len, NULL, NULL, &error);
 
-       for (len = 0; text [len] != 0; ++len)
-               ;
+       if (!error) {
+               MONO_OBJECT_SETREF (sb, chunkPrevious, NULL);
+               mono_string_utf16_to_builder_copy (sb, ut, len);
+       } else
+               g_error_free (error);
 
-       sb->length = len;
+       g_free (ut);
 }
 
 MonoStringBuilder *
-mono_string_utf16_to_builder2 (gunichar2 *text)
+mono_string_utf8_to_builder2 (char *text)
 {
-       int len;
-       MonoStringBuilder *sb;
-       static MonoClass *string_builder_class;
-       static MonoMethod *sb_ctor;
-       void *args [1];
-       MonoObject *exc;
-
        if (!text)
                return NULL;
 
-       if (!string_builder_class) {
-               MonoMethodDesc *desc;
+       MonoStringBuilder *sb = mono_string_builder_new ();
+       mono_string_utf8_to_builder (sb, text);
 
-               string_builder_class = mono_class_from_name (mono_defaults.corlib, "System.Text", "StringBuilder");
-               g_assert (string_builder_class);
-               desc = mono_method_desc_new (":.ctor(int)", FALSE);
-               sb_ctor = mono_method_desc_search_in_class (desc, string_builder_class);
-               g_assert (sb_ctor);
-               mono_method_desc_free (desc);
-       }
+       return sb;
+}
 
-       for (len = 0; text [len] != 0; ++len)
-               ;
 
-       sb = (MonoStringBuilder*)mono_object_new (mono_domain_get (), string_builder_class);
-       g_assert (sb);
-       args [0] = &len;
-       mono_runtime_invoke (sb_ctor, sb, args, &exc);
-       g_assert (!exc);
+void
+mono_string_utf16_to_builder (MonoStringBuilder *sb, gunichar2 *text)
+{
+       if (!sb || !text)
+               return;
 
-       sb->length = len;
-       memcpy (mono_string_chars (sb->str), text, len * 2);
+       guint32 len;
+       for (len = 0; text [len] != 0; ++len);
 
-       return sb;
+       mono_string_utf16_to_builder_copy (sb, text, len);
 }
 
 /**
@@ -831,35 +816,38 @@ mono_string_utf16_to_builder2 (gunichar2 *text)
  *
  * The return value must be released with g_free.
  */
-gpointer
+gchar*
 mono_string_builder_to_utf8 (MonoStringBuilder *sb)
 {
        GError *error = NULL;
-       gchar *tmp, *res = NULL;
 
        if (!sb)
                return NULL;
 
-       if ((sb->str == sb->cached_str) && (sb->str->length == 0)) {
-               /* 
-                * The sb could have been allocated with the default capacity and be empty.
-                * we need to alloc a buffer of the default capacity in this case.
-                */
-               MONO_OBJECT_SETREF (sb, str, mono_string_new_size (mono_domain_get (), 16));
-               sb->cached_str = NULL;
-       }
 
-       tmp = g_utf16_to_utf8 (mono_string_chars (sb->str), sb->length, NULL, NULL, &error);
+       gunichar2 *str_utf16 = mono_string_builder_to_utf16 (sb);
+
+       guint str_len = mono_string_builder_string_length (sb);
+
+       gchar *tmp = g_utf16_to_utf8 (str_utf16, str_len, NULL, NULL, &error);
+
        if (error) {
                g_error_free (error);
+               g_free (str_utf16);
                mono_raise_exception (mono_get_exception_execution_engine ("Failed to convert StringBuilder from utf16 to utf8"));
+               return NULL;
        } else {
-               res = mono_marshal_alloc (mono_stringbuilder_capacity (sb) + 1);
-               memcpy (res, tmp, sb->length + 1);
+               guint len = mono_string_builder_length (sb) + 1;
+               gchar *res = mono_marshal_alloc (len * sizeof (gchar));
+               g_assert (str_len < len);
+               memcpy (res, tmp, str_len * sizeof (gchar));
+               res[str_len] = '\0';
+
+
+               g_free (str_utf16);
                g_free (tmp);
+               return res;
        }
-
-       return res;
 }
 
 /**
@@ -872,35 +860,43 @@ mono_string_builder_to_utf8 (MonoStringBuilder *sb)
  *
  * The return value must not be freed.
  */
-gpointer
+gunichar2*
 mono_string_builder_to_utf16 (MonoStringBuilder *sb)
 {
        if (!sb)
                return NULL;
 
-       g_assert (sb->str);
+       g_assert (sb->chunkChars);
 
-       /*
-        * The stringbuilder might not have ownership of this string. If this is
-        * the case, we must duplicate the string, so that we don't munge immutable
-        * strings
-        */
-       if (sb->str == sb->cached_str) {
-               /* 
-                * The sb could have been allocated with the default capacity and be empty.
-                * we need to alloc a buffer of the default capacity in this case.
-                */
-               if (sb->str->length == 0)
-                       MONO_OBJECT_SETREF (sb, str, mono_string_new_size (mono_domain_get (), 16));
-               else
-                       MONO_OBJECT_SETREF (sb, str, mono_string_new_utf16 (mono_domain_get (), mono_string_chars (sb->str), mono_stringbuilder_capacity (sb)));
-               sb->cached_str = NULL;
-       }
-       
-       if (sb->length == 0)
-               *(mono_string_chars (sb->str)) = '\0';
+       guint len = mono_string_builder_length (sb);
+
+       if (len == 0)
+               len = 1;
+
+       gunichar2 *str = mono_marshal_alloc ((len + 1) * sizeof (gunichar2));
+       str[len] = '\0';
+
+       if (len == 0)
+               return str;
+
+       MonoStringBuilder* chunk = sb;
+       do {
+               if (chunk->chunkLength > 0) {
+                       // Check that we will not overrun our boundaries.
+                       gunichar2 *source = (gunichar2 *)chunk->chunkChars->vector;
+
+                       if (chunk->chunkLength <= len) {
+                               memcpy (str + chunk->chunkOffset, source, chunk->chunkLength * sizeof(gunichar2));
+                       } else {
+                               g_error ("A chunk in the StringBuilder had a length longer than expected from the offset.");
+                       }
+
+                       len -= chunk->chunkLength;
+               }
+               chunk = chunk->chunkPrevious;
+       } while (chunk != NULL);
 
-       return mono_string_chars (sb->str);
+       return str;
 }
 
 static gpointer
index 03fc446a2f089ad10ea354ea51a6d3f6ffd09361..22af5900a3ec04ee0602c0057f4d61c01e2ca04e 100644 (file)
@@ -244,10 +244,10 @@ mono_string_utf8_to_builder (MonoStringBuilder *sb, char *text);
 void
 mono_string_utf16_to_builder (MonoStringBuilder *sb, gunichar2 *text);
 
-gpointer
+gchar*
 mono_string_builder_to_utf8 (MonoStringBuilder *sb);
 
-gpointer
+gunichar2*
 mono_string_builder_to_utf16 (MonoStringBuilder *sb);
 
 gpointer
index e3caae5927a9796b6a9785bb598dfa8e181dfe86..ccbe6d92e4dad1c86565b59910db201a0197dd6a 100644 (file)
@@ -87,8 +87,8 @@
                return retval;                                                                            \
        };                              }G_STMT_END
 
-/* 16 == default capacity */
-#define mono_stringbuilder_capacity(sb) ((sb)->str ? ((sb)->str->length) : 16)
+#define mono_string_builder_length(sb) sb->chunkOffset + sb->chunkChars->max_length
+#define mono_string_builder_string_length(sb) sb->chunkOffset + sb->chunkLength
 
 /* 
  * Macros which cache the results of lookups locally.
@@ -210,13 +210,16 @@ struct _MonoAppDomain {
        MonoDomain *data;
 };
 
-typedef struct {
+typedef struct _MonoStringBuilder MonoStringBuilder;
+
+struct _MonoStringBuilder {
        MonoObject object;
-       gint32 length;
-       MonoString *str;
-       MonoString *cached_str;
-       gint32 max_capacity;
-} MonoStringBuilder;
+       MonoArray  *chunkChars;
+       MonoStringBuilder* chunkPrevious;      // Link to the block logically before this block
+       int chunkLength;                  // The index in ChunkChars that represent the end of the block
+       int chunkOffset;                  // The logial offset (sum of all characters in previous blocks)
+       int maxCapacity;
+};
 
 typedef struct {
        MonoType *type;
index 58ff2a98ad257a0ea657884a0c180bbace898e46..c35a3406b899dd2b63143cec3009cb841a295a20 100644 (file)
@@ -467,14 +467,6 @@ mono_marshal_xdomain_copy_out_value (MonoObject *src, MonoObject *dst)
                break;
        }
 
-       if (mono_object_class (src) == mono_defaults.stringbuilder_class) {
-               MonoStringBuilder *src_sb = (MonoStringBuilder *) src;
-               MonoStringBuilder *dst_sb = (MonoStringBuilder *) dst;
-       
-               MONO_OBJECT_SETREF (dst_sb, str, mono_string_new_utf16 (mono_object_domain (dst), mono_string_chars (src_sb->str), mono_string_length (src_sb->str)));
-               dst_sb->cached_str = NULL;
-               dst_sb->length = src_sb->length;
-       }
 }
 
 
@@ -2001,13 +1993,5 @@ mono_marshal_xdomain_copy_value (MonoObject *val)
                break;
        }
 
-       if (mono_object_class (val) == mono_defaults.stringbuilder_class) {
-               MonoStringBuilder *oldsb = (MonoStringBuilder *) val;
-               MonoStringBuilder *newsb = (MonoStringBuilder *) mono_object_new (domain, mono_defaults.stringbuilder_class);
-               MONO_OBJECT_SETREF (newsb, str, mono_string_new_utf16 (domain, mono_string_chars (oldsb->str), mono_string_length (oldsb->str)));
-               newsb->length = oldsb->length;
-               newsb->max_capacity = (gint32)0x7fffffff;
-               return (MonoObject *) newsb;
-       }
        return NULL;
 }
index 0db2f5bb3cd31e819816596436d0066631195fa0..9e340acdb2f964fd0eb7ad9d6e17bb511575a952 100644 (file)
@@ -13,7 +13,7 @@ public class Test: MarshalByRefObject
                Test server = (Test) domain.CreateInstanceAndUnwrap(typeof(Test).Assembly.FullName, "Test");
                return server.RunTest ();
        }
-       
+
        public int RunTest ()
        {
                try
@@ -58,13 +58,22 @@ public class Test: MarshalByRefObject
                                ba [n] = n;
                                
                        server.Run8 (ba);
-                       
+
                        for (int n=0; n<ba.Length; n++)
                                CheckValue (ba[n], (byte) (ba.Length - n), 180);
                        
                        StringBuilder sb = new StringBuilder ("un");
-                       server.Run9 (sb);
+                       server.Run9_1 (sb);
                        Test.CheckValue (sb, new StringBuilder ("un"), 190);
+
+                       StringBuilder sb2 = new StringBuilder ("prefix");
+                       StringBuilder sb3 = server.Run9_2 (sb2);
+                       Test.CheckValue (sb2, new StringBuilder ("prefix"), 192);
+                       Test.CheckValue (sb3, new StringBuilder ("prefix-middle"), 192);
+                       StringBuilder sb4 = server.Run9_3 (sb3);
+                       Test.CheckValue (sb3, new StringBuilder ("prefix-middle"), 193);
+                       Test.CheckValue (sb4, new StringBuilder ("prefix-middle-end"), 193);
+
                        
                }
                catch (TestException ex)
@@ -107,7 +116,10 @@ public class Test: MarshalByRefObject
                        StringBuilder sb2 = (StringBuilder) ob2;
 
                        if (sb1.ToString () != sb2.ToString ())
-                               throw new TestException ("Strings are not equal", ec);
+                               throw new TestException ("String in StringBuilders are not equal", ec);
+
+                       if (sb1.Length != sb2.Length)
+                               throw new TestException ("Lengths in StringBuilders are not equal", ec);
                }
                else if (!ob1.Equals (ob2))
                        throw new TestException ("Objects are not equal", ec);
@@ -201,14 +213,31 @@ public class Remo: MarshalByRefObject
                        bytes[n] = (byte) (bytes.Length - n);
                }
        }
-       
-       public void Run9 ([In,Out] StringBuilder sb)
+
+       public void Run9_1 ([In,Out] StringBuilder sb)
        {
                CheckThisDomain (90);
                Test.CheckValue (sb, new StringBuilder ("un"), 91);
                sb.Append ("-dos");
        }
-       
+
+       public StringBuilder Run9_2 ([In] StringBuilder sb)
+       {
+               CheckThisDomain (91);
+               Test.CheckValue (sb, new StringBuilder ("prefix"), 92);
+               sb.Append ("-middle");
+               return sb;
+       }
+
+       public StringBuilder Run9_3 ([In,Out] StringBuilder sb)
+       {
+               CheckThisDomain (92);
+               Test.CheckValue (sb, new StringBuilder ("prefix-middle"), 93);
+               sb.Append ("-end");
+
+               return sb;
+       }
+
        public void Peta ()
        {
                throw new Exception ("peta");
index 7c83a8441a1f4c2996814887cd1f2470b2dfc239..0154d608954f93d6ed2e6b6ee373f26cfa68c19d 100644 (file)
@@ -1097,12 +1097,18 @@ mono_test_marshal_stringbuilder (char *s, int n)
 }
 
 LIBTEST_API int STDCALL  
-mono_test_marshal_stringbuilder2 (char *s, int n)
+mono_test_marshal_stringbuilder_append (char *s, int length)
 {
-       const char m[] = "EFGH";
+       const char out_sentinel[] = "CSHARP_";
+       const char out_len = strlen (out_sentinel);
+
+       for (int i=0; i < length; i++) {
+               s [i] = out_sentinel [i % out_len];
+       }
+
+       s [length] = '\0';
+
 
-       strncpy(s, m, n);
-       s [n] = '\0';
        return 0;
 }
 
index 9a7e83ab859be0a79469cccfc8fc5ed6ecd8efba..abc81f8d70d77fe44b7a2588b0c7e98d96825339 100644 (file)
@@ -296,12 +296,12 @@ public class Tests {
        [DllImport ("libtest", EntryPoint="mono_test_marshal_stringbuilder")]
        public static extern void mono_test_marshal_stringbuilder (StringBuilder sb, int len);
 
-       [DllImport ("libtest", EntryPoint="mono_test_marshal_stringbuilder2")]
-       public static extern void mono_test_marshal_stringbuilder2 (StringBuilder sb, int len);
-
        [DllImport ("libtest", EntryPoint="mono_test_marshal_stringbuilder_default")]
        public static extern void mono_test_marshal_stringbuilder_default (StringBuilder sb, int len);
 
+       [DllImport ("libtest", EntryPoint="mono_test_marshal_stringbuilder_append")]
+       public static extern void mono_test_marshal_stringbuilder_append (StringBuilder sb, int len);
+
        [DllImport ("libtest", EntryPoint="mono_test_marshal_stringbuilder_unicode", CharSet=CharSet.Unicode)]
        public static extern void mono_test_marshal_stringbuilder_unicode (StringBuilder sb, int len);
 
@@ -808,11 +808,33 @@ public class Tests {
                if (res != "This is my message.  Isn't it nice?")
                        return 1;  
 
-               // Test that cached_str is cleared
-               mono_test_marshal_stringbuilder2 (sb, sb.Capacity);
-               res = sb.ToString();
-               if (res != "EFGH")
-                       return 2;
+               // Test StringBuilder with default capacity (16)
+               StringBuilder sb2 = new StringBuilder();
+               mono_test_marshal_stringbuilder_default (sb2, sb2.Capacity);
+               if (sb2.ToString () != "This is my messa")
+                       return 3;
+
+               return 0;
+       }
+
+       public static int test_0_marshal_stringbuilder_append () {
+               const String in_sentinel = "MONO_";
+               const String out_sentinel = "CSHARP_";
+               const int iterations = 100;
+               StringBuilder sb = new StringBuilder(255);
+               StringBuilder check = new StringBuilder(255);
+
+               for (int i = 0; i < iterations; i++) {
+                       sb.Append (in_sentinel[i % in_sentinel.Length]);
+                       check.Append (out_sentinel[i % out_sentinel.Length]);
+
+                       mono_test_marshal_stringbuilder_append (sb, sb.Length);
+
+                       String res = sb.ToString();
+                       String checkRev = check.ToString();
+                       if (res != checkRev)
+                               return 1;
+               }
 
                // Test StringBuilder with default capacity (16)
                StringBuilder sb2 = new StringBuilder();