This is an automated email from the ASF dual-hosted git repository. desruisseaux pushed a commit to branch geoapi-4.0 in repository https://gitbox.apache.org/repos/asf/sis.git
commit 69f581c4ae2cd225207d9a575e2f0b0facd9b552 Author: Martin Desruisseaux <[email protected]> AuthorDate: Fri Jul 8 00:06:40 2022 +0200 Switch the position of offset and length in `entriesForCodes` bit patterns. It makes easier the use of compressed offset in next commit. --- .../apache/sis/internal/storage/inflater/LZW.java | 40 ++++++++++++---------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/LZW.java b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/LZW.java index bdff8a2024..a1b37f7e01 100644 --- a/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/LZW.java +++ b/storage/sis-geotiff/src/main/java/org/apache/sis/internal/storage/inflater/LZW.java @@ -80,16 +80,21 @@ final class LZW extends CompressionChannel { private int codeSize; /** - * Position of the lowest bit in an {@link #entriesForCodes} element where the length is stored. - * The length is extracted from an element by {@code element >>> LOWEST_LENGTH_BIT}. - * The offset is chosen for allowing {@value #MAX_CODE_SIZE} bits for storing the length. + * Position of the lowest bit in an {@link #entriesForCodes} element where the offset is stored. + * The position is chosen for leaving {@value #MAX_CODE_SIZE} bits for storing the length before + * the offset value. * * <div class="note"><b>Rational:</b> * even in the worst case scenario where the same byte is always appended to the sequence, * the maximal length can not exceeded the dictionary size because a {@link #CLEAR_CODE} * will be emitted when the dictionary is full.</div> */ - private static final int LOWEST_LENGTH_BIT = Integer.SIZE - MAX_CODE_SIZE; + private static final int LOWEST_OFFSET_BIT = MAX_CODE_SIZE; + + /** + * The mask to apply on an {@link #entriesForCodes} element for getting the length. + */ + private static final int LENGTH_MASK = (1 << LOWEST_OFFSET_BIT) - 1; /** * Extracts the number of bytes of an entry stored in the {@link #stringsFromCode} array. @@ -98,15 +103,9 @@ final class LZW extends CompressionChannel { * @return number of consecutive bytes to read in {@link #stringsFromCode} array. */ private static int length(final int element) { - return element >>> LOWEST_LENGTH_BIT; + return element & LENGTH_MASK; } - /** - * The mask to apply on an {@link #entriesForCodes} element for getting the offset. - * The actual offset is {@code (element & OFFSET_MASK)}. - */ - private static final int OFFSET_MASK = (1 << LOWEST_LENGTH_BIT) - 1; - /** * Extracts the index of the first byte of an entry stored in the {@link #stringsFromCode} array. * @@ -114,19 +113,24 @@ final class LZW extends CompressionChannel { * @return index of the first byte to read in {@link #stringsFromCode} array. */ private static int offset(final int element) { - return element & OFFSET_MASK; + return element >>> LOWEST_OFFSET_BIT; } /** * Encodes an offset together with its length. */ private static int offsetAndLength(final int offset, final int length) { - final int element = offset | (length << LOWEST_LENGTH_BIT); + final int element = (offset << LOWEST_OFFSET_BIT) | length; assert offset(element) == offset : offset; assert length(element) == length : length; return element; } + /** + * Maximal value + 1 that the offset can take. The offset takes all the bits after the length. + */ + private static final int OFFSET_LIMIT = 1 << (Integer.SIZE - LOWEST_OFFSET_BIT); + /** * Pointers to byte sequences for a code in the {@link #entriesForCodes} array. * Each element is a value encoded by {@link #offsetAndLength(int, int)} method. @@ -181,9 +185,9 @@ final class LZW extends CompressionChannel { super(input); indexOfFreeEntry = FIRST_ADAPTATIVE_CODE; entriesForCodes = new int [(1 << MAX_CODE_SIZE) - OFFSET_TO_MAXIMUM]; - stringsFromCode = new byte[4 << MAX_CODE_SIZE]; // Dynamically expanded if needed. + stringsFromCode = new byte[32 * 1024]; // Dynamically expanded if needed. for (int i=0; i < (1 << Byte.SIZE); i++) { - entriesForCodes[i] = i | (1 << LOWEST_LENGTH_BIT); + entriesForCodes[i] = (i << LOWEST_OFFSET_BIT) | 1; stringsFromCode[i] = (byte) i; } } @@ -230,8 +234,8 @@ final class LZW extends CompressionChannel { */ if (pendingEntry != 0) { final int remaining = target.remaining(); - final int stringOffset = pendingEntry & OFFSET_MASK; - final int stringLength = pendingEntry >>> LOWEST_LENGTH_BIT; + final int stringOffset = offset(pendingEntry); + final int stringLength = length(pendingEntry); target.put(stringsFromCode, stringOffset, Math.min(stringLength, remaining)); if (stringLength <= remaining) { pendingEntry = 0; @@ -301,7 +305,7 @@ final class LZW extends CompressionChannel { final int newLength = stringLength + 1; final int lastNewByte = newOffset + stringLength; if (lastNewByte >= stringsFromCode.length) { - final int capacity = Math.min(indexOfFreeString * 2, OFFSET_MASK + 1); + final int capacity = Math.min(indexOfFreeString * 2, OFFSET_LIMIT); if (lastNewByte >= capacity) { throw new IOException("Dictionary overflow"); }
