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