1 /******************************************************************************* 2 3 copyright: Copyright (c) 2005 John Chapman. All rights reserved 4 5 license: BSD style: $(LICENSE) 6 7 version: Initial release: 2005 8 9 author: John Chapman 10 11 ******************************************************************************/ 12 13 module tango.text.locale.Collation; 14 15 private import tango.text.locale.Core; 16 17 version (Windows) 18 private import tango.text.locale.Win32; 19 else version (Posix) 20 private import tango.text.locale.Posix; 21 22 /** 23 Compares strings using the specified case and cultural comparision rules. 24 */ 25 public class StringComparer { 26 27 private static StringComparer invariant_; 28 private static StringComparer invariantIgnoreCase_; 29 private Culture culture_; 30 private bool ignoreCase_; 31 32 shared static this() { 33 invariant_ = new StringComparer(Culture.invariantCulture(), false); 34 invariantIgnoreCase_ = new StringComparer(Culture.invariantCulture(), true); 35 } 36 37 /** 38 Creates an instance that compares strings using the rules of the specified culture. 39 Params: 40 culture = A Culture instance whose rules are used to compare strings. 41 ignoreCase = true to perform case-insensitive comparisons; false to perform case-sensitive comparisions. 42 */ 43 public this(Culture culture, bool ignoreCase) { 44 culture_ = culture; 45 ignoreCase_ = ignoreCase; 46 } 47 48 /** 49 Compares two strings and returns the sort order. 50 Returns: 51 -1 is strA is less than strB; 0 if strA is equal to strB; 1 if strA is greater than strB. 52 Params: 53 strA = A string to compare to strB. 54 strB = A string to compare to strA. 55 */ 56 public int compare(const(char)[] strA, const(char)[] strB) { 57 return nativeMethods.compareString(culture_.id, strA, 0, strA.length, strB, 0, strB.length, ignoreCase_); 58 } 59 60 /** 61 Indicates whether the two strings are equal. 62 Returns: 63 true if strA and strB are equal; otherwise, false. 64 Params: 65 strA = A string to compare to strB. 66 strB = A string to compare to strA. 67 */ 68 public bool equals(const(char)[] strA, const(char)[] strB) { 69 return (compare(strA, strB) == 0); 70 } 71 72 /** 73 $(I Property.) Retrieves an instance that performs case-sensitive comparisons using the rules of the current culture. 74 Returns: 75 A new StringComparer instance. 76 */ 77 public static StringComparer currentCulture() { 78 return new StringComparer(Culture.current, false); 79 } 80 81 /** 82 $(I Property.) Retrieves an instance that performs case-insensitive comparisons using the rules of the current culture. 83 Returns: 84 A new StringComparer instance. 85 */ 86 public static StringComparer currentCultureIgnoreCase() { 87 return new StringComparer(Culture.current, true); 88 } 89 90 /** 91 $(I Property.) Retrieves an instance that performs case-sensitive comparisons using the rules of the invariant culture. 92 Returns: 93 A new StringComparer instance. 94 */ 95 public static StringComparer invariantCulture() { 96 return invariant_; 97 } 98 99 /** 100 $(I Property.) Retrieves an instance that performs case-insensitive comparisons using the rules of the invariant culture. 101 Returns: 102 A new StringComparer instance. 103 */ 104 public static StringComparer invariantCultureIgnoreCase() { 105 return invariantIgnoreCase_; 106 } 107 108 } 109 110 /** 111 $(I Delegate.) Represents the method that will handle the string comparison. 112 Remarks: 113 The delegate has the signature $(I int delegate(const(char)[], const(char)[])). 114 */ 115 alias int delegate(const(char)[], const(char)[]) StringComparison; 116 117 /** 118 Sorts strings according to the rules of the specified culture. 119 */ 120 public class StringSorter { 121 122 private static StringSorter invariant_; 123 private static StringSorter invariantIgnoreCase_; 124 private Culture culture_; 125 private StringComparison comparison_; 126 127 shared static this() { 128 invariant_ = new StringSorter(StringComparer.invariantCulture()); 129 invariantIgnoreCase_ = new StringSorter(StringComparer.invariantCultureIgnoreCase()); 130 } 131 132 /** 133 Creates an instance using the specified StringComparer. 134 Params: 135 comparer = The StringComparer to use when comparing strings. $(I Optional.) 136 */ 137 public this(StringComparer comparer = null) { 138 if (comparer is null) 139 comparer = StringComparer.currentCulture(); 140 comparison_ = &comparer.compare; 141 } 142 143 /** 144 Creates an instance using the specified delegate. 145 Params: 146 comparison = The delegate to use when comparing strings. 147 Remarks: 148 The comparison parameter must have the same signature as StringComparison. 149 */ 150 public this(StringComparison comparison) { 151 comparison_ = comparison; 152 } 153 154 /** 155 Sorts all the elements in an array. 156 Params: 157 array = The array of strings to _sort. 158 */ 159 public inout(void) sort(ref inout(char)[][] array) { 160 sort(array, 0, array.length); 161 } 162 163 /** 164 Sorts a range of the elements in an array. 165 Params: 166 array = The array of strings to _sort. 167 index = The starting index of the range. 168 count = The number of elements in the range. 169 */ 170 public inout(void) sort(ref inout(char)[][] array, size_t index, size_t count) { 171 inout(void) qsort(size_t left, size_t right, inout(int*) dummy = null) { 172 do { 173 size_t i = left, j = right; 174 const(char)[] pivot = array[left + ((right - left) >> 1)]; 175 176 do { 177 while (comparison_(array[i], pivot) < 0) 178 i++; 179 while (comparison_(pivot, array[j]) < 0) 180 j--; 181 182 if (i > j) 183 break; 184 else if (i < j) { 185 auto temp = array[i]; 186 array[i] = array[j]; 187 array[j] = temp; 188 } 189 190 i++; 191 j--; 192 } while (i <= j); 193 194 if (j - left <= right - i) { 195 if (left < j) 196 qsort(left, j); 197 left = i; 198 } 199 else { 200 if (i < right) 201 qsort(i, right); 202 right = j; 203 } 204 } while (left < right); 205 } 206 207 qsort(index, index + (count - 1)); 208 } 209 210 /** 211 $(I Property.) Retrieves an instance that performs a case-sensitive sort using the rules of the current culture. 212 Returns: A StringSorter instance. 213 */ 214 @property public static StringSorter currentCulture() { 215 return new StringSorter(StringComparer.currentCulture()); 216 } 217 218 /** 219 $(I Property.) Retrieves an instance that performs a case-insensitive sort using the rules of the current culture. 220 Returns: A StringSorter instance. 221 */ 222 @property public static StringSorter currentCultureIgnoreCase() { 223 return new StringSorter(StringComparer.currentCultureIgnoreCase()); 224 } 225 226 /** 227 $(I Property.) Retrieves an instance that performs a case-sensitive sort using the rules of the invariant culture. 228 Returns: A StringSorter instance. 229 */ 230 public static StringSorter invariantCulture() { 231 return invariant_; 232 } 233 234 /** 235 $(I Property.) Retrieves an instance that performs a case-insensitive sort using the rules of the invariant culture. 236 Returns: A StringSorter instance. 237 */ 238 public static StringSorter invariantCultureIgnoreCase() { 239 return invariantIgnoreCase_; 240 } 241 242 }