1 /* 2 * Hunt - A refined core library for D programming language. 3 * 4 * Copyright (C) 2018-2019 HuntLabs 5 * 6 * Website: https://www.huntlabs.net/ 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module hunt.util.Comparator; 13 14 import std.traits; 15 debug import hunt.logging.ConsoleLogger; 16 17 /** 18 * A comparison function, which imposes a <i>total ordering</i> on some 19 * collection of objects. Comparators can be passed to a sort method (such 20 * as {@link Collections#sort(List,Comparator) Collections.sort} or {@link 21 * Arrays#sort(Object[],Comparator) Arrays.sort}) to allow precise control 22 * over the sort order. Comparators can also be used to control the order of 23 * certain data structures (such as {@link SortedSet sorted sets} or {@link 24 * SortedMap sorted maps}), or to provide an ordering for collections of 25 * objects that don't have a {@link Comparable natural ordering}.<p> 26 * 27 * The ordering imposed by a comparator <tt>c</tt> on a set of elements 28 * <tt>S</tt> is said to be <i>consistent with equals</i> if and only if 29 * <tt>c.compare(e1, e2)==0</tt> has the same bool value as 30 * <tt>e1.equals(e2)</tt> for every <tt>e1</tt> and <tt>e2</tt> in 31 * <tt>S</tt>.<p> 32 * 33 * Caution should be exercised when using a comparator capable of imposing an 34 * ordering inconsistent with equals to order a sorted set (or sorted map). 35 * Suppose a sorted set (or sorted map) with an explicit comparator <tt>c</tt> 36 * is used with elements (or keys) drawn from a set <tt>S</tt>. If the 37 * ordering imposed by <tt>c</tt> on <tt>S</tt> is inconsistent with equals, 38 * the sorted set (or sorted map) will behave "strangely." In particular the 39 * sorted set (or sorted map) will violate the general contract for set (or 40 * map), which is defined in terms of <tt>equals</tt>.<p> 41 * 42 * For example, suppose one adds two elements {@code a} and {@code b} such that 43 * {@code (a.equals(b) && c.compare(a, b) != 0)} 44 * to an empty {@code TreeSet} with comparator {@code c}. 45 * The second {@code add} operation will return 46 * true (and the size of the tree set will increase) because {@code a} and 47 * {@code b} are not equivalent from the tree set's perspective, even though 48 * this is contrary to the specification of the 49 * {@link Set#add Set.add} method.<p> 50 * 51 * Note: It is generally a good idea for comparators to also implement 52 * <tt>java.io.Serializable</tt>, as they may be used as ordering methods in 53 * serializable data structures (like {@link TreeSet}, {@link TreeMap}). In 54 * order for the data structure to serialize successfully, the comparator (if 55 * provided) must implement <tt>Serializable</tt>.<p> 56 * 57 * For the mathematically inclined, the <i>relation</i> that defines the 58 * <i>imposed ordering</i> that a given comparator <tt>c</tt> imposes on a 59 * given set of objects <tt>S</tt> is:<pre> 60 * {(x, y) such that c.compare(x, y) <= 0}. 61 * </pre> The <i>quotient</i> for this total order is:<pre> 62 * {(x, y) such that c.compare(x, y) == 0}. 63 * </pre> 64 * 65 * It follows immediately from the contract for <tt>compare</tt> that the 66 * quotient is an <i>equivalence relation</i> on <tt>S</tt>, and that the 67 * imposed ordering is a <i>total order</i> on <tt>S</tt>. When we say that 68 * the ordering imposed by <tt>c</tt> on <tt>S</tt> is <i>consistent with 69 * equals</i>, we mean that the quotient for the ordering is the equivalence 70 * relation defined by the objects' {@link Object#equals(Object) 71 * equals(Object)} method(s):<pre> 72 * {(x, y) such that x.equals(y)}. </pre> 73 * 74 * <p>Unlike {@code Comparable}, a comparator may optionally permit 75 * comparison of null arguments, while maintaining the requirements for 76 * an equivalence relation. 77 * 78 * <p>This interface is a member of the 79 * <a href="{@docRoot}/../technotes/guides/collections/index.html"> 80 * Java Collections Framework</a>. 81 * 82 * @param (T) the type of objects that may be compared by this comparator 83 * 84 * @author Josh Bloch 85 * @author Neal Gafter 86 * @see Comparable 87 * @see java.io.Serializable 88 */ 89 interface Comparator(T) { 90 /** 91 * Compares its two arguments for order. Returns a negative integer, 92 * zero, or a positive integer as the first argument is less than, equal 93 * to, or greater than the second.<p> 94 * 95 * In the foregoing description, the notation 96 * <tt>sgn(</tt><i>expression</i><tt>)</tt> designates the mathematical 97 * <i>signum</i> function, which is defined to return one of <tt>-1</tt>, 98 * <tt>0</tt>, or <tt>1</tt> according to whether the value of 99 * <i>expression</i> is negative, zero or positive.<p> 100 * 101 * The implementor must ensure that <tt>sgn(compare(x, y)) == 102 * -sgn(compare(y, x))</tt> for all <tt>x</tt> and <tt>y</tt>. (This 103 * implies that <tt>compare(x, y)</tt> must throw an exception if and only 104 * if <tt>compare(y, x)</tt> throws an exception.)<p> 105 * 106 * The implementor must also ensure that the relation is transitive: 107 * <tt>((compare(x, y)>0) && (compare(y, z)>0))</tt> implies 108 * <tt>compare(x, z)>0</tt>.<p> 109 * 110 * Finally, the implementor must ensure that <tt>compare(x, y)==0</tt> 111 * implies that <tt>sgn(compare(x, z))==sgn(compare(y, z))</tt> for all 112 * <tt>z</tt>.<p> 113 * 114 * It is generally the case, but <i>not</i> strictly required that 115 * <tt>(compare(x, y)==0) == (x.equals(y))</tt>. Generally speaking, 116 * any comparator that violates this condition should clearly indicate 117 * this fact. The recommended language is "Note: this comparator 118 * imposes orderings that are inconsistent with equals." 119 * 120 * @param o1 the first object to be compared. 121 * @param o2 the second object to be compared. 122 * @return a negative integer, zero, or a positive integer as the 123 * first argument is less than, equal to, or greater than the 124 * second. 125 * @throws NullPointerException if an argument is null and this 126 * comparator does not permit null arguments 127 * @throws ClassCastException if the arguments' types prevent them from 128 * being compared by this comparator. 129 */ 130 int compare(T o1, T o2) nothrow; 131 132 // /** 133 // * Indicates whether some other object is "equal to" this 134 // * comparator. This method must obey the general contract of 135 // * {@link Object#equals(Object)}. Additionally, this method can return 136 // * <tt>true</tt> <i>only</i> if the specified object is also a comparator 137 // * and it imposes the same ordering as this comparator. Thus, 138 // * <code>comp1.equals(comp2)</code> implies that <tt>sgn(comp1.compare(o1, 139 // * o2))==sgn(comp2.compare(o1, o2))</tt> for every object reference 140 // * <tt>o1</tt> and <tt>o2</tt>.<p> 141 // * 142 // * Note that it is <i>always</i> safe <i>not</i> to override 143 // * <tt>Object.equals(Object)</tt>. However, overriding this method may, 144 // * in some cases, improve performance by allowing programs to determine 145 // * that two distinct comparators impose the same order. 146 // * 147 // * @param obj the reference object with which to compare. 148 // * @return <code>true</code> only if the specified object is also 149 // * a comparator and it imposes the same ordering as this 150 // * comparator. 151 // * @see Object#equals(Object) 152 // * @see Object#hashCode() 153 // */ 154 // bool equals(Object obj); 155 156 // /** 157 // * Returns a comparator that imposes the reverse ordering of this 158 // * comparator. 159 // * 160 // * @return a comparator that imposes the reverse ordering of this 161 // * comparator. 162 // */ 163 // Comparator!(T) reversed() { 164 // return Collections.reverseOrder(this); 165 // } 166 167 // /** 168 // * Returns a lexicographic-order comparator with another comparator. 169 // * If this {@code Comparator} considers two elements equal, i.e. 170 // * {@code compare(a, b) == 0}, {@code other} is used to determine the order. 171 // * 172 // * <p>The returned comparator is serializable if the specified comparator 173 // * is also serializable. 174 // * 175 // * @apiNote 176 // * For example, to sort a collection of {@code string} based on the length 177 // * and then case-insensitive natural ordering, the comparator can be 178 // * composed using following code, 179 // * 180 // * <pre>{@code 181 // * Comparator<string> cmp = Comparator.comparingInt(string::length) 182 // * .thenComparing(string.CASE_INSENSITIVE_ORDER); 183 // * }</pre> 184 // * 185 // * @param other the other comparator to be used when this comparator 186 // * compares two objects that are equal. 187 // * @return a lexicographic-order comparator composed of this and then the 188 // * other comparator 189 // * @throws NullPointerException if the argument is null. 190 // */ 191 // Comparator!(T) thenComparing(Comparator<T> other) { 192 // Objects.requireNonNull(other); 193 // return (Comparator!(T) & Serializable) (c1, c2) -> { 194 // int res = compare(c1, c2); 195 // return (res != 0) ? res : other.compare(c1, c2); 196 // }; 197 // } 198 199 // /** 200 // * Returns a lexicographic-order comparator with a function that 201 // * extracts a key to be compared with the given {@code Comparator}. 202 // * 203 // * @implSpec This implementation behaves as if {@code 204 // * thenComparing(comparing(keyExtractor, cmp))}. 205 // * 206 // * @param !(U) the type of the sort key 207 // * @param keyExtractor the function used to extract the sort key 208 // * @param keyComparator the {@code Comparator} used to compare the sort key 209 // * @return a lexicographic-order comparator composed of this comparator 210 // * and then comparing on the key extracted by the keyExtractor function 211 // * @throws NullPointerException if either argument is null. 212 // * @see #comparing(Function, Comparator) 213 // * @see #thenComparing(Comparator) 214 // */ 215 // !(U) Comparator!(T) thenComparing( 216 // Function<T, U> keyExtractor, 217 // Comparator<U> keyComparator) 218 // { 219 // return thenComparing(comparing(keyExtractor, keyComparator)); 220 // } 221 222 // /** 223 // * Returns a lexicographic-order comparator with a function that 224 // * extracts a {@code Comparable} sort key. 225 // * 226 // * @implSpec This implementation behaves as if {@code 227 // * thenComparing(comparing(keyExtractor))}. 228 // * 229 // * @param !(U) the type of the {@link Comparable} sort key 230 // * @param keyExtractor the function used to extract the {@link 231 // * Comparable} sort key 232 // * @return a lexicographic-order comparator composed of this and then the 233 // * {@link Comparable} sort key. 234 // * @throws NullPointerException if the argument is null. 235 // * @see #comparing(Function) 236 // * @see #thenComparing(Comparator) 237 // */ 238 // <U extends Comparable<U>> Comparator!(T) thenComparing( 239 // Function<T, U> keyExtractor) 240 // { 241 // return thenComparing(comparing(keyExtractor)); 242 // } 243 244 // /** 245 // * Returns a lexicographic-order comparator with a function that 246 // * extracts a {@code int} sort key. 247 // * 248 // * @implSpec This implementation behaves as if {@code 249 // * thenComparing(comparingInt(keyExtractor))}. 250 // * 251 // * @param keyExtractor the function used to extract the integer sort key 252 // * @return a lexicographic-order comparator composed of this and then the 253 // * {@code int} sort key 254 // * @throws NullPointerException if the argument is null. 255 // * @see #comparingInt(ToIntFunction) 256 // * @see #thenComparing(Comparator) 257 // */ 258 // Comparator!(T) thenComparingInt(ToIntFunction<T> keyExtractor) { 259 // return thenComparing(comparingInt(keyExtractor)); 260 // } 261 262 // /** 263 // * Returns a lexicographic-order comparator with a function that 264 // * extracts a {@code long} sort key. 265 // * 266 // * @implSpec This implementation behaves as if {@code 267 // * thenComparing(comparingLong(keyExtractor))}. 268 // * 269 // * @param keyExtractor the function used to extract the long sort key 270 // * @return a lexicographic-order comparator composed of this and then the 271 // * {@code long} sort key 272 // * @throws NullPointerException if the argument is null. 273 // * @see #comparingLong(ToLongFunction) 274 // * @see #thenComparing(Comparator) 275 // */ 276 // Comparator!(T) thenComparingLong(ToLongFunction<T> keyExtractor) { 277 // return thenComparing(comparingLong(keyExtractor)); 278 // } 279 280 // /** 281 // * Returns a lexicographic-order comparator with a function that 282 // * extracts a {@code double} sort key. 283 // * 284 // * @implSpec This implementation behaves as if {@code 285 // * thenComparing(comparingDouble(keyExtractor))}. 286 // * 287 // * @param keyExtractor the function used to extract the double sort key 288 // * @return a lexicographic-order comparator composed of this and then the 289 // * {@code double} sort key 290 // * @throws NullPointerException if the argument is null. 291 // * @see #comparingDouble(ToDoubleFunction) 292 // * @see #thenComparing(Comparator) 293 // */ 294 // Comparator!(T) thenComparingDouble(ToDoubleFunction<T> keyExtractor) { 295 // return thenComparing(comparingDouble(keyExtractor)); 296 // } 297 298 // /** 299 // * Returns a comparator that imposes the reverse of the <em>natural 300 // * ordering</em>. 301 // * 302 // * <p>The returned comparator is serializable and throws {@link 303 // * NullPointerException} when comparing {@code null}. 304 // * 305 // * @param !(T) the {@link Comparable} type of element to be compared 306 // * @return a comparator that imposes the reverse of the <i>natural 307 // * ordering</i> on {@code Comparable} objects. 308 // * @see Comparable 309 // */ 310 // static <T extends Comparable<T>> Comparator!(T) reverseOrder() { 311 // return Collections.reverseOrder(); 312 // } 313 314 // /** 315 // * Returns a comparator that compares {@link Comparable} objects in natural 316 // * order. 317 // * 318 // * <p>The returned comparator is serializable and throws {@link 319 // * NullPointerException} when comparing {@code null}. 320 // * 321 // * @param !(T) the {@link Comparable} type of element to be compared 322 // * @return a comparator that imposes the <i>natural ordering</i> on {@code 323 // * Comparable} objects. 324 // * @see Comparable 325 // */ 326 // @SuppressWarnings("unchecked") 327 // static <T extends Comparable<T>> Comparator!(T) naturalOrder() { 328 // return (Comparator!(T)) Comparators.NaturalOrderComparator.INSTANCE; 329 // } 330 331 // /** 332 // * Returns a null-friendly comparator that considers {@code null} to be 333 // * less than non-null. When both are {@code null}, they are considered 334 // * equal. If both are non-null, the specified {@code Comparator} is used 335 // * to determine the order. If the specified comparator is {@code null}, 336 // * then the returned comparator considers all non-null values to be equal. 337 // * 338 // * <p>The returned comparator is serializable if the specified comparator 339 // * is serializable. 340 // * 341 // * @param !(T) the type of the elements to be compared 342 // * @param comparator a {@code Comparator} for comparing non-null values 343 // * @return a comparator that considers {@code null} to be less than 344 // * non-null, and compares non-null objects with the supplied 345 // * {@code Comparator}. 346 // */ 347 // static !(T) Comparator!(T) nullsFirst(Comparator<T> comparator) { 348 // return new Comparators.NullComparator<>(true, comparator); 349 // } 350 351 // /** 352 // * Returns a null-friendly comparator that considers {@code null} to be 353 // * greater than non-null. When both are {@code null}, they are considered 354 // * equal. If both are non-null, the specified {@code Comparator} is used 355 // * to determine the order. If the specified comparator is {@code null}, 356 // * then the returned comparator considers all non-null values to be equal. 357 // * 358 // * <p>The returned comparator is serializable if the specified comparator 359 // * is serializable. 360 // * 361 // * @param !(T) the type of the elements to be compared 362 // * @param comparator a {@code Comparator} for comparing non-null values 363 // * @return a comparator that considers {@code null} to be greater than 364 // * non-null, and compares non-null objects with the supplied 365 // * {@code Comparator}. 366 // */ 367 // static !(T) Comparator!(T) nullsLast(Comparator<T> comparator) { 368 // return new Comparators.NullComparator<>(false, comparator); 369 // } 370 371 // /** 372 // * Accepts a function that extracts a sort key from a type {@code T}, and 373 // * returns a {@code Comparator!(T)} that compares by that sort key using 374 // * the specified {@link Comparator}. 375 // * 376 // * <p>The returned comparator is serializable if the specified function 377 // * and comparator are both serializable. 378 // * 379 // * @apiNote 380 // * For example, to obtain a {@code Comparator} that compares {@code 381 // * Person} objects by their last name ignoring case differences, 382 // * 383 // * <pre>{@code 384 // * Comparator<Person> cmp = Comparator.comparing( 385 // * Person::getLastName, 386 // * string.CASE_INSENSITIVE_ORDER); 387 // * }</pre> 388 // * 389 // * @param !(T) the type of element to be compared 390 // * @param !(U) the type of the sort key 391 // * @param keyExtractor the function used to extract the sort key 392 // * @param keyComparator the {@code Comparator} used to compare the sort key 393 // * @return a comparator that compares by an extracted key using the 394 // * specified {@code Comparator} 395 // * @throws NullPointerException if either argument is null 396 // */ 397 // static <T, U> Comparator!(T) comparing( 398 // Function<T, U> keyExtractor, 399 // Comparator<U> keyComparator) 400 // { 401 // Objects.requireNonNull(keyExtractor); 402 // Objects.requireNonNull(keyComparator); 403 // return (Comparator!(T) & Serializable) 404 // (c1, c2) -> keyComparator.compare(keyExtractor.apply(c1), 405 // keyExtractor.apply(c2)); 406 // } 407 408 // /** 409 // * Accepts a function that extracts a {@link java.lang.Comparable 410 // * Comparable} sort key from a type {@code T}, and returns a {@code 411 // * Comparator!(T)} that compares by that sort key. 412 // * 413 // * <p>The returned comparator is serializable if the specified function 414 // * is also serializable. 415 // * 416 // * @apiNote 417 // * For example, to obtain a {@code Comparator} that compares {@code 418 // * Person} objects by their last name, 419 // * 420 // * <pre>{@code 421 // * Comparator<Person> byLastName = Comparator.comparing(Person::getLastName); 422 // * }</pre> 423 // * 424 // * @param !(T) the type of element to be compared 425 // * @param !(U) the type of the {@code Comparable} sort key 426 // * @param keyExtractor the function used to extract the {@link 427 // * Comparable} sort key 428 // * @return a comparator that compares by an extracted key 429 // * @throws NullPointerException if the argument is null 430 // */ 431 // static <T, U extends Comparable<U>> Comparator!(T) comparing( 432 // Function<T, U> keyExtractor) 433 // { 434 // Objects.requireNonNull(keyExtractor); 435 // return (Comparator!(T) & Serializable) 436 // (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2)); 437 // } 438 439 // /** 440 // * Accepts a function that extracts an {@code int} sort key from a type 441 // * {@code T}, and returns a {@code Comparator!(T)} that compares by that 442 // * sort key. 443 // * 444 // * <p>The returned comparator is serializable if the specified function 445 // * is also serializable. 446 // * 447 // * @param !(T) the type of element to be compared 448 // * @param keyExtractor the function used to extract the integer sort key 449 // * @return a comparator that compares by an extracted key 450 // * @see #comparing(Function) 451 // * @throws NullPointerException if the argument is null 452 // */ 453 // static !(T) Comparator!(T) comparingInt(ToIntFunction<T> keyExtractor) { 454 // Objects.requireNonNull(keyExtractor); 455 // return (Comparator!(T) & Serializable) 456 // (c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2)); 457 // } 458 459 // /** 460 // * Accepts a function that extracts a {@code long} sort key from a type 461 // * {@code T}, and returns a {@code Comparator!(T)} that compares by that 462 // * sort key. 463 // * 464 // * <p>The returned comparator is serializable if the specified function is 465 // * also serializable. 466 // * 467 // * @param !(T) the type of element to be compared 468 // * @param keyExtractor the function used to extract the long sort key 469 // * @return a comparator that compares by an extracted key 470 // * @see #comparing(Function) 471 // * @throws NullPointerException if the argument is null 472 // */ 473 // static !(T) Comparator!(T) comparingLong(ToLongFunction<T> keyExtractor) { 474 // Objects.requireNonNull(keyExtractor); 475 // return (Comparator!(T) & Serializable) 476 // (c1, c2) -> Long.compare(keyExtractor.applyAsLong(c1), keyExtractor.applyAsLong(c2)); 477 // } 478 479 // /** 480 // * Accepts a function that extracts a {@code double} sort key from a type 481 // * {@code T}, and returns a {@code Comparator!(T)} that compares by that 482 // * sort key. 483 // * 484 // * <p>The returned comparator is serializable if the specified function 485 // * is also serializable. 486 // * 487 // * @param !(T) the type of element to be compared 488 // * @param keyExtractor the function used to extract the double sort key 489 // * @return a comparator that compares by an extracted key 490 // * @see #comparing(Function) 491 // * @throws NullPointerException if the argument is null 492 // */ 493 // static!(T) Comparator!(T) comparingDouble(ToDoubleFunction<T> keyExtractor) { 494 // Objects.requireNonNull(keyExtractor); 495 // return (Comparator!(T) & Serializable) 496 // (c1, c2) -> Double.compare(keyExtractor.applyAsDouble(c1), keyExtractor.applyAsDouble(c2)); 497 // } 498 } 499 500 501 int compare(T)(T x, T y) nothrow if(isOrderingComparable!(T)) { 502 try { 503 return (x < y) ? -1 : ((x == y) ? 0 : 1); 504 } catch(Exception ex) { 505 debug warning(ex.msg); 506 return 0; 507 } 508 } 509 510 // FIXME: Needing refactor or cleanup -@zxp at 12/30/2018, 9:43:22 AM 511 // opCmp in a class, struct or interface should be nothrow. 512 bool lessThan(T)(ref T a, ref T b) nothrow if(isOrderingComparable!(T)) { 513 try { 514 return a < b; 515 } catch(Exception ex) { 516 debug warning(ex.msg); 517 return false; 518 } 519 } 520 521 bool greaterthan(T)(ref T a, ref T b) nothrow if(isOrderingComparable!(T)) { 522 try { 523 return a > b; 524 } catch(Exception ex) { 525 debug warning(ex.msg); 526 return false; 527 } 528 }