1/* GENERATED SOURCE. DO NOT MODIFY. */
2// © 2016 and later: Unicode, Inc. and others.
3// License & terms of use: http://www.unicode.org/copyright.html#License
4/*
5 *******************************************************************************
6 * Copyright (C) 1996-2015, International Business Machines
7 * Corporation and others.  All Rights Reserved.
8 *******************************************************************************
9 * CollationCompare.java, ported from collationcompare.h/.cpp
10 *
11 * C++ version created on: 2012feb14 with new and old collation code
12 * created by: Markus W. Scherer
13 */
14
15package android.icu.impl.coll;
16
17import android.icu.text.Collator;
18
19/**
20 * @hide Only a subset of ICU is exposed in Android
21 */
22public final class CollationCompare /* all static */ {
23    public static int compareUpToQuaternary(CollationIterator left, CollationIterator right,
24            CollationSettings settings) {
25        int options = settings.options;
26        long variableTop;
27        if ((options & CollationSettings.ALTERNATE_MASK) == 0) {
28            variableTop = 0;
29        } else {
30            // +1 so that we can use "<" and primary ignorables test out early.
31            variableTop = settings.variableTop + 1;
32        }
33        boolean anyVariable = false;
34
35        // Fetch CEs, compare primaries, store secondary & tertiary weights.
36        for (;;) {
37            // We fetch CEs until we get a non-ignorable primary or reach the end.
38            long leftPrimary;
39            do {
40                long ce = left.nextCE();
41                leftPrimary = ce >>> 32;
42                if (leftPrimary < variableTop && leftPrimary > Collation.MERGE_SEPARATOR_PRIMARY) {
43                    // Variable CE, shift it to quaternary level.
44                    // Ignore all following primary ignorables, and shift further variable CEs.
45                    anyVariable = true;
46                    do {
47                        // Store only the primary of the variable CE.
48                        left.setCurrentCE(ce & 0xffffffff00000000L);
49                        for (;;) {
50                            ce = left.nextCE();
51                            leftPrimary = ce >>> 32;
52                            if (leftPrimary == 0) {
53                                left.setCurrentCE(0);
54                            } else {
55                                break;
56                            }
57                        }
58                    } while (leftPrimary < variableTop && leftPrimary > Collation.MERGE_SEPARATOR_PRIMARY);
59                }
60            } while (leftPrimary == 0);
61
62            long rightPrimary;
63            do {
64                long ce = right.nextCE();
65                rightPrimary = ce >>> 32;
66                if (rightPrimary < variableTop && rightPrimary > Collation.MERGE_SEPARATOR_PRIMARY) {
67                    // Variable CE, shift it to quaternary level.
68                    // Ignore all following primary ignorables, and shift further variable CEs.
69                    anyVariable = true;
70                    do {
71                        // Store only the primary of the variable CE.
72                        right.setCurrentCE(ce & 0xffffffff00000000L);
73                        for (;;) {
74                            ce = right.nextCE();
75                            rightPrimary = ce >>> 32;
76                            if (rightPrimary == 0) {
77                                right.setCurrentCE(0);
78                            } else {
79                                break;
80                            }
81                        }
82                    } while (rightPrimary < variableTop && rightPrimary > Collation.MERGE_SEPARATOR_PRIMARY);
83                }
84            } while (rightPrimary == 0);
85
86            if (leftPrimary != rightPrimary) {
87                // Return the primary difference, with script reordering.
88                if (settings.hasReordering()) {
89                    leftPrimary = settings.reorder(leftPrimary);
90                    rightPrimary = settings.reorder(rightPrimary);
91                }
92                return (leftPrimary < rightPrimary) ? Collation.LESS : Collation.GREATER;
93            }
94            if (leftPrimary == Collation.NO_CE_PRIMARY) {
95                break;
96            }
97        }
98
99        // Compare the buffered secondary & tertiary weights.
100        // We might skip the secondary level but continue with the case level
101        // which is turned on separately.
102        if (CollationSettings.getStrength(options) >= Collator.SECONDARY) {
103            if ((options & CollationSettings.BACKWARD_SECONDARY) == 0) {
104                int leftIndex = 0;
105                int rightIndex = 0;
106                for (;;) {
107                    int leftSecondary;
108                    do {
109                        leftSecondary = ((int) left.getCE(leftIndex++)) >>> 16;
110                    } while (leftSecondary == 0);
111
112                    int rightSecondary;
113                    do {
114                        rightSecondary = ((int) right.getCE(rightIndex++)) >>> 16;
115                    } while (rightSecondary == 0);
116
117                    if (leftSecondary != rightSecondary) {
118                        return (leftSecondary < rightSecondary) ? Collation.LESS : Collation.GREATER;
119                    }
120                    if (leftSecondary == Collation.NO_CE_WEIGHT16) {
121                        break;
122                    }
123                }
124            } else {
125                // The backwards secondary level compares secondary weights backwards
126                // within segments separated by the merge separator (U+FFFE, weight 02).
127                int leftStart = 0;
128                int rightStart = 0;
129                for (;;) {
130                    // Find the merge separator or the NO_CE terminator.
131                    long p;
132                    int leftLimit = leftStart;
133                    while ((p = left.getCE(leftLimit) >>> 32) > Collation.MERGE_SEPARATOR_PRIMARY
134                            || p == 0) {
135                        ++leftLimit;
136                    }
137                    int rightLimit = rightStart;
138                    while ((p = right.getCE(rightLimit) >>> 32) > Collation.MERGE_SEPARATOR_PRIMARY
139                            || p == 0) {
140                        ++rightLimit;
141                    }
142
143                    // Compare the segments.
144                    int leftIndex = leftLimit;
145                    int rightIndex = rightLimit;
146                    for (;;) {
147                        int leftSecondary = 0;
148                        while (leftSecondary == 0 && leftIndex > leftStart) {
149                            leftSecondary = ((int) left.getCE(--leftIndex)) >>> 16;
150                        }
151
152                        int rightSecondary = 0;
153                        while (rightSecondary == 0 && rightIndex > rightStart) {
154                            rightSecondary = ((int) right.getCE(--rightIndex)) >>> 16;
155                        }
156
157                        if (leftSecondary != rightSecondary) {
158                            return (leftSecondary < rightSecondary) ? Collation.LESS : Collation.GREATER;
159                        }
160                        if (leftSecondary == 0) {
161                            break;
162                        }
163                    }
164
165                    // Did we reach the end of either string?
166                    // Both strings have the same number of merge separators,
167                    // or else there would have been a primary-level difference.
168                    assert (left.getCE(leftLimit) == right.getCE(rightLimit));
169                    if (p == Collation.NO_CE_PRIMARY) {
170                        break;
171                    }
172                    // Skip both merge separators and continue.
173                    leftStart = leftLimit + 1;
174                    rightStart = rightLimit + 1;
175                }
176            }
177        }
178
179        if ((options & CollationSettings.CASE_LEVEL) != 0) {
180            int strength = CollationSettings.getStrength(options);
181            int leftIndex = 0;
182            int rightIndex = 0;
183            for (;;) {
184                int leftCase, leftLower32, rightCase;
185                if (strength == Collator.PRIMARY) {
186                    // Primary+caseLevel: Ignore case level weights of primary ignorables.
187                    // Otherwise we would get a-umlaut > a
188                    // which is not desirable for accent-insensitive sorting.
189                    // Check for (lower 32 bits) == 0 as well because variable CEs are stored
190                    // with only primary weights.
191                    long ce;
192                    do {
193                        ce = left.getCE(leftIndex++);
194                        leftCase = (int) ce;
195                    } while ((ce >>> 32) == 0 || leftCase == 0);
196                    leftLower32 = leftCase;
197                    leftCase &= 0xc000;
198
199                    do {
200                        ce = right.getCE(rightIndex++);
201                        rightCase = (int) ce;
202                    } while ((ce >>> 32) == 0 || rightCase == 0);
203                    rightCase &= 0xc000;
204                } else {
205                    // Secondary+caseLevel: By analogy with the above,
206                    // ignore case level weights of secondary ignorables.
207                    //
208                    // Note: A tertiary CE has uppercase case bits (0.0.ut)
209                    // to keep tertiary+caseFirst well-formed.
210                    //
211                    // Tertiary+caseLevel: Also ignore case level weights of secondary ignorables.
212                    // Otherwise a tertiary CE's uppercase would be no greater than
213                    // a primary/secondary CE's uppercase.
214                    // (See UCA well-formedness condition 2.)
215                    // We could construct a special case weight higher than uppercase,
216                    // but it's simpler to always ignore case weights of secondary ignorables,
217                    // turning 0.0.ut into 0.0.0.t.
218                    // (See LDML Collation, Case Parameters.)
219                    do {
220                        leftCase = (int) left.getCE(leftIndex++);
221                    } while ((leftCase & 0xffff0000) == 0);
222                    leftLower32 = leftCase;
223                    leftCase &= 0xc000;
224
225                    do {
226                        rightCase = (int) right.getCE(rightIndex++);
227                    } while ((rightCase & 0xffff0000) == 0);
228                    rightCase &= 0xc000;
229                }
230
231                // No need to handle NO_CE and MERGE_SEPARATOR specially:
232                // There is one case weight for each previous-level weight,
233                // so level length differences were handled there.
234                if (leftCase != rightCase) {
235                    if ((options & CollationSettings.UPPER_FIRST) == 0) {
236                        return (leftCase < rightCase) ? Collation.LESS : Collation.GREATER;
237                    } else {
238                        return (leftCase < rightCase) ? Collation.GREATER : Collation.LESS;
239                    }
240                }
241                if ((leftLower32 >>> 16) == Collation.NO_CE_WEIGHT16) {
242                    break;
243                }
244            }
245        }
246        if (CollationSettings.getStrength(options) <= Collator.SECONDARY) {
247            return Collation.EQUAL;
248        }
249
250        int tertiaryMask = CollationSettings.getTertiaryMask(options);
251
252        int leftIndex = 0;
253        int rightIndex = 0;
254        int anyQuaternaries = 0;
255        for (;;) {
256            int leftLower32, leftTertiary;
257            do {
258                leftLower32 = (int) left.getCE(leftIndex++);
259                anyQuaternaries |= leftLower32;
260                assert ((leftLower32 & Collation.ONLY_TERTIARY_MASK) != 0 || (leftLower32 & 0xc0c0) == 0);
261                leftTertiary = leftLower32 & tertiaryMask;
262            } while (leftTertiary == 0);
263
264            int rightLower32, rightTertiary;
265            do {
266                rightLower32 = (int) right.getCE(rightIndex++);
267                anyQuaternaries |= rightLower32;
268                assert ((rightLower32 & Collation.ONLY_TERTIARY_MASK) != 0 || (rightLower32 & 0xc0c0) == 0);
269                rightTertiary = rightLower32 & tertiaryMask;
270            } while (rightTertiary == 0);
271
272            if (leftTertiary != rightTertiary) {
273                if (CollationSettings.sortsTertiaryUpperCaseFirst(options)) {
274                    // Pass through NO_CE and keep real tertiary weights larger than that.
275                    // Do not change the artificial uppercase weight of a tertiary CE (0.0.ut),
276                    // to keep tertiary CEs well-formed.
277                    // Their case+tertiary weights must be greater than those of
278                    // primary and secondary CEs.
279                    if (leftTertiary > Collation.NO_CE_WEIGHT16) {
280                        if ((leftLower32 & 0xffff0000) != 0) {
281                            leftTertiary ^= 0xc000;
282                        } else {
283                            leftTertiary += 0x4000;
284                        }
285                    }
286                    if (rightTertiary > Collation.NO_CE_WEIGHT16) {
287                        if ((rightLower32 & 0xffff0000) != 0) {
288                            rightTertiary ^= 0xc000;
289                        } else {
290                            rightTertiary += 0x4000;
291                        }
292                    }
293                }
294                return (leftTertiary < rightTertiary) ? Collation.LESS : Collation.GREATER;
295            }
296            if (leftTertiary == Collation.NO_CE_WEIGHT16) {
297                break;
298            }
299        }
300        if (CollationSettings.getStrength(options) <= Collator.TERTIARY) {
301            return Collation.EQUAL;
302        }
303
304        if (!anyVariable && (anyQuaternaries & 0xc0) == 0) {
305            // If there are no "variable" CEs and no non-zero quaternary weights,
306            // then there are no quaternary differences.
307            return Collation.EQUAL;
308        }
309
310        leftIndex = 0;
311        rightIndex = 0;
312        for (;;) {
313            long leftQuaternary;
314            do {
315                long ce = left.getCE(leftIndex++);
316                leftQuaternary = ce & 0xffff;
317                if (leftQuaternary <= Collation.NO_CE_WEIGHT16) {
318                    // Variable primary or completely ignorable or NO_CE.
319                    leftQuaternary = ce >>> 32;
320                } else {
321                    // Regular CE, not tertiary ignorable.
322                    // Preserve the quaternary weight in bits 7..6.
323                    leftQuaternary |= 0xffffff3fL;
324                }
325            } while (leftQuaternary == 0);
326
327            long rightQuaternary;
328            do {
329                long ce = right.getCE(rightIndex++);
330                rightQuaternary = ce & 0xffff;
331                if (rightQuaternary <= Collation.NO_CE_WEIGHT16) {
332                    // Variable primary or completely ignorable or NO_CE.
333                    rightQuaternary = ce >>> 32;
334                } else {
335                    // Regular CE, not tertiary ignorable.
336                    // Preserve the quaternary weight in bits 7..6.
337                    rightQuaternary |= 0xffffff3fL;
338                }
339            } while (rightQuaternary == 0);
340
341            if (leftQuaternary != rightQuaternary) {
342                // Return the difference, with script reordering.
343                if (settings.hasReordering()) {
344                    leftQuaternary = settings.reorder(leftQuaternary);
345                    rightQuaternary = settings.reorder(rightQuaternary);
346                }
347                return (leftQuaternary < rightQuaternary) ? Collation.LESS : Collation.GREATER;
348            }
349            if (leftQuaternary == Collation.NO_CE_PRIMARY) {
350                break;
351            }
352        }
353        return Collation.EQUAL;
354    }
355}
356