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