Imported Upstream version 4.0.0~alpha1

Former-commit-id: 806294f5ded97629b74c85c09952f2a74fe182d9
This commit is contained in:
Jo Shields
2015-04-07 09:35:12 +01:00
parent 283343f570
commit 3c1f479b9d
22469 changed files with 2931443 additions and 869343 deletions

View File

@ -5,13 +5,11 @@
// Miguel de Icaza (miguel@ximian.com)
// Nick Drochak (ndrochak@gol.com)
// Gonzalo Paniagua Javier (gonzalo@ximian.com)
// Marek Safar (marek.safar@gmail.com)
//
// (C) Ximian, Inc. http://www.ximian.com
//
//
//
// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
// Copyright 2015 Xamarin, Inc (http://www.xamarin.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
@ -38,6 +36,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Reflection;
namespace System
{
@ -82,7 +81,7 @@ namespace System
}
internal class ShortComparer : IComparer, System.Collections.Generic.IComparer<short>
{
{
public int Compare (object x, object y)
{
short ix = (short) x;
@ -157,26 +156,37 @@ namespace System
internal static void GetInfo (Type enumType, out MonoEnumInfo info)
{
/* First check the thread-local cache without locking */
if (cache != null && cache.TryGetValue (enumType, out info)) {
return;
}
var user_type = !(enumType is MonoType);
/* Threads could die, so keep a global cache too */
lock (global_cache_monitor) {
if (global_cache.TryGetValue (enumType, out info)) {
if (cache == null)
cache = new Dictionary<Type, MonoEnumInfo> ();
cache [enumType] = info;
if (user_type) {
GetUserEnumInfo (enumType, out info);
} else {
/* First check the thread-local cache without locking */
if (cache != null && cache.TryGetValue (enumType, out info)) {
return;
}
/* Threads could die, so keep a global cache too */
lock (global_cache_monitor) {
if (global_cache.TryGetValue (enumType, out info)) {
if (cache == null)
cache = new Dictionary<Type, MonoEnumInfo> ();
cache [enumType] = info;
return;
}
}
// TODO: return info with ulong values only to avoid all sorts of
// Array trick and slow paths
get_enum_info (enumType, out info);
}
get_enum_info (enumType, out info);
SortEnums (info.utype, info.values, info.names);
Type et = Enum.GetUnderlyingType (enumType);
SortEnums (et, info.values, info.names);
// User types can have unreliable/not-implemented GetHashCode
if (user_type)
return;
if (info.names.Length > 50) {
info.name_hash = new Dictionary<string, int> (info.names.Length);
@ -188,10 +198,48 @@ namespace System
global_cache [enumType] = cached;
}
}
internal static void SortEnums (Type et, Array values, Array names)
static void GetUserEnumInfo (Type type, out MonoEnumInfo mei)
{
IComparer ic = null;
mei = new MonoEnumInfo ();
mei.utype = typeof (UInt64);
var fields = type.GetFields (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);
mei.names = new string [fields.Length];
var values = new UInt64 [fields.Length];
mei.values = values;
for (int i = 0; i < fields.Length; ++i) {
mei.names [i] = fields [i].Name;
values [i] = ToUInt64 (fields [i].GetRawConstantValue ());
}
}
public static ulong ToUInt64 (object value)
{
switch (Convert.GetTypeCode (value)) {
case TypeCode.SByte:
case TypeCode.Int16:
case TypeCode.Int32:
case TypeCode.Int64:
return (UInt64) Convert.ToInt64 (value, CultureInfo.InvariantCulture);
case TypeCode.Byte:
case TypeCode.UInt16:
case TypeCode.UInt32:
case TypeCode.UInt64:
case TypeCode.Boolean:
case TypeCode.Char:
return Convert.ToUInt64 (value, CultureInfo.InvariantCulture);
default:
throw new ArgumentException ("Value is not the enum or a valid enum underlying type", "value");
}
}
internal static void SortEnums (Type et, Array values, string[] names)
{
IComparer ic;
if (et == typeof (int))
ic = int_comparer;
else if (et == typeof (short))
@ -200,10 +248,12 @@ namespace System
ic = sbyte_comparer;
else if (et == typeof (long))
ic = long_comparer;
else
ic = null;
Array.Sort (values, names, ic);
}
};
}
[Serializable]
[ComVisible (true)]
@ -274,12 +324,9 @@ namespace System
return Convert.ToSingle (Value, provider);
}
object IConvertible.ToType (Type targetType, IFormatProvider provider)
object IConvertible.ToType (Type type, IFormatProvider provider)
{
if (targetType == null)
throw new ArgumentNullException ("targetType");
return Convert.ToType (this, targetType, provider, false);
return Convert.DefaultToType ((IConvertible)this, type, provider);
}
ushort IConvertible.ToUInt16 (IFormatProvider provider)
@ -341,9 +388,9 @@ namespace System
//
// It also tries to use the non-boxing version of the various Array.BinarySearch methods
//
static int FindPosition (Type enumType, object value, Array values)
static int FindPosition (Type underlyingEnumType, object value, Array values)
{
switch (Type.GetTypeCode (GetUnderlyingType (enumType))) {
switch (Type.GetTypeCode (underlyingEnumType)) {
case TypeCode.SByte:
sbyte [] sbyte_array = values as sbyte [];
return Array.BinarySearch (sbyte_array, (sbyte) value, MonoEnumInfo.sbyte_comparer);
@ -394,10 +441,14 @@ namespace System
throw new ArgumentException ("enumType is not an Enum type.", "enumType");
MonoEnumInfo info;
value = ToObject (enumType, value);
MonoEnumInfo.GetInfo (enumType, out info);
int i = FindPosition (enumType, value, info.values);
if (enumType is MonoType)
value = ToObject (enumType, value);
else
value = MonoEnumInfo.ToUInt64 (value);
int i = FindPosition (info.utype, value, info.values);
return (i >= 0) ? info.names [i] : null;
}
@ -416,18 +467,31 @@ namespace System
MonoEnumInfo.GetInfo (enumType, out info);
Type vType = value.GetType ();
if (vType == typeof(String)) {
if (vType == typeof (String)) {
return ((IList)(info.names)).Contains (value);
} else if ((vType == info.utype) || (vType == enumType)) {
value = ToObject (enumType, value);
MonoEnumInfo.GetInfo (enumType, out info);
}
return FindPosition (enumType, value, info.values) >= 0;
} else {
if ((vType == info.utype || !(enumType is MonoType)) || (vType == enumType)) {
if (enumType is MonoType)
value = ToObject (enumType, value);
else
value = MonoEnumInfo.ToUInt64 (value);
MonoEnumInfo.GetInfo (enumType, out info);
return FindPosition (info.utype, value, info.values) >= 0;
}
if (IsValidEnumType (info.utype))
throw new ArgumentException("The value parameter is not the correct type. "
+ "It must be type String or the same type as the underlying type "
+ "of the Enum.");
}
throw new InvalidOperationException ("Unknown enum type.");
}
static bool IsValidEnumType (Type type)
{
return (type.IsPrimitive && type != typeof (double) && type != typeof (float));
}
[MethodImplAttribute (MethodImplOptions.InternalCall)]
@ -614,7 +678,6 @@ namespace System
return true;
}
#if NET_4_0
public static bool TryParse<TEnum> (string value, out TEnum result) where TEnum : struct
{
return TryParse (value, false, out result);
@ -637,7 +700,6 @@ namespace System
return Parse (tenum_type, value, ignoreCase, out result);
}
#endif
[MethodImplAttribute (MethodImplOptions.InternalCall)]
private extern int compare_value_to (object other);
@ -994,15 +1056,18 @@ namespace System
"\"x\",\"F\",\"f\",\"D\" or \"d\".");
}
#if NET_4_0
[MethodImplAttribute (MethodImplOptions.InternalCall)]
private static extern bool InternalHasFlag (Enum a, Enum b);
public bool HasFlag (Enum flag)
{
var val = get_value ();
ulong mvalue = GetValue (val, Type.GetTypeCode (val.GetType ()));
ulong fvalue = GetValue (flag, Type.GetTypeCode (flag.GetType ()));
if (flag == null)
throw new ArgumentNullException ("flag");
return ((mvalue & fvalue) == fvalue);
if (!this.GetType ().IsEquivalentTo (flag.GetType ()))
throw new ArgumentException (Environment.GetResourceString ("Argument_EnumTypeDoesNotMatch", flag.GetType (), this.GetType ()));
return InternalHasFlag (this, flag);
}
#endif
}
}