[Mono-list] Array.Copy

Martin Baulig martin@gnome.org
06 Mar 2002 20:07:15 +0100


--=-=-=

Hi guys,

here's a patch for my new Array.Copy implementation:


--=-=-=
Content-Type: application/octet-stream
Content-Disposition: attachment; filename=diff

Index: Array.cs
===================================================================
RCS file: /cvs/public/mcs/class/corlib/System/Array.cs,v
retrieving revision 1.24
diff -u -u -r1.24 Array.cs
--- Array.cs	2002/03/06 10:40:05	1.24
+++ Array.cs	2002/03/06 15:14:07
@@ -63,12 +63,9 @@
 		public extern void SetValue (object value, int[] idxs);
 
 		[MethodImplAttribute(MethodImplOptions.InternalCall)]
-		internal extern object GetValueImpl (int pos);
+		internal extern static void CopyImpl (Array source, int source_idx, Array dest, int dest_idx, int length);
 
 		[MethodImplAttribute(MethodImplOptions.InternalCall)]
-		internal extern void SetValueImpl (object value, int pos);
-
-		[MethodImplAttribute(MethodImplOptions.InternalCall)]
 		internal extern static Array CreateInstanceImpl(Type elementType, int[] lengths, int [] bounds);
 
 		// Properties
@@ -358,48 +355,7 @@
 
 		public static void Copy (Array source, int source_idx, Array dest, int dest_idx, int length)
 		{
-			if (source == null || dest == null)
-				throw new ArgumentNullException ();
-
-			if (length < 0)
-				throw new ArgumentOutOfRangeException ();
-
-			if (source == null || dest == null)
-				throw new ArgumentNullException ();
-
-			if (source_idx < source.GetLowerBound (0) || dest_idx < dest.GetLowerBound (0))
-				throw new ArgumentException ();
-
-			source_idx -= source.GetLowerBound (0);
-			dest_idx -= dest.GetLowerBound (0);
-
-			if (source_idx + length > source.Length || dest_idx + length > dest.Length)
-				throw new ArgumentException ();
-
-			if (source.Rank != dest.Rank)
-				throw new RankException ();
-
-			// FIXME: This should be implemented in C so that we can use memcpy()
-			//        whereever possible.
-
-			for (int i = 0; i < length; i++) 
-			{
-				Object srcval = source.GetValueImpl (source_idx + i);
-
-				bool argumentException = false;
-				bool castException = false;
-
-				try {
-					dest.SetValueImpl (srcval, dest_idx + i);
-				} catch (ArgumentException) {
-					argumentException = true;
-				} catch (InvalidCastException) {
-					castException = true;
-				}
-
-				if (argumentException || castException)
-					throw new ArrayTypeMismatchException ();
-			}
+			CopyImpl (source, source_idx, dest, dest_idx, length);
 		}
 		
 		public static int IndexOf (Array array, object value)
Index: ChangeLog
===================================================================
RCS file: /cvs/public/mcs/class/corlib/System/ChangeLog,v
retrieving revision 1.211
diff -u -u -r1.211 ChangeLog
--- ChangeLog	2002/03/06 13:21:22	1.211
+++ ChangeLog	2002/03/06 15:14:09
@@ -1,3 +1,7 @@
+2002-03-06  Martin Baulig  <martin@gnome.org>
+
+	* Array.cs (Copy): This is now implemented in C.
+
 2002-03-06  Dietmar Maurer  <dietmar@ximian.com>
 
 	* Int64.cs (Parse): bug fix for max. negative value. 

--=-=-=
Content-Type: application/octet-stream
Content-Disposition: attachment; filename=diff

Index: ChangeLog
===================================================================
RCS file: /cvs/public/mono/mono/metadata/ChangeLog,v
retrieving revision 1.204
diff -u -u -r1.204 ChangeLog
--- ChangeLog	2002/03/06 10:23:33	1.204
+++ ChangeLog	2002/03/06 15:13:11
@@ -1,5 +1,18 @@
 2002-03-06  Martin Baulig  <martin@gnome.org>
 
+	* icall.c (ves_icall_System_Array_GetValueImpl): This is now a static function,
+	no longer an interncall.
+	(ves_icall_System_Array_SetValueImpl): Likewise.
+	(ves_icall_System_Array_SetValueImpl): Added `guint32 raise_exception' argument and
+	returns a boolean indicating whether the call was successful.
+	(ves_icall_System_Array_CopyImpl): New internall. Implements Array.Copy in C and
+	uses memcpy() whenever appropriate.
+	(ves_icall_System_Array_FastCopy): Removed.
+
+	* exception.c (mono_get_exception_rank): New exception.
+
+2002-03-06  Martin Baulig  <martin@gnome.org>
+
 	* icall.c (ves_icall_System_Array_CreateInstanceImpl): Make this work with
 	non-zero lower bounds. See testcases #F10-#F13.
 
Index: exception.c
===================================================================
RCS file: /cvs/public/mono/mono/metadata/exception.c,v
retrieving revision 1.9
diff -u -u -r1.9 exception.c
--- exception.c	2002/03/05 19:00:35	1.9
+++ exception.c	2002/03/06 15:13:11
@@ -105,6 +105,13 @@
 }
 
 MonoException *
+mono_get_exception_rank ()
+{
+	return mono_exception_from_name (mono_defaults.corlib, "System",
+					 "RankException");
+}
+
+MonoException *
 mono_get_exception_type_load ()
 {
 	return mono_exception_from_name (mono_defaults.corlib, "System",
Index: exception.h
===================================================================
RCS file: /cvs/public/mono/mono/metadata/exception.h,v
retrieving revision 1.7
diff -u -u -r1.7 exception.h
--- exception.h	2002/03/05 19:00:35	1.7
+++ exception.h	2002/03/06 15:13:11
@@ -44,6 +44,9 @@
 mono_get_exception_array_type_mismatch (void);
 
 MonoException *
+mono_get_exception_rank                (void);
+
+MonoException *
 mono_get_exception_type_load           (void);
 
 MonoException *
Index: icall.c
===================================================================
RCS file: /cvs/public/mono/mono/metadata/icall.c,v
retrieving revision 1.82
diff -u -u -r1.82 icall.c
--- icall.c	2002/03/06 10:23:33	1.82
+++ icall.c	2002/03/06 15:13:13
@@ -85,8 +85,9 @@
 	return ves_icall_System_Array_GetValueImpl (this, pos);
 }
 
-static void
-ves_icall_System_Array_SetValueImpl (MonoObject *this, MonoObject *value, guint32 pos)
+static guint32
+ves_icall_System_Array_SetValueImpl (MonoObject *this, MonoObject *value, guint32 pos,
+				     guint32 raise_exception)
 {
 	MonoArray *ao, *vo;
 	MonoClass *ac, *vc, *ec;
@@ -113,22 +114,29 @@
 
 	if (!vo) {
 		memset (ea, 0,  esize);
-		return;
+		return 1;
 	}
 
 #define NO_WIDENING_CONVERSION G_STMT_START{\
-	mono_raise_exception (mono_get_exception_argument ( \
-		"value", "not a widening conversion")); \
+	if (raise_exception) \
+		mono_raise_exception (mono_get_exception_argument ( \
+			"value", "not a widening conversion")); \
+	return 0; \
 }G_STMT_END
 
 #define CHECK_WIDENING_CONVERSION(extra) G_STMT_START{\
-	if (esize < vsize + ## extra) \
-		mono_raise_exception (mono_get_exception_argument ( \
-			"value", "not a widening conversion")); \
+	if (esize < vsize + ## extra) { \
+		if (raise_exception) \
+			mono_raise_exception (mono_get_exception_argument ( \
+				"value", "not a widening conversion")); \
+		return 0; \
+	} \
 }G_STMT_END
 
 #define INVALID_CAST G_STMT_START{\
-	mono_raise_exception (mono_get_exception_invalid_cast ()); \
+	if (raise_exception) \
+		mono_raise_exception (mono_get_exception_invalid_cast ()); \
+	return 0; \
 }G_STMT_END
 
 	/* Check element (destination) type. */
@@ -165,12 +173,12 @@
 
 	if (!ec->valuetype) {
 		*ea = (gpointer)vo;
-		return;
+		return 1;
 	}
 
 	if (mono_object_isinst (value, ec)) {
 		memcpy (ea, (char *)vo + sizeof (MonoObject), esize);
-		return;
+		return 1;
 	}
 
 	if (!vc->valuetype)
@@ -193,7 +201,7 @@
 	case MONO_TYPE_CHAR: \
 		CHECK_WIDENING_CONVERSION(0); \
 		*(## etype *) ea = (## etype) u64; \
-		return; \
+		return 1; \
 	/* You can't assign a signed value to an unsigned array. */ \
 	case MONO_TYPE_I1: \
 	case MONO_TYPE_I2: \
@@ -214,7 +222,7 @@
 	case MONO_TYPE_I8: \
 		CHECK_WIDENING_CONVERSION(0); \
 		*(## etype *) ea = (## etype) i64; \
-		return; \
+		return 1; \
 	/* You can assign an unsigned value to a signed array if the array's */ \
 	/* element size is larger than the value size. */ \
 	case MONO_TYPE_U1: \
@@ -224,7 +232,7 @@
 	case MONO_TYPE_CHAR: \
 		CHECK_WIDENING_CONVERSION(1); \
 		*(## etype *) ea = (## etype) u64; \
-		return; \
+		return 1; \
 	/* You can't assign a floating point number to an integer array. */ \
 	case MONO_TYPE_R4: \
 	case MONO_TYPE_R8: \
@@ -238,7 +246,7 @@
 	case MONO_TYPE_R8: \
 		CHECK_WIDENING_CONVERSION(0); \
 		*(## etype *) ea = (## etype) r64; \
-		return; \
+		return 1; \
 	/* All integer values fit into a floating point array, so we don't */ \
 	/* need to CHECK_WIDENING_CONVERSION here. */ \
 	case MONO_TYPE_I1: \
@@ -246,14 +254,14 @@
 	case MONO_TYPE_I4: \
 	case MONO_TYPE_I8: \
 		*(## etype *) ea = (## etype) i64; \
-		return; \
+		return 1; \
 	case MONO_TYPE_U1: \
 	case MONO_TYPE_U2: \
 	case MONO_TYPE_U4: \
 	case MONO_TYPE_U8: \
 	case MONO_TYPE_CHAR: \
 		*(## etype *) ea = (## etype) u64; \
-		return; \
+		return 1; \
 	} \
 }G_STMT_END
 
@@ -339,8 +347,7 @@
 	}
 
 	INVALID_CAST;
-	/* Not reached, INVALID_CAST does not return. Just to avoid a compiler warning ... */
-	return;
+	return 0;
 
 #undef INVALID_CAST
 #undef NO_WIDENING_CONVERSION
@@ -386,8 +393,88 @@
 	for (i = 1; i < ac->rank; i++)
 		pos = pos*ao->bounds [i].length + ind [i] - 
 			ao->bounds [i].lower_bound;
+
+	ves_icall_System_Array_SetValueImpl (this, value, pos, 1);
+}
+
+
+static void
+ves_icall_System_Array_CopyImpl (MonoArray *source, int source_idx, MonoArray* dest, int dest_idx, int length)
+{
+	MonoArray *sa, *da;
+	MonoClass *sc, *dc;
+	gpointer dptr, sptr;
+	gint32 esize, i;
+
+	MONO_CHECK_ARG_NULL (dest);
+
+	sa = (MonoArray *)source;
+	if (sa)
+		sc = (MonoClass *)sa->obj.vtable->klass->element_class;
+	else
+		sc = NULL;
+
+	da = (MonoArray *)dest;
+	dc = (MonoClass *)da->obj.vtable->klass->element_class;
+
+	if (length < 0)
+		mono_raise_exception (mono_get_exception_argument_out_of_range (NULL));
+
+	MONO_CHECK_ARG (dest_idx, dest_idx >= da->bounds [0].lower_bound);
+	MONO_CHECK_ARG (length,
+			(length >= 0) &&
+			(dest_idx + length <= da->bounds [0].lower_bound +
+			 da->bounds [0].length));
+
+	esize = mono_array_element_size (dc);
+
+	dest_idx -= da->bounds [0].lower_bound;
+	dptr = (char*)da->vector + (dest_idx * esize);
 
-	ves_icall_System_Array_SetValueImpl (this, value, pos);
+	if (!sa) {
+		/* Array.Clear */
+		memset (dptr, 0, esize * length);
+		return;
+	}
+
+	MONO_CHECK_ARG (source_idx, source_idx >= sa->bounds [0].lower_bound);
+	MONO_CHECK_ARG (length,
+			(source_idx + length <= sa->bounds [0].lower_bound +
+			 sa->bounds [0].length));
+
+	source_idx -= sa->bounds [0].lower_bound;
+	sptr = (char*)sa->vector + (source_idx * esize);
+
+	if (sa->obj.vtable->klass->rank != da->obj.vtable->klass->rank)
+		mono_raise_exception (mono_get_exception_rank ());
+
+	if (!sc->valuetype && !dc->valuetype) {
+		memcpy (dptr, sptr, esize * length);
+		return;
+	}
+
+	if (sc->valuetype && dc->valuetype && (sc->byval_arg.type == dc->byval_arg.type)) {
+		memcpy (dptr, sptr, esize * length);
+		return;
+	}
+
+	for (i = 0; i < length; i++) {
+		MonoObject *value;
+		int svt, dvt;
+
+		value = ves_icall_System_Array_GetValueImpl ((MonoObject *) sa, i);
+		if (ves_icall_System_Array_SetValueImpl ((MonoObject *) da, value, i, 0))
+			continue;
+
+		svt = sc->valuetype || (sc->byval_arg.type == MONO_TYPE_STRING);
+		dvt = dc->valuetype || (dc->byval_arg.type == MONO_TYPE_STRING);
+
+		if ((dc->valuetype || dc->byval_arg.type == MONO_TYPE_STRING) &&
+		    (sc->byval_arg.type == MONO_TYPE_OBJECT))
+			mono_raise_exception (mono_get_exception_invalid_cast ());
+		else
+			mono_raise_exception (mono_get_exception_array_type_mismatch ());
+	}
 }
 
 static MonoArray *
@@ -451,16 +538,6 @@
 }
 
 static void
-ves_icall_System_Array_FastCopy (MonoArray *source, int source_idx, MonoArray* dest, int dest_idx, int length)
-{
-	int element_size = mono_array_element_size (source->obj.vtable->klass);
-	void * dest_addr = mono_array_addr_with_size (dest, element_size, dest_idx);
-	void * source_addr = mono_array_addr_with_size (source, element_size, dest_idx);
-
-	memcpy (dest_addr, source_addr, element_size * length);
-}
-
-static void
 ves_icall_InitializeArray (MonoArray *array, MonoClassField *field_handle)
 {
 	MonoClass *klass = array->obj.vtable->klass;
@@ -1555,13 +1632,11 @@
 	 */
 	"System.Array::GetValue",         ves_icall_System_Array_GetValue,
 	"System.Array::SetValue",         ves_icall_System_Array_SetValue,
-	"System.Array::GetValueImpl",     ves_icall_System_Array_GetValueImpl,
-	"System.Array::SetValueImpl",     ves_icall_System_Array_SetValueImpl,
 	"System.Array::GetRank",          ves_icall_System_Array_GetRank,
 	"System.Array::GetLength",        ves_icall_System_Array_GetLength,
 	"System.Array::GetLowerBound",    ves_icall_System_Array_GetLowerBound,
 	"System.Array::CreateInstanceImpl",   ves_icall_System_Array_CreateInstanceImpl,
-	"System.Array::FastCopy",         ves_icall_System_Array_FastCopy,
+	"System.Array::CopyImpl",         ves_icall_System_Array_CopyImpl,
 	"System.Array::Clone",            mono_array_clone,
 
 	/*

--=-=-=



-- 
Martin Baulig
martin@gnome.org

--=-=-=--