diff --git a/Baselib/Baselib.csproj b/Baselib/Baselib.csproj index ab1ff3b..712ea2b 100644 --- a/Baselib/Baselib.csproj +++ b/Baselib/Baselib.csproj @@ -17,6 +17,7 @@ + diff --git a/Baselib/src/System/AppDomain.cs b/Baselib/src/System/AppDomain.cs index 1fe9ce0..d5a3842 100644 --- a/Baselib/src/System/AppDomain.cs +++ b/Baselib/src/System/AppDomain.cs @@ -3,7 +3,6 @@ namespace system { public sealed class AppDomain { - public static AppDomain CurrentDomain => System.Threading.LazyInitializer.EnsureInitialized(ref theInstance); @@ -18,5 +17,71 @@ namespace system } private static AppDomain theInstance; + + + + // + // GetAssemblies + // + + public System.Reflection.Assembly[] GetAssemblies() + { + var classLoaderObject = + ((java.lang.Object) (object) this).getClass().getClassLoader(); + InitClassLoaderFields(classLoaderObject); + var domains = (java.util.Set) Util.JavaUnsafe.getObject( + classLoaderObject, _DomainsOffset); + int n = domains.size(); + int i = 0; + var assemblies = new System.Reflection.Assembly[n]; + for (var it = domains.iterator(); it.hasNext() && i < n; i++) + { + var domain = (java.security.ProtectionDomain) it.next(); + assemblies[i] = + system.reflection.RuntimeAssembly.GetAssemblyForDomain(domain); + } + return assemblies; + } + + // + // GetClassesInAssembly + // + + public java.util.Vector GetAllClasses() + { + var classLoaderObject = + ((java.lang.Object) (object) this).getClass().getClassLoader(); + InitClassLoaderFields(classLoaderObject); + return (java.util.Vector) Util.JavaUnsafe.getObject( + classLoaderObject, _ClassesOffset); + } + + // + // InitClassLoaderFields + // + + private void InitClassLoaderFields(java.lang.ClassLoader classLoaderObject) + { + if (_ClassesOffset == -1 || _DomainsOffset == -1) + { + var classLoaderClass = + ((java.lang.Object) (object) classLoaderObject).getClass(); + for (;;) + { + if (classLoaderClass == + (java.lang.Class) typeof(java.lang.ClassLoader)) + break; + classLoaderClass = classLoaderClass.getSuperclass(); + } + + _ClassesOffset = Util.JavaUnsafe.objectFieldOffset( + classLoaderClass.getDeclaredField("classes")); + _DomainsOffset = Util.JavaUnsafe.objectFieldOffset( + classLoaderClass.getDeclaredField("domains")); + } + } + + [java.attr.RetainType] static long _ClassesOffset = -1; + [java.attr.RetainType] static long _DomainsOffset = -1; } } diff --git a/Baselib/src/System/Array.cs b/Baselib/src/System/Array.cs index ecbc643..77a17a2 100644 --- a/Baselib/src/System/Array.cs +++ b/Baselib/src/System/Array.cs @@ -1427,10 +1427,10 @@ namespace system (exc) => new System.IndexOutOfRangeException(exc.getMessage()) ); - system.Util.DefineException( + /*system.Util.DefineException( (java.lang.Class) typeof(java.util.ConcurrentModificationException), (exc) => new System.InvalidOperationException(exc.getMessage()) - ); + );*/ system.Util.DefineException( (java.lang.Class) typeof(java.lang.ArrayStoreException), diff --git a/Baselib/src/System/Boolean.cs b/Baselib/src/System/Boolean.cs index f9e0c9f..7cd832c 100644 --- a/Baselib/src/System/Boolean.cs +++ b/Baselib/src/System/Boolean.cs @@ -3,7 +3,8 @@ namespace system { public class Boolean : system.ValueType, system.ValueMethod, java.lang.Cloneable, - System.IConvertible + System.IComparable, System.IComparable, + System.IConvertible, System.IEquatable { [java.attr.RetainType] protected int v; @@ -36,6 +37,33 @@ namespace system public override string ToString() => Get() != 0 ? "True" : "False"; + public string ToString(System.IFormatProvider provider) => ToString(); + + + + // System.IEquatable + public bool Equals(bool v) => (Get() != 0 ? v : (! v)); + + + + // System.IComparable + public virtual int CompareTo(object obj) + { + if (obj is Boolean objBoolean) + return CompareTo(objBoolean.Get() != 0 ? true : false); + else if (object.ReferenceEquals(obj, null)) + return 1; + throw new System.ArgumentException(); + } + + // System.IComparable + public int CompareTo(bool b) + { + return (Get() == 0) ? (b ? -1 : 0) + : (b ? 0 : 1); + } + + void ValueMethod.Clear() => Set(0); void ValueMethod.CopyTo(ValueType into) => ((Boolean) into).Set(Get()); @@ -63,8 +91,6 @@ namespace system // CodeNumber.Indirection methods // - - public int Get_U8() => (byte) Get(); public int Get_I8() => Get(); public void Set_I8(int v) => Set(v); @@ -92,8 +118,6 @@ namespace system // IConvertible // - - public System.TypeCode GetTypeCode() => System.TypeCode.Boolean; bool System.IConvertible.ToBoolean(System.IFormatProvider provider) @@ -123,11 +147,9 @@ namespace system System.Decimal System.IConvertible.ToDecimal(System.IFormatProvider provider) => System.Convert.ToDecimal(Get()); System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider provider) - => throw new System.InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo_Int32_DateTime")); - string System.IConvertible.ToString(System.IFormatProvider provider) - => ToString(); + => throw new System.InvalidCastException(); object System.IConvertible.ToType(System.Type type, System.IFormatProvider provider) - => null;//System.Convert.DefaultToType((System.IConvertible) this, type, provider); + => system.Convert.DefaultToType((System.IConvertible) this, type, provider); diff --git a/Baselib/src/System/Byte.cs b/Baselib/src/System/Byte.cs index e0922b1..6d25168 100644 --- a/Baselib/src/System/Byte.cs +++ b/Baselib/src/System/Byte.cs @@ -2,7 +2,8 @@ namespace system { - public class SByte : system.ValueType, system.ValueMethod, + public class SByte : system.ValueType, system.ValueMethod, java.lang.Cloneable, + System.IComparable, System.IComparable, System.IConvertible, System.IEquatable, System.IFormattable { @@ -44,8 +45,31 @@ namespace system { if (string.IsNullOrEmpty(format)) return ToString(); - return ParseNumbers.FormatNumber( - (java.lang.String) (object) format, provider, java.lang.Integer.valueOf(Get())); + return ParseNumbers.FormatNumber((java.lang.String) (object) format, provider, + java.lang.Integer.valueOf(Get())); + } + + public string ToString(string format) => ToString(format, null); + + public string ToString(System.IFormatProvider provider) => ToString(); + + + + // System.IComparable + public virtual int CompareTo(object obj) + { + if (obj is SByte objSByte) + return CompareTo((sbyte) objSByte.Get()); + else if (object.ReferenceEquals(obj, null)) + return 1; + throw new System.ArgumentException(); + } + + // System.IComparable + public int CompareTo(sbyte b) + { + var a = Get(); + return (a < b ? -1 : a > b ? 1 : 0); } @@ -76,8 +100,6 @@ namespace system // CodeNumber.Indirection methods // - - public int Get_U8() => (byte) Get(); public int Get_I8() => (sbyte) Get(); public void Set_I8(int v) => Set((int) ((byte) v | ((uint) Get() & (uint) 0xFFFFFF00))); @@ -105,8 +127,6 @@ namespace system // IConvertible // - - public virtual System.TypeCode GetTypeCode() => System.TypeCode.SByte; bool System.IConvertible.ToBoolean(System.IFormatProvider provider) @@ -136,11 +156,9 @@ namespace system System.Decimal System.IConvertible.ToDecimal(System.IFormatProvider provider) => System.Convert.ToDecimal(Get()); System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider provider) - => throw new System.InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo_Int32_DateTime")); - string System.IConvertible.ToString(System.IFormatProvider provider) - => ToString(); + => throw new System.InvalidCastException(); object System.IConvertible.ToType(System.Type type, System.IFormatProvider provider) - => null;//System.Convert.DefaultToType((System.IConvertible) this, type, provider); + => system.Convert.DefaultToType((System.IConvertible) this, type, provider); @@ -173,7 +191,7 @@ namespace system #pragma warning disable 0659 - public class Byte : SByte, System.IEquatable + public class Byte : SByte, System.IComparable, System.IEquatable { new public static Byte Box(int v) => new Byte() { v = (sbyte) v }; @@ -188,12 +206,26 @@ namespace system return (objByte != null && objByte.Get() == Get()); } - // System.IEquatable + // System.IEquatable public bool Equals(byte v) => v == Get(); public override System.TypeCode GetTypeCode() => System.TypeCode.Byte; + // System.IComparable + public override int CompareTo(object obj) + { + if (obj is Byte objByte) + return CompareTo((byte) objByte.Get()); + else if (object.ReferenceEquals(obj, null)) + return 1; + throw new System.ArgumentException(); + } + // System.IComparable + public int CompareTo(byte v) => CompareTo((sbyte) Get(), (sbyte) v); + + public static int CompareTo(sbyte a, sbyte b) + => a == b ? 0 : (a & 0xFF) < (b & 0xFF) ? -1 : 1; // diff --git a/Baselib/src/System/Char.cs b/Baselib/src/System/Char.cs index 4f94049..a3ab8f3 100644 --- a/Baselib/src/System/Char.cs +++ b/Baselib/src/System/Char.cs @@ -2,7 +2,8 @@ namespace system { - public class Char : system.ValueType, system.ValueMethod, + public class Char : system.ValueType, system.ValueMethod, java.lang.Cloneable, + System.IComparable, System.IComparable, System.IConvertible, System.IEquatable { @@ -41,13 +42,27 @@ namespace system public override string ToString() => java.lang.String.valueOf((char) Get()); - /*public string ToString(IFormatProvider provider) - { - return java.lang.String.valueOf(Get(this)); - }*/ + public string ToString(System.IFormatProvider provider) => ToString(); public static string ToString(char c) => java.lang.String.valueOf(c); + + + // System.IComparable + public virtual int CompareTo(object obj) + { + if (obj is Char objChar) + return CompareTo(objChar.Get()); + else if (object.ReferenceEquals(obj, null)) + return 1; + throw new System.ArgumentException(); + } + + // System.IComparable + public int CompareTo(char b) => Get() - ((int) b); + + + //public static char ToUpper(char c, system.globalization.CultureInfo cultureInfo) public static char ToUpperInvariant(char c) => @@ -66,8 +81,7 @@ namespace system static char StringCharAt(string str, int idx) { - if (str == null) - throw new System.ArgumentNullException(); + ThrowHelper.ThrowIfNull(str); if ((uint) idx >= (uint) str.Length) throw new System.ArgumentOutOfRangeException(); return str[idx]; @@ -97,8 +111,6 @@ namespace system // CodeNumber.Indirection methods // - - public int Get_U8() => (byte) Get(); public int Get_I8() => Get(); public void Set_I8(int v) => Set(v); @@ -122,8 +134,6 @@ namespace system // IConvertible // - - public System.TypeCode GetTypeCode() => System.TypeCode.Char; bool System.IConvertible.ToBoolean(System.IFormatProvider provider) @@ -153,11 +163,9 @@ namespace system System.Decimal System.IConvertible.ToDecimal(System.IFormatProvider provider) => System.Convert.ToDecimal(Get()); System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider provider) - => throw new System.InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo_Int32_DateTime")); - string System.IConvertible.ToString(System.IFormatProvider provider) - => ToString(); + => throw new System.InvalidCastException(); object System.IConvertible.ToType(System.Type type, System.IFormatProvider provider) - => null;//System.Convert.DefaultToType((System.IConvertible) this, type, provider); + => system.Convert.DefaultToType((System.IConvertible) this, type, provider); diff --git a/Baselib/src/System/Double.cs b/Baselib/src/System/Double.cs index 10c04c6..e8b6829 100644 --- a/Baselib/src/System/Double.cs +++ b/Baselib/src/System/Double.cs @@ -2,7 +2,8 @@ namespace system { - public class Double : system.ValueType, system.ValueMethod, + public class Double : system.ValueType, system.ValueMethod, java.lang.Cloneable, + System.IComparable, System.IComparable, System.IConvertible, System.IEquatable, System.IFormattable { @@ -56,6 +57,29 @@ namespace system (java.lang.String) (object) format, provider, java.lang.Double.valueOf(Get())); } + public string ToString(string format) => ToString(format, null); + + public string ToString(System.IFormatProvider provider) => ToString(); + + + + // System.IComparable + public virtual int CompareTo(object obj) + { + if (obj is Double objDouble) + return CompareTo(objDouble.Get()); + else if (object.ReferenceEquals(obj, null)) + return 1; + throw new System.ArgumentException(); + } + + // System.IComparable + public int CompareTo(double b) + { + var a = Get(); + return (a < b ? -1 : a > b ? 1 : 0); + } + void ValueMethod.Clear() => Set(0); @@ -119,8 +143,6 @@ namespace system // IConvertible // - - public System.TypeCode GetTypeCode() => System.TypeCode.Double; bool System.IConvertible.ToBoolean(System.IFormatProvider provider) @@ -150,11 +172,9 @@ namespace system System.Decimal System.IConvertible.ToDecimal(System.IFormatProvider provider) => System.Convert.ToDecimal(Get()); System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider provider) - => throw new System.InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo_Int32_DateTime")); - string System.IConvertible.ToString(System.IFormatProvider provider) - => ToString(); + => throw new System.InvalidCastException(); object System.IConvertible.ToType(System.Type type, System.IFormatProvider provider) - => null;//System.Convert.DefaultToType((System.IConvertible) this, type, provider); + => system.Convert.DefaultToType((System.IConvertible) this, type, provider); diff --git a/Baselib/src/System/GenericType.cs b/Baselib/src/System/GenericType.cs index c3c83de..820eba2 100644 --- a/Baselib/src/System/GenericType.cs +++ b/Baselib/src/System/GenericType.cs @@ -121,18 +121,27 @@ namespace system if (genericObject.TryCast(castToType) != null) return obj; if (obj is system.Array.ProxySyncRoot objArray) - { - var proxy = Array.GetProxy(objArray.SyncRoot, castToType, false); - if (proxy != null) - return proxy; - } + obj = objArray.SyncRoot; } - else + + if (obj != null) { + // handle the cases where ShouldCallGenericCast in GenericUtil + // identifies an interface that should be implemented by an + // array object, or a string var proxy = Array.GetProxy(obj, castToType, false); if (proxy != null) return proxy; + + // check if the object (which might not be array or string) + // can actually be cast to the target type + if ( (! castToType.IsGenericType) + && castToType is RuntimeType castToRuntimeType + && castToRuntimeType.JavaClassForArray() + .isAssignableFrom(((java.lang.Object) obj).getClass())) + return obj; } + if (@throw) ThrowInvalidCastException(obj, castToType); return null; diff --git a/Baselib/src/System/Globalization/CompareInfo.cs b/Baselib/src/System/Globalization/CompareInfo.cs index c0ab4a8..4f2a886 100644 --- a/Baselib/src/System/Globalization/CompareInfo.cs +++ b/Baselib/src/System/Globalization/CompareInfo.cs @@ -44,6 +44,21 @@ namespace system.globalization { JavaBreakIter = java.text.BreakIterator.getCharacterInstance(locale); } + // + // Equals + // + + public override bool Equals(object other) + => other is CompareInfo otherCompareInfo && Name == otherCompareInfo.Name; + + public override int GetHashCode() => Name.GetHashCode(); + + public string Name => CultureInfoRef.Name; + + public override string ToString() => "CompareInfo - " + CultureInfoRef.ToString(); + + + // // GetCompareInfo // @@ -57,12 +72,6 @@ namespace system.globalization { public static CompareInfo InvariantCompareInfo => system.globalization.CultureInfo.InvariantCulture.CompareInfo; - // - // - // - - public override string ToString() => "CompareInfo - " + CultureInfoRef.ToString(); - // @@ -95,6 +104,166 @@ namespace system.globalization { return true; } + + + // + // Compare (public API) + // + + public virtual int Compare(string string1, string string2) + => CompareString(string1, 0, -1, string2, 0, -1, CompareOptions.None); + + public virtual int Compare(string string1, string string2, CompareOptions options) + => CompareString(string1, 0, -1, string2, 0, -1, options); + + public virtual int Compare(string string1, int offset1, string string2, int offset2) + => CompareString(string1, offset1, -1, string2, offset2, -1, CompareOptions.None); + + public virtual int Compare(string string1, int offset1, string string2, int offset2, + CompareOptions options) + => CompareString(string1, offset1, -1, string2, offset2, -1, options); + + public virtual int Compare(string string1, int offset1, int length1, + string string2, int offset2, int length2) + { + if (length1 < 0 || length2 < 0) + throw new ArgumentOutOfRangeException(); + return CompareString(string1, offset1, length1, string2, offset2, length2, CompareOptions.None); + } + + public virtual int Compare(string string1, int offset1, int length1, + string string2, int offset2, int length2, + CompareOptions options) + { + if (length1 < 0 || length2 < 0) + throw new ArgumentOutOfRangeException(); + return CompareString(string1, offset1, length1, string2, offset2, length2, options); + } + + // + // CompareString (internal method) + // + + private int CompareString(string string1, int offset1, int length1, + string string2, int offset2, int length2, + CompareOptions options) + { + if (offset1 < 0 || offset2 < 0) + throw new ArgumentOutOfRangeException(); + int endOffset1 = GetEndOffset(string1, offset1, length1); + int endOffset2 = GetEndOffset(string2, offset2, length2); + + if (string1 == null) + return (string2 == null) ? 0 : -1; + else if (string2 == null) + return 1; + + if ((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) != 0) + { + bool ignoreCase; + if (options == CompareOptions.Ordinal) + ignoreCase = false; + else if (options == CompareOptions.OrdinalIgnoreCase) + ignoreCase = true; + else + throw new System.ArgumentException(); + + return CompareStringOrdinal(string1, offset1, endOffset1, + string2, offset2, endOffset2, + ignoreCase); + } + else + { + return CompareStringCulture(string1, offset1, endOffset1, + string2, offset2, endOffset2, + CompareOptionsToCollatorMask(options)); + } + + static int GetEndOffset(string str, int ofs, int len) + { + if (str == null) + { + if (ofs == 0 && len <= 0) + return -1; + } + else + { + int strLen = ((java.lang.String) (object) str).length(); + if (len == -1) + { + if (ofs < strLen) + return strLen; + } + else if ((ofs += len) <= strLen) + return ofs; + } + throw new ArgumentOutOfRangeException(); + } + } + + // + // CompareStringOrdinal (internal method) + // + + private static int CompareStringOrdinal(string string1, int index1, int endIndex1, + string string2, int index2, int endIndex2, + bool ignoreCase) + { + var str1 = (java.lang.String) (object) + (((java.lang.String) (object) string1).substring(index1, endIndex1)); + var str2 = (java.lang.String) (object) + (((java.lang.String) (object) string2).substring(index2, endIndex2)); + return ignoreCase ? str1.compareToIgnoreCase(str2) : str1.compareTo(str2); + } + + // + // CompareStringCulture (internal method) + // + + private int CompareStringCulture(string string1, int index1, int endIndex1, + string string2, int index2, int endIndex2, + uint mask) + { + // create iterators for the two strings. see also IndexOfStringCulture + + var iterator1 = new Iterator(this, mask, + new java.text.StringCharacterIterator( + string1, index1, endIndex1, index1)); + + var iterator2 = new Iterator(this, mask, + new java.text.StringCharacterIterator( + string2, index2, endIndex2, index2)); + + for (;;) + { + var order1 = iterator1.Next(); + var order2 = iterator2.Next(); + + if (order1 == null) + return (order2 == null) ? 0 : -1; + else if (order2 == null) + return 1; + + int n1 = order1.Length; + int n2 = order2.Length; + int n = (n1 <= n2) ? n1 : n2; + for (int i = 0; i < n; i++) + { + int o1 = order1[i]; + int o2 = order2[i]; + if (o1 != o2) + return o1 - o2; + if (o1 == 0) + break; + } + + if (n1 != n2) + return n1 - n2; + } + } + + + // // IndexOf (char, public API) // @@ -255,12 +424,12 @@ namespace system.globalization { // public static int IndexOfString(string source, string value, int startIndex, - CompareOptions options, CompareInfo compareInfo) + CompareOptions options, CompareInfo compareInfo) { ThrowHelper.ThrowIfNull(source); int sourceLength = ((java.lang.String) (object) source).length(); - if (startIndex >= sourceLength) + if (startIndex < 0 || startIndex >= sourceLength) throw new System.ArgumentOutOfRangeException(); if (options == CompareOptions.Ordinal) @@ -620,7 +789,7 @@ namespace system.globalization { int sourceLength = ((java.lang.String) (object) source).length(); if (! haveStartIndex) startIndex = sourceLength - 1; - else if (startIndex >= sourceLength) + else if (startIndex < 0 || startIndex >= sourceLength) throw new System.ArgumentOutOfRangeException(); if (options == CompareOptions.Ordinal) @@ -1359,7 +1528,7 @@ namespace system.globalization { else if (small.sequence[S] == 0) { // if the small sequence ends before the large sequence, - // this cannot be a made. this is to correctly emulate + // this cannot be a match. this is to correctly emulate // the .Net comparison, where, for example, a search for // just "A" cannot match the (AE) symbol. diff --git a/Baselib/src/System/Globalization/CultureInfo.cs b/Baselib/src/System/Globalization/CultureInfo.cs index b3a706f..b344f8a 100644 --- a/Baselib/src/System/Globalization/CultureInfo.cs +++ b/Baselib/src/System/Globalization/CultureInfo.cs @@ -8,6 +8,7 @@ namespace system.globalization { [java.attr.RetainType] java.util.Locale JavaLocale; [java.attr.RetainType] volatile CompareInfo CompareInfoRef; + [java.attr.RetainType] volatile TextInfo TextInfoRef; @@ -42,6 +43,7 @@ namespace system.globalization { } JavaLocale = locale; CompareInfoRef = new CompareInfo(this, JavaLocale); + TextInfoRef = new TextInfo(this, JavaLocale); } @@ -92,6 +94,8 @@ namespace system.globalization { public virtual CompareInfo CompareInfo => CompareInfoRef; + public virtual TextInfo TextInfo => TextInfoRef; + public static CultureInfo CurrentCulture => system.threading.Thread.CurrentThread.CurrentCulture; diff --git a/Baselib/src/System/Globalization/TextInfo.cs b/Baselib/src/System/Globalization/TextInfo.cs new file mode 100644 index 0000000..be4cec2 --- /dev/null +++ b/Baselib/src/System/Globalization/TextInfo.cs @@ -0,0 +1,85 @@ + +using System; +using System.Runtime.Serialization; + +namespace system.globalization { + + [Serializable] + public class TextInfo : ICloneable, IDeserializationCallback + { + [java.attr.RetainType] CultureInfo CultureInfoRef; + [java.attr.RetainType] java.util.Locale JavaLocale; + + // + // called by CultureInfo + // + + public TextInfo(CultureInfo cultureInfo, java.util.Locale locale) + { + CultureInfoRef = cultureInfo; + JavaLocale = locale; + } + + // + // + // + + public static TextInfo CurrentTextInfo + => system.threading.Thread.CurrentThread.CurrentCulture.TextInfo; + + public static TextInfo InvariantTextInfo + => system.globalization.CultureInfo.InvariantCulture.TextInfo; + + // + // ToLower, ToUpper, ToTitleCase + // + + public virtual char ToLower(char c) + => ((java.lang.String) (object) + ((java.lang.String) (object) java.lang.String.valueOf(c)) + .toLowerCase(JavaLocale)).charAt(0); + + public virtual string ToLower(string s) + => ((java.lang.String) (object) s).toLowerCase(JavaLocale); + + public virtual char ToUpper(char c) + => ((java.lang.String) (object) + ((java.lang.String) (object) java.lang.String.valueOf(c)) + .toUpperCase(JavaLocale)).charAt(0); + + public virtual string ToUpper(string s) + => ((java.lang.String) (object) s).toUpperCase(JavaLocale); + + public virtual char ToTitleCase(string s) + { + // java.lang.Character.toTitleCase(java.lang.String.toUpperCase(locale)) + throw new System.PlatformNotSupportedException(); + } + + // + // Equals + // + + public override bool Equals(object other) + => other is TextInfo otherTextInfo && CultureName == otherTextInfo.CultureName; + + public override int GetHashCode() => CultureName.GetHashCode(); + + public string CultureName => CultureInfoRef.Name; + + public override string ToString() => "TextInfo - " + CultureInfoRef.ToString(); + + public bool IsReadOnly => true; + + public virtual object Clone() => MemberwiseClone(); + + // + // + // + + void IDeserializationCallback.OnDeserialization(object sender) + => throw new PlatformNotSupportedException(); + + } + +} diff --git a/Baselib/src/System/Int16.cs b/Baselib/src/System/Int16.cs index 9f9fbf9..8314ec2 100644 --- a/Baselib/src/System/Int16.cs +++ b/Baselib/src/System/Int16.cs @@ -2,7 +2,7 @@ namespace system { - public class Int16 : system.ValueType, system.ValueMethod, + public class Int16 : system.ValueType, system.ValueMethod, java.lang.Cloneable, System.IComparable, System.IComparable, System.IConvertible, System.IEquatable, System.IFormattable { @@ -58,17 +58,17 @@ namespace system // System.IComparable public virtual int CompareTo(object obj) { - if (object.ReferenceEquals(obj, null)) - return 1; if (obj is Int16 objInt16) return CompareTo((short) objInt16.Get()); + else if (object.ReferenceEquals(obj, null)) + return 1; throw new System.ArgumentException(); } // System.IComparable public int CompareTo(short b) { - int a = Get(); + var a = Get(); return (a < b ? -1 : a > b ? 1 : 0); } @@ -215,10 +215,10 @@ namespace system // System.IComparable public override int CompareTo(object obj) { - if (object.ReferenceEquals(obj, null)) - return 1; if (obj is UInt16 objUInt16) return CompareTo((ushort) objUInt16.Get()); + else if (object.ReferenceEquals(obj, null)) + return 1; throw new System.ArgumentException(); } diff --git a/Baselib/src/System/Int32.cs b/Baselib/src/System/Int32.cs index 54f62ec..830a30e 100644 --- a/Baselib/src/System/Int32.cs +++ b/Baselib/src/System/Int32.cs @@ -2,7 +2,7 @@ namespace system { - public class Int32 : system.ValueType, system.ValueMethod, + public class Int32 : system.ValueType, system.ValueMethod, java.lang.Cloneable, System.IComparable, System.IComparable, System.IConvertible, System.IEquatable, System.IFormattable { @@ -58,20 +58,22 @@ namespace system public string ToString(System.IFormatProvider provider) => ToString(); + + // System.IComparable public virtual int CompareTo(object obj) { - if (object.ReferenceEquals(obj, null)) - return 1; if (obj is Int32 objInt32) return CompareTo((int) objInt32.Get()); + else if (object.ReferenceEquals(obj, null)) + return 1; throw new System.ArgumentException(); } // System.IComparable public int CompareTo(int b) { - int a = Get(); + var a = Get(); return (a < b ? -1 : a > b ? 1 : 0); } @@ -151,8 +153,6 @@ namespace system // CodeNumber.Indirection methods // - - public int Get_U8() => (byte) Get(); public int Get_I8() => (sbyte) Get(); public void Set_I8(int v) => Set((int) ((byte) v | ((uint) Get() & (uint) 0xFFFFFF00))); @@ -176,8 +176,6 @@ namespace system // IConvertible // - - public virtual System.TypeCode GetTypeCode() => System.TypeCode.Int32; bool System.IConvertible.ToBoolean(System.IFormatProvider provider) @@ -273,10 +271,10 @@ namespace system // System.IComparable public override int CompareTo(object obj) { - if (object.ReferenceEquals(obj, null)) - return 1; if (obj is UInt32 objUInt32) return CompareTo((uint) objUInt32.Get()); + else if (object.ReferenceEquals(obj, null)) + return 1; throw new System.ArgumentException(); } diff --git a/Baselib/src/System/Int64.cs b/Baselib/src/System/Int64.cs index c1ab858..f865b5e 100644 --- a/Baselib/src/System/Int64.cs +++ b/Baselib/src/System/Int64.cs @@ -2,7 +2,8 @@ namespace system { - public class Int64 : system.ValueType, system.ValueMethod, + public class Int64 : system.ValueType, system.ValueMethod, java.lang.Cloneable, + System.IComparable, System.IComparable, System.IConvertible, System.IEquatable, System.IFormattable { @@ -63,6 +64,25 @@ namespace system + // System.IComparable + public virtual int CompareTo(object obj) + { + if (obj is Int64 objInt64) + return CompareTo((long) objInt64.Get()); + else if (object.ReferenceEquals(obj, null)) + return 1; + throw new System.ArgumentException(); + } + + // System.IComparable + public int CompareTo(long b) + { + var a = Get(); + return (a < b ? -1 : a > b ? 1 : 0); + } + + + public static long OverflowAdd(long a, long b) { long c = a + b; @@ -123,8 +143,6 @@ namespace system // CodeNumber.Indirection methods // - - public int Get_U8() => (byte) Get(); public int Get_I8() => (sbyte) Get(); public void Set_I8(int v) => Set((int) ((byte) v | ((ulong) Get() & (ulong) 0xFFFFFFFFFFFFFF00))); @@ -148,8 +166,6 @@ namespace system // IConvertible // - - public virtual System.TypeCode GetTypeCode() => System.TypeCode.Int64; bool System.IConvertible.ToBoolean(System.IFormatProvider provider) @@ -227,12 +243,14 @@ namespace system public static int Size => 8; public static readonly IntPtr Zero = new IntPtr(0); + + new public static IntPtr Box(long v) => new IntPtr(v); } #pragma warning disable 0659 - public class UInt64 : Int64, System.IEquatable + public class UInt64 : Int64, System.IComparable, System.IEquatable { new public static UInt64 Box(long v) => new UInt64() { v = v }; @@ -255,8 +273,17 @@ namespace system public override System.TypeCode GetTypeCode() => System.TypeCode.UInt64; - //public int CompareTo(ulong v) => java.lang.Long.compareUnsigned(Get(), (long) v); + // System.IComparable + public override int CompareTo(object obj) + { + if (obj is UInt64 objUInt64) + return CompareTo((ulong) objUInt64.Get()); + else if (object.ReferenceEquals(obj, null)) + return 1; + throw new System.ArgumentException(); + } + // System.IComparable public int CompareTo(ulong v) => CompareTo(Get(), (long) v); public static int CompareTo(long a, long b) @@ -368,4 +395,19 @@ namespace system } + + + public class UIntPtr : UInt64 + { + + public UIntPtr(int v) => this.v = v; + public UIntPtr(long v) => this.v = v; + + public static int Size => 8; + + public static readonly UIntPtr Zero = new UIntPtr(0); + + new public static UIntPtr Box(long v) => new UIntPtr(v); + } + } diff --git a/Baselib/src/System/Reflection/CustomAttribute.cs b/Baselib/src/System/Reflection/CustomAttribute.cs new file mode 100644 index 0000000..4c2724a --- /dev/null +++ b/Baselib/src/System/Reflection/CustomAttribute.cs @@ -0,0 +1,8 @@ + + +namespace system.reflection +{ + + public struct CustomAttributeTypedArgument { } + +} diff --git a/Baselib/src/System/Reflection/RuntimeAssembly.cs b/Baselib/src/System/Reflection/RuntimeAssembly.cs index 4a324c1..e475550 100644 --- a/Baselib/src/System/Reflection/RuntimeAssembly.cs +++ b/Baselib/src/System/Reflection/RuntimeAssembly.cs @@ -1,6 +1,5 @@ using System; -using System.Reflection; using System.Globalization; using System.Runtime.Serialization; @@ -11,65 +10,93 @@ namespace system.reflection public class RuntimeAssembly : System.Reflection.Assembly, ISerializable { - private java.security.CodeSource JavaCodeSource; + [java.attr.RetainType] private java.security.ProtectionDomain JavaDomain; + private System.Reflection.Module[] theModule; + private static java.util.concurrent.ConcurrentHashMap _DomainToAssemblyMap; // // // - protected RuntimeAssembly(java.security.CodeSource codeSource) + private RuntimeAssembly(java.security.ProtectionDomain domain) { - JavaCodeSource = codeSource; + JavaDomain = domain; } // - // + // GetAssemblyForDomain // - public static RuntimeAssembly GetExecutingAssembly(ref system.threading.StackCrawlMark stackMark) + public static System.Reflection.Assembly GetAssemblyForDomain( + java.security.ProtectionDomain domain) { + if (domain == null) + throw new DllNotFoundException(); + var map = System.Threading.LazyInitializer + .EnsureInitialized( + ref _DomainToAssemblyMap); + var assembly = (RuntimeAssembly) map.get(domain); + if (assembly == null) + { + var newAssembly = new RuntimeAssembly(domain); + assembly = (RuntimeAssembly) + map.putIfAbsent(domain, newAssembly) ?? newAssembly; + } + return assembly; + } + + // + // GetExecutingAssembly + // + + public static RuntimeAssembly GetExecutingAssembly( + ref system.threading.StackCrawlMark stackMark) + { + java.security.ProtectionDomain domain = null; var stackTrace = (new java.lang.Throwable()).getStackTrace(); foreach (var stackElem in stackTrace) { var clsnm = stackElem.getClassName(); if (! clsnm.StartsWith("system.reflection.")) - return GetAssemblyForClass(java.lang.Class.forName(clsnm)); - } - throw new DllNotFoundException(); - } - - static RuntimeAssembly GetAssemblyForClass(java.lang.Class cls) - { - var jar = cls?.getProtectionDomain()?.getCodeSource(); - if (jar != null) - { - var map = System.Threading.LazyInitializer - .EnsureInitialized( - ref _CodeSourceToAssemblyMap); - var assembly = (RuntimeAssembly) map.get(jar); - if (assembly == null) { - var newAssembly = new RuntimeAssembly(jar); - assembly = (RuntimeAssembly) map.putIfAbsent(jar, newAssembly) ?? newAssembly; + domain = java.lang.Class.forName(clsnm)?.getProtectionDomain(); + break; } - return assembly; } - throw new DllNotFoundException(); + return (RuntimeAssembly) GetAssemblyForDomain(domain); } - private static java.util.concurrent.ConcurrentHashMap _CodeSourceToAssemblyMap; + // + // GetModules + // + + public override System.Reflection.Module[] GetModules(bool getResourceModules) + { + return System.Threading.LazyInitializer + .EnsureInitialized(ref theModule, () => + { + var mod = (System.Reflection.Module) (object) + (new RuntimeModule() { JavaDomain = JavaDomain }); + return new System.Reflection.Module[] { mod }; + }); + } // - // + // GetName // public override System.Reflection.AssemblyName GetName(bool copiedName) { - var name = new System.Reflection.AssemblyName(JavaCodeSource.getLocation().getFile()); + var name = new System.Reflection.AssemblyName( + JavaDomain.getCodeSource().getLocation().getFile()); name.Version = new Version(); return name; } + // + // nInit + // + [java.attr.RetainName] public static void nInit(System.Reflection.AssemblyName thisAssemblyName, out RuntimeAssembly assembly, diff --git a/Baselib/src/System/Reflection/RuntimeModule.cs b/Baselib/src/System/Reflection/RuntimeModule.cs index 8b40feb..56dc9d0 100644 --- a/Baselib/src/System/Reflection/RuntimeModule.cs +++ b/Baselib/src/System/Reflection/RuntimeModule.cs @@ -4,10 +4,38 @@ using System.Runtime.InteropServices; namespace system.reflection { - public abstract class Module { } - - public sealed class RuntimeModule + public abstract class Module { + public abstract System.Type[] GetTypes(); + } + + public sealed class RuntimeModule : Module + { + [java.attr.RetainType] public java.security.ProtectionDomain JavaDomain; + + public override System.Type[] GetTypes() + { + for (;;) + { + try + { + var types = new System.Collections.Generic.List(); + + var iterator = AppDomain.CurrentDomain.GetAllClasses().iterator(); + while (iterator.hasNext()) + { + var cls = (java.lang.Class) iterator.next(); + if (cls.getProtectionDomain() == JavaDomain) + types.Add(system.RuntimeType.GetType(cls)); + } + + return types.ToArray(); + } + catch (java.util.ConcurrentModificationException) + { + } + } + } public MetadataImport MetadataImport => _MetadataImport; public StructLayoutAttribute StructLayoutAttribute => _StructLayoutAttribute; diff --git a/Baselib/src/System/Runtime/RuntimeHelpers.cs b/Baselib/src/System/Runtime/RuntimeHelpers.cs index 36f14cc..c916dde 100644 --- a/Baselib/src/System/Runtime/RuntimeHelpers.cs +++ b/Baselib/src/System/Runtime/RuntimeHelpers.cs @@ -16,6 +16,9 @@ namespace system.runtime.compilerservices { return 0; } + public static int GetHashCode(object o) + => (o != null) ? o.GetHashCode() : 0; + } } diff --git a/Baselib/src/System/Single.cs b/Baselib/src/System/Single.cs index 157da55..ae0dddd 100644 --- a/Baselib/src/System/Single.cs +++ b/Baselib/src/System/Single.cs @@ -2,7 +2,8 @@ namespace system { - public class Single : system.ValueType, system.ValueMethod, + public class Single : system.ValueType, system.ValueMethod, java.lang.Cloneable, + System.IComparable, System.IComparable, System.IConvertible, System.IEquatable, System.IFormattable { @@ -44,7 +45,7 @@ namespace system - // System.IEquatable + // System.IEquatable public bool Equals(float v) => v == Get(); // System.IFormattable @@ -56,6 +57,29 @@ namespace system (java.lang.String) (object) format, provider, java.lang.Float.valueOf(Get())); } + public string ToString(string format) => ToString(format, null); + + public string ToString(System.IFormatProvider provider) => ToString(); + + + + // System.IComparable + public virtual int CompareTo(object obj) + { + if (obj is Single objSingle) + return CompareTo(objSingle.Get()); + else if (object.ReferenceEquals(obj, null)) + return 1; + throw new System.ArgumentException(); + } + + // System.IComparable + public int CompareTo(float b) + { + var a = Get(); + return (a < b ? -1 : a > b ? 1 : 0); + } + void ValueMethod.Clear() => Set(0); @@ -84,8 +108,6 @@ namespace system // IConvertible // - - public System.TypeCode GetTypeCode() => System.TypeCode.Single; bool System.IConvertible.ToBoolean(System.IFormatProvider provider) @@ -115,11 +137,9 @@ namespace system System.Decimal System.IConvertible.ToDecimal(System.IFormatProvider provider) => System.Convert.ToDecimal(Get()); System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider provider) - => throw new System.InvalidCastException(Environment.GetResourceString("InvalidCast_FromTo_Int32_DateTime")); - string System.IConvertible.ToString(System.IFormatProvider provider) - => ToString(); + => throw new System.InvalidCastException(); object System.IConvertible.ToType(System.Type type, System.IFormatProvider provider) - => null;//System.Convert.DefaultToType((System.IConvertible) this, type, provider); + => system.Convert.DefaultToType((System.IConvertible) this, type, provider); diff --git a/Baselib/src/System/String.cs b/Baselib/src/System/String.cs index f1426ee..2e597cf 100644 --- a/Baselib/src/System/String.cs +++ b/Baselib/src/System/String.cs @@ -52,36 +52,56 @@ namespace system return new string(buffer); } + // + // ToLower, ToUpper + // + + public static string ToLower(string self) + => system.globalization.TextInfo.CurrentTextInfo.ToLower(self); + + public static string ToLowerInvariant(string self) + => system.globalization.TextInfo.InvariantTextInfo.ToLower(self); + + public static string ToUpper(string self) + => system.globalization.TextInfo.CurrentTextInfo.ToUpper(self); + + public static string ToUpperInvariant(string self) + => system.globalization.TextInfo.InvariantTextInfo.ToUpper(self); + // // Concat object // + static void AppendIfNotNull(java.lang.StringBuilder sb, object obj) + { + if (obj is string) + { + sb.append((string) obj); + } + else if (obj != null) + { + var str = obj.ToString(); + if (str != null) + sb.append(str); + } + } + public static string Concat(object[] objs) { - if (objs == null) - throw new System.ArgumentNullException(); + ThrowHelper.ThrowIfNull(objs); var sb = new java.lang.StringBuilder(); - int n = objs.Length; - for (int i = 0; i < n; i++) - { - var o = objs[i]; - if (o != null) - sb.append(o.ToString()); - } + foreach (var obj in objs) + AppendIfNotNull(sb, obj); return sb.ToString(); } public static string Concat(object objA, object objB, object objC, object objD) { var sb = new java.lang.StringBuilder(); - if (objA != null) - sb.append(objA.ToString()); - if (objB != null) - sb.append(objB.ToString()); - if (objC != null) - sb.append(objC.ToString()); - if (objC != null) - sb.append(objD.ToString()); + AppendIfNotNull(sb, objA); + AppendIfNotNull(sb, objB); + AppendIfNotNull(sb, objC); + AppendIfNotNull(sb, objD); return sb.ToString(); } @@ -96,32 +116,22 @@ namespace system // Concat string // - public static string Concat(params string[] strs) + public static string Concat(string[] strs) { - if (strs == null) - throw new System.ArgumentNullException(); + ThrowHelper.ThrowIfNull(strs); var sb = new java.lang.StringBuilder(); - int n = strs.Length; - for (int i = 0; i < n; i++) - { - var s = strs[i]; - if (s != null) - sb.append(s); - } + foreach (var str in strs) + AppendIfNotNull(sb, str); return sb.ToString(); } public static string Concat(string strA, string strB, string strC, string strD) { var sb = new java.lang.StringBuilder(); - if (strA != null) - sb.append(strA); - if (strB != null) - sb.append(strB); - if (strC != null) - sb.append(strC); - if (strD != null) - sb.append(strD); + AppendIfNotNull(sb, strA); + AppendIfNotNull(sb, strB); + AppendIfNotNull(sb, strC); + AppendIfNotNull(sb, strD); return sb.ToString(); } @@ -134,47 +144,184 @@ namespace system // Concat enumerator // - #if false - [java.attr.RetainName] public static string Concat(System.Collections.Generic.IEnumerable enumerable) { - if (enumerable == null) - throw new System.ArgumentNullException(); + ThrowHelper.ThrowIfNull(enumerable); var sb = new java.lang.StringBuilder(); - using (var enumerator = enumerable.GetEnumerator()) - { - while (enumerator.MoveNext()) - { - var e = enumerator.Current; - if (e != null) - { - string s = e.ToString(); - if (s != null) - sb.append(s); - } - } - } + foreach (var obj in enumerable) + AppendIfNotNull(sb, obj); return sb.ToString(); } - //[java.attr.RetainName] public static string Concat(System.Collections.Generic.IEnumerable enumerable) + => Concat(enumerable); + + // + // Split + // + + public static string[] Split(string str, char[] separator) + => InternalSplit((java.lang.String) (object) str, separator, System.Int32.MaxValue, System.StringSplitOptions.None); + + public static string[] Split(string str, string[] separator) + => InternalSplit((java.lang.String) (object) str, separator, System.Int32.MaxValue, System.StringSplitOptions.None); + + public static string[] Split(string str, char[] separator, int count) + => InternalSplit((java.lang.String) (object) str, separator, count, System.StringSplitOptions.None); + + public static string[] Split(string str, string[] separator, int count) + => InternalSplit((java.lang.String) (object) str, separator, count, System.StringSplitOptions.None); + + public static string[] Split(string str, char[] separator, System.StringSplitOptions options) + => InternalSplit((java.lang.String) (object) str, separator, System.Int32.MaxValue, options); + + public static string[] Split(string str, string[] separator, System.StringSplitOptions options) + => InternalSplit((java.lang.String) (object) str, separator, System.Int32.MaxValue, options); + + public static string[] Split(string str, char[] separator, int count, System.StringSplitOptions options) + => InternalSplit((java.lang.String) (object) str, separator, count, options); + + public static string[] Split(string str, string[] separator, int count, System.StringSplitOptions options) + => InternalSplit((java.lang.String) (object) str, separator, count, options); + + private static string[] InternalSplit(java.lang.String str, + object separator, int count, + System.StringSplitOptions options) { - if (enumerable == null) - throw new System.ArgumentNullException(); - var sb = new java.lang.StringBuilder(); - using (var enumerator = enumerable.GetEnumerator()) + if (count < 0) + throw new System.ArgumentOutOfRangeException(); + + bool omit = (options == System.StringSplitOptions.None) ? false + : (options == System.StringSplitOptions.RemoveEmptyEntries) ? true + : throw new System.ArgumentException(); + + var emptyArray = new string[0]; + if (count == 0) + return emptyArray; + + int length = str.length(); + var list = new java.util.ArrayList(); + + if (separator is char[] charSeparator) + SplitCharacter(str, length, list, count, omit, charSeparator); + else if (separator is java.lang.String[] strSeparator) + SplitString(str, length, list, count, omit, strSeparator); + else // assuming separator is null + SplitWhiteSpace(str, length, list, count, omit); + + return (string[]) list.toArray(emptyArray); + } + + private static void SplitWhiteSpace(java.lang.String str, int length, + java.util.ArrayList list, int maxCount, + bool omit) + { + int listCount = 0; + int lastIndex = -1; + for (int index = 0; index < length; index++) { - while (enumerator.MoveNext()) + if (! Char.IsWhiteSpace(str.charAt(index))) + continue; + if (index == ++lastIndex && omit) + continue; + if (++listCount == maxCount) { - var s = enumerator.Current; - if (s != null) - sb.append(s); + list.add(str.substring(lastIndex)); + return; + } + list.add(str.substring(lastIndex, index)); + lastIndex = index; + } + if (length != ++lastIndex || ! omit) + list.add(str.substring(lastIndex)); + } + + private static void SplitCharacter(java.lang.String str, int length, + java.util.ArrayList list, int maxCount, + bool omit, char[] anyOf) + { + int listCount = 0; + int lastIndex = -1; + for (int index = 0; index < length; index++) + { + if (! CharAtIsAnyOf(str, index, anyOf)) + continue; + if (index == ++lastIndex && omit) + continue; + if (++listCount == maxCount) + { + list.add(str.substring(lastIndex)); + return; + } + list.add(str.substring(lastIndex, index)); + lastIndex = index; + } + if (length != ++lastIndex || ! omit) + list.add(str.substring(lastIndex)); + } + + private static void SplitString(java.lang.String str, int length, + java.util.ArrayList list, int maxCount, + bool omit, java.lang.String[] anyOfStr) + { + int anyOfNum = anyOfStr.Length; + char[] anyOfChar = new char[anyOfNum]; + for (int index = 0; index < anyOfNum; index++) + { + var s = anyOfStr[index]; + anyOfChar[index] = + (s != null && s.length() > 0) ? s.charAt(index) : '\0'; + } + + int listCount = 0; + int lastIndex = 0; + for (int index = 0; index < length; ) + { + int len = StrAtIsAnyOf(str, index, anyOfNum, anyOfChar, anyOfStr); + if (len == -1) + index++; + else + { + if (index != lastIndex || ! omit) + { + if (++listCount == maxCount) + { + list.add(str.substring(lastIndex)); + return; + } + list.add(str.substring(lastIndex, index)); + } + lastIndex = (index += len); } } - return sb.ToString(); + if (length != lastIndex || ! omit) + list.add(str.substring(lastIndex)); + } + + private static bool CharAtIsAnyOf(java.lang.String str, int idx, char[] anyOf) + { + char ch1 = str.charAt(idx); + foreach (var ch2 in anyOf) + if (ch2 == ch1) + return true; + return false; + } + + private static int StrAtIsAnyOf(java.lang.String str, int idx, int anyOfNum, + char[] anyOfChar, java.lang.String[] anyOfStr) + { + char ch = str.charAt(idx); + for (int i = 0; i < anyOfNum; i++) + { + if (anyOfChar[i] == ch) + { + int len = anyOfStr[i].length(); + if (str.regionMatches(idx, anyOfStr[i], 0, len)) + return len; + } + } + return -1; } - #endif // // Join @@ -208,6 +355,56 @@ namespace system }); } + // + // Replace + // + + public static string Replace(java.lang.String str, char oldChar, char newChar) + => str.replace(oldChar, newChar); + + public static string Replace(java.lang.String str, string oldStr, string newStr) + { + ThrowHelper.ThrowIfNull(oldStr); + int lenOld = ((java.lang.String) (object) oldStr).length(); + if (lenOld == 0) + throw new System.ArgumentException(); + + int idx1 = str.indexOf(oldStr, 0); + if (idx1 == -1) + return (string) (object) str; + int idx0 = 0; + int len = str.length(); + var sb = new java.lang.StringBuilder(); + for (;;) + { + sb.append(str.substring(idx0, idx1)); + if (newStr != null) + sb.append(newStr); + if ( (idx0 = idx1 + lenOld) >= len + || (idx1 = str.indexOf(oldStr, idx0)) == -1) + { + sb.append(str.substring(idx0)); + return sb.ToString(); + } + } + } + + // + // Copy + // + + public static string Copy(java.lang.String str) + { + ThrowHelper.ThrowIfNull(str); + return java.lang.String.valueOf(str.toCharArray()); + } + + public static string Intern(java.lang.String str) + { + ThrowHelper.ThrowIfNull(str); + return str.intern(); + } + // // CopyTo // @@ -215,8 +412,7 @@ namespace system public static void CopyTo(java.lang.String str, int sourceIndex, char[] destination, int destinationIndex, int count) { - if (destination == null) - throw new System.ArgumentNullException(); + ThrowHelper.ThrowIfNull(destination); if ( count < 0 || sourceIndex < 0 || destinationIndex < 0 || count > str.length() - sourceIndex || destinationIndex > destination.Length - count) @@ -276,6 +472,196 @@ namespace system + // + // CompareOrdinal + // + + public static int CompareOrdinal(java.lang.String strA, java.lang.String strB) + { + if (object.ReferenceEquals(strA, strB)) + return 0; + if (strA == null) + return -1; + if (strB == null) + return 1; + return strA.compareTo(strB); + } + + public static int CompareOrdinal(java.lang.String strA, int indexA, + java.lang.String strB, int indexB, int length) + { + if (object.ReferenceEquals(strA, strB)) + return 0; + if (strA == null) + return -1; + if (strB == null) + return 1; + int endIndexA, endIndexB; + if ( indexA < 0 || (endIndexA = indexA + length) > strA.length() + || indexB < 0 || (endIndexB = indexB + length) > strB.length()) + throw new System.ArgumentOutOfRangeException(); + return ((java.lang.String) (object) strA.substring(indexA, endIndexA)) + .compareTo((java.lang.String) (object) strB.substring(indexB, endIndexB)); + } + + + + // + // Compare without length + // + + public static int Compare(string strA, string strB) + => system.globalization.CompareInfo.CurrentCompareInfo.Compare(strA, strB, + System.Globalization.CompareOptions.None); + + public static int Compare(string strA, string strB, bool ignoreCase) + => system.globalization.CompareInfo.CurrentCompareInfo.Compare(strA, strB, + ignoreCase ? System.Globalization.CompareOptions.IgnoreCase + : System.Globalization.CompareOptions.None); + + public static int Compare(string strA, string strB, System.StringComparison option) + { + var (compareInfo, compareOption) = StringComparisonToCompareArguments(option); + return compareInfo.Compare(strA, strB, compareOption); + } + + public static int Compare(string strA, string strB, + bool ignoreCase, System.Globalization.CultureInfo culture) + => culture.CompareInfo.Compare(strA, strB, + ignoreCase ? System.Globalization.CompareOptions.IgnoreCase + : System.Globalization.CompareOptions.None); + + public static int Compare(string strA, string strB, + System.Globalization.CultureInfo culture, + System.Globalization.CompareOptions options) + => culture.CompareInfo.Compare(strA, strB, options); + + // + // Compare with length + // + + public static int Compare(string strA, int indexA, string strB, int indexB, int length) + => Compare(strA, indexA, strB, indexB, length, + system.globalization.CompareInfo.CurrentCompareInfo, + System.Globalization.CompareOptions.None); + + public static int Compare(string strA, int indexA, string strB, int indexB, int length, + bool ignoreCase) + => Compare(strA, indexA, strB, indexB, length, + system.globalization.CompareInfo.CurrentCompareInfo, + System.Globalization.CompareOptions.IgnoreCase); + + public static int Compare(string strA, int indexA, string strB, int indexB, int length, + System.StringComparison comparisonType) + { + var (compareInfo, compareOption) = StringComparisonToCompareArguments(comparisonType); + return Compare(strA, indexA, strB, indexB, length, compareInfo, compareOption); + } + + public static int Compare(string strA, int indexA, string strB, int indexB, int length, + bool ignoreCase, system.globalization.CultureInfo culture) + => Compare(strA, indexA, strB, indexB, length, culture.CompareInfo, + ignoreCase ? System.Globalization.CompareOptions.IgnoreCase + : System.Globalization.CompareOptions.None); + + public static int Compare(string strA, int indexA, string strB, int indexB, int length, + system.globalization.CultureInfo culture, + System.Globalization.CompareOptions options) + => Compare(strA, indexA, strB, indexB, length, culture.CompareInfo, options); + + private static int Compare(string strA, int indexA, string strB, int indexB, int length, + system.globalization.CompareInfo compareInfo, + System.Globalization.CompareOptions compareOptions) + { + int lengthA = length; + if (strA != null) + { + int maxlenA = ((java.lang.String) (object) strA).length() - indexA; + if (maxlenA < lengthA) + lengthA = maxlenA; + } + + int lengthB = length; + if (strB != null) + { + int maxlenB = ((java.lang.String) (object) strB).length() - indexB; + if (maxlenB < lengthB) + lengthB = maxlenB; + } + + return compareInfo.Compare( + strA, indexA, lengthA, strB, indexB, lengthB, compareOptions); + } + + + + // + // IndexOfAny, LastIndexOfAny + // + + public static int IndexOfAny(java.lang.String str, char[] anyOf) + => InternalIndexOfAny(str, anyOf, 1, /* index */ true, 0, + /* count */ false, 0); + + public static int IndexOfAny(java.lang.String str, char[] anyOf, int startIndex) + => InternalIndexOfAny(str, anyOf, 1, /* index */ true, startIndex, + /* count */ false, 0); + + public static int IndexOfAny(java.lang.String str, char[] anyOf, int startIndex, int count) + => InternalIndexOfAny(str, anyOf, 1, /* index */ true, startIndex, + /* count */ true, count); + + public static int LastIndexOfAny(java.lang.String str, char[] anyOf) + => InternalIndexOfAny(str, anyOf, -1, /* index */ false, 0, + /* count */ false, 0); + + public static int LastIndexOfAny(java.lang.String str, char[] anyOf, int startIndex) + => InternalIndexOfAny(str, anyOf, -1, /* index */ true, startIndex, + /* count */ false, 0); + + public static int LastIndexOfAny(java.lang.String str, char[] anyOf, int startIndex, int count) + => InternalIndexOfAny(str, anyOf, -1, /* index */ true, startIndex, + /* count */ true, count); + + private static int InternalIndexOfAny(java.lang.String str, char[] anyOf, int dir, + bool haveStartIndex, int startIndex, + bool haveCount, int count) + { + ThrowHelper.ThrowIfNull(anyOf); + + int length = str.length(); + if (haveCount && count < 0) + throw new System.ArgumentOutOfRangeException(); + int endIndex; + + if (dir == 1) + { + // IndexOfAny + endIndex = haveCount ? (startIndex + count) : length; + if (startIndex < 0 || endIndex > length) + throw new System.ArgumentOutOfRangeException(); + } + else + { + // LastIndexOfAny + if (! haveStartIndex) + startIndex = length - 1; + endIndex = haveCount ? (startIndex - count + 1) : 0; + if (endIndex < 0 || startIndex >= length) + throw new System.ArgumentOutOfRangeException(); + } + + for (int index = startIndex; index != endIndex; index += dir) + { + if (CharAtIsAnyOf(str, index, anyOf)) + return index; + } + + return -1; + } + + + // // IndexOf (char, ordinal) // @@ -475,9 +861,6 @@ namespace system - // - // IndexOfAny - // @@ -501,18 +884,46 @@ namespace system public static bool StartsWith(java.lang.String str, string pfx) { - if (pfx == null) - throw new System.ArgumentNullException(); + ThrowHelper.ThrowIfNull(pfx); return str.startsWith(pfx); } public static bool EndsWith(java.lang.String str, string sfx) { - if (sfx == null) - throw new System.ArgumentNullException(); + ThrowHelper.ThrowIfNull(sfx); return str.endsWith(sfx); } + + + // + // Contains + // + + + + public static bool Contains(java.lang.String large, char small) + => large.indexOf(small, 0) >= 0; + + public static bool Contains(java.lang.String large, string small) + => large.indexOf(small, 0) >= 0; + + public static bool Contains(string large, char small, System.StringComparison option) + { + var (compareInfo, compareOption) = StringComparisonToCompareArguments(option); + return system.globalization.CompareInfo.IndexOfChar( + large, small, 0, compareOption, compareInfo) >= 0; + } + + public static bool Contains(string large, string small, System.StringComparison option) + { + var (compareInfo, compareOption) = StringComparisonToCompareArguments(option); + return system.globalization.CompareInfo.IndexOfString( + large, small, 0, compareOption, compareInfo) >= 0; + } + + + // // // @@ -521,6 +932,18 @@ namespace system public static bool IsNullOrEmpty(java.lang.String str) => (str == null || str.length() == 0); + public static bool IsNullOrWhiteSpace(java.lang.String str) + { + if (str != null) + { + int n = str.length(); + for (int i = 0; i < n; i++) + if (! Char.IsWhiteSpace(str.charAt(i))) + return false; + } + return true; + } + public static char[] ToCharArray(java.lang.String str) => str.toCharArray(); // @@ -582,28 +1005,74 @@ namespace system public static object CreateWrapper(object maybeString, System.Type castToType) { - if ( maybeString is java.lang.String + if ( maybeString is string reallyString && ( object.ReferenceEquals(castToType, cachedComparableString) - || object.ReferenceEquals(castToType, cachedEquatableString))) + || object.ReferenceEquals(castToType, cachedEquatableString) + || object.ReferenceEquals(castToType, cachedIComparable) + || object.ReferenceEquals(castToType, cachedIConvertible))) { - return new Wrapper(maybeString); + return new Wrapper(reallyString); } return null; } [java.attr.RetainType] private static readonly System.Type cachedComparableString; [java.attr.RetainType] private static readonly System.Type cachedEquatableString; + [java.attr.RetainType] private static readonly System.Type cachedIComparable; + [java.attr.RetainType] private static readonly System.Type cachedIConvertible; - class Wrapper : System.IComparable, System.IEquatable + class Wrapper : System.IComparable, System.IEquatable, + System.IComparable, System.IConvertible { - [java.attr.RetainType] private java.lang.String str; - public Wrapper(object _s) => str = (java.lang.String) (object) _s; - // CompareTo implementation is wrong, should be culture sensitive + [java.attr.RetainType] private string str; + public Wrapper(string _s) => str = _s; + // generic CompareTo implementation is culture sensitive public int CompareTo(string other) - => str.compareTo((java.lang.String) (object) other); + => system.String.Compare(str, other); // Equals is not sensitive to culture or case public bool Equals(string other) - => str.@equals((java.lang.String) (object) other); + => ((java.lang.String) (object) str).@equals( + (java.lang.String) (object) other); + // non-generic CompareTo implementation is culture sensitive + public int CompareTo(object other) + { + return (other is string ostr) ? system.String.Compare(str, ostr) + : (other == null) ? 1 + : throw new System.ArgumentException(); + } + // IConvertible + public string ToString(System.IFormatProvider provider) => str; + public System.TypeCode GetTypeCode() => System.TypeCode.String; + bool System.IConvertible.ToBoolean(System.IFormatProvider provider) + => System.Convert.ToBoolean(str, provider); + char System.IConvertible.ToChar(System.IFormatProvider provider) + => System.Convert.ToChar(str, provider); + sbyte System.IConvertible.ToSByte(System.IFormatProvider provider) + => System.Convert.ToSByte(str, provider); + byte System.IConvertible.ToByte(System.IFormatProvider provider) + => System.Convert.ToByte(str, provider); + short System.IConvertible.ToInt16(System.IFormatProvider provider) + => System.Convert.ToInt16(str, provider); + ushort System.IConvertible.ToUInt16(System.IFormatProvider provider) + => System.Convert.ToUInt16(str, provider); + int System.IConvertible.ToInt32(System.IFormatProvider provider) + => System.Convert.ToInt16(str, provider); + uint System.IConvertible.ToUInt32(System.IFormatProvider provider) + => System.Convert.ToUInt32(str, provider); + long System.IConvertible.ToInt64(System.IFormatProvider provider) + => System.Convert.ToInt64(str, provider); + ulong System.IConvertible.ToUInt64(System.IFormatProvider provider) + => System.Convert.ToUInt64(str, provider); + float System.IConvertible.ToSingle(System.IFormatProvider provider) + => System.Convert.ToSingle(str, provider); + double System.IConvertible.ToDouble(System.IFormatProvider provider) + => System.Convert.ToDouble(str, provider); + System.Decimal System.IConvertible.ToDecimal(System.IFormatProvider provider) + => System.Convert.ToDecimal(str, provider); + System.DateTime System.IConvertible.ToDateTime(System.IFormatProvider provider) + => System.Convert.ToDateTime(str, provider); + object System.IConvertible.ToType(System.Type type, System.IFormatProvider provider) + => system.Convert.DefaultToType((System.IConvertible) this, type, provider); } @@ -623,6 +1092,8 @@ namespace system cachedComparableString = typeof(System.IComparable); cachedEquatableString = typeof(System.IEquatable); + cachedIComparable = typeof(System.IComparable); + cachedIConvertible = typeof(System.IConvertible); } } @@ -661,8 +1132,12 @@ namespace java.lang public abstract string toUpperCase(java.util.Locale locale); public abstract string toLowerCase(java.util.Locale locale); public abstract int compareTo(java.lang.String other); + public abstract int compareToIgnoreCase(java.lang.String other); public abstract bool equals(java.lang.String other); + public abstract string intern(); + public abstract string replace(char oldChar, char newChar); [java.attr.Discard] extern public static string format(string fmt, object[] args); [java.attr.Discard] extern public static string valueOf(char c); + [java.attr.Discard] extern public static string valueOf(char[] data); } } diff --git a/Baselib/src/System/Text/RegularExpressions/Match.cs b/Baselib/src/System/Text/RegularExpressions/Match.cs index 6e6d23b..20d602c 100644 --- a/Baselib/src/System/Text/RegularExpressions/Match.cs +++ b/Baselib/src/System/Text/RegularExpressions/Match.cs @@ -15,7 +15,7 @@ namespace system.text.regularexpressions groupCollection = new GroupCollection(this, matcher, input); } - private Match() : base(0, "", 0, 0) + private Match() : base(-1, "", -1, -1) { groupCollection = new GroupCollection(this, null, null); } diff --git a/Baselib/src/System/Text/RegularExpressions/Regex.cs b/Baselib/src/System/Text/RegularExpressions/Regex.cs index 56cac05..988ce5b 100644 --- a/Baselib/src/System/Text/RegularExpressions/Regex.cs +++ b/Baselib/src/System/Text/RegularExpressions/Regex.cs @@ -16,6 +16,49 @@ namespace system.text.regularexpressions JavaPattern = java.util.regex.Pattern.compile(pattern); } + public Regex(string pattern, System.Text.RegularExpressions.RegexOptions options) + { + int flags = 0; + + if ((options & System.Text.RegularExpressions.RegexOptions.CultureInvariant) != 0) + options &= ~System.Text.RegularExpressions.RegexOptions.CultureInvariant; + else + { + flags |= java.util.regex.Pattern.UNICODE_CASE + | java.util.regex.Pattern.CANON_EQ; + } + + if ((options & System.Text.RegularExpressions.RegexOptions.IgnoreCase) != 0) + { + options &= ~System.Text.RegularExpressions.RegexOptions.IgnoreCase; + flags |= java.util.regex.Pattern.CASE_INSENSITIVE; + } + + if ((options & System.Text.RegularExpressions.RegexOptions.IgnorePatternWhitespace) != 0) + { + options &= ~System.Text.RegularExpressions.RegexOptions.IgnorePatternWhitespace; + flags |= java.util.regex.Pattern.COMMENTS; + } + + if ((options & System.Text.RegularExpressions.RegexOptions.Multiline) != 0) + { + options &= ~System.Text.RegularExpressions.RegexOptions.Multiline; + flags |= java.util.regex.Pattern.MULTILINE; + } + + if ((options & System.Text.RegularExpressions.RegexOptions.Singleline) != 0) + { + options &= ~System.Text.RegularExpressions.RegexOptions.Singleline; + flags |= java.util.regex.Pattern.DOTALL; + } + + options &= ~System.Text.RegularExpressions.RegexOptions.Compiled; + if (options != 0) + throw new System.ArgumentOutOfRangeException(); + + JavaPattern = java.util.regex.Pattern.compile(pattern); + } + // // Match // @@ -35,6 +78,50 @@ namespace system.text.regularexpressions public static MatchCollection Matches(string input, string pattern) => new Regex(pattern).Matches(input); + // + // IsMatch + // + + public bool IsMatch(string input) + => Match(input).Success; + + // + // Escape + // + + public static string Escape(string str) + { + int idx1 = str.IndexOfAny(EscapeChars); + if (idx1 == -1) + return str; + int idx0 = 0; + int len = ((java.lang.String) (object) str).length(); + var sb = new java.lang.StringBuilder(); + for (;;) + { + sb.append(((java.lang.String) (object) str).substring(idx0, idx1)); + sb.append('\\'); + var ch = ((java.lang.String) (object) str).charAt(idx1); + if (ch == '\u0009') ch = 't'; + else if (ch == '\u000A') ch = 'n'; + else if (ch == '\u000C') ch = 'f'; + else if (ch == '\u000D') ch = 'r'; + sb.append(ch); + + if ( (idx0 = idx1 + 1) >= len + || (idx1 = str.IndexOfAny(EscapeChars, idx0)) == -1) + { + sb.append(((java.lang.String) (object) str).substring(idx0)); + return sb.ToString(); + } + } + } + + [java.attr.RetainType] private static readonly char[] EscapeChars = { + '\u0009', '\u000A', '\u000C', '\u000D', '\u0020', // spaces + '#', '$', '(', ')', '*', '+', '.', '?', '[', '\\', '^', '{', '|' }; + // |{^\[?.+*)($# SPC(32)TAB(9)0x000D,0x000C, 0x000A,0x0009 + // // ISerializable // diff --git a/Baselib/system.filter b/Baselib/system.filter index 6de524f..4b5eb92 100644 --- a/Baselib/system.filter +++ b/Baselib/system.filter @@ -4,3 +4,5 @@ System.Collections.Generic.Stack`1 System.Collections.Generic.Queue`1 System.ComponentModel.CategoryAttribute + +System.Text.RegularExpressions.RegexOptions diff --git a/CilToJava/src/CilMethod.cs b/CilToJava/src/CilMethod.cs index c9a743e..aa3bb7a 100644 --- a/CilToJava/src/CilMethod.cs +++ b/CilToJava/src/CilMethod.cs @@ -644,6 +644,29 @@ namespace SpaceFlint.CilToJava + public static void FixNameForVirtualToStaticCall(JavaMethodRef method, CilType callClass) + { + // this method is called from CodeCall.ConvertVirtualToStaticCall, + // which converts a virtual call to a static call by inserting an + // initial 'this' parameter. + // if the target method was altered by AppendMethodNameSuffix, + // then we also have to insert the name for that initial 'this'. + + string name = method.Name; + int idx = name.IndexOf(CilMain.OPEN_PARENS); + if (idx != -1) + { + string newName = name.Substring(0, idx) + + CilMain.OPEN_PARENS + + callClass.JavaName.Replace('.', '-') + + CilMain.CLOSE_PARENS + + name.Substring(idx); + method.Name = newName; + } + } + + + internal static bool CompareMethods(MethodDefinition m1, MethodDefinition m2) { if (m1.Name != m2.Name) diff --git a/CilToJava/src/CodeArray.cs b/CilToJava/src/CodeArray.cs index 770cd3c..e057a14 100644 --- a/CilToJava/src/CodeArray.cs +++ b/CilToJava/src/CodeArray.cs @@ -272,7 +272,8 @@ namespace SpaceFlint.CilToJava else { if ( elemType.PrimitiveType == TypeCode.Int16 - && arrayType.PrimitiveType == TypeCode.Char) + && ( arrayType.PrimitiveType == TypeCode.Char + || arrayType.PrimitiveType == TypeCode.UInt16)) { // ldelem.i2 with a char[] array, should be 'caload' not 'saload' elemType = arrayType.AdjustRank(-arrayType.ArrayRank); @@ -358,7 +359,8 @@ namespace SpaceFlint.CilToJava else { if ( elemType.PrimitiveType == TypeCode.Int16 - && arrayType.PrimitiveType == TypeCode.Char) + && ( arrayType.PrimitiveType == TypeCode.Char + || arrayType.PrimitiveType == TypeCode.UInt16)) { // stelem.i2 with a char[] array, should be 'castore' not 'sastore' elemType = arrayType.AdjustRank(-arrayType.ArrayRank); diff --git a/CilToJava/src/CodeCall.cs b/CilToJava/src/CodeCall.cs index 77d4547..bf34c6b 100644 --- a/CilToJava/src/CodeCall.cs +++ b/CilToJava/src/CodeCall.cs @@ -398,6 +398,9 @@ namespace SpaceFlint.CilToJava parameters[0].Type = JavaType.ObjectType; } + else + CilMethod.FixNameForVirtualToStaticCall(tempMethod, callClass); + code.NewInstruction(0xB8 /* invokestatic */, new JavaType(0, 0, callClass.JavaName), tempMethod); diff --git a/CilToJava/src/CodeCompare.cs b/CilToJava/src/CodeCompare.cs index 27264ae..6a4b3e8 100644 --- a/CilToJava/src/CodeCompare.cs +++ b/CilToJava/src/CodeCompare.cs @@ -748,9 +748,15 @@ namespace SpaceFlint.CilToJava } } } - else + + stackMap.ResetLocalsInFrame((ushort) inst.Offset, resetLocals); + + if (inst.OpCode.Code >= Code.Ceq && inst.OpCode.Code <= Code.Clt_Un) { - stackMap.ResetLocalsInFrame((ushort) inst.Offset, resetLocals); + // also reset the additional frame created while processing + // 'ceq'-type instructions, see also method Compare() above + stackMap.ResetLocalsInFrame( + (ushort) (inst.Offset + 1), resetLocals); } inst = inst.Next; diff --git a/CilToJava/src/CodeMisc.cs b/CilToJava/src/CodeMisc.cs index 3432d9c..7acd85d 100644 --- a/CilToJava/src/CodeMisc.cs +++ b/CilToJava/src/CodeMisc.cs @@ -267,12 +267,22 @@ namespace SpaceFlint.CilToJava { var dataType = CilType.From(typeRef); - var stackTop1 = (CilType) code.StackMap.PopStack(CilMain.Where); - var stackTop2 = (CilType) code.StackMap.PopStack(CilMain.Where); - if (CodeSpan.LoadStore(false, stackTop2, null, dataType, code)) + var valueType = (CilType) code.StackMap.PopStack(CilMain.Where); + var intoType = (CilType) code.StackMap.PopStack(CilMain.Where); + if (CodeSpan.LoadStore(false, intoType, null, dataType, code)) return; - code.StackMap.PushStack(stackTop2); - code.StackMap.PushStack(stackTop1); + + if ( (! dataType.IsReference) + && intoType is BoxedType intoBoxedType + && dataType.PrimitiveType == intoBoxedType.UnboxedType.PrimitiveType) + { + // 'stobj primitive' with a primitive value on the stack + intoBoxedType.SetValueOV(code); + return; + } + + code.StackMap.PushStack(intoType); + code.StackMap.PushStack(valueType); GenericUtil.ValueCopy(dataType, code, true); code.StackMap.PopStack(CilMain.Where); diff --git a/CilToJava/src/GenericUtil.cs b/CilToJava/src/GenericUtil.cs index 12908dd..d805cb6 100644 --- a/CilToJava/src/GenericUtil.cs +++ b/CilToJava/src/GenericUtil.cs @@ -768,13 +768,25 @@ namespace SpaceFlint.CilToJava if (fromType.Equals(intoType)) return false; // no, if same type (by value) + // if casting to one of the non-generic types of that a string + // implements, and the source is either a string or an object + + bool fromTypeIsObjectType = fromType.Equals(JavaType.ObjectType); + + if ( (fromTypeIsObjectType || fromType.Equals(JavaType.StringType)) + && ( intoType.JavaName == "system.IComparable" + || intoType.JavaName == "system.IConvertible")) + { + return true; + } + // if casting to one of the types that any array should implememt, // and the castee is an array, or 'object', or one of those types, // then always call TestCast/CallCast, because we might have to // create a helper proxy for an array object - bool fromTypeMayBeArray = ( fromType.ArrayRank != 0 - || fromType.Equals(JavaType.ObjectType) + bool fromTypeMayBeArray = ( fromTypeIsObjectType + || fromType.ArrayRank != 0 || IsArray(fromType.JavaName)); return (fromTypeMayBeArray && IsArray(intoType.JavaName)); diff --git a/Tests/src/TestCompareInfo.cs b/Tests/src/TestString.cs similarity index 56% rename from Tests/src/TestCompareInfo.cs rename to Tests/src/TestString.cs index 16d4b63..2108ef9 100644 --- a/Tests/src/TestCompareInfo.cs +++ b/Tests/src/TestString.cs @@ -6,19 +6,102 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; namespace Tests { [TestClass] - public class TestCompareInfo : BaseTest + public class TestString : BaseTest { public override void TestMain() { - TestIndexOf1(); + TestSplit(); + TestIndexOf(); + TestCompare(); + TestCast("Test"); } - // - // - // - static void TestIndexOf1() + + void TestSplit() + { + // This example demonstrates the String() methods that use + // the StringSplitOptions enumeration. + string s1 = ",ONE,,TWO,,,THREE,,"; + string s2 = "[stop]" + + "ONE[stop][stop]" + + "TWO[stop][stop][stop]" + + "THREE[stop][stop]"; + char[] charSeparators = new char[] {','}; + string[] stringSeparators = new string[] {"[stop]"}; + string[] result; + // ------------------------------------------------------------------------------ + // Split a string delimited by characters. + // ------------------------------------------------------------------------------ + // Display the original string and delimiter characters. + Console.WriteLine("String = \"{0}\" Delimiter = '{1}'", s1, charSeparators[0]); + + // Split a string delimited by characters and return all elements. + Console.Write("Split by char, omit=0: "); + result = s1.Split(charSeparators, StringSplitOptions.None); + Show(result); + + // Split a string delimited by characters and return all non-empty elements. + Console.Write("Split by char, omit=1: "); + result = s1.Split(charSeparators, StringSplitOptions.RemoveEmptyEntries); + Show(result); + + // Split the original string into the string and empty string before the + // delimiter and the remainder of the original string after the delimiter. + Console.Write("Split by char, omit=0, lim=2: "); + result = s1.Split(charSeparators, 2, StringSplitOptions.None); + Show(result); + + // Split the original string into the string after the delimiter and the + // remainder of the original string after the delimiter. + Console.Write("Split by char, omit=1, lim=2: "); + result = s1.Split(charSeparators, 2, StringSplitOptions.RemoveEmptyEntries); + Show(result); + + // ------------------------------------------------------------------------------ + // Split a string delimited by another string. + // ------------------------------------------------------------------------------ + // Display the original string and delimiter string. + Console.WriteLine("String = \"{0}\" Delimiter = \"{1}\"", s2, stringSeparators[0]); + + // Split a string delimited by another string and return all elements. + Console.Write("Split by str, omit=0: "); + result = s2.Split(stringSeparators, StringSplitOptions.None); + Show(result); + + // Split the original string at the delimiter and return all non-empty elements. + Console.Write("Split by str, omit=1: "); + result = s2.Split(stringSeparators, StringSplitOptions.RemoveEmptyEntries); + Show(result); + + // Split the original string into the empty string before the + // delimiter and the remainder of the original string after the delimiter. + Console.Write("Split by str, omit=0, lim=2: "); + result = s2.Split(stringSeparators, 2, StringSplitOptions.None); + Show(result); + + // Split the original string into the string after the delimiter and the + // remainder of the original string after the delimiter. + Console.Write("Split by str, omit=1, lim=2: "); + result = s2.Split(stringSeparators, 2, StringSplitOptions.RemoveEmptyEntries); + Show(result); + + // Display the array of separated strings using a local function + void Show(string[] entries) + { + Console.Write("{0} results: ", entries.Length); + foreach (string entry in entries) + { + Console.Write("<{0}>", entry); + } + Console.WriteLine(); + } + } + + + + static void TestIndexOf() { // based on examples in documentation page for // System.Globalization.CompareInfo.IndexOf methods @@ -109,14 +192,44 @@ namespace Tests PrintMarker( " Ü : ", -1, myComp.LastIndexOf( myStr, 'Ü', iS, CompareOptions.IgnoreCase ) ); PrintMarker( " ü : ", -1, myComp.LastIndexOf( myStr, 'ü', iS, CompareOptions.IgnoreCase ) ); Console.WriteLine(); + + static void PrintMarker( String Prefix, int First, int Last ) { + if (First > -1) Console.Write($"\t\tFirst({First})"); + if (Last > -1) Console.Write($"\t\tLast({First})"); + if (First < 0 && Last < 0) + Console.Write($"\t\tNone\t"); + } } - public static void PrintMarker( String Prefix, int First, int Last ) { - if (First > -1) Console.Write($"\t\tFirst({First})"); - if (Last > -1) Console.Write($"\t\tLast({First})"); - if (First < 0 && Last < 0) - Console.Write($"\t\tNone\t"); + + + void TestCompare() + { + // Defines the strings to compare. + String myStr1 = "My Uncle Bill's clients"; + String myStr2 = "My uncle bill's clients"; + + // Creates a CompareInfo that uses the InvariantCulture. + CompareInfo myComp = CultureInfo.InvariantCulture.CompareInfo; + + // Compares two strings using myComp. + Console.WriteLine( "Comparing \"{0}\" and \"{1}\"", myStr1, myStr2 ); + Console.WriteLine( " With no CompareOptions : {0}", myComp.Compare( myStr1, myStr2 ) ); + Console.WriteLine( " With None : {0}", myComp.Compare( myStr1, myStr2, CompareOptions.None ) ); + Console.WriteLine( " With Ordinal : {0}", myComp.Compare( myStr1, myStr2, CompareOptions.Ordinal ) ); + //Console.WriteLine( " With StringSort : {0}", myComp.Compare( myStr1, myStr2, CompareOptions.StringSort ) ); + Console.WriteLine( " With IgnoreCase : {0}", myComp.Compare( myStr1, myStr2, CompareOptions.IgnoreCase ) ); + //Console.WriteLine( " With IgnoreSymbols : {0}", myComp.Compare( myStr1, myStr2, CompareOptions.IgnoreSymbols ) ); + //Console.WriteLine( " With IgnoreCase and IgnoreSymbols : {0}", myComp.Compare( myStr1, myStr2, CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols ) ); } + + + + void TestCast(object str) + { + Console.WriteLine("Convertible? " + ((str as IConvertible) != null) + + " Comparable? " + ((str as IComparable) != null)); + } + } } - diff --git a/USAGE.md b/USAGE.md index b6aacb0..740f56c 100644 --- a/USAGE.md +++ b/USAGE.md @@ -93,5 +93,3 @@ Here are some known differences, deficiencies and incompatibilities of the Blueb - Standard numeric format strings are supported, but a custom format, or an `IFormatProvider` which also implements `NumberFormatInfo` will cause `ToString` functions to throw an exception. - Non-ordinal, culture-dependant string comparisons and casing are not 100% same, because of differences between Windows NLS and the `java.text` package. - -- `String` is not castable to `IConvertible` or to the non-generic `IComparable` interface.