IGNITE-12447 Modification of S#compact method - Fixes #7139.

Signed-off-by: Ivan Rakov <irakov@apache.org>
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/tostring/GridToStringBuilder.java b/modules/core/src/main/java/org/apache/ignite/internal/util/tostring/GridToStringBuilder.java
index 58abd55..4dd3741 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/util/tostring/GridToStringBuilder.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/util/tostring/GridToStringBuilder.java
@@ -38,6 +38,7 @@
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReadWriteLock;
 import java.util.function.Supplier;
+import java.util.function.Function;
 import org.apache.ignite.IgniteException;
 import org.apache.ignite.IgniteSystemProperties;
 import org.apache.ignite.internal.util.GridUnsafe;
@@ -1832,26 +1833,46 @@
      * @param col Collection of integers.
      * @return Compacted string representation of given collections.
      */
-    public static String compact(@NotNull Collection<Integer> col) {
+    public static String compact(Collection<Integer> col) {
+        return compact(col, i -> i + 1);
+    }
+
+    /**
+     * Returns sorted and compacted string representation of given {@code col}.
+     * Two nearby numbers are compacted to one continuous segment.
+     * E.g. collection of [1, 2, 3, 5, 6, 7, 10] with
+     * {@code nextValFun = i -> i + 1} will be compacted to [1-3, 5-7, 10].
+     *
+     * @param col Collection of numbers.
+     * @param nextValFun Function to get nearby number.
+     * @return Compacted string representation of given collections.
+     */
+    public static <T extends Number & Comparable<? super T>> String compact(
+        Collection<T> col,
+        Function<T, T> nextValFun
+    ) {
+        assert nonNull(col);
+        assert nonNull(nextValFun);
+
         if (col.isEmpty())
             return "[]";
 
         SB sb = new SB();
         sb.a('[');
 
-        List<Integer> l = new ArrayList<>(col);
+        List<T> l = new ArrayList<>(col);
         Collections.sort(l);
 
-        int left = l.get(0), right = left;
+        T left = l.get(0), right = left;
         for (int i = 1; i < l.size(); i++) {
-            int val = l.get(i);
+            T val = l.get(i);
 
-            if (right == val || right + 1 == val) {
+            if (right.compareTo(val) == 0 || nextValFun.apply(right).compareTo(val) == 0) {
                 right = val;
                 continue;
             }
 
-            if (left == right)
+            if (left.compareTo(right) == 0)
                 sb.a(left);
             else
                 sb.a(left).a('-').a(right);
@@ -1861,7 +1882,7 @@
             left = right = val;
         }
 
-        if (left == right)
+        if (left.compareTo(right) == 0)
             sb.a(left);
         else
             sb.a(left).a('-').a(right);
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/util/tostring/GridToStringBuilderSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/util/tostring/GridToStringBuilderSelfTest.java
index bd57a6d..108ef42 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/util/tostring/GridToStringBuilderSelfTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/util/tostring/GridToStringBuilderSelfTest.java
@@ -22,6 +22,7 @@
 import java.lang.reflect.Array;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -30,6 +31,7 @@
 import java.util.concurrent.Callable;
 import java.util.concurrent.CyclicBarrier;
 import java.util.concurrent.locks.ReadWriteLock;
+import java.util.function.Function;
 import org.apache.ignite.IgniteLogger;
 import org.apache.ignite.IgniteSystemProperties;
 import org.apache.ignite.internal.IgniteInternalFuture;
@@ -41,8 +43,11 @@
 import org.apache.ignite.testframework.junits.common.GridCommonTest;
 import org.junit.Test;
 
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
 import static org.apache.ignite.IgniteSystemProperties.IGNITE_TO_STRING_COLLECTION_LIMIT;
 import static org.apache.ignite.IgniteSystemProperties.IGNITE_TO_STRING_MAX_LENGTH;
+import static org.apache.ignite.internal.util.tostring.GridToStringBuilder.compact;
 import static org.apache.ignite.internal.util.tostring.GridToStringBuilder.identity;
 
 /**
@@ -586,6 +591,80 @@
             allocated1 - allocated0 < 1_000_000);
     }
 
+
+
+    /**
+     * Checking that method
+     * {@link GridToStringBuilder#compact(Collection, Function) compact} works
+     * correctly for {@link Integer}.
+     */
+    @Test
+    public void testCompactIntegers() {
+        List<Integer> emptyList = emptyList();
+        List<Integer> intList = asList(1, 2, 3, 9, 8, 7, 12);
+
+        String compactStr = "[1-3, 7-9, 12]";
+
+        Function<Integer, Integer> nextVal = i -> i + 1;
+
+        checkCompact(emptyList, intList, nextVal, compactStr);
+
+        assertEquals("[]", compact(emptyList));
+        assertEquals(compactStr, compact(intList));
+    }
+
+    /**
+     * Checking that method
+     * {@link GridToStringBuilder#compact(Collection, Function) compact} works
+     * correctly for {@link Double}.
+     */
+    @Test
+    public void testCompactDoubles() {
+        checkCompact(
+            emptyList(),
+            asList(1.0, 2.0, 3.0, 9.0, 8.0, 7.0, 12.0),
+            i -> i + 1.0,
+            "[1.0-3.0, 7.0-9.0, 12.0]"
+        );
+    }
+
+    /**
+     * Checking that method
+     * {@link GridToStringBuilder#compact(Collection, Function) compact} works
+     * correctly for {@link Long}.
+     */
+    @Test
+    public void testCompactLongs() {
+        checkCompact(
+            emptyList(),
+            asList(1L, 2L, 3L, 9L, 8L, 7L, 12L),
+            i -> i + 1L,
+            "[1-3, 7-9, 12]"
+        );
+    }
+
+    /**
+     * Checking the correct operation of method
+     * {@link GridToStringBuilder#compact(Collection, Function) compact}.
+     * For an empty collection of numbers, "[] " is expected, and for a
+     * non-empty collection, the value of the parameter {@code numCol} is
+     * expected.
+     *
+     * @param emptyCol Empty collection.
+     * @param numCol Not an empty collection of numbers.
+     * @param nextNum Function for getting the next number.
+     * @param compactStr Expected compact string for param {@code numCol}.
+     */
+    private <T extends Number & Comparable<? super T>> void checkCompact(
+        Collection<T> emptyCol,
+        Collection<T> numCol,
+        Function<T, T> nextNum,
+        String compactStr
+    ) {
+        assertEquals("[]", compact(emptyCol, nextNum));
+        assertEquals(compactStr, compact(numCol, nextNum));
+    }
+
     /**
      * @param exp Expected.
      * @param w Wrapper.