/** * Writes a length. * * @param a the data array. * @param length the length to be written. * @param pos the starting position. * @return the number of elements coding <code>length</code>. */ private static int writeInt(final char a[][], int length, long pos) { if (length < (1 << 15)) { CharBigArrays.set(a, pos, (char) length); return 1; } CharBigArrays.set(a, pos++, (char) (length >>> 16 | 0x8000)); CharBigArrays.set(a, pos, (char) (length & 0xFFFF)); return 2; }
/** * Creates a new front-coded list containing the arrays returned by the given iterator. * * @param arrays an iterator returning arrays. * @param ratio the desired ratio. */ public CharArrayFrontCodedList(final Iterator<char[]> arrays, final int ratio) { if (ratio < 1) throw new IllegalArgumentException("Illegal ratio (" + ratio + ")"); char[][] array = CharBigArrays.EMPTY_BIG_ARRAY; long[] p = LongArrays.EMPTY_ARRAY; char[][] a = new char[2][]; long curSize = 0; int n = 0, b = 0, common, length, minLength; while (arrays.hasNext()) { a[b] = arrays.next(); length = a[b].length; if (n % ratio == 0) { p = LongArrays.grow(p, n / ratio + 1); p[n / ratio] = curSize; array = CharBigArrays.grow(array, curSize + count(length) + length, curSize); curSize += writeInt(array, length, curSize); CharBigArrays.copyToBig(a[b], 0, array, curSize, length); curSize += length; } else { minLength = a[1 - b].length; if (length < minLength) minLength = length; for (common = 0; common < minLength; common++) if (a[0][common] != a[1][common]) break; length -= common; array = CharBigArrays.grow(array, curSize + count(length) + count(common) + length, curSize); curSize += writeInt(array, length, curSize); curSize += writeInt(array, common, curSize); CharBigArrays.copyToBig(a[b], common, array, curSize, length); curSize += length; } b = 1 - b; n++; } this.n = n; this.ratio = ratio; this.array = CharBigArrays.trim(array, curSize); this.p = LongArrays.trim(p, (n + ratio - 1) / ratio); }
/** * Extracts the array at the given index. * * @param index an index. * @param a the array that will store the result (we assume that it can hold the result). * @param offset an offset into <code>a</code> where elements will be store. * @param length a maximum number of elements to store in <code>a</code>. * @return the length of the extracted array. */ private int extract(final int index, final char a[], final int offset, final int length) { final int delta = index % ratio; // The delta inside the block. final long startPos = p[ index / ratio]; // The position into the array of the first entire word before the // index-th. long pos, prevArrayPos; int arrayLength = readInt(array, pos = startPos), currLen = 0, actualCommon; if (delta == 0) { pos = p[index / ratio] + count(arrayLength); CharBigArrays.copyFromBig(array, pos, a, offset, Math.min(length, arrayLength)); return arrayLength; } int common = 0; for (int i = 0; i < delta; i++) { prevArrayPos = pos + count(arrayLength) + (i != 0 ? count(common) : 0); pos = prevArrayPos + arrayLength; arrayLength = readInt(array, pos); common = readInt(array, pos + count(arrayLength)); actualCommon = Math.min(common, length); if (actualCommon <= currLen) currLen = actualCommon; else { CharBigArrays.copyFromBig(array, prevArrayPos, a, currLen + offset, actualCommon - currLen); currLen = actualCommon; } } if (currLen < length) CharBigArrays.copyFromBig( array, pos + count(arrayLength) + count(common), a, currLen + offset, Math.min(arrayLength, length - currLen)); return arrayLength + common; }
/** * Reads a coded length. * * @param a the data big array. * @param pos the starting position. * @return the length coded at <code>pos</code>. */ private static int readInt(final char a[][], long pos) { final char c0 = CharBigArrays.get(a, pos); return c0 < 0x8000 ? c0 : (c0 & 0x7FFF) << 16 | CharBigArrays.get(a, pos + 1); }