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
The following commit(s) were added to refs/heads/geoapi-4.0 by this push: new 38b7778 Add a constant for the number of bits in `Long.SIZE`. Used in bit shifts. 38b7778 is described below commit 38b777853144c9f165be134611ff891d3a7ef385 Author: Martin Desruisseaux <martin.desruisse...@geomatys.com> AuthorDate: Thu Nov 4 19:18:30 2021 +0100 Add a constant for the number of bits in `Long.SIZE`. Used in bit shifts. --- .../java/org/apache/sis/image/MaskedImage.java | 5 ++-- .../java/org/apache/sis/index/tree/PointTree.java | 3 ++- .../org/apache/sis/internal/util/Numerics.java | 17 ++++++++++-- .../java/org/apache/sis/util/CharSequences.java | 2 +- .../apache/sis/util/collection/IntegerList.java | 3 ++- .../org/apache/sis/internal/util/NumericsTest.java | 30 +++++++++++++++++++++- 6 files changed, 52 insertions(+), 8 deletions(-) diff --git a/core/sis-feature/src/main/java/org/apache/sis/image/MaskedImage.java b/core/sis-feature/src/main/java/org/apache/sis/image/MaskedImage.java index 9b4b3ec..63ec657 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/image/MaskedImage.java +++ b/core/sis-feature/src/main/java/org/apache/sis/image/MaskedImage.java @@ -39,6 +39,7 @@ import org.apache.sis.internal.coverage.j2d.ImageUtilities; import org.apache.sis.internal.coverage.j2d.TilePlaceholder; import static org.apache.sis.internal.util.Numerics.ceilDiv; +import static org.apache.sis.internal.util.Numerics.LONG_SHIFT; /** @@ -275,9 +276,9 @@ final class MaskedImage extends SourceAlignedImage { */ for (int y=yStart; y<yEnd; y++) { int index = (y - maskBounds.y) * maskScanlineStride; // Index in unit of bits for now (converted later). - final int emax = (index + imax) / Long.SIZE; // Last index in unit of long elements, inclusive. + final int emax = (index + imax) >>> LONG_SHIFT; // Last index in unit of long elements, inclusive. final int shift = (index += xoff) & (Long.SIZE-1); // First bit to read in the long, 0 = highest bit. - index /= Long.SIZE; // Convert from bit (pixel) index to long[] index. + index >>>= LONG_SHIFT; // Convert from bit (pixel) index to long[] index. /* * We want a value such as `base + index*Long.SIZE + lower` is equal to `xStart` * when all variables point to the first potentially masked pixel of the tile: diff --git a/core/sis-feature/src/main/java/org/apache/sis/index/tree/PointTree.java b/core/sis-feature/src/main/java/org/apache/sis/index/tree/PointTree.java index c1a672c..81e0d0e 100644 --- a/core/sis-feature/src/main/java/org/apache/sis/index/tree/PointTree.java +++ b/core/sis-feature/src/main/java/org/apache/sis/index/tree/PointTree.java @@ -27,6 +27,7 @@ import java.util.stream.Stream; import java.util.stream.StreamSupport; import org.opengis.geometry.Envelope; import org.opengis.referencing.crs.CoordinateReferenceSystem; +import org.apache.sis.internal.util.Numerics; import org.apache.sis.util.ArgumentChecks; import org.apache.sis.util.resources.Errors; import org.apache.sis.util.collection.CheckedContainer; @@ -106,7 +107,7 @@ public class PointTree<E> extends AbstractSet<E> implements CheckedContainer<E>, * The maximum number of dimensions (inclusive) that this class currently supports. * Current maximum is {@value}. This restriction come from 2⁶ = {@value Long#SIZE}. */ - public static final int MAXIMUM_DIMENSIONS = 6; + public static final int MAXIMUM_DIMENSIONS = Numerics.LONG_SHIFT; /** * The type of elements in this set. diff --git a/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java b/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java index 5d18ba9..f986424 100644 --- a/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java +++ b/core/sis-utility/src/main/java/org/apache/sis/internal/util/Numerics.java @@ -39,7 +39,7 @@ import static java.lang.Math.ulp; * Miscellaneous utilities methods working on floating point numbers. * * @author Martin Desruisseaux (Geomatys) - * @version 1.1 + * @version 1.2 * @since 0.3 * @module */ @@ -155,6 +155,19 @@ public final class Numerics extends Static { public static final int MAX_INTEGER_CONVERTIBLE_TO_FLOAT = 1 << (SIGNIFICAND_SIZE_OF_FLOAT + 1); /** + * Right shift to apply for a result equivalent to a division by {@Long#SIZE} (ignoring negative numbers). + * The value is {@value} so that the following relationship hold: 2⁶ = {@value Long#SIZE}. + * + * <h4>Usage</h4> + * The {@code x / Long.SIZE} operation can be replaced by {@code x >>> LONG_SHIFT} if <var>x</var> is positive. + * The compiler may not do this optimization itself because those two operations are not equivalent for negative + * <var>x</var> values (even with {@code >>} instead of {@code >>>}). By contrast it is not worth to apply such + * replacement on multiplications because the {@code x * Long.SIZE} and {@code x << LONG_SHIFT} operations are + * equivalent for all numbers (positive or negative), so the compiler is more likely to optimize itself. + */ + public static final int LONG_SHIFT = 6; + + /** * Do not allow instantiation of this class. */ private Numerics() { @@ -174,7 +187,7 @@ public final class Numerics extends Static { * @return a mask with the given bit set, or 0 if the given argument is negative or ≥ {@value Long#SIZE}. */ public static long bitmask(final int bit) { - return (bit >= 0 && bit < Long.SIZE) ? (1L << bit) : 0; + return (bit & ~(Long.SIZE - 1)) == 0 ? (1L << bit) : 0; } /** diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/CharSequences.java b/core/sis-utility/src/main/java/org/apache/sis/util/CharSequences.java index 1da7c98..685cd0a 100644 --- a/core/sis-utility/src/main/java/org/apache/sis/util/CharSequences.java +++ b/core/sis-utility/src/main/java/org/apache/sis/util/CharSequences.java @@ -1094,7 +1094,7 @@ search: for (; fromIndex <= toIndex; fromIndex++) { final int length = text.length(); int toRemove = length - maxLength; if (toRemove > 0) { - toRemove += 5; // Space needed for the " (…) " string. + toRemove += 5; // Space needed for the " (…) " string. /* * We will remove characters from 'lower' to 'upper' both exclusive. We try to * adjust 'lower' and 'upper' in such a way that the first and last characters diff --git a/core/sis-utility/src/main/java/org/apache/sis/util/collection/IntegerList.java b/core/sis-utility/src/main/java/org/apache/sis/util/collection/IntegerList.java index 9c9ab31..d073336 100644 --- a/core/sis-utility/src/main/java/org/apache/sis/util/collection/IntegerList.java +++ b/core/sis-utility/src/main/java/org/apache/sis/util/collection/IntegerList.java @@ -33,6 +33,7 @@ import java.io.ObjectOutputStream; import org.apache.sis.util.ArraysExt; import org.apache.sis.util.ArgumentChecks; import org.apache.sis.internal.jdk9.JDK9; +import org.apache.sis.internal.util.Numerics; /** @@ -65,7 +66,7 @@ public class IntegerList extends AbstractList<Integer> implements RandomAccess, * The shift to apply on {@code index} in order to produce a result equivalent to {@code index} / {@value #VALUE_SIZE}. * The following relation must hold: {@code (1 << BASE_SHIFT) == VALUE_SIZE}. */ - private static final int BASE_SHIFT = 6; + private static final int BASE_SHIFT = Numerics.LONG_SHIFT; /** * The mask to apply on {@code index} in order to produce a result equivalent to {@code index} % {@value #VALUE_SIZE}. diff --git a/core/sis-utility/src/test/java/org/apache/sis/internal/util/NumericsTest.java b/core/sis-utility/src/test/java/org/apache/sis/internal/util/NumericsTest.java index 3bced31..d6ec734 100644 --- a/core/sis-utility/src/test/java/org/apache/sis/internal/util/NumericsTest.java +++ b/core/sis-utility/src/test/java/org/apache/sis/internal/util/NumericsTest.java @@ -34,13 +34,41 @@ import static org.junit.Assert.*; * Tests the {@link Numerics} class. * * @author Martin Desruisseaux (Geomatys) - * @version 1.1 + * @version 1.2 * @since 0.3 * @module */ @SuppressWarnings("UnnecessaryBoxing") public final strictfp class NumericsTest extends TestCase { /** + * Verifies the value of {@link Numerics#LONG_SHIFT}. + */ + @Test + public void verifyMaxDimension() { + assertEquals(Long.SIZE, 1 << Numerics.LONG_SHIFT); + for (int i=350; i<400; i += 17) { + assertEquals(i / Long.SIZE, i >> Numerics.LONG_SHIFT); + assertEquals(i * Long.SIZE, i << Numerics.LONG_SHIFT); + } + } + + /** + * Tests {@link Numerics#bitmask(int)}. + */ + @Test + public void testBitmask() { + assertEquals( 1L, Numerics.bitmask(0)); + assertEquals( 2L, Numerics.bitmask(1)); + assertEquals(32L, Numerics.bitmask(5)); + assertEquals(Long.SIZE, Numerics.bitmask(Numerics.LONG_SHIFT)); + assertEquals(Long.MIN_VALUE, Numerics.bitmask(Long.SIZE - 1)); + assertEquals( 0L, Numerics.bitmask(Long.SIZE)); + assertEquals( 0L, Numerics.bitmask(100)); + assertEquals( 0L, Numerics.bitmask(-1)); + assertEquals( 0L, Numerics.bitmask(-256)); + } + + /** * Tests {@link Numerics#ceilDiv(int, int)} and {@link Numerics#ceilDiv(long, long)}. */ @Test