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 aa27c5dff7de00f3283e43138573caeca673ab60
Author: Martin Desruisseaux <martin.desruisse...@geomatys.com>
AuthorDate: Wed Feb 26 15:19:36 2025 +0100

    Add internal utility methods which will be needed for GeoHEIF:
    - For using arrays of long as keys in a hash map.
    - For aligning pixel coordinates to tiles border.
---
 .../org/apache/sis/storage/aggregate/Group.java    | 22 +-----
 .../org/apache/sis/storage/base/ArrayOfLongs.java  | 86 ++++++++++++++++++++++
 .../main/org/apache/sis/util/privy/Numerics.java   | 19 +++++
 .../test/org/apache/sis/pending/jdk/JDK18Test.java | 53 +++++++++++++
 .../org/apache/sis/util/privy/NumericsTest.java    | 26 ++++---
 5 files changed, 174 insertions(+), 32 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/Group.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/Group.java
index 0e7c83f46b..e673244f99 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/Group.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/aggregate/Group.java
@@ -17,13 +17,13 @@
 package org.apache.sis.storage.aggregate;
 
 import java.util.List;
-import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.Map;
 import java.util.HashMap;
 import java.util.Locale;
 import java.util.stream.Stream;
 import org.apache.sis.util.privy.Strings;
+import org.apache.sis.storage.base.ArrayOfLongs;
 import org.apache.sis.storage.event.StoreListeners;
 import org.apache.sis.coverage.grid.GridCoverageProcessor;
 
@@ -137,25 +137,7 @@ abstract class Group<E> {
      * @return shared instance of the given array.
      */
     final long[] unique(final long[] array) {
-        Object existing = sharedInstances.putIfAbsent(new Key(array), array);
-        return (existing != null) ? (long[]) existing : array;
-    }
-
-    /**
-     * Workaround for the use of arrays as keys in a hash map.
-     */
-    private static final class Key {
-        private final long[] array;
-
-        Key(final long[] array) {
-            this.array = array;
-        }
-        @Override public boolean equals(final Object other) {
-            return (other instanceof Key) && Arrays.equals(array, ((Key) 
other).array);
-        }
-        @Override public int hashCode() {
-            return Arrays.hashCode(array);
-        }
+        return new ArrayOfLongs(array).unique(sharedInstances);
     }
 
     /**
diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/ArrayOfLongs.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/ArrayOfLongs.java
new file mode 100644
index 0000000000..a6478a59f9
--- /dev/null
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/storage/base/ArrayOfLongs.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.sis.storage.base;
+
+import java.util.Map;
+import java.util.Arrays;
+
+
+/**
+ * Workaround for the use of {@code long[]} arrays as keys in a hash map.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ */
+public final class ArrayOfLongs {
+    /**
+     * The array.
+     */
+    private final long[] array;
+
+    /**
+     * Creates a new key.
+     *
+     * @param array the array.
+     */
+    public ArrayOfLongs(final long[] array) {
+        this.array = array;
+    }
+
+    /**
+     * Returns a unique instance of the array wrapped by this key.
+     *
+     * @param  sharedInstances  a map containing shared instances of arrays.
+     * @return a shared instance of the array wrapped by this key.
+     * @throws ClassCastException if this key is associated in given map to an 
object other than a {@code long[]}.
+     */
+    public long[] unique(final Map<? super ArrayOfLongs, ? super long[]> 
sharedInstances) {
+        Object existing = sharedInstances.putIfAbsent(this, array);
+        return (existing != null) ? (long[]) existing : array;
+    }
+
+    /**
+     * Returns whether the given object is a key wrapping
+     * an array equals to the array wrapped by this key.
+     *
+     * @param  other  the other object to compare with this key.
+     * @return whether the two objects are wrapping equal arrays.
+     */
+    @Override
+    public boolean equals(final Object other) {
+        return (other instanceof ArrayOfLongs) && Arrays.equals(array, 
((ArrayOfLongs) other).array);
+    }
+
+    /**
+     * Returns a hash code value for this key.
+     *
+     * @return the array hash code.
+     */
+    @Override
+    public int hashCode() {
+        return Arrays.hashCode(array);
+    }
+
+    /**
+     * Returns a string representation of the wrapped array.
+     *
+     * @return a string representation for debugging purposes.
+     */
+    @Override
+    public String toString() {
+        return Arrays.toString(array);
+    }
+}
diff --git 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/privy/Numerics.java 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/privy/Numerics.java
index 433b7d2455..bbd5cf0e39 100644
--- 
a/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/privy/Numerics.java
+++ 
b/endorsed/src/org.apache.sis.util/main/org/apache/sis/util/privy/Numerics.java
@@ -209,6 +209,25 @@ public final class Numerics extends Static {
         return x == Math.rint(x);       // `rint` is reported faster than 
`floor`.
     }
 
+    /**
+     * Makes the given value a multiple of the given divisor, rounding up.
+     * If the given value is already a multiple of the divisor, then it is 
returned as-is.
+     * Otherwise, this method returns the next multiple of the divisor which 
is greater than the given value.
+     *
+     * @param  value    the value which need to be a multiple of {@code 
divisor}.
+     * @param  divisor  the divisor. Cannot be zero. The sign is ignored 
(always handed as positive).
+     * @return the smallest multiple of {@code divisor} which is ≥ {@code 
value}.
+     */
+    public static int snapToCeil(int value, final int divisor) {
+        final int r = value % divisor;      // Always has the sign of `value`.
+        if (r > 0) {
+            value += Math.abs(divisor) - r;
+        } else {
+            value -= r;
+        }
+        return value;
+    }
+
     /**
      * Returns x/y with the requirement that the division must be integer.
      *
diff --git 
a/endorsed/src/org.apache.sis.util/test/org/apache/sis/pending/jdk/JDK18Test.java
 
b/endorsed/src/org.apache.sis.util/test/org/apache/sis/pending/jdk/JDK18Test.java
new file mode 100644
index 0000000000..33542335f2
--- /dev/null
+++ 
b/endorsed/src/org.apache.sis.util/test/org/apache/sis/pending/jdk/JDK18Test.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.sis.pending.jdk;
+
+import static org.apache.sis.pending.jdk.JDK18.ceilDiv;
+
+// Test dependencies
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.*;
+import org.apache.sis.test.TestCase;
+
+
+/**
+ * Tests the {@link JDK18} class.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ */
+public final class JDK18Test extends TestCase {
+    /**
+     * Creates a new test case.
+     */
+    public JDK18Test() {
+    }
+
+    /**
+     * Tests {@link JDK18#ceilDiv(int, int)} and {@link JDK18#ceilDiv(long, 
long)}.
+     */
+    @Test
+    public void testCeilDiv() {
+        assertEquals( 4,  ceilDiv( 12,  3 ));
+        assertEquals( 4L, ceilDiv( 12L, 3L));
+        assertEquals( 3,  ceilDiv(  8,  3 ));
+        assertEquals( 3L, ceilDiv(  8L, 3L));
+        assertEquals(-4,  ceilDiv(-12,  3 ));
+        assertEquals(-4L, ceilDiv(-12L, 3L));
+        assertEquals(-2,  ceilDiv( -8,  3 ));
+        assertEquals(-2L, ceilDiv( -8L, 3L));
+    }
+}
diff --git 
a/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/privy/NumericsTest.java
 
b/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/privy/NumericsTest.java
index e87ecd09c6..e912cd12ec 100644
--- 
a/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/privy/NumericsTest.java
+++ 
b/endorsed/src/org.apache.sis.util/test/org/apache/sis/util/privy/NumericsTest.java
@@ -24,7 +24,6 @@ import static java.lang.Double.NEGATIVE_INFINITY;
 import org.apache.sis.math.MathFunctions;
 import org.apache.sis.util.ComparisonMode;
 import static org.apache.sis.util.privy.Numerics.*;
-import static org.apache.sis.pending.jdk.JDK18.ceilDiv;
 import static org.apache.sis.pending.jdk.JDK19.FLOAT_PRECISION;
 import static org.apache.sis.pending.jdk.JDK19.DOUBLE_PRECISION;
 
@@ -77,18 +76,21 @@ public final class NumericsTest extends TestCase {
     }
 
     /**
-     * Tests {@link Numerics#ceilDiv(int, int)} and {@link 
Numerics#ceilDiv(long, long)}.
+     * Tests {@link Numerics#snapToCeil(int, int)}.
      */
-    @Test
-    public void testCeilDiv() {
-        assertEquals( 4,  ceilDiv( 12,  3 ));
-        assertEquals( 4L, ceilDiv( 12L, 3L));
-        assertEquals( 3,  ceilDiv(  8,  3 ));
-        assertEquals( 3L, ceilDiv(  8L, 3L));
-        assertEquals(-4,  ceilDiv(-12,  3 ));
-        assertEquals(-4L, ceilDiv(-12L, 3L));
-        assertEquals(-2,  ceilDiv( -8,  3 ));
-        assertEquals(-2L, ceilDiv( -8L, 3L));
+    public void testSnapToCeil() {
+        boolean negative = false;
+        do {    // Executed exactly twice.
+            final int divisor = negative ? -3 : 3;
+            assertEquals(  9, Numerics.snapToCeil(  9, divisor));
+            assertEquals( 12, Numerics.snapToCeil( 10, divisor));
+            assertEquals( 12, Numerics.snapToCeil( 11, divisor));
+            assertEquals( 12, Numerics.snapToCeil( 12, divisor));
+            assertEquals( -9, Numerics.snapToCeil( -9, divisor));
+            assertEquals( -9, Numerics.snapToCeil(-10, divisor));
+            assertEquals( -9, Numerics.snapToCeil(-11, divisor));
+            assertEquals(-12, Numerics.snapToCeil(-12, divisor));
+        } while (negative = !negative);
     }
 
     /**

Reply via email to