12ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/* GENERATED SOURCE. DO NOT MODIFY. */
2f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert// © 2016 and later: Unicode, Inc. and others.
3f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html#License
42ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/*
52ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller*******************************************************************************
62ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller* Copyright (C) 2013-2014, International Business Machines
72ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller* Corporation and others.  All Rights Reserved.
82ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller*******************************************************************************
92ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller* ContractionsAndExpansions.java, ported from collationsets.h/.cpp
102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller*
112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller* C++ version created on: 2013feb09
122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller* created by: Markus W. Scherer
132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller*/
142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerpackage android.icu.impl.coll;
162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Iterator;
182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.impl.Trie2;
202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.text.UnicodeSet;
212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.CharsTrie;
222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport android.icu.util.CharsTrie.Entry;
232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
241537b2f39245c07b00aa78c3600f7aebcb172490Neil Fuller/**
251537b2f39245c07b00aa78c3600f7aebcb172490Neil Fuller * @hide Only a subset of ICU is exposed in Android
26836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller */
272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerpublic final class ContractionsAndExpansions {
281fba789ac68efdd9120a7373f49daef42833e674Neil Fuller    // C++: The following fields are @internal, only public for access by callback.
292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private CollationData data;
302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private UnicodeSet contractions;
312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private UnicodeSet expansions;
322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private CESink sink;
332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private boolean addPrefixes;
342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private int checkTailored = 0;  // -1: collected tailored  +1: exclude tailored
352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private UnicodeSet tailored = new UnicodeSet();
362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private UnicodeSet ranges;
372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private StringBuilder unreversedPrefix = new StringBuilder();
382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private String suffix;
392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private long[] ces = new long[Collation.MAX_EXPANSION_LENGTH];
402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static interface CESink {
422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        void handleCE(long ce);
432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        void handleExpansion(long ces[], int start, int length);
442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public ContractionsAndExpansions(UnicodeSet con, UnicodeSet exp, CESink s, boolean prefixes) {
472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        contractions = con;
482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        expansions = exp;
492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        sink = s;
502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        addPrefixes = prefixes;
512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public void forData(CollationData d) {
542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Add all from the data, can be tailoring or base.
552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (d.base != null) {
562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            checkTailored = -1;
572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        data = d;
592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Iterator<Trie2.Range> trieIterator = data.trie.iterator();
602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Trie2.Range range;
612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        while (trieIterator.hasNext() && !(range = trieIterator.next()).leadSurrogate) {
622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            enumCnERange(range.startCodePoint, range.endCodePoint, range.value, this);
632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (d.base == null) {
652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return;
662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Add all from the base data but only for un-tailored code points.
682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        tailored.freeze();
692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        checkTailored = 1;
702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        data = d.base;
712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        trieIterator = data.trie.iterator();
722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        while (trieIterator.hasNext() && !(range = trieIterator.next()).leadSurrogate) {
732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            enumCnERange(range.startCodePoint, range.endCodePoint, range.value, this);
742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void enumCnERange(int start, int end, int ce32, ContractionsAndExpansions cne) {
782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (cne.checkTailored == 0) {
792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // There is no tailoring.
802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // No need to collect nor check the tailored set.
812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else if (cne.checkTailored < 0) {
822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // Collect the set of code points with mappings in the tailoring data.
832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (ce32 == Collation.FALLBACK_CE32) {
842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return; // fallback to base, not tailored
852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                cne.tailored.add(start, end);
872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // checkTailored > 0: Exclude tailored ranges from the base data enumeration.
892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else if (start == end) {
902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (cne.tailored.contains(start)) {
912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return;
922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else if (cne.tailored.containsSome(start, end)) {
942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (cne.ranges == null) {
952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                cne.ranges = new UnicodeSet();
962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            cne.ranges.set(start, end).removeAll(cne.tailored);
982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int count = cne.ranges.getRangeCount();
992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            for (int i = 0; i < count; ++i) {
1002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                cne.handleCE32(cne.ranges.getRangeStart(i), cne.ranges.getRangeEnd(i), ce32);
1012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
1022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
1032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        cne.handleCE32(start, end, ce32);
1042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
1052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public void forCodePoint(CollationData d, int c) {
1072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int ce32 = d.getCE32(c);
1082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (ce32 == Collation.FALLBACK_CE32) {
1092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            d = d.base;
1102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            ce32 = d.getCE32(c);
1112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
1122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        data = d;
1132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        handleCE32(c, c, ce32);
1142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
1152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void handleCE32(int start, int end, int ce32) {
1172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (;;) {
1182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ((ce32 & 0xff) < Collation.SPECIAL_CE32_LOW_BYTE) {
1192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // !isSpecialCE32()
1202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (sink != null) {
1212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    sink.handleCE(Collation.ceFromSimpleCE32(ce32));
1222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
1232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return;
1242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
1252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            switch (Collation.tagFromCE32(ce32)) {
1262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case Collation.FALLBACK_TAG:
1272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return;
1282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case Collation.RESERVED_TAG_3:
1292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case Collation.BUILDER_DATA_TAG:
1302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case Collation.LEAD_SURROGATE_TAG:
1312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Java porting note: U_INTERNAL_PROGRAM_ERROR is set to errorCode in ICU4C.
1322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                throw new AssertionError(
1332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        String.format("Unexpected CE32 tag type %d for ce32=0x%08x",
1342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                Collation.tagFromCE32(ce32), ce32));
1352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case Collation.LONG_PRIMARY_TAG:
1362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (sink != null) {
1372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    sink.handleCE(Collation.ceFromLongPrimaryCE32(ce32));
1382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
1392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return;
1402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case Collation.LONG_SECONDARY_TAG:
1412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (sink != null) {
1422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    sink.handleCE(Collation.ceFromLongSecondaryCE32(ce32));
1432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
1442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return;
1452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case Collation.LATIN_EXPANSION_TAG:
1462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (sink != null) {
1472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    ces[0] = Collation.latinCE0FromCE32(ce32);
1482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    ces[1] = Collation.latinCE1FromCE32(ce32);
1492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    sink.handleExpansion(ces, 0, 2);
1502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
1512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Optimization: If we have a prefix,
1522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // then the relevant strings have been added already.
1532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (unreversedPrefix.length() == 0) {
1542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    addExpansions(start, end);
1552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
1562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return;
1572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case Collation.EXPANSION32_TAG:
1582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (sink != null) {
1592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    int idx = Collation.indexFromCE32(ce32);
1602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    int length = Collation.lengthFromCE32(ce32);
1612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    for (int i = 0; i < length; ++i) {
1622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        ces[i] = Collation.ceFromCE32(data.ce32s[idx + i]);
1632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
1642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    sink.handleExpansion(ces, 0, length);
1652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
1662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Optimization: If we have a prefix,
1672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // then the relevant strings have been added already.
1682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (unreversedPrefix.length() == 0) {
1692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    addExpansions(start, end);
1702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
1712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return;
1722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case Collation.EXPANSION_TAG:
1732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (sink != null) {
1742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    int idx = Collation.indexFromCE32(ce32);
1752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    int length = Collation.lengthFromCE32(ce32);
1762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    sink.handleExpansion(data.ces, idx, length);
1772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
1782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Optimization: If we have a prefix,
1792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // then the relevant strings have been added already.
1802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (unreversedPrefix.length() == 0) {
1812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    addExpansions(start, end);
1822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
1832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return;
1842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case Collation.PREFIX_TAG:
1852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                handlePrefixes(start, end, ce32);
1862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return;
1872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case Collation.CONTRACTION_TAG:
1882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                handleContractions(start, end, ce32);
1892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return;
1902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case Collation.DIGIT_TAG:
1912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Fetch the non-numeric-collation CE32 and continue.
1922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                ce32 = data.ce32s[Collation.indexFromCE32(ce32)];
1932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
1942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case Collation.U0000_TAG:
1952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                assert (start == 0 && end == 0);
1962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Fetch the normal ce32 for U+0000 and continue.
1972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                ce32 = data.ce32s[0];
1982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
1992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case Collation.HANGUL_TAG:
2002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (sink != null) {
2012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // TODO: This should be optimized,
2022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    // especially if [start..end] is the complete Hangul range. (assert that)
2032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    UTF16CollationIterator iter = new UTF16CollationIterator(data);
2042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    StringBuilder hangul = new StringBuilder(1);
2052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    for (int c = start; c <= end; ++c) {
2062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        hangul.setLength(0);
2072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        hangul.appendCodePoint(c);
2082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        iter.setText(false, hangul, 0);
2092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        int length = iter.fetchCEs();
2102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        // Ignore the terminating non-CE.
2112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        assert (length >= 2 && iter.getCE(length - 1) == Collation.NO_CE);
2122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        sink.handleExpansion(iter.getCEs(), 0, length - 1);
2132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
2142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
2152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Optimization: If we have a prefix,
2162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // then the relevant strings have been added already.
2172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (unreversedPrefix.length() == 0) {
2182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    addExpansions(start, end);
2192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
2202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return;
2212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case Collation.OFFSET_TAG:
2222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Currently no need to send offset CEs to the sink.
2232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return;
2242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            case Collation.IMPLICIT_TAG:
2252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // Currently no need to send implicit CEs to the sink.
2262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return;
2272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
2282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
2302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void handlePrefixes(int start, int end, int ce32) {
2322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int index = Collation.indexFromCE32(ce32);
2332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        ce32 = data.getCE32FromContexts(index); // Default if no prefix match.
2342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        handleCE32(start, end, ce32);
2352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (!addPrefixes) {
2362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return;
2372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        CharsTrie.Iterator prefixes = new CharsTrie(data.contexts, index + 2).iterator();
2392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        while (prefixes.hasNext()) {
2402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            Entry e = prefixes.next();
2412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            setPrefix(e.chars);
2422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // Prefix/pre-context mappings are special kinds of contractions
2432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // that always yield expansions.
2442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            addStrings(start, end, contractions);
2452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            addStrings(start, end, expansions);
2462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            handleCE32(start, end, e.value);
2472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        resetPrefix();
2492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
2502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    void handleContractions(int start, int end, int ce32) {
2522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int index = Collation.indexFromCE32(ce32);
2532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if ((ce32 & Collation.CONTRACT_SINGLE_CP_NO_MATCH) != 0) {
2542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // No match on the single code point.
2552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // We are underneath a prefix, and the default mapping is just
2562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // a fallback to the mappings for a shorter prefix.
2572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            assert (unreversedPrefix.length() != 0);
2582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
2592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            ce32 = data.getCE32FromContexts(index); // Default if no suffix match.
2602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            assert (!Collation.isContractionCE32(ce32));
2612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            handleCE32(start, end, ce32);
2622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        CharsTrie.Iterator suffixes = new CharsTrie(data.contexts, index + 2).iterator();
2642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        while (suffixes.hasNext()) {
2652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            Entry e = suffixes.next();
2662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            suffix = e.chars.toString();
2672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            addStrings(start, end, contractions);
2682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (unreversedPrefix.length() != 0) {
2692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                addStrings(start, end, expansions);
2702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
2712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            handleCE32(start, end, e.value);
2722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        suffix = null;
2742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
2752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    void addExpansions(int start, int end) {
2772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (unreversedPrefix.length() == 0 && suffix == null) {
2782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (expansions != null) {
2792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                expansions.add(start, end);
2802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
2812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else {
2822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            addStrings(start, end, expansions);
2832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
2852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    void addStrings(int start, int end, UnicodeSet set) {
2872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (set == null) {
2882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return;
2892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        StringBuilder s = new StringBuilder(unreversedPrefix);
2912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        do {
2922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            s.appendCodePoint(start);
2932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (suffix != null) {
2942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                s.append(suffix);
2952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
2962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            set.add(s);
2972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            s.setLength(unreversedPrefix.length());
2982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } while (++start <= end);
2992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
3002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // Prefixes are reversed in the data structure.
3022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void setPrefix(CharSequence pfx) {
3032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        unreversedPrefix.setLength(0);
3042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        unreversedPrefix.append(pfx).reverse();
3052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
3062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private void resetPrefix() {
3082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        unreversedPrefix.setLength(0);
3092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
3102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller}