//
-// System.Globalization.CompareInfo
+// System.Globalization.CompareInfo.cs
//
// Authors:
// Rodrigo Moya (rodrigo@ximian.com)
//
using System.Reflection;
+using System.Collections;
using System.Runtime.Serialization;
using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
using Mono.Globalization.Unicode;
namespace System.Globalization
{
[Serializable]
- public class CompareInfo : IDeserializationCallback
- {
+#if !MOONLIGHT
+ [ComVisible (true)]
+ public class CompareInfo : IDeserializationCallback {
+
static readonly bool useManagedCollation =
Environment.internalGetEnvironmentVariable ("MONO_DISABLE_MANAGED_COLLATION")
- != "yes";
+ != "yes" && MSCompatUnicodeTable.IsReady;
internal static bool UseManagedCollation {
- get { return useManagedCollation && MSCompatUnicodeTable.IsReady; }
+ get { return useManagedCollation; }
}
+ void IDeserializationCallback.OnDeserialization(object sender)
+ {
+ 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;
+ }
+ }
+ }
+
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ private extern void construct_compareinfo (string locale);
+
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ private extern void 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);
+
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ private extern void assign_sortkey (object key, string source,
+ CompareOptions options);
+
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ private extern int internal_index (string source, int sindex,
+ int count, char value,
+ CompareOptions options,
+ bool first);
+
+ [MethodImplAttribute (MethodImplOptions.InternalCall)]
+ private extern int internal_index (string source, int sindex,
+ int count, string value,
+ CompareOptions options,
+ bool first);
+
+#else
+ public class CompareInfo {
+ internal static bool UseManagedCollation {
+ get { return true; }
+ }
+#endif
+ const CompareOptions ValidCompareOptions_NoStringSort =
+ CompareOptions.None | CompareOptions.IgnoreCase | CompareOptions.IgnoreNonSpace |
+ CompareOptions.IgnoreSymbols | CompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth |
+ CompareOptions.OrdinalIgnoreCase | CompareOptions.Ordinal;
+
+ const CompareOptions ValidCompareOptions = ValidCompareOptions_NoStringSort | CompareOptions.StringSort;
+
// Keep in synch with MonoCompareInfo in the runtime.
private int culture;
[NonSerialized]
private string icu_name;
- [NonSerialized]
- private IntPtr ICU_collator;
+// [NonSerialized]
+// private IntPtr ICU_collator;
+
+#pragma warning disable 169
private int win32LCID; // Unused, but MS.NET serializes this
+ private string m_name; // Unused, but MS.NET serializes this
+#pragma warning restore 169
[NonSerialized]
SimpleCollator collator;
+
+ // Maps culture IDs to SimpleCollator objects
+ private static Hashtable collators;
+
+ [NonSerialized]
+ // Protects access to 'collators'
+ private static object monitor = new Object ();
/* Hide the .ctor() */
CompareInfo() {}
- [MethodImplAttribute (MethodImplOptions.InternalCall)]
- private extern void construct_compareinfo (string locale);
-
internal CompareInfo (CultureInfo ci)
{
this.culture = ci.LCID;
- if (UseManagedCollation)
- collator = new SimpleCollator (ci);
- else {
+ if (UseManagedCollation) {
+ lock (monitor) {
+ if (collators == null)
+ collators = new Hashtable ();
+ collator = (SimpleCollator)collators [ci.LCID];
+ if (collator == null) {
+ collator = new SimpleCollator (ci);
+ collators [ci.LCID] = collator;
+ }
+ }
+ } else {
+#if !MOONLIGHT
this.icu_name = ci.IcuName;
this.construct_compareinfo (icu_name);
+#endif
}
}
-
- [MethodImplAttribute (MethodImplOptions.InternalCall)]
- private extern void free_internal_collator ();
~CompareInfo ()
{
+#if !MOONLIGHT
free_internal_collator ();
+#endif
}
- [MethodImplAttribute (MethodImplOptions.InternalCall)]
- private extern int internal_compare (string str1, int offset1,
- int length1, string str2,
- int offset2, int length2,
- CompareOptions options);
-
+#if !MOONLIGHT
private int internal_compare_managed (string str1, int offset1,
int length1, string str2,
int offset2, int length2,
internal_compare (str1, offset1, length1,
str2, offset2, length2, options);
}
-
+#else
+ private int internal_compare_switch (string str1, int offset1,
+ int length1, string str2,
+ int offset2, int length2,
+ CompareOptions options)
+ {
+ return collator.Compare (str1, offset1, length1,
+ str2, offset2, length2, options);
+ }
+#endif
public virtual int Compare (string string1, string string2)
{
- /* Short cut... */
- if(string1.Length == 0 && string2.Length == 0)
- return(0);
-
- return(internal_compare_switch (string1, 0, string1.Length,
- string2, 0, string2.Length,
- CompareOptions.None));
+ return Compare (string1, string2, CompareOptions.None);
}
public virtual int Compare (string string1, string string2,
CompareOptions options)
{
+ if ((options & ValidCompareOptions) != options)
+ throw new ArgumentException ("options");
+
+ if (string1 == null) {
+ if (string2 == null)
+ return 0;
+ return -1;
+ }
+ if (string2 == null)
+ return 1;
+
/* Short cut... */
if(string1.Length == 0 && string2.Length == 0)
return(0);
public virtual int Compare (string string1, int offset1,
string string2, int offset2)
{
- /* Not in the spec, but ms does these short
- * cuts before checking the offsets (breaking
- * the offset >= string length specified check
- * in the process...)
- */
- 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");
- }
-
- if(offset1 > string1.Length) {
- throw new ArgumentOutOfRangeException ("Offset1 is greater than or equal to the length of string1");
- }
-
- if(offset2 > string2.Length) {
- throw new ArgumentOutOfRangeException ("Offset2 is greater than or equal to the length of string2");
- }
-
- return(internal_compare_switch (string1, offset1,
- string1.Length-offset1,
- string2, offset2,
- string2.Length-offset2,
- CompareOptions.None));
+ return Compare (string1, offset1, string2, offset2, CompareOptions.None);
}
public virtual int Compare (string string1, int offset1,
string string2, int offset2,
CompareOptions options)
{
+ if ((options & ValidCompareOptions) != options)
+ throw new ArgumentException ("options");
+
+ if (string1 == null) {
+ if (string2 == null)
+ return 0;
+ return -1;
+ }
+ if (string2 == null)
+ return 1;
+
/* Not in the spec, but ms does these short
* cuts before checking the offsets (breaking
* the offset >= string length specified check
return(internal_compare_switch (string1, offset1,
string1.Length-offset1,
string2, offset2,
- string2.Length-offset1,
+ string2.Length-offset2,
options));
}
int length1, string string2,
int offset2, int length2)
{
- /* Not in the spec, but ms does these short
- * cuts before checking the offsets (breaking
- * the offset >= string length specified check
- * in the process...)
- */
- 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 ("Offsets and lengths must not be less than zero");
- }
-
- if(offset1 > string1.Length) {
- throw new ArgumentOutOfRangeException ("Offset1 is greater than or equal to the length of string1");
- }
-
- if(offset2 > string2.Length) {
- throw new ArgumentOutOfRangeException ("Offset2 is greater than or equal to the length of string2");
- }
-
- if(length1 > string1.Length-offset1) {
- throw new ArgumentOutOfRangeException ("Length1 is greater than the number of characters from offset1 to the end of string1");
- }
-
- if(length2 > string2.Length-offset2) {
- throw new ArgumentOutOfRangeException ("Length2 is greater than the number of characters from offset2 to the end of string2");
- }
-
- return(internal_compare_switch (string1, offset1, length1,
- string2, offset2, length2,
- CompareOptions.None));
+ return Compare (string1, offset1, length1, string2, offset2, length2, CompareOptions.None);
}
- [MonoTODO("Add support for CompareOptions.OrdinalIgnoreCase")]
public virtual int Compare (string string1, int offset1,
int length1, string string2,
int offset2, int length2,
CompareOptions options)
{
+ if ((options & ValidCompareOptions) != options)
+ throw new ArgumentException ("options");
+
+ if (string1 == null) {
+ if (string2 == null)
+ return 0;
+ return -1;
+ }
+ if (string2 == null)
+ return 1;
+
/* Not in the spec, but ms does these short
* cuts before checking the offsets (breaking
* the offset >= string length specified check
{
return(LCID);
}
-
- [MethodImplAttribute (MethodImplOptions.InternalCall)]
- private extern void assign_sortkey (object key, string source,
- CompareOptions options);
public virtual SortKey GetSortKey(string source)
{
public virtual SortKey GetSortKey(string source,
CompareOptions options)
{
+ switch (options) {
+ case CompareOptions.Ordinal:
+ case CompareOptions.OrdinalIgnoreCase:
+ throw new ArgumentException ("Now allowed CompareOptions.", "options");
+ }
+#if !MOONLIGHT
if (UseManagedCollation)
return collator.GetSortKey (source, options);
SortKey key=new SortKey (culture, source, options);
assign_sortkey (key, source, options);
return(key);
+#else
+ return collator.GetSortKey (source, options);
+#endif
}
public virtual int IndexOf (string source, char value)
CompareOptions.None));
}
- [MethodImplAttribute (MethodImplOptions.InternalCall)]
- private extern int internal_index (string source, int sindex,
- int count, char value,
- CompareOptions options,
- bool first);
-
+#if !MOONLIGHT
private int internal_index_managed (string s, int sindex,
int count, char c, CompareOptions opt,
bool first)
int count, char c, CompareOptions opt,
bool first)
{
- return UseManagedCollation &&
-#if NET_2_0
- ((CompareOptions.Ordinal & opt) == 0 ||
- (CompareOptions.OrdinalIgnoreCase & opt) == 0) ?
-#else
- (CompareOptions.Ordinal & opt) == 0 ?
-#endif
+ // - 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);
}
+#else
+ private int internal_index_switch (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);
+ }
+#endif
- [MonoTODO("Add support for CompareOptions.OrdinalIgnoreCase")]
public virtual int IndexOf (string source, char value,
int startIndex, int count,
CompareOptions options)
if(count<0 || (source.Length - startIndex) < count) {
throw new ArgumentOutOfRangeException ("count");
}
- if((options & CompareOptions.StringSort)!=0) {
- throw new ArgumentException ("StringSort is not a valid CompareOption for this method");
- }
+ if ((options & ValidCompareOptions_NoStringSort) != options)
+ throw new ArgumentException ("options");
if(count==0) {
return(-1);
}
}
- [MethodImplAttribute (MethodImplOptions.InternalCall)]
- private extern int internal_index (string source, int sindex,
- int count, string value,
- CompareOptions options,
- bool first);
-
+#if !MOONLIGHT
private int internal_index_managed (string s1, int sindex,
int count, string s2, CompareOptions opt,
bool first)
int count, string s2, CompareOptions opt,
bool first)
{
- return UseManagedCollation &&
-#if NET_2_0
- ((CompareOptions.Ordinal & opt) == 0 ||
- (CompareOptions.OrdinalIgnoreCase & opt) == 0) ?
-#else
- (CompareOptions.Ordinal & opt) == 0 ?
-#endif
+ // - 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);
}
+#else
+ private int internal_index_switch (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);
+ }
+#endif
- [MonoTODO("Add support for CompareOptions.OrdinalIgnoreCase")]
public virtual int IndexOf (string source, string value,
int startIndex, int count,
CompareOptions options)
if(count<0 || (source.Length - startIndex) < count) {
throw new ArgumentOutOfRangeException ("count");
}
+ if ((options & ValidCompareOptions_NoStringSort) != options)
+ throw new ArgumentException ("options");
+ if(value.Length==0) {
+ return(0);
+ }
if(count==0) {
return(-1);
}
throw new ArgumentNullException("prefix");
}
+ if ((options & ValidCompareOptions_NoStringSort) != options)
+ throw new ArgumentException ("options");
+
if (UseManagedCollation)
return collator.IsPrefix (source, prefix, options);
throw new ArgumentNullException("suffix");
}
+ if ((options & ValidCompareOptions_NoStringSort) != options)
+ throw new ArgumentException ("options");
+
if (UseManagedCollation)
return collator.IsSuffix (source, suffix, options);
CompareOptions.None));
}
- [MonoTODO("Add support for CompareOptions.OrdinalIgnoreCase")]
public virtual int LastIndexOf(string source, char value,
int startIndex, int count,
CompareOptions options)
if(count < 0 || (startIndex - count) < -1) {
throw new ArgumentOutOfRangeException("count");
}
- if((options & CompareOptions.StringSort)!=0) {
- throw new ArgumentException ("StringSort is not a valid CompareOption for this method");
- }
+ if ((options & ValidCompareOptions_NoStringSort) != options)
+ throw new ArgumentException ("options");
if(count==0) {
return(-1);
if(count < 0 || (startIndex - count) < -1) {
throw new ArgumentOutOfRangeException("count");
}
+ if ((options & ValidCompareOptions_NoStringSort) != options)
+ throw new ArgumentException ("options");
if(count == 0) {
return(-1);
}
value, options, false));
}
-#if NET_2_0
- public static bool IsSortable (char c)
+ [ComVisible (false)]
+ public static bool IsSortable (char ch)
{
- return MSCompatUnicodeTable.IsSortable (c);
+ return MSCompatUnicodeTable.IsSortable (ch);
}
- public static bool IsSortable (string s)
+ [ComVisible (false)]
+ public static bool IsSortable (string text)
{
- return MSCompatUnicodeTable.IsSortable (s);
+ return MSCompatUnicodeTable.IsSortable (text);
}
-#endif
public override string ToString()
{
return("CompareInfo - "+culture);
}
- void IDeserializationCallback.OnDeserialization(object sender)
- {
- 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;
- }
- }
- }
-
/* LAMESPEC: not mentioned in the spec, but corcompare
* shows it. Some documentation about what it does
* would be nice.
return(culture);
}
}
+
+ [ComVisible (false)]
+ public virtual string Name {
+ get { return icu_name; }
+ }
}
}