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) 1996-2011, International Business Machines Corporation and   *
72ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * others. All Rights Reserved.                                               *
82ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller ******************************************************************************
92ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */
102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/**
122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Store bits (Unicode character properties) in bit set vectors.
13f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert *
142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * This is a port of the C++ class UPropsVectors from ICU4C
15f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert *
162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * @author Shaopeng Jia
17836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller * @hide draft / provisional / internal are hidden on Android
182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */
192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerpackage android.icu.impl;
212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Arrays;
232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerimport java.util.Comparator;
242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller/**
262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Unicode Properties Vectors associated with code point ranges.
27f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert *
282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Rows of primitive integers in a contiguous array store the range limits and
292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * the properties vectors.
30f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert *
312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * In each row, row[0] contains the start code point and row[1] contains the
322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * limit code point, which is the start of the next range.
33f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert *
342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * Initially, there is only one range [0..0x110000] with values 0.
35f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert *
362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * It would be possible to store only one range boundary per row, but
372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller * self-contained rows allow to later sort them by contents.
38836e6b40a94ec3fb7545a76cb072960442b7eee9Neil Fuller * @hide Only a subset of ICU is exposed in Android
392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller */
402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fullerpublic class PropsVectors {
412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private int v[];
422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private int columns; // number of columns, plus two for start
432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // and limit values
442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private int maxRows;
452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private int rows;
462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private int prevRow; // search optimization: remember last row seen
472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private boolean isCompacted;
482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // internal function to compare elements in v and target. Return true iff
50f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    // elements in v starting from index1 to index1 + length - 1
512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // are exactly the same as elements in target
522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // starting from index2 to index2 + length - 1
53f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert    private boolean areElementsSame(int index1, int[] target, int index2,
542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int length) {
552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (int i = 0; i < length; ++i) {
562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (v[index1 + i] != target[index2 + i]) {
572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return false;
582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return true;
612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
62f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // internal function which given rangeStart, returns
642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // index where v[index]<=rangeStart<v[index+1].
652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // The returned index is a multiple of columns, and therefore
662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // points to the start of a row.
672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private int findRow(int rangeStart) {
682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int index = 0;
692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // check the vicinity of the last-seen row (start
712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // searching with an unrolled loop)
722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        index = prevRow * columns;
742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (rangeStart >= v[index]) {
752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (rangeStart < v[index + 1]) {
762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // same row as last seen
772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return index;
782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                index += columns;
802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (rangeStart < v[index + 1]) {
812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    ++prevRow;
822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return index;
832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    index += columns;
852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (rangeStart < v[index + 1]) {
862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        prevRow += 2;
872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        return index;
882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    } else if ((rangeStart - v[index + 1]) < 10) {
892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        // we are close, continue looping
902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        prevRow += 2;
912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        do {
922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            ++prevRow;
932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            index += columns;
942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        } while (rangeStart >= v[index + 1]);
952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        return index;
962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        } else if (rangeStart < v[1]) {
1002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // the very first row
1012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            prevRow = 0;
1022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return 0;
1032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
1042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // do a binary search for the start of the range
1062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int start = 0;
1072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int mid = 0;
1082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int limit = rows;
1092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        while (start < limit - 1) {
1102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            mid = (start + limit) / 2;
1112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            index = columns * mid;
1122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (rangeStart < v[index]) {
1132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                limit = mid;
1142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (rangeStart < v[index + 1]) {
1152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                prevRow = mid;
1162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return index;
1172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else {
1182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                start = mid;
1192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
1202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
1212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // must be found because all ranges together always cover
1232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // all of Unicode
1242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        prevRow = start;
1252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        index = start * columns;
1262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return index;
1272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
1282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
1302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Special pseudo code points for storing the initialValue and the
1312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * errorValue which are used to initialize a Trie or similar.
1322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
1332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public final static int FIRST_SPECIAL_CP = 0x110000;
1342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public final static int INITIAL_VALUE_CP = 0x110000;
1352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public final static int ERROR_VALUE_CP = 0x110001;
1362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public final static int MAX_CP = 0x110001;
1372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public final static int INITIAL_ROWS = 1 << 12;
1392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public final static int MEDIUM_ROWS = 1 << 16;
1402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public final static int MAX_ROWS = MAX_CP + 1;
1412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
1432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Constructor.
1442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @param numOfColumns Number of value integers (32-bit int) per row.
1452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
1462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public PropsVectors(int numOfColumns) {
1472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (numOfColumns < 1) {
1482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException("numOfColumns need to be no "
1492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    + "less than 1; but it is " + numOfColumns);
1502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
1512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        columns = numOfColumns + 2; // count range start and limit columns
1522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        v = new int[INITIAL_ROWS * columns];
1532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        maxRows = INITIAL_ROWS;
1542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        rows = 2 + (MAX_CP - FIRST_SPECIAL_CP);
1552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        prevRow = 0;
1562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        isCompacted = false;
1572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        v[0] = 0;
1582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        v[1] = 0x110000;
1592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int index = columns;
1602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (int cp = FIRST_SPECIAL_CP; cp <= MAX_CP; ++cp) {
1612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            v[index] = cp;
1622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            v[index + 1] = cp + 1;
1632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            index += columns;
1642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
1652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
1662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
1682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * In rows for code points [start..end], select the column, reset the mask
1692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * bits and set the value bits (ANDed with the mask).
170f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *
1712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalArgumentException
172f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *
1732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException
174f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *
1752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IndexOutOfBoundsException
1762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
1772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public void setValue(int start, int end, int column, int value, int mask) {
1782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (start < 0 || start > end || end > MAX_CP || column < 0
1792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                || column >= (columns - 2)) {
1802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException();
1812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
1822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (isCompacted) {
1832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalStateException("Shouldn't be called after"
1842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    + "compact()!");
1852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
1862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int firstRow, lastRow;
1882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int limit = end + 1;
1892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        boolean splitFirstRow, splitLastRow;
1902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // skip range start and limit columns
1912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        column += 2;
1922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        value &= mask;
1932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // find the rows whose ranges overlap with the input range
1952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // find the first and last row, always successful
1962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        firstRow = findRow(start);
1972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        lastRow = findRow(end);
1982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
1992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*
2002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Rows need to be split if they partially overlap with the input range
2012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * (only possible for the first and last rows) and if their value
2022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * differs from the input value.
2032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
2042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        splitFirstRow = (start != v[firstRow] && value != (v[firstRow + column] & mask));
2052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        splitLastRow = (limit != v[lastRow + 1] && value != (v[lastRow + column] & mask));
2062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // split first/last rows if necessary
2082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (splitFirstRow || splitLastRow) {
2092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int rowsToExpand = 0;
2102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (splitFirstRow) {
2112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                ++rowsToExpand;
2122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
2132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (splitLastRow) {
2142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                ++rowsToExpand;
2152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
2162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int newMaxRows = 0;
2172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if ((rows + rowsToExpand) > maxRows) {
2182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (maxRows < MEDIUM_ROWS) {
2192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    newMaxRows = MEDIUM_ROWS;
2202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else if (maxRows < MAX_ROWS) {
2212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    newMaxRows = MAX_ROWS;
2222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
2232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    throw new IndexOutOfBoundsException(
2242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            "MAX_ROWS exceeded! Increase it to a higher value" +
2252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                            "in the implementation");
2262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
2272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                int[] temp = new int[newMaxRows * columns];
2282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                System.arraycopy(v, 0, temp, 0, rows * columns);
2292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                v = temp;
2302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                maxRows = newMaxRows;
2312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
2322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // count the number of row cells to move after the last row,
2342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // and move them
2352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int count = (rows * columns) - (lastRow + columns);
2362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (count > 0) {
2372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                System.arraycopy(v, lastRow + columns, v, lastRow
2382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        + (1 + rowsToExpand) * columns, count);
2392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
2402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            rows += rowsToExpand;
2412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // split the first row, and move the firstRow pointer
2432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // to the second part
2442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (splitFirstRow) {
2452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // copy all affected rows up one and move the lastRow pointer
2462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                count = lastRow - firstRow + columns;
2472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                System.arraycopy(v, firstRow, v, firstRow + columns, count);
2482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                lastRow += columns;
2492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // split the range and move the firstRow pointer
2512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                v[firstRow + 1] = v[firstRow + columns] = start;
2522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                firstRow += columns;
2532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
2542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // split the last row
2562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (splitLastRow) {
2572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // copy the last row data
2582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                System.arraycopy(v, lastRow, v, lastRow + columns, columns);
2592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // split the range and move the firstRow pointer
2612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                v[lastRow + 1] = v[lastRow + columns] = limit;
2622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
2632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // set the "row last seen" to the last row for the range
2662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        prevRow = lastRow / columns;
2672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // set the input value in all remaining rows
2692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        firstRow += column;
2702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        lastRow += column;
2712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        mask = ~mask;
2722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (;;) {
2732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            v[firstRow] = (v[firstRow] & mask) | value;
2742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (firstRow == lastRow) {
2752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                break;
2762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
2772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            firstRow += columns;
2782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
2802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
2822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Always returns 0 if called after compact().
2832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
2842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int getValue(int c, int column) {
2852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (isCompacted || c < 0 || c > MAX_CP || column < 0
2862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                || column >= (columns - 2)) {
2872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return 0;
2882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
2892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int index = findRow(c);
2902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return v[index + 2 + column];
2912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
2922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
2932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
2942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Returns an array which contains value elements
295f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * in row rowIndex.
2962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
2972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException
2982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalArgumentException
2992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int[] getRow(int rowIndex) {
3012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (isCompacted) {
3022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalStateException(
3032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    "Illegal Invocation of the method after compact()");
3042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (rowIndex < 0 || rowIndex > rows) {
3062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException("rowIndex out of bound!");
3072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int[] rowToReturn = new int[columns - 2];
3092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        System.arraycopy(v, rowIndex * columns + 2, rowToReturn, 0,
3102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                         columns - 2);
3112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return rowToReturn;
3122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
3132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
3152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Returns an int which is the start codepoint
3162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * in row rowIndex.
317f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *
3182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException
319f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *
3202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalArgumentException
3212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int getRowStart(int rowIndex) {
3232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (isCompacted) {
3242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalStateException(
3252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    "Illegal Invocation of the method after compact()");
3262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (rowIndex < 0 || rowIndex > rows) {
3282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException("rowIndex out of bound!");
3292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return v[rowIndex * columns];
3312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
3322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
334f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * Returns an int which is the limit codepoint
3352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * minus 1 in row rowIndex.
336f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *
3372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException
338f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *
3392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalArgumentException
3402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int getRowEnd(int rowIndex) {
3422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (isCompacted) {
3432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalStateException(
3442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    "Illegal Invocation of the method after compact()");
3452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (rowIndex < 0 || rowIndex > rows) {
3472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalArgumentException("rowIndex out of bound!");
3482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return v[rowIndex * columns + 1] - 1;
3502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
351f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
3522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
3532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Compact the vectors:
3542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * - modify the memory
3552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * - keep only unique vectors
3562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * - store them contiguously from the beginning of the memory
357f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * - for each (non-unique) row, call the respective function in
3582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *   CompactHandler
3592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
3602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * The handler's rowIndex is the index of the row in the compacted
361f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * memory block. Therefore, it starts at 0 increases in increments of the
3622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * columns value.
3632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     *
3642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * In a first phase, only special values are delivered (each exactly once).
3652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Then CompactHandler::startRealValues() is called
3662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * where rowIndex is the length of the compacted array.
367f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     * Then, in the second phase, the CompactHandler::setRowIndexForRange() is
3682ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * called for each row of real values.
3692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
3702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public void compact(CompactHandler compactor) {
3712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (isCompacted) {
3722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return;
3732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Set the flag now: Sorting and compacting destroys the builder
3762ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // data structure.
3772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        isCompacted = true;
3782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int valueColumns = columns - 2; // not counting start & limit
3792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // sort the properties vectors to find unique vector values
3812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Integer[] indexArray = new Integer[rows];
3822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (int i = 0; i < rows; ++i) {
3832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            indexArray[i] = Integer.valueOf(columns * i);
3842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
3852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        Arrays.sort(indexArray, new Comparator<Integer>() {
387f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert            @Override
3882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            public int compare(Integer o1, Integer o2) {
3892ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                int indexOfRow1 = o1.intValue();
3902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                int indexOfRow2 = o2.intValue();
3912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                int count = columns; // includes start/limit columns
3922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
3932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // start comparing after start/limit
3942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                // but wrap around to them
3952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                int index = 2;
3962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                do {
3972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (v[indexOfRow1 + index] != v[indexOfRow2 + index]) {
3982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        return v[indexOfRow1 + index] < v[indexOfRow2 + index] ? -1
3992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                                : 1;
4002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
4012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    if (++index == columns) {
4022ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        index = 0;
4032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    }
4042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } while (--count > 0);
4052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                return 0;
4072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
4082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        });
4092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*
4112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * Find and set the special values. This has to do almost the same work
4122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * as the compaction below, to find the indexes where the special-value
4132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * rows will move.
4142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
4152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int count = -valueColumns;
4162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (int i = 0; i < rows; ++i) {
4172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int start = v[indexArray[i].intValue()];
4182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // count a new values vector if it is different
4202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // from the current one
4212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (count < 0 || !areElementsSame(indexArray[i].intValue() + 2, v,
4222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    indexArray[i-1].intValue() + 2, valueColumns)) {
4232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                count += valueColumns;
4242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
4252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4262ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (start == INITIAL_VALUE_CP) {
4272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                compactor.setRowIndexForInitialValue(count);
4282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            } else if (start == ERROR_VALUE_CP) {
4292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                compactor.setRowIndexForErrorValue(count);
4302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
4312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
4322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // count is at the beginning of the last vector,
4342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // add valueColumns to include that last vector
4352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        count += valueColumns;
4362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // Call the handler once more to signal the start of
4382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // delivering real values.
4392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        compactor.startRealValues(count);
4402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4412ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        /*
442f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert         * Move vector contents up to a contiguous array with only unique
4432ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * vector values, and call the handler function for each vector.
444f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert         *
445f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert         * This destroys the Properties Vector structure and replaces it
4462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         * with an array of just vector values.
4472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller         */
4482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        int[] temp = new int[count];
4492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        count = -valueColumns;
4502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        for (int i = 0; i < rows; ++i) {
4512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int start = v[indexArray[i].intValue()];
4522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int limit = v[indexArray[i].intValue() + 1];
4532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // count a new values vector if it is different
4552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            // from the current one
456f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert            if (count < 0 || !areElementsSame(indexArray[i].intValue() + 2,
4572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    temp, count, valueColumns)) {
4582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                count += valueColumns;
4592ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                System.arraycopy(v, indexArray[i].intValue() + 2, temp, count,
4602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                        valueColumns);
4612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
4622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            if (start < FIRST_SPECIAL_CP) {
4642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                compactor.setRowIndexForRange(start, limit - 1, count);
4652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
4662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
4672ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        v = temp;
468f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
4692ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // count is at the beginning of the last vector,
4702ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        // add one to include that last vector
4712ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        rows = count / valueColumns + 1;
4722ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
4732ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4742ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
4752ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Get the vectors array after calling compact().
476f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *
4772ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException
4782ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
4792ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int[] getCompactedArray() {
4802ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (!isCompacted) {
4812ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalStateException(
4822ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    "Illegal Invocation of the method before compact()");
4832ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
4842ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return v;
4852ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
4862ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
4872ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
4882ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Get the number of rows for the compacted array.
489f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *
4902ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException
4912ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
4922ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int getCompactedRows() {
4932ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (!isCompacted) {
4942ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalStateException(
4952ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    "Illegal Invocation of the method before compact()");
4962ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
4972ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return rows;
4982ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
4992ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5002ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
5012ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Get the number of columns for the compacted array.
502f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert     *
5032ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * @throws IllegalStateException
5042ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
5052ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public int getCompactedColumns() {
5062ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        if (!isCompacted) {
5072ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            throw new IllegalStateException(
5082ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    "Illegal Invocation of the method before compact()");
5092ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5102ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return columns - 2;
5112ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
5122ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5132ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    /*
5142ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * Call compact(), create a IntTrie with indexes into the compacted
5152ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     * vectors array.
5162ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller     */
5172ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public IntTrie compactToTrieWithRowIndexes() {
5182ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        PVecToTrieCompactHandler compactor = new PVecToTrieCompactHandler();
5192ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        compact(compactor);
5202ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        return compactor.builder.serialize(new DefaultGetFoldedValue(
5212ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                compactor.builder), new DefaultGetFoldingOffset());
5222ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
5232ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5242ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // inner class implementation of Trie.DataManipulate
5252ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static class DefaultGetFoldingOffset implements Trie.DataManipulate {
526f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        @Override
5272ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public int getFoldingOffset(int value) {
5282ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return value;
5292ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5302ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
5312ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5322ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    // inner class implementation of TrieBuilder.DataManipulate
5332ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    private static class DefaultGetFoldedValue implements
5342ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            TrieBuilder.DataManipulate {
5352ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        private IntTrieBuilder builder;
5362ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
5372ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public DefaultGetFoldedValue(IntTrieBuilder inBuilder) {
5382ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            builder = inBuilder;
5392ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5402ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller
541f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert        @Override
5422ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public int getFoldedValue(int start, int offset) {
543f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert            int initialValue = builder.m_initialValue_;
5442ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            int limit = start + 0x400;
5452ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            while (start < limit) {
5462ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                boolean[] inBlockZero = new boolean[1];
5472ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                int value = builder.getValue(start, inBlockZero);
5482ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                if (inBlockZero[0]) {
5492ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    start += TrieBuilder.DATA_BLOCK_LENGTH;
5502ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else if (value != initialValue) {
5512ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    return offset;
5522ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                } else {
5532ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                    ++start;
5542ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller                }
5552ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            }
5562ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller            return 0;
5572ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        }
5582ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
559f86f25d102340da66b9c7cb6b2d5ecdc0de43ecfFredrik Roubert
5602ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    public static interface CompactHandler {
5612ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public void setRowIndexForRange(int start, int end, int rowIndex);
5622ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public void setRowIndexForInitialValue(int rowIndex);
5632ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public void setRowIndexForErrorValue(int rowIndex);
5642ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller        public void startRealValues(int rowIndex);
5652ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller    }
5662ae130017183d2f66d55bf0ca51f8da3294644fdNeil Fuller}