/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.text;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;


PackedIntVector stores a two-dimensional array of integers, optimized for inserting and deleting rows and for offsetting the values in segments of a given column.
@hide
/** * PackedIntVector stores a two-dimensional array of integers, * optimized for inserting and deleting rows and for * offsetting the values in segments of a given column. * * @hide */
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) public class PackedIntVector { private final int mColumns; private int mRows; private int mRowGapStart; private int mRowGapLength; private int[] mValues; private int[] mValueGap; // starts, followed by lengths
Creates a new PackedIntVector with the specified width and a height of 0.
Params:
  • columns – the width of the PackedIntVector.
/** * Creates a new PackedIntVector with the specified width and * a height of 0. * * @param columns the width of the PackedIntVector. */
public PackedIntVector(int columns) { mColumns = columns; mRows = 0; mRowGapStart = 0; mRowGapLength = mRows; mValues = null; mValueGap = new int[2 * columns]; }
Returns the value at the specified row and column.
Params:
  • row – the index of the row to return.
  • column – the index of the column to return.
Throws:
  • IndexOutOfBoundsException – if the row is out of range (row < 0 || row >= size()) or the column is out of range (column < 0 || column >= width()).
Returns:the value stored at the specified position.
/** * Returns the value at the specified row and column. * * @param row the index of the row to return. * @param column the index of the column to return. * * @return the value stored at the specified position. * * @throws IndexOutOfBoundsException if the row is out of range * (row &lt; 0 || row >= size()) or the column is out of range * (column &lt; 0 || column >= width()). */
public int getValue(int row, int column) { final int columns = mColumns; if (((row | column) < 0) || (row >= size()) || (column >= columns)) { throw new IndexOutOfBoundsException(row + ", " + column); } if (row >= mRowGapStart) { row += mRowGapLength; } int value = mValues[row * columns + column]; int[] valuegap = mValueGap; if (row >= valuegap[column]) { value += valuegap[column + columns]; } return value; }
Sets the value at the specified row and column.
Params:
  • row – the index of the row to set.
  • column – the index of the column to set.
Throws:
  • IndexOutOfBoundsException – if the row is out of range (row < 0 || row >= size()) or the column is out of range (column < 0 || column >= width()).
/** * Sets the value at the specified row and column. * * @param row the index of the row to set. * @param column the index of the column to set. * * @throws IndexOutOfBoundsException if the row is out of range * (row &lt; 0 || row >= size()) or the column is out of range * (column &lt; 0 || column >= width()). */
public void setValue(int row, int column, int value) { if (((row | column) < 0) || (row >= size()) || (column >= mColumns)) { throw new IndexOutOfBoundsException(row + ", " + column); } if (row >= mRowGapStart) { row += mRowGapLength; } int[] valuegap = mValueGap; if (row >= valuegap[column]) { value -= valuegap[column + mColumns]; } mValues[row * mColumns + column] = value; }
Sets the value at the specified row and column. Private internal version: does not check args.
Params:
  • row – the index of the row to set.
  • column – the index of the column to set.
/** * Sets the value at the specified row and column. * Private internal version: does not check args. * * @param row the index of the row to set. * @param column the index of the column to set. * */
private void setValueInternal(int row, int column, int value) { if (row >= mRowGapStart) { row += mRowGapLength; } int[] valuegap = mValueGap; if (row >= valuegap[column]) { value -= valuegap[column + mColumns]; } mValues[row * mColumns + column] = value; }
Increments all values in the specified column whose row >= the specified row by the specified delta.
Params:
  • startRow – the row at which to begin incrementing. This may be == size(), which case there is no effect.
  • column – the index of the column to set.
Throws:
  • IndexOutOfBoundsException – if the row is out of range (startRow < 0 || startRow > size()) or the column is out of range (column < 0 || column >= width()).
/** * Increments all values in the specified column whose row >= the * specified row by the specified delta. * * @param startRow the row at which to begin incrementing. * This may be == size(), which case there is no effect. * @param column the index of the column to set. * * @throws IndexOutOfBoundsException if the row is out of range * (startRow &lt; 0 || startRow > size()) or the column * is out of range (column &lt; 0 || column >= width()). */
public void adjustValuesBelow(int startRow, int column, int delta) { if (((startRow | column) < 0) || (startRow > size()) || (column >= width())) { throw new IndexOutOfBoundsException(startRow + ", " + column); } if (startRow >= mRowGapStart) { startRow += mRowGapLength; } moveValueGapTo(column, startRow); mValueGap[column + mColumns] += delta; }
Inserts a new row of values at the specified row offset.
Params:
  • row – the row above which to insert the new row. This may be == size(), which case the new row is added at the end.
  • values – the new values to be added. If this is null, a row of zeroes is added.
Throws:
  • IndexOutOfBoundsException – if the row is out of range (row < 0 || row > size()) or if the length of the values array is too small (values.length < width()).
/** * Inserts a new row of values at the specified row offset. * * @param row the row above which to insert the new row. * This may be == size(), which case the new row is added * at the end. * @param values the new values to be added. If this is null, * a row of zeroes is added. * * @throws IndexOutOfBoundsException if the row is out of range * (row &lt; 0 || row > size()) or if the length of the * values array is too small (values.length < width()). */
public void insertAt(int row, int[] values) { if ((row < 0) || (row > size())) { throw new IndexOutOfBoundsException("row " + row); } if ((values != null) && (values.length < width())) { throw new IndexOutOfBoundsException("value count " + values.length); } moveRowGapTo(row); if (mRowGapLength == 0) { growBuffer(); } mRowGapStart++; mRowGapLength--; if (values == null) { for (int i = mColumns - 1; i >= 0; i--) { setValueInternal(row, i, 0); } } else { for (int i = mColumns - 1; i >= 0; i--) { setValueInternal(row, i, values[i]); } } }
Deletes the specified number of rows starting with the specified row.
Params:
  • row – the index of the first row to be deleted.
  • count – the number of rows to delete.
Throws:
  • IndexOutOfBoundsException – if any of the rows to be deleted are out of range (row < 0 || count < 0 || row + count > size()).
/** * Deletes the specified number of rows starting with the specified * row. * * @param row the index of the first row to be deleted. * @param count the number of rows to delete. * * @throws IndexOutOfBoundsException if any of the rows to be deleted * are out of range (row &lt; 0 || count &lt; 0 || * row + count > size()). */
public void deleteAt(int row, int count) { if (((row | count) < 0) || (row + count > size())) { throw new IndexOutOfBoundsException(row + ", " + count); } moveRowGapTo(row + count); mRowGapStart -= count; mRowGapLength += count; // TODO: Reclaim memory when the new height is much smaller // than the allocated size. }
Returns the number of rows in the PackedIntVector. This number will change as rows are inserted and deleted.
Returns:the number of rows.
/** * Returns the number of rows in the PackedIntVector. This number * will change as rows are inserted and deleted. * * @return the number of rows. */
public int size() { return mRows - mRowGapLength; }
Returns the width of the PackedIntVector. This number is set at construction and will not change.
Returns:the number of columns.
/** * Returns the width of the PackedIntVector. This number is set * at construction and will not change. * * @return the number of columns. */
public int width() { return mColumns; }
Grows the value and gap arrays to be large enough to store at least one more than the current number of rows.
/** * Grows the value and gap arrays to be large enough to store at least * one more than the current number of rows. */
private final void growBuffer() { final int columns = mColumns; int[] newvalues = ArrayUtils.newUnpaddedIntArray( GrowingArrayUtils.growSize(size()) * columns); int newsize = newvalues.length / columns; final int[] valuegap = mValueGap; final int rowgapstart = mRowGapStart; int after = mRows - (rowgapstart + mRowGapLength); if (mValues != null) { System.arraycopy(mValues, 0, newvalues, 0, columns * rowgapstart); System.arraycopy(mValues, (mRows - after) * columns, newvalues, (newsize - after) * columns, after * columns); } for (int i = 0; i < columns; i++) { if (valuegap[i] >= rowgapstart) { valuegap[i] += newsize - mRows; if (valuegap[i] < rowgapstart) { valuegap[i] = rowgapstart; } } } mRowGapLength += newsize - mRows; mRows = newsize; mValues = newvalues; }
Moves the gap in the values of the specified column to begin at the specified row.
/** * Moves the gap in the values of the specified column to begin at * the specified row. */
private final void moveValueGapTo(int column, int where) { final int[] valuegap = mValueGap; final int[] values = mValues; final int columns = mColumns; if (where == valuegap[column]) { return; } else if (where > valuegap[column]) { for (int i = valuegap[column]; i < where; i++) { values[i * columns + column] += valuegap[column + columns]; } } else /* where < valuegap[column] */ { for (int i = where; i < valuegap[column]; i++) { values[i * columns + column] -= valuegap[column + columns]; } } valuegap[column] = where; }
Moves the gap in the row indices to begin at the specified row.
/** * Moves the gap in the row indices to begin at the specified row. */
private final void moveRowGapTo(int where) { if (where == mRowGapStart) { return; } else if (where > mRowGapStart) { int moving = where + mRowGapLength - (mRowGapStart + mRowGapLength); final int columns = mColumns; final int[] valuegap = mValueGap; final int[] values = mValues; final int gapend = mRowGapStart + mRowGapLength; for (int i = gapend; i < gapend + moving; i++) { int destrow = i - gapend + mRowGapStart; for (int j = 0; j < columns; j++) { int val = values[i * columns+ j]; if (i >= valuegap[j]) { val += valuegap[j + columns]; } if (destrow >= valuegap[j]) { val -= valuegap[j + columns]; } values[destrow * columns + j] = val; } } } else /* where < mRowGapStart */ { int moving = mRowGapStart - where; final int columns = mColumns; final int[] valuegap = mValueGap; final int[] values = mValues; final int gapend = mRowGapStart + mRowGapLength; for (int i = where + moving - 1; i >= where; i--) { int destrow = i - where + gapend - moving; for (int j = 0; j < columns; j++) { int val = values[i * columns+ j]; if (i >= valuegap[j]) { val += valuegap[j + columns]; } if (destrow >= valuegap[j]) { val -= valuegap[j + columns]; } values[destrow * columns + j] = val; } } } mRowGapStart = where; } }