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 40715a5f7c3913470593a36950cabad95ff9ed30
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Thu Jan 3 10:35:57 2019 +0100

    Bug fix: wrong mask value if the number of dimensions is 64.
---
 .../src/main/java/org/apache/sis/io/wkt/Formatter.java  |  2 +-
 .../java/org/apache/sis/metadata/sql/Dispatcher.java    |  3 ++-
 .../java/org/apache/sis/geometry/CoordinateFormat.java  |  3 ++-
 .../operation/transform/PassThroughTransform.java       |  3 ++-
 .../java/org/apache/sis/internal/util/Numerics.java     | 17 +++++++++++++++++
 .../java/org/apache/sis/internal/netcdf/Variable.java   |  3 ++-
 .../sis/internal/storage/io/ChannelDataOutput.java      |  3 ++-
 7 files changed, 28 insertions(+), 6 deletions(-)

diff --git 
a/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java 
b/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java
index 2089d58..033c40d 100644
--- a/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java
+++ b/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java
@@ -1613,7 +1613,7 @@ public class Formatter implements Localized {
      */
     public boolean hasContextualUnit(final int depth) {
         ArgumentChecks.ensurePositive("depth", depth);
-        return (depth < Long.SIZE) && (hasContextualUnit & (1L << depth)) != 0;
+        return (hasContextualUnit & Numerics.bitmask(depth)) != 0;
     }
 
     /**
diff --git 
a/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/Dispatcher.java 
b/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/Dispatcher.java
index 6cc95e5..fa2a268 100644
--- 
a/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/Dispatcher.java
+++ 
b/core/sis-metadata/src/main/java/org/apache/sis/metadata/sql/Dispatcher.java
@@ -31,6 +31,7 @@ import org.apache.sis.metadata.KeyNamePolicy;
 import org.apache.sis.metadata.ValueExistencePolicy;
 import org.apache.sis.internal.system.Semaphores;
 import org.apache.sis.internal.metadata.Dependencies;
+import org.apache.sis.internal.util.Numerics;
 
 
 /**
@@ -206,7 +207,7 @@ final class Dispatcher implements InvocationHandler {
             throws ReflectiveOperationException, SQLException, 
MetadataStoreException
     {
         Object value = null;
-        final long nullBit = 1L << 
info.asIndexMap(source.standard).get(method.getName());     // Okay even if 
overflow.
+        final long nullBit = 
Numerics.bitmask(info.asIndexMap(source.standard).get(method.getName()));     
// Okay even if overflow.
         /*
          * The NULL_COLLECTION semaphore prevents creation of new empty 
collections by getter methods
          * (a consequence of lazy instantiation). The intent is to avoid 
creation of unnecessary objects
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/geometry/CoordinateFormat.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/geometry/CoordinateFormat.java
index a535e81..7844846 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/geometry/CoordinateFormat.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/geometry/CoordinateFormat.java
@@ -41,6 +41,7 @@ import org.opengis.referencing.cs.CoordinateSystemAxis;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 import org.opengis.referencing.crs.TemporalCRS;
 import org.apache.sis.internal.util.LocalizedParseException;
+import org.apache.sis.internal.util.Numerics;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.ArgumentChecks;
 import org.apache.sis.util.CharSequences;
@@ -365,7 +366,7 @@ public class CoordinateFormat extends 
CompoundFormat<DirectPosition> {
      * Returns {@code true} if the value at the given dimension needs to have 
its sign reversed.
      */
     private boolean isNegative(final int dimension) {
-        return (dimension < Long.SIZE) && (negate & (1L << dimension)) != 0;
+        return (negate & Numerics.bitmask(dimension)) != 0;
     }
 
     /**
diff --git 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PassThroughTransform.java
 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PassThroughTransform.java
index 6f98355..9fe1d1b 100644
--- 
a/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PassThroughTransform.java
+++ 
b/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/PassThroughTransform.java
@@ -30,6 +30,7 @@ import org.apache.sis.referencing.operation.matrix.Matrices;
 import org.apache.sis.referencing.operation.matrix.MatrixSIS;
 import org.apache.sis.internal.referencing.DirectPositionView;
 import org.apache.sis.internal.metadata.WKTKeywords;
+import org.apache.sis.internal.util.Numerics;
 import org.apache.sis.geometry.GeneralDirectPosition;
 import org.apache.sis.io.wkt.Formatter;
 import org.apache.sis.util.ComparisonMode;
@@ -796,7 +797,7 @@ public class PassThroughTransform extends 
AbstractMathTransform implements Seria
      * used operation in {@link #tryConcatenate(boolean, MathTransform, 
MathTransformFactory)}.
      */
     private static long maskLowBits(final int n) {
-        return (1L << n) - 1;
+        return Numerics.bitmask(n) - 1;
     }
 
     /**
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 60977d6..3e4e0bd 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
@@ -147,6 +147,23 @@ public final class Numerics extends Static {
     }
 
     /**
+     * Returns a mask with the given bit set. The bit should be a number from 
0 inclusive to {@value Long#SIZE} exclusive.
+     * If the given bit is outside that range, then this method returns 0. The 
later condition is the main difference with
+     * the {@code 1L << bit} operation since {@code 1L << 64} computes 1. By 
contrast, {@code bitmask(64)} returns 0.
+     *
+     * <p>This method is invoked in contexts where we really need value 0 for 
a {@code bit} value of {@value Long#SIZE}.
+     * For example if we want to compute the maximal value of an unsigned 
integer of the given number of bits, we can use
+     * {@code bitmask(n) - 1}. If <var>n</var> = 64, then {@code bitmask(64) - 
1} = -1 which is the desired value (the
+     * signed value -1 has the same bits pattern than the maximal possible 
value in unsigned integer representation).</p>
+     *
+     * @param  bit  the bit to set.
+     * @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;
+    }
+
+    /**
      * Returns the smallest (closest to negative infinity) long value that is 
greater than or equals to x/y.
      *
      * @param  x  the dividend.
diff --git 
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java 
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java
index 9914d10..0e469e6 100644
--- 
a/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java
+++ 
b/storage/sis-netcdf/src/main/java/org/apache/sis/internal/netcdf/Variable.java
@@ -35,6 +35,7 @@ import org.apache.sis.measure.NumberRange;
 import org.apache.sis.util.Numbers;
 import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.collection.WeakHashSet;
+import org.apache.sis.internal.util.Numerics;
 import org.apache.sis.internal.util.CollectionsExt;
 import org.apache.sis.util.logging.WarningListeners;
 import org.apache.sis.util.resources.Errors;
@@ -505,7 +506,7 @@ public abstract class Variable extends NamedElement {
             final int size = dataType.size() * Byte.SIZE;
             if (size > 0 && size <= Long.SIZE) {
                 long min = 0;
-                long max = (1L << size) - 1;
+                long max = Numerics.bitmask(size) - 1;
                 if (!dataType.isUnsigned) {
                     max >>>= 1;
                     min = ~max;
diff --git 
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelDataOutput.java
 
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelDataOutput.java
index 92ac00d..65d6272 100644
--- 
a/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelDataOutput.java
+++ 
b/storage/sis-storage/src/main/java/org/apache/sis/internal/storage/io/ChannelDataOutput.java
@@ -29,6 +29,7 @@ import java.nio.LongBuffer;
 import java.nio.ShortBuffer;
 import java.nio.channels.SeekableByteChannel;
 import java.nio.channels.WritableByteChannel;
+import org.apache.sis.internal.util.Numerics;
 import org.apache.sis.internal.storage.Resources;
 
 import static org.apache.sis.util.ArgumentChecks.ensureBetween;
@@ -171,7 +172,7 @@ public class ChannelDataOutput extends ChannelData 
implements Flushable {
         if (numBits != 0) {
             int bitOffset = getBitOffset();
             if (bitOffset != 0) {
-                bits &= (1L << numBits) - 1; // Make sure that high-order bits 
are zero.
+                bits &= Numerics.bitmask(numBits) - 1;                  // 
Make sure that high-order bits are zero.
                 final int r = numBits - (Byte.SIZE - bitOffset);
                 /*
                  * 'r' is the number of bits than we can not store in the 
current byte. This value may be negative,

Reply via email to