using System.Reflection;
using System.Runtime.Serialization;
using System.Runtime.CompilerServices;
+using Mono.Globalization.Unicode;
namespace System.Globalization
{
[Serializable]
public class CompareInfo : IDeserializationCallback
{
+ static readonly bool useManagedCollation =
+ Environment.internalGetEnvironmentVariable ("MONO_DISABLE_MANAGED_COLLATION")
+ != "yes" && MSCompatUnicodeTable.IsReady;
+
+ internal static bool UseManagedCollation {
+ get { return useManagedCollation; }
+ }
+
// Keep in synch with MonoCompareInfo in the runtime.
private int culture;
[NonSerialized]
[NonSerialized]
private IntPtr ICU_collator;
private int win32LCID; // Unused, but MS.NET serializes this
+#if NET_2_0
+ private string m_name; // Unused, but MS.NET serializes this
+#endif
+
+ [NonSerialized]
+ SimpleCollator collator;
/* Hide the .ctor() */
CompareInfo() {}
internal CompareInfo (CultureInfo ci)
{
this.culture = ci.LCID;
- this.icu_name = ci.IcuName;
- this.construct_compareinfo (icu_name);
+ if (UseManagedCollation)
+ collator = new SimpleCollator (ci);
+ else {
+ this.icu_name = ci.IcuName;
+ this.construct_compareinfo (icu_name);
+ }
}
[MethodImplAttribute (MethodImplOptions.InternalCall)]
private extern void free_internal_collator ();
-
+
~CompareInfo ()
{
free_internal_collator ();
}
-
-
+
[MethodImplAttribute (MethodImplOptions.InternalCall)]
private extern int internal_compare (string str1, int offset1,
int length1, string str2,
int offset2, int length2,
CompareOptions options);
+ private int internal_compare_managed (string str1, int offset1,
+ int length1, string str2,
+ int offset2, int length2,
+ CompareOptions options)
+ {
+ return collator.Compare (str1, offset1, length1,
+ str2, offset2, length2, options);
+ }
+
+ private int internal_compare_switch (string str1, int offset1,
+ int length1, string str2,
+ int offset2, int length2,
+ CompareOptions options)
+ {
+ return UseManagedCollation ?
+ internal_compare_managed (str1, offset1, length1,
+ str2, offset2, length2, options) :
+ internal_compare (str1, offset1, length1,
+ str2, offset2, length2, options);
+ }
+
public virtual int Compare (string string1, string string2)
{
- /* Short cuts... */
- if(string1.Length == 0) {
- if(string2.Length == 0) {
- return(0);
- } else {
- return(-1);
- }
- } else if(string2.Length == 0) {
- return(1);
- }
+ /* Short cut... */
+ if(string1.Length == 0 && string2.Length == 0)
+ return(0);
- return(internal_compare (string1, 0, string1.Length,
+ return(internal_compare_switch (string1, 0, string1.Length,
string2, 0, string2.Length,
CompareOptions.None));
}
public virtual int Compare (string string1, string string2,
CompareOptions options)
{
- /* Short cuts... */
- if(string1.Length == 0) {
- if(string2.Length == 0) {
- return(0);
- } else {
- return(-1);
- }
- } else if(string2.Length == 0) {
- return(1);
- }
+ /* Short cut... */
+ if(string1.Length == 0 && string2.Length == 0)
+ return(0);
- return(internal_compare (string1, 0, string1.Length,
+ return(internal_compare_switch (string1, 0, string1.Length,
string2, 0, string2.Length,
options));
}
* the offset >= string length specified check
* in the process...)
*/
- if(string1.Length == 0 ||
- offset1 == string1.Length) {
- if(string2.Length == 0 ||
- offset2 == string2.Length) {
- return(0);
- } else {
- return(-1);
- }
- } else if(string2.Length == 0 ||
- offset2 == string2.Length) {
- return(1);
- }
+ if ((string1.Length == 0 || offset1 == string1.Length) &&
+ (string2.Length == 0 || offset2 == string2.Length))
+ return(0);
if(offset1 < 0 || offset2 < 0) {
throw new ArgumentOutOfRangeException ("Offsets must not be less than zero");
throw new ArgumentOutOfRangeException ("Offset2 is greater than or equal to the length of string2");
}
- return(internal_compare (string1, offset1,
+ return(internal_compare_switch (string1, offset1,
string1.Length-offset1,
string2, offset2,
string2.Length-offset2,
* the offset >= string length specified check
* in the process...)
*/
- if(string1.Length == 0 ||
- offset1 == string1.Length) {
- if(string2.Length == 0 ||
- offset2 == string2.Length) {
- return(0);
- } else {
- return(-1);
- }
- } else if(string2.Length == 0 ||
- offset2 == string2.Length) {
- return(1);
- }
+ if((string1.Length == 0 || offset1 == string1.Length) &&
+ (string2.Length == 0 || offset2 == string2.Length))
+ return(0);
if(offset1 < 0 || offset2 < 0) {
throw new ArgumentOutOfRangeException ("Offsets must not be less than zero");
throw new ArgumentOutOfRangeException ("Offset2 is greater than or equal to the length of string2");
}
- return(internal_compare (string1, offset1,
+ return(internal_compare_switch (string1, offset1,
string1.Length-offset1,
string2, offset2,
string2.Length-offset1,
* the offset >= string length specified check
* in the process...)
*/
- if(string1.Length == 0 ||
- offset1 == string1.Length ||
- length1 == 0) {
- if(string2.Length == 0 ||
- offset2 == string2.Length ||
- length2 == 0) {
- return(0);
- } else {
- return(-1);
- }
- } else if(string2.Length == 0 ||
- offset2 == string2.Length ||
- length2 == 0) {
- return(1);
- }
+ if((string1.Length == 0 ||
+ offset1 == string1.Length ||
+ length1 == 0) &&
+ (string2.Length == 0 ||
+ offset2 == string2.Length ||
+ length2 == 0))
+ return(0);
if(offset1 < 0 || length1 < 0 ||
offset2 < 0 || length2 < 0) {
throw new ArgumentOutOfRangeException ("Length2 is greater than the number of characters from offset2 to the end of string2");
}
- return(internal_compare (string1, offset1, length1,
+ return(internal_compare_switch (string1, offset1, length1,
string2, offset2, length2,
CompareOptions.None));
}
* the offset >= string length specified check
* in the process...)
*/
- if(string1.Length == 0 ||
- offset1 == string1.Length ||
- length1 == 0) {
- if(string2.Length == 0 ||
- offset2 == string2.Length ||
- length2 == 0) {
+ if((string1.Length == 0 ||
+ offset1 == string1.Length ||
+ length1 == 0) &&
+ (string2.Length == 0 ||
+ offset2 == string2.Length ||
+ length2 == 0))
return(0);
- } else {
- return(-1);
- }
- } else if(string2.Length == 0 ||
- offset2 == string2.Length ||
- length2 == 0) {
- return(1);
- }
if(offset1 < 0 || length1 < 0 ||
offset2 < 0 || length2 < 0) {
throw new ArgumentOutOfRangeException ("Length2 is greater than the number of characters from offset2 to the end of string2");
}
- return(internal_compare (string1, offset1, length1,
+ return(internal_compare_switch (string1, offset1, length1,
string2, offset2, length2,
options));
}
public virtual SortKey GetSortKey(string source,
CompareOptions options)
{
+#if NET_2_0
+ switch (options) {
+ case CompareOptions.Ordinal:
+ case CompareOptions.OrdinalIgnoreCase:
+ throw new ArgumentException ("Now allowed CompareOptions.", "options");
+ }
+#endif
+ if (UseManagedCollation)
+ return collator.GetSortKey (source, options);
SortKey key=new SortKey (culture, source, options);
/* Need to do the icall here instead of in the
int count, char value,
CompareOptions options,
bool first);
-
+
+ private int internal_index_managed (string s, int sindex,
+ int count, char c, CompareOptions opt,
+ bool first)
+ {
+ return first ?
+ collator.IndexOf (s, c, sindex, count, opt) :
+ collator.LastIndexOf (s, c, sindex, count, opt);
+ }
+
+ private int internal_index_switch (string s, int sindex,
+ int count, char c, CompareOptions opt,
+ bool first)
+ {
+ // - forward IndexOf() icall is much faster than
+ // manged version, so always use icall. However,
+ // it does not work for OrdinalIgnoreCase, so
+ // do not avoid managed collator for that option.
+ return UseManagedCollation && ! (first && opt == CompareOptions.Ordinal) ?
+ internal_index_managed (s, sindex, count, c, opt, first) :
+ internal_index (s, sindex, count, c, opt, first);
+ }
+
public virtual int IndexOf (string source, char value,
int startIndex, int count,
CompareOptions options)
}
return(-1);
} else {
- return (internal_index (source, startIndex,
+ return (internal_index_switch (source, startIndex,
count, value, options,
true));
}
int count, string value,
CompareOptions options,
bool first);
-
+
+ private int internal_index_managed (string s1, int sindex,
+ int count, string s2, CompareOptions opt,
+ bool first)
+ {
+ return first ?
+ collator.IndexOf (s1, s2, sindex, count, opt) :
+ collator.LastIndexOf (s1, s2, sindex, count, opt);
+ }
+
+ private int internal_index_switch (string s1, int sindex,
+ int count, string s2, CompareOptions opt,
+ bool first)
+ {
+ // - forward IndexOf() icall is much faster than
+ // manged version, so always use icall. However,
+ // it does not work for OrdinalIgnoreCase, so
+ // do not avoid managed collator for that option.
+ return UseManagedCollation && ! (first && opt == CompareOptions.Ordinal) ?
+ internal_index_managed (s1, sindex, count, s2, opt, first) :
+ internal_index (s1, sindex, count, s2, opt, first);
+ }
+
public virtual int IndexOf (string source, string value,
int startIndex, int count,
CompareOptions options)
return(-1);
}
- return (internal_index (source, startIndex, count,
+ return (internal_index_switch (source, startIndex, count,
value, options, true));
}
throw new ArgumentNullException("prefix");
}
+ if (UseManagedCollation)
+ return collator.IsPrefix (source, prefix, options);
+
if(source.Length < prefix.Length) {
return(false);
} else {
throw new ArgumentNullException("suffix");
}
+ if (UseManagedCollation)
+ return collator.IsSuffix (source, suffix, options);
+
if(source.Length < suffix.Length) {
return(false);
} else {
}
return(-1);
} else {
- return (internal_index (source, startIndex,
+ return (internal_index_switch (source, startIndex,
count, value, options,
false));
}
return(0);
}
- return(internal_index (source, startIndex, count,
+ return(internal_index_switch (source, startIndex, count,
value, options, false));
}
+#if NET_2_0
+ public static bool IsSortable (char c)
+ {
+ return MSCompatUnicodeTable.IsSortable (c);
+ }
+
+ public static bool IsSortable (string s)
+ {
+ return MSCompatUnicodeTable.IsSortable (s);
+ }
+#endif
+
public override string ToString()
{
return("CompareInfo - "+culture);
void IDeserializationCallback.OnDeserialization(object sender)
{
- /* This will build the ICU collator, and store
- * the pointer in ICU_collator
- */
- try {
- this.construct_compareinfo (icu_name);
- } catch {
- ICU_collator=IntPtr.Zero;
+ if (UseManagedCollation) {
+ collator = new SimpleCollator (new CultureInfo (culture));
+ } else {
+ /* This will build the ICU collator, and store
+ * the pointer in ICU_collator
+ */
+ try {
+ this.construct_compareinfo (icu_name);
+ } catch {
+ ICU_collator=IntPtr.Zero;
+ }
}
}