17935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/*
27935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert*******************************************************************************
3f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert* Copyright (C) 2013-2015, International Business Machines
47935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert* Corporation and others.  All Rights Reserved.
57935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert*******************************************************************************
67935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert* CollationSettings.java, ported from collationsettings.h/.cpp
77935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert*
87935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert* C++ version created on: 2013feb07
97935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert* created by: Markus W. Scherer
107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert*/
117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpackage com.ibm.icu.impl.coll;
137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Arrays;
157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.Collator;
177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/**
197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Collation settings/options/attributes.
207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * These are the values that can be changed via API.
217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */
227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpublic final class CollationSettings extends SharedObject {
237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Options bit 0: Perform the FCD check on the input text and deliver normalized text.
257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static final int CHECK_FCD = 1;
277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Options bit 1: Numeric collation.
297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Also known as CODAN = COllate Digits As Numbers.
307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Treat digit sequences as numbers with CE sequences in numeric order,
327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * rather than returning a normal CE for each digit.
337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static final int NUMERIC = 2;
357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * "Shifted" alternate handling, see ALTERNATE_MASK.
377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    static final int SHIFTED = 4;
397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Options bits 3..2: Alternate-handling mask. 0 for non-ignorable.
417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Reserve values 8 and 0xc for shift-trimmed and blanked.
427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    static final int ALTERNATE_MASK = 0xc;
447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Options bits 6..4: The 3-bit maxVariable value bit field is shifted by this value.
467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    static final int MAX_VARIABLE_SHIFT = 4;
487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /** maxVariable options bit mask before shifting. */
497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    static final int MAX_VARIABLE_MASK = 0x70;
507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /** Options bit 7: Reserved/unused/0. */
517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Options bit 8: Sort uppercase first if caseLevel or caseFirst is on.
537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    static final int UPPER_FIRST = 0x100;
557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Options bit 9: Keep the case bits in the tertiary weight (they trump other tertiary values)
577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * unless case level is on (when they are *moved* into the separate case level).
587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * By default, the case bits are removed from the tertiary weight (ignored).
597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     *
607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * When CASE_FIRST is off, UPPER_FIRST must be off too, corresponding to
617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * the tri-value UCOL_CASE_FIRST attribute: UCOL_OFF vs. UCOL_LOWER_FIRST vs. UCOL_UPPER_FIRST.
627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static final int CASE_FIRST = 0x200;
647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Options bit mask for caseFirst and upperFirst, before shifting.
667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Same value as caseFirst==upperFirst.
677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static final int CASE_FIRST_AND_UPPER_MASK = CASE_FIRST | UPPER_FIRST;
697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Options bit 10: Insert the case level between the secondary and tertiary levels.
717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static final int CASE_LEVEL = 0x400;
737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Options bit 11: Compare secondary weights backwards. ("French secondary")
757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public static final int BACKWARD_SECONDARY = 0x800;
777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Options bits 15..12: The 4-bit strength value bit field is shifted by this value.
797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * It is the top used bit field in the options. (No need to mask after shifting.)
807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    static final int STRENGTH_SHIFT = 12;
827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /** Strength options bit mask before shifting. */
837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    static final int STRENGTH_MASK = 0xf000;
847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /** maxVariable values */
867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    static final int MAX_VAR_SPACE = 0;
877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    static final int MAX_VAR_PUNCT = 1;
887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    static final int MAX_VAR_SYMBOL = 2;
897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    static final int MAX_VAR_CURRENCY = 3;
907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    CollationSettings() {}
927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @Override
947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public CollationSettings clone() {
957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        CollationSettings newSettings = (CollationSettings)super.clone();
96f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        // Note: The reorderTable, reorderRanges, and reorderCodes need not be cloned
977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // because, in Java, they only get replaced but not modified.
987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        newSettings.fastLatinPrimaries = fastLatinPrimaries.clone();
997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return newSettings;
1007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @Override
1037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public boolean equals(Object other) {
1047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if(other == null) { return false; }
1057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if(!this.getClass().equals(other.getClass())) { return false; }
1067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        CollationSettings o = (CollationSettings)other;
1077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if(options != o.options) { return false; }
1087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if((options & ALTERNATE_MASK) != 0 && variableTop != o.variableTop) { return false; }
1097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if(!Arrays.equals(reorderCodes, o.reorderCodes)) { return false; }
1107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return true;
1117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    @Override
1147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public int hashCode() {
1157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int h = options << 8;
1167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if((options & ALTERNATE_MASK) != 0) { h ^= variableTop; }
1177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        h ^= reorderCodes.length;
1187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        for(int i = 0; i < reorderCodes.length; ++i) {
1197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            h ^= (reorderCodes[i] << i);
1207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
1217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return h;
1227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void resetReordering() {
1257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // When we turn off reordering, we want to set a null permutation
1267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // rather than a no-op permutation.
1277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        reorderTable = null;
128f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        minHighNoReorder = 0;
129f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        reorderRanges = null;
1307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        reorderCodes = EMPTY_INT_ARRAY;
1317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
132f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert
133f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    void aliasReordering(CollationData data, int[] codesAndRanges, int codesLength, byte[] table) {
134f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        int[] codes;
135f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        if(codesLength == codesAndRanges.length) {
136f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            codes = codesAndRanges;
137f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        } else {
138f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            // TODO: Java 6: Arrays.copyOf(codes, codesLength);
139f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            codes = new int[codesLength];
140f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            System.arraycopy(codesAndRanges, 0, codes, 0, codesLength);
141f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        }
142f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        int rangesStart = codesLength;
143f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        int rangesLimit = codesAndRanges.length;
144f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        int rangesLength = rangesLimit - rangesStart;
145f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        if(table != null &&
146f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                (rangesLength == 0 ?
147f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                        !reorderTableHasSplitBytes(table) :
148f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                        rangesLength >= 2 &&
149f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                        // The first offset must be 0. The last offset must not be 0.
150f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                        (codesAndRanges[rangesStart] & 0xffff) == 0 &&
151f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                        (codesAndRanges[rangesLimit - 1] & 0xffff) != 0)) {
152f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            reorderTable = table;
153f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            reorderCodes = codes;
154f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            // Drop ranges before the first split byte. They are reordered by the table.
155f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            // This then speeds up reordering of the remaining ranges.
156f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            int firstSplitByteRangeIndex = rangesStart;
157f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            while(firstSplitByteRangeIndex < rangesLimit &&
158f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                    (codesAndRanges[firstSplitByteRangeIndex] & 0xff0000) == 0) {
159f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                // The second byte of the primary limit is 0.
160f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                ++firstSplitByteRangeIndex;
161f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            }
162f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            if(firstSplitByteRangeIndex == rangesLimit) {
163f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                assert(!reorderTableHasSplitBytes(table));
164f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                minHighNoReorder = 0;
165f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                reorderRanges = null;
166f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            } else {
167f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                assert(table[codesAndRanges[firstSplitByteRangeIndex] >>> 24] == 0);
168f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                minHighNoReorder = codesAndRanges[rangesLimit - 1] & 0xffff0000L;
169f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                setReorderRanges(codesAndRanges, firstSplitByteRangeIndex,
170f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                        rangesLimit - firstSplitByteRangeIndex);
171f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            }
172f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            return;
173f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        }
174f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        // Regenerate missing data.
175f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        setReordering(data, codes);
176f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    }
177f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert
178f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    public void setReordering(CollationData data, int[] codes) {
179f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        if(codes.length == 0 || (codes.length == 1 && codes[0] == Collator.ReorderCodes.NONE)) {
180f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            resetReordering();
181f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            return;
182f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        }
183f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        UVector32 rangesList = new UVector32();
184f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        data.makeReorderRanges(codes, rangesList);
185f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        int rangesLength = rangesList.size();
186f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        if(rangesLength == 0) {
187f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            resetReordering();
188f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            return;
189f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        }
190f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        int[] ranges = rangesList.getBuffer();
191f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        // ranges[] contains at least two (limit, offset) pairs.
192f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        // The first offset must be 0. The last offset must not be 0.
193f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        // Separators (at the low end) and trailing weights (at the high end)
194f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        // are never reordered.
195f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        assert(rangesLength >= 2);
196f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        assert((ranges[0] & 0xffff) == 0 && (ranges[rangesLength - 1] & 0xffff) != 0);
197f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        minHighNoReorder = ranges[rangesLength - 1] & 0xffff0000L;
198f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert
199f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        // Write the lead byte permutation table.
200f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        // Set a 0 for each lead byte that has a range boundary in the middle.
201f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        byte[] table = new byte[256];
202f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        int b = 0;
203f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        int firstSplitByteRangeIndex = -1;
204f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        for(int i = 0; i < rangesLength; ++i) {
205f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            int pair = ranges[i];
206f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            int limit1 = pair >>> 24;
207f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            while(b < limit1) {
208f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                table[b] = (byte)(b + pair);
209f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                ++b;
210f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            }
211f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            // Check the second byte of the limit.
212f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            if((pair & 0xff0000) != 0) {
213f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                table[limit1] = 0;
214f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                b = limit1 + 1;
215f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                if(firstSplitByteRangeIndex < 0) {
216f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                    firstSplitByteRangeIndex = i;
217f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                }
218f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            }
219f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        }
220f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        while(b <= 0xff) {
221f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            table[b] = (byte)b;
222f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            ++b;
223f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        }
224f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        int rangesStart;
225f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        if(firstSplitByteRangeIndex < 0) {
226f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            // The lead byte permutation table alone suffices for reordering.
227f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            rangesStart = rangesLength = 0;
228f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        } else {
229f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            // Remove the ranges below the first split byte.
230f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            rangesStart = firstSplitByteRangeIndex;
231f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            rangesLength -= firstSplitByteRangeIndex;
232f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        }
233f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        setReorderArrays(codes, ranges, rangesStart, rangesLength, table);
234f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    }
235f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert
236f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    private void setReorderArrays(int[] codes,
237f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            int[] ranges, int rangesStart, int rangesLength, byte[] table) {
238f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        // Very different from C++. See the comments after the reorderCodes declaration.
2397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if(codes == null) {
2407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            codes = EMPTY_INT_ARRAY;
2417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
2427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        assert (codes.length == 0) == (table == null);
2437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        reorderTable = table;
2447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        reorderCodes = codes;
245f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        setReorderRanges(ranges, rangesStart, rangesLength);
246f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    }
247f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert
248f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    private void setReorderRanges(int[] ranges, int rangesStart, int rangesLength) {
249f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        if(rangesLength == 0) {
250f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            reorderRanges = null;
251f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        } else {
252f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            reorderRanges = new long[rangesLength];
253f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            int i = 0;
254f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            do {
255f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                reorderRanges[i++] = ranges[rangesStart++] & 0xffffffffL;
256f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            } while(i < rangesLength);
257f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        }
258f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    }
259f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert
260f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    public void copyReorderingFrom(CollationSettings other) {
261f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        if(!other.hasReordering()) {
262f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            resetReordering();
263f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            return;
264f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        }
265f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        minHighNoReorder = other.minHighNoReorder;
266f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        reorderTable = other.reorderTable;
267f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        reorderRanges = other.reorderRanges;
268f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        reorderCodes = other.reorderCodes;
269f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    }
270f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert
271f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    public boolean hasReordering() { return reorderTable != null; }
272f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert
273f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    private static boolean reorderTableHasSplitBytes(byte[] table) {
274f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        assert(table[0] == 0);
275f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        for(int i = 1; i < 256; ++i) {
276f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            if(table[i] == 0) {
277f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert                return true;
278f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            }
279f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        }
280f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        return false;
281f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    }
282f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert
283f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    public long reorder(long p) {
284f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        byte b = reorderTable[(int)p >>> 24];
285f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        if(b != 0 || p <= Collation.NO_CE_PRIMARY) {
286f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            return ((b & 0xffL) << 24) | (p & 0xffffff);
287f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        } else {
288f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert            return reorderEx(p);
289f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        }
290f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    }
291f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert
292f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    private long reorderEx(long p) {
293f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        assert minHighNoReorder > 0;
294f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        if(p >= minHighNoReorder) { return p; }
295f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        // Round up p so that its lower 16 bits are >= any offset bits.
296f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        // Then compare q directly with (limit, offset) pairs.
297f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        long q = p | 0xffff;
298f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        long r;
299f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        int i = 0;
300f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        while(q >= (r = reorderRanges[i])) { ++i; }
301f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert        return p + ((long)(short)r << 24);
3027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
3037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // In C++, we use enums for attributes and their values, with a special value for the default.
3057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // Combined getter/setter methods handle many attributes.
3067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // In Java, we have specific methods for getting, setting, and set-to-default,
3077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // except that this class uses bits in its own bit set for simple values.
3087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void setStrength(int value) {
3107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int noStrength = options & ~STRENGTH_MASK;
3117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        switch(value) {
3127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case Collator.PRIMARY:
3137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case Collator.SECONDARY:
3147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case Collator.TERTIARY:
3157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case Collator.QUATERNARY:
3167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case Collator.IDENTICAL:
3177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            options = noStrength | (value << STRENGTH_SHIFT);
3187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            break;
3197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        default:
3207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            throw new IllegalArgumentException("illegal strength value " + value);
3217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
3227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
3237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void setStrengthDefault(int defaultOptions) {
3257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int noStrength = options & ~STRENGTH_MASK;
3267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        options = noStrength | (defaultOptions & STRENGTH_MASK);
3277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
3287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    static int getStrength(int options) {
3307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return options >> STRENGTH_SHIFT;
3317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
3327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public int getStrength() {
3347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return getStrength(options);
3357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
3367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /** Sets the options bit for an on/off attribute. */
3387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void setFlag(int bit, boolean value) {
3397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if(value) {
3407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            options |= bit;
3417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } else {
3427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            options &= ~bit;
3437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
3447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
3457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void setFlagDefault(int bit, int defaultOptions) {
3477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        options = (options & ~bit) | (defaultOptions & bit);
3487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
3497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public boolean getFlag(int bit) {
3517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return (options & bit) != 0;
3527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
3537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void setCaseFirst(int value) {
3557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        assert value == 0 || value == CASE_FIRST || value == CASE_FIRST_AND_UPPER_MASK;
3567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int noCaseFirst = options & ~CASE_FIRST_AND_UPPER_MASK;
3577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        options = noCaseFirst | value;
3587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
3597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void setCaseFirstDefault(int defaultOptions) {
3617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int noCaseFirst = options & ~CASE_FIRST_AND_UPPER_MASK;
3627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        options = noCaseFirst | (defaultOptions & CASE_FIRST_AND_UPPER_MASK);
3637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
3647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public int getCaseFirst() {
3667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return options & CASE_FIRST_AND_UPPER_MASK;
3677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
3687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void setAlternateHandlingShifted(boolean value) {
3707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int noAlternate = options & ~ALTERNATE_MASK;
3717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        if(value) {
3727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            options = noAlternate | SHIFTED;
3737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        } else {
3747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            options = noAlternate;
3757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
3767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
3777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void setAlternateHandlingDefault(int defaultOptions) {
3797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int noAlternate = options & ~ALTERNATE_MASK;
3807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        options = noAlternate | (defaultOptions & ALTERNATE_MASK);
3817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
3827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public boolean getAlternateHandling() {
3847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return (options & ALTERNATE_MASK) != 0;
3857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
3867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
3877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public void setMaxVariable(int value, int defaultOptions) {
3887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        int noMax = options & ~MAX_VARIABLE_MASK;
3897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        switch(value) {
3907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case MAX_VAR_SPACE:
3917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case MAX_VAR_PUNCT:
3927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case MAX_VAR_SYMBOL:
3937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case MAX_VAR_CURRENCY:
3947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            options = noMax | (value << MAX_VARIABLE_SHIFT);
3957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            break;
3967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        case -1:
3977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            options = noMax | (defaultOptions & MAX_VARIABLE_MASK);
3987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            break;
3997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        default:
4007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            throw new IllegalArgumentException("illegal maxVariable value " + value);
4017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        }
4027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
4037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
4047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public int getMaxVariable() {
4057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return (options & MAX_VARIABLE_MASK) >> MAX_VARIABLE_SHIFT;
4067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
4077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
4087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /**
4097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     * Include case bits in the tertiary level if caseLevel=off and caseFirst!=off.
4107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert     */
4117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    static boolean isTertiaryWithCaseBits(int options) {
4127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return (options & (CASE_LEVEL | CASE_FIRST)) == CASE_FIRST;
4137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
4147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    static int getTertiaryMask(int options) {
4157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // Remove the case bits from the tertiary weight when caseLevel is on or caseFirst is off.
4167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return isTertiaryWithCaseBits(options) ?
4177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                Collation.CASE_AND_TERTIARY_MASK : Collation.ONLY_TERTIARY_MASK;
4187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
4197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
4207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    static boolean sortsTertiaryUpperCaseFirst(int options) {
4217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // On tertiary level, consider case bits and sort uppercase first
4227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        // if caseLevel is off and caseFirst==upperFirst.
4237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return (options & (CASE_LEVEL | CASE_FIRST_AND_UPPER_MASK)) == CASE_FIRST_AND_UPPER_MASK;
4247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
4257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
4267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public boolean dontCheckFCD() {
4277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return (options & CHECK_FCD) == 0;
4287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
4297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
4307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    boolean hasBackwardSecondary() {
4317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return (options & BACKWARD_SECONDARY) != 0;
4327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
4337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
4347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public boolean isNumeric() {
4357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        return (options & NUMERIC) != 0;
4367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
4377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
4387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /** CHECK_FCD etc. */
4397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public int options = (Collator.TERTIARY << STRENGTH_SHIFT) |  // DEFAULT_STRENGTH
4407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert            (MAX_VAR_PUNCT << MAX_VARIABLE_SHIFT);
4417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /** Variable-top primary weight. */
4427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public long variableTop;
443f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    /**
444f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     * 256-byte table for reordering permutation of primary lead bytes; null if no reordering.
445f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     * A 0 entry at a non-zero index means that the primary lead byte is "split"
446f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     * (there are different offsets for primaries that share that lead byte)
447f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     * and the reordering offset must be determined via the reorderRanges.
448f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     */
4497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public byte[] reorderTable;
450f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    /** Limit of last reordered range. 0 if no reordering or no split bytes. */
451f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    long minHighNoReorder;
452f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    /**
453f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     * Primary-weight ranges for script reordering,
454f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     * to be used by reorder(p) for split-reordered primary lead bytes.
455f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     *
456f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     * <p>Each entry is a (limit, offset) pair.
457f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     * The upper 16 bits of the entry are the upper 16 bits of the
458f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     * exclusive primary limit of a range.
459f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     * Primaries between the previous limit and this one have their lead bytes
460f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     * modified by the signed offset (-0xff..+0xff) stored in the lower 16 bits.
461f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     *
462f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     * <p>CollationData.makeReorderRanges() writes a full list where the first range
463f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     * (at least for terminators and separators) has a 0 offset.
464f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     * The last range has a non-zero offset.
465f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     * minHighNoReorder is set to the limit of that last range.
466f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     *
467f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     * <p>In the settings object, the initial ranges before the first split lead byte
468f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     * are omitted for efficiency; they are handled by reorder(p) via the reorderTable.
469f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     * If there are no split-reordered lead bytes, then no ranges are needed.
470f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert     */
471f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    long[] reorderRanges;
4727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /** Array of reorder codes; ignored if length == 0. */
4737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public int[] reorderCodes = EMPTY_INT_ARRAY;
474f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    // Note: In C++, we keep a memory block around for the reorder codes,
475f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert    // the ranges, and the permutation table,
4767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // and modify them for new codes.
4777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // In Java, we simply copy references and then never modify the array contents.
4787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // The caller must abandon the arrays.
4797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // Reorder codes from the public setter API must be cloned.
4807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    private static final int[] EMPTY_INT_ARRAY = new int[0];
4817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
4827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    /** Options for CollationFastLatin. Negative if disabled. */
4837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public int fastLatinOptions = -1;
4847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // fastLatinPrimaries.length must be equal to CollationFastLatin.LATIN_LIMIT,
4857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    // but we do not import CollationFastLatin to reduce circular dependencies.
4867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    public char[] fastLatinPrimaries = new char[0x180];  // mutable contents
4877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert}
488