< prev index next >

src/java.base/share/classes/java/util/Comparators.java

Print this page
rev 17656 : [mq]: 8134512-provide-Alpha-Numeric-logical-Comparator
   1 /*
   2  * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any


  76         @Override
  77         public int compare(T a, T b) {
  78             if (a == null) {
  79                 return (b == null) ? 0 : (nullFirst ? -1 : 1);
  80             } else if (b == null) {
  81                 return nullFirst ? 1: -1;
  82             } else {
  83                 return (real == null) ? 0 : real.compare(a, b);
  84             }
  85         }
  86 
  87         @Override
  88         public Comparator<T> thenComparing(Comparator<? super T> other) {
  89             Objects.requireNonNull(other);
  90             return new NullComparator<>(nullFirst, real == null ? other : real.thenComparing(other));
  91         }
  92 
  93         @Override
  94         public Comparator<T> reversed() {
  95             return new NullComparator<>(!nullFirst, real == null ? null : real.reversed());







































































































































































































  96         }
  97     }
  98 }
   1 /*
   2  * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any


  76         @Override
  77         public int compare(T a, T b) {
  78             if (a == null) {
  79                 return (b == null) ? 0 : (nullFirst ? -1 : 1);
  80             } else if (b == null) {
  81                 return nullFirst ? 1: -1;
  82             } else {
  83                 return (real == null) ? 0 : real.compare(a, b);
  84             }
  85         }
  86 
  87         @Override
  88         public Comparator<T> thenComparing(Comparator<? super T> other) {
  89             Objects.requireNonNull(other);
  90             return new NullComparator<>(nullFirst, real == null ? other : real.thenComparing(other));
  91         }
  92 
  93         @Override
  94         public Comparator<T> reversed() {
  95             return new NullComparator<>(!nullFirst, real == null ? null : real.reversed());
  96         }
  97     }
  98 
  99     /**
 100      * The comparator for comparing character sequences that consist solely
 101      * of decimal digits.  The result of comparing is as if the values were
 102      * compared numerically.
 103      */
 104     private static class DecimalComparator implements Comparator<CharSequence>,
 105             Serializable {
 106 
 107         private static final long serialVersionUID = 0x661e8cc550c7704dL;
 108 
 109         private static final Comparator<CharSequence>
 110                 DECIMAL_COMPARATOR_LEADING_ZEROES_FIRST =
 111                 new DecimalComparator(true) {
 112                     @Override
 113                     public Comparator<CharSequence> reversed() {
 114                         return DECIMAL_COMPARATOR_LEADING_ZEROES_FIRST_REVERSED;
 115                     }
 116                 };
 117 
 118         private static final Comparator<CharSequence>
 119                 DECIMAL_COMPARATOR_LEADING_ZEROES_LAST =
 120                 new DecimalComparator(false) {
 121                     @Override
 122                     public Comparator<CharSequence> reversed() {
 123                         return DECIMAL_COMPARATOR_LEADING_ZEROES_LAST_REVERSED;
 124                     }
 125                 };
 126 
 127         private static final Comparator<CharSequence>
 128                 DECIMAL_COMPARATOR_LEADING_ZEROES_FIRST_REVERSED =
 129                 new DecimalComparator(true) {
 130                     @Override
 131                     public Comparator<CharSequence> reversed() {
 132                         return DECIMAL_COMPARATOR_LEADING_ZEROES_FIRST;
 133                     }
 134                     @Override
 135                     public int compare(CharSequence cs1, CharSequence cs2) {
 136                         return super.compare(cs2, cs1);
 137                     }
 138                 };
 139 
 140         private static final Comparator<CharSequence>
 141                 DECIMAL_COMPARATOR_LEADING_ZEROES_LAST_REVERSED =
 142                 new DecimalComparator(false) {
 143                     @Override
 144                     public Comparator<CharSequence> reversed() {
 145                         return DECIMAL_COMPARATOR_LEADING_ZEROES_LAST;
 146                     }
 147                     @Override
 148                     public int compare(CharSequence cs1, CharSequence cs2) {
 149                         return super.compare(cs2, cs1);
 150                     }
 151                 };
 152 
 153         private final boolean leadingZeroesFirst;
 154 
 155         private DecimalComparator(boolean leadingZeroesFirst) {
 156             this.leadingZeroesFirst = leadingZeroesFirst;
 157         }
 158 
 159         static Comparator<CharSequence> getInstance(boolean leadingZeroesFirst) {
 160             return leadingZeroesFirst ? DECIMAL_COMPARATOR_LEADING_ZEROES_FIRST
 161                     : DECIMAL_COMPARATOR_LEADING_ZEROES_LAST;
 162         }
 163 
 164         private boolean canSkipLeadingZeroes(CharSequence s, int len) {
 165             for (int i = 0; i < len;) {
 166                 int cp = Character.codePointAt(s, i);
 167                 if (Character.digit(cp, 10) != 0)
 168                     return false;
 169                 i += Character.charCount(cp);
 170             }
 171             return true;
 172         }
 173 
 174         @Override
 175         public int compare(CharSequence cs1, CharSequence cs2) {
 176             int len1 = Character.codePointCount(cs1, 0, cs1.length());
 177             int len2 = Character.codePointCount(cs2, 0, cs2.length());
 178             int dlen = len1 - len2;
 179             if (len1 == 0 || len2 == 0) {
 180                 return dlen;
 181             } else if (dlen > 0) {
 182                 if (!canSkipLeadingZeroes(cs1, dlen))
 183                     return 1;
 184                 int off = Character.offsetByCodePoints(cs1, 0, dlen);
 185                 cs1 = cs1.subSequence(off, cs1.length());
 186             } else if (dlen < 0) {
 187                 if (!canSkipLeadingZeroes(cs2, -dlen))
 188                     return -1;
 189                 int off = Character.offsetByCodePoints(cs2, 0, -dlen);
 190                 cs2 = cs2.subSequence(off, cs2.length());
 191             }
 192             int cmp = 0;
 193             for (int i1 = 0, i2 = 0; i1 < cs1.length(); ) {
 194                 int cp1 = Character.codePointAt(cs1, i1);
 195                 int cp2 = Character.codePointAt(cs2, i2);
 196                 if (cp1 != cp2) {
 197                     if (cmp == 0) {
 198                         cmp = cp1 - cp2;
 199                     }
 200                     int cmpNum = Character.digit(cp1, 10) -
 201                             Character.digit(cp2, 10);
 202                     if (cmpNum != 0) {
 203                         return cmpNum;
 204                     }
 205                 }
 206                 i1 += Character.charCount(cp1);
 207                 i2 += Character.charCount(cp2);
 208             }
 209             return dlen == 0 ? cmp : (leadingZeroesFirst ^ (dlen < 0) ? -1 : 1);
 210         }
 211     }
 212 
 213     /**
 214      * Compares char sequences, taking into account their numeric part if one
 215      * exists.
 216      *
 217      * @see Comparator#comparingAlphaDecimal(Comparator)
 218      * @see Comparator#comparingAlphaDecimalLeadingZeroesFirst(Comparator)
 219      */
 220     static class AlphaDecimalComparator<T extends CharSequence>
 221             implements Comparator<T>, Serializable {
 222 
 223         private static final long serialVersionUID = 0xd7a7129b9ca1056dL;
 224 
 225         private final Comparator<? super CharSequence> alphaComparator;
 226         private final Comparator<CharSequence> decimalComparator;
 227 
 228         AlphaDecimalComparator(Comparator<? super CharSequence> alphaComparator,
 229                                boolean leadingZeroesFirst) {
 230             this(alphaComparator, DecimalComparator.getInstance(leadingZeroesFirst));
 231         }
 232 
 233         private AlphaDecimalComparator(Comparator<? super CharSequence> alphaComparator,
 234                                        Comparator<CharSequence> decimalComparator) {
 235             this.alphaComparator = alphaComparator;
 236             this.decimalComparator = decimalComparator;
 237         }
 238 
 239         @Override
 240         public Comparator<T> reversed() {
 241             return new AlphaDecimalComparator<>(alphaComparator.reversed(),
 242                     decimalComparator.reversed());
 243         }
 244 
 245         @Override
 246         public int compare(T cs1, T cs2) {
 247             Decomposer d1 = new Decomposer(cs1);
 248             Decomposer d2 = new Decomposer(cs2);
 249             for (;;) {
 250                 int cmp;
 251                 if ((cmp = alphaComparator.compare(d1.get(), d2.get())) != 0 ||
 252                     (cmp = decimalComparator.compare(d1.get(), d2.get())) != 0)
 253                 {
 254                     return cmp;
 255                 }
 256                 if (d1.eos() && d2.eos()) return 0;
 257             }
 258         }
 259 
 260         /**
 261          * Given a CharSequence, splits it into a series of subsequences so that
 262          * every character of the very first subsequence (possibly empty) is
 263          * not a decimal digit;  then every character of the second subsequence
 264          * is a decimal digit, and so on.
 265          */
 266         private static class Decomposer {
 267             private final CharSequence sequence;
 268             private boolean expectingDecimal = false;
 269             private int index = 0;
 270 
 271             Decomposer(CharSequence sequence) {
 272                 this.sequence = sequence;
 273             }
 274 
 275             CharSequence get() {
 276                 int start = index, end = start, len = sequence.length() - start;
 277                 while (len > 0) {
 278                     int cp = Character.codePointAt(sequence, end);
 279                     int ct = Character.getType(cp);
 280                     boolean isDecimal = (ct == Character.DECIMAL_DIGIT_NUMBER);
 281                     if (isDecimal ^ expectingDecimal) {
 282                         break;
 283                     }
 284                     int cpWidth = Character.charCount(cp);
 285                     end += cpWidth;
 286                     len -= cpWidth;
 287                 }
 288                 expectingDecimal = !expectingDecimal;
 289                 return sequence.subSequence(start, index = end);
 290             }
 291 
 292             boolean eos() {
 293                 return index >= sequence.length();
 294             }
 295         }
 296     }
 297 }
< prev index next >