LANG-536 - Add isSorted() to ArrayUtils. Patch supplied by James Sawle. Closes #32 in GitHub.

git-svn-id: https://svn.apache.org/repos/asf/commons/proper/lang/trunk@1632874 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/pom.xml b/pom.xml
index a5da63e..47f522c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -374,6 +374,9 @@
       <name>Scott Sanders</name>
     </contributor>
     <contributor>
+      <name>James Sawle</name>
+    </contributor>
+    <contributor>
       <name>Ralph Schaer</name>
     </contributor>
     <contributor>
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index d2932ce..2ddb50e 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -22,6 +22,7 @@
   <body>
 
   <release version="3.4" date="tba" description="tba">
+    <action issue="LANG-536" type="add" dev="djones" due-to="James Sawle">Add isSorted() to ArrayUtils</action>
     <action issue="LANG-1041" type="fix" dev="britter" due-to="Alexandre Bartel">Fix MethodUtilsTest so it does not depend on JDK method ordering</action>
     <action issue="LANG-827" type="update" dev="djones">CompareToBuilder's doc doesn't specify precedence of fields it uses in performing comparisons</action>
     <action issue="LANG-1000" type="fix" dev="djones">ParseException when trying to parse UTC dates with Z as zone designator using DateFormatUtils.ISO_DATETIME_TIME_ZONE_FORMAT</action>
diff --git a/src/main/java/org/apache/commons/lang3/ArrayUtils.java b/src/main/java/org/apache/commons/lang3/ArrayUtils.java
index 06fb274..644c0b8 100644
--- a/src/main/java/org/apache/commons/lang3/ArrayUtils.java
+++ b/src/main/java/org/apache/commons/lang3/ArrayUtils.java
@@ -19,6 +19,7 @@
 import java.lang.reflect.Array;
 import java.util.Arrays;
 import java.util.BitSet;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -26,6 +27,7 @@
 import org.apache.commons.lang3.builder.HashCodeBuilder;
 import org.apache.commons.lang3.builder.ToStringBuilder;
 import org.apache.commons.lang3.builder.ToStringStyle;
+import org.apache.commons.lang3.math.NumberUtils;
 import org.apache.commons.lang3.mutable.MutableInt;
 
 /**
@@ -5356,7 +5358,7 @@
         if (isEmpty(array) || isEmpty(values)) {
             return clone(array);
         }
-        final HashMap<Byte, MutableInt> occurrences = new HashMap<Byte, MutableInt>(values.length);
+        final Map<Byte, MutableInt> occurrences = new HashMap<Byte, MutableInt>(values.length);
         for (final byte v : values) {
             final Byte boxed = Byte.valueOf(v);
             final MutableInt count = occurrences.get(boxed);
@@ -6087,4 +6089,255 @@
         }
         return result;
     }
+
+    /**
+     * <p>This method checks whether the provided array is sorted according to the class's 
+     * {@code compareTo} method.</p>
+     *
+     * @param array the array to check
+     * @param <T> the datatype of the array to check, it must implement {@code Comparable}
+     * @return whether the array is sorted
+     * @since 3.4
+     */
+    public static <T extends Comparable<? super T>> boolean isSorted(final T[] array) {
+        return isSorted(array, new Comparator<T>() {
+            @Override
+            public int compare(T o1, T o2) {
+                return o1.compareTo(o2);
+            }
+        });
+    }
+   
+
+    /**
+     * <p>This method checks whether the provided array is sorted according to the provided {@code Comparator}.</p>
+     *
+     * @param array the array to check
+     * @param comparator the {@code Comparator} to compare over
+     * @param <T> the datatype of the array
+     * @return whether the array is sorted
+     * @since 3.4
+     */
+    public static <T> boolean isSorted(final T[] array, final Comparator<T> comparator) {
+        if (comparator == null) {
+            throw new IllegalArgumentException("Comparator should not be null.");
+        }
+        
+        if(array == null || array.length < 2) {
+            return true;
+        }
+
+        T previous = array[0];
+        final int n = array.length;
+        for(int i = 1; i < n; i++) {
+            final T current = array[i];
+            if (comparator.compare(previous, current) > 0) {
+                return false;
+            }
+
+            previous = current;
+        }
+        return true;
+    }
+
+    /**
+     * <p>This method checks whether the provided array is sorted according to natural ordering.</p>
+     *
+     * @param array the array to check
+     * @return whether the array is sorted according to natural ordering
+     * @since 3.4
+     */
+    public static boolean isSorted(int[] array) {
+        if(array == null || array.length < 2) {
+            return true;
+        }
+
+        int previous = array[0];
+        final int n = array.length;
+        for(int i = 1; i < n; i++) {
+            final int current = array[i];
+            if(NumberUtils.compare(previous, current) > 0) {
+                return false;
+            }
+
+            previous = current;
+        }
+        return true;
+    }
+
+    /**
+     * <p>This method checks whether the provided array is sorted according to natural ordering.</p>
+     *
+     * @param array the array to check
+     * @return whether the array is sorted according to natural ordering
+     * @since 3.4
+     */
+    public static boolean isSorted(long[] array) {
+        if(array == null || array.length < 2) {
+            return true;
+        }
+
+        long previous = array[0];
+        final int n = array.length;
+        for(int i = 1; i < n; i++) {
+            final long current = array[i];
+            if(NumberUtils.compare(previous, current) > 0) {
+                return false;
+            }
+
+            previous = current;
+        }
+        return true;
+    }
+
+    /**
+     * <p>This method checks whether the provided array is sorted according to natural ordering.</p>
+     *
+     * @param array the array to check
+     * @return whether the array is sorted according to natural ordering
+     * @since 3.4
+     */
+    public static boolean isSorted(short[] array) {
+        if(array == null || array.length < 2) {
+            return true;
+        }
+
+        short previous = array[0];
+        final int n = array.length;
+        for(int i = 1; i < n; i++) {
+            final short current = array[i];
+            if(NumberUtils.compare(previous, current) > 0) {
+                return false;
+            }
+
+            previous = current;
+        }
+        return true;
+    }
+
+    /**
+     * <p>This method checks whether the provided array is sorted according to natural ordering.</p>
+     *
+     * @param array the array to check
+     * @return whether the array is sorted according to natural ordering
+     * @since 3.4
+     */
+    public static boolean isSorted(final double[] array) {
+        if(array == null || array.length < 2) {
+            return true;
+        }
+
+        double previous = array[0];
+        final int n = array.length;
+        for(int i = 1; i < n; i++) {
+            final double current = array[i];
+            if(Double.compare(previous, current) > 0) {
+                return false;
+            }
+
+            previous = current;
+        }
+        return true;
+    }
+
+    /**
+     * <p>This method checks whether the provided array is sorted according to natural ordering.</p>
+     *
+     * @param array the array to check
+     * @return whether the array is sorted according to natural ordering
+     * @since 3.4
+     */
+    public static boolean isSorted(final float[] array) {
+        if(array == null || array.length < 2) {
+            return true;
+        }
+
+        float previous = array[0];
+        final int n = array.length;
+        for(int i = 1; i < n; i++) {
+            final float current = array[i];
+            if(Float.compare(previous, current) > 0) {
+                return false;
+            }
+
+            previous = current;
+        }
+        return true;
+    }
+
+    /**
+     * <p>This method checks whether the provided array is sorted according to natural ordering.</p>
+     *
+     * @param array the array to check
+     * @return whether the array is sorted according to natural ordering
+     * @since 3.4
+     */
+    public static boolean isSorted(byte[] array) {
+        if(array == null || array.length < 2) {
+            return true;
+        }
+
+        byte previous = array[0];
+        final int n = array.length;
+        for(int i = 1; i < n; i++) {
+            final byte current = array[i];
+            if(NumberUtils.compare(previous, current) > 0) {
+                return false;
+            }
+
+            previous = current;
+        }
+        return true;
+    }
+
+    /**
+     * <p>This method checks whether the provided array is sorted according to natural ordering.</p>
+     *
+     * @param array the array to check
+     * @return whether the array is sorted according to natural ordering
+     * @since 3.4
+     */
+    public static boolean isSorted(char[] array) {
+        if(array == null || array.length < 2) {
+            return true;
+        }
+
+        char previous = array[0];
+        final int n = array.length;
+        for(int i = 1; i < n; i++) {
+            final char current = array[i];
+            if(CharUtils.compare(previous, current) > 0) {
+                return false;
+            }
+
+            previous = current;
+        }
+        return true;
+    }
+
+    /**
+     * <p>This method checks whether the provided array is sorted according to natural ordering
+     * ({@code false} before {@code true}).</p>
+     *
+     * @param array the array to check
+     * @return whether the array is sorted according to natural ordering
+     * @since 3.4
+     */
+    public static boolean isSorted(boolean[] array) {
+        if(array == null || array.length < 2) {
+            return true;
+        }
+
+        boolean previous = array[0];
+        final int n = array.length;
+        for(int i = 1; i < n; i++) {
+            final boolean current = array[i];
+            if(BooleanUtils.compare(previous, current) > 0) {
+                return false;
+            }
+
+            previous = current;
+        }
+        return true;
+    }
 }
diff --git a/src/main/java/org/apache/commons/lang3/BooleanUtils.java b/src/main/java/org/apache/commons/lang3/BooleanUtils.java
index fcbad66..1832fe0 100644
--- a/src/main/java/org/apache/commons/lang3/BooleanUtils.java
+++ b/src/main/java/org/apache/commons/lang3/BooleanUtils.java
@@ -1085,4 +1085,25 @@
         }
     }
 
+    /**
+     * <p>Compares two {@code boolean} values. This is the same functionality as provided in Java 7.</p>
+     *
+     * @param x the first {@code boolean} to compare
+     * @param y the second {@code boolean} to compare
+     * @return the value {@code 0} if {@code x == y};
+     *         a value less than {@code 0} if {@code !x && y}; and
+     *         a value greater than {@code 0} if {@code x && !y}
+     * @since 3.4
+     */
+    public static int compare(boolean x, boolean y) {
+        if (x == y) {
+            return 0;
+        }
+        if (x) {
+            return 1;
+        } else {
+            return -1;
+        }
+    }
+
 }
diff --git a/src/main/java/org/apache/commons/lang3/CharUtils.java b/src/main/java/org/apache/commons/lang3/CharUtils.java
index f8f284e..3f19a21 100644
--- a/src/main/java/org/apache/commons/lang3/CharUtils.java
+++ b/src/main/java/org/apache/commons/lang3/CharUtils.java
@@ -535,5 +535,18 @@
     public static boolean isAsciiAlphanumeric(final char ch) {
         return isAsciiAlpha(ch) || isAsciiNumeric(ch);
     }
-    
+
+    /**
+     * <p>Compares two {@code char} values numerically. This is the same functionality as provided in Java 7.</p>
+     *
+     * @param x the first {@code char} to compare
+     * @param y the second {@code char} to compare
+     * @return the value {@code 0} if {@code x == y};
+     *         a value less than {@code 0} if {@code x < y}; and
+     *         a value greater than {@code 0} if {@code x > y}
+     * @since 3.4
+     */
+    public static int compare(char x, char y) {
+        return x-y;
+    }
 }
diff --git a/src/main/java/org/apache/commons/lang3/math/NumberUtils.java b/src/main/java/org/apache/commons/lang3/math/NumberUtils.java
index 9eaf57d..14f4bf4 100644
--- a/src/main/java/org/apache/commons/lang3/math/NumberUtils.java
+++ b/src/main/java/org/apache/commons/lang3/math/NumberUtils.java
@@ -1495,4 +1495,80 @@
         }
     }
 
+    /**
+     * <p>Compares two {@code int} values numerically. This is the same functionality as provided in Java 7.</p>
+     *
+     * @param x the first {@code int} to compare
+     * @param y the second {@code int} to compare
+     * @return the value {@code 0} if {@code x == y};
+     *         a value less than {@code 0} if {@code x < y}; and
+     *         a value greater than {@code 0} if {@code x > y}
+     * @since 3.4
+     */
+    public static int compare(int x, int y) {
+        if (x == y) {
+            return 0;
+        }
+        if (x < y) {
+            return -1;
+        } else {
+            return 1;
+        }
+    }
+
+    /**
+     * <p>Compares to {@code long} values numerically. This is the same functionality as provided in Java 7.</p>
+     *
+     * @param x the first {@code long} to compare
+     * @param y the second {@code long} to compare
+     * @return the value {@code 0} if {@code x == y};
+     *         a value less than {@code 0} if {@code x < y}; and
+     *         a value greater than {@code 0} if {@code x > y}
+     * @since 3.4
+     */
+    public static int compare(long x, long y) {
+        if (x == y) {
+            return 0;
+        }
+        if (x < y) {
+            return -1;
+        } else {
+            return 1;
+        }
+    }
+
+    /**
+     * <p>Compares to {@code short} values numerically. This is the same functionality as provided in Java 7.</p>
+     *
+     * @param x the first {@code short} to compare
+     * @param y the second {@code short} to compare
+     * @return the value {@code 0} if {@code x == y};
+     *         a value less than {@code 0} if {@code x < y}; and
+     *         a value greater than {@code 0} if {@code x > y}
+     * @since 3.4
+     */
+    public static int compare(short x, short y) {
+        if (x == y) {
+            return 0;
+        }
+        if (x < y) {
+            return -1;
+        } else {
+            return 1;
+        }
+    }
+
+    /**
+     * <p>Compares two {@code byte} values numerically. This is the same functionality as provided in Java 7.</p>
+     *
+     * @param x the first {@code byte} to compare
+     * @param y the second {@code byte} to compare
+     * @return the value {@code 0} if {@code x == y};
+     *         a value less than {@code 0} if {@code x < y}; and
+     *         a value greater than {@code 0} if {@code x > y}
+     * @since 3.4
+     */
+    public static int compare(byte x, byte y) {
+        return x-y;
+    }
 }
diff --git a/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java b/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java
index af7ceba..27150ae 100644
--- a/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/ArrayUtilsTest.java
@@ -16,19 +16,12 @@
  */
 package org.apache.commons.lang3;
 
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.*;
 
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Modifier;
 import java.util.Arrays;
+import java.util.Comparator;
 import java.util.Date;
 import java.util.Map;
 
@@ -3472,4 +3465,165 @@
         } catch (final IllegalArgumentException e) {}
     }
 
+    @Test
+    public void testIsSorted() {
+        Integer[] array = null;
+        assertTrue(ArrayUtils.isSorted(array));
+
+        array = new Integer[]{1};
+        assertTrue(ArrayUtils.isSorted(array));
+
+        array = new Integer[]{1,2,3};
+        assertTrue(ArrayUtils.isSorted(array));
+
+        array = new Integer[]{1,3,2};
+        assertFalse(ArrayUtils.isSorted(array));
+    }
+
+    @Test
+    public void testIsSortedComparator() {
+        Comparator<Integer> c = new Comparator<Integer>() {
+                public int compare(Integer o1, Integer o2) {
+                        return o2.compareTo(o1);
+                    }
+            };
+
+        Integer[] array = null;
+        assertTrue(ArrayUtils.isSorted(array, c));
+
+        array = new Integer[]{1};
+        assertTrue(ArrayUtils.isSorted(array, c));
+
+        array = new Integer[]{3,2,1};
+        assertTrue(ArrayUtils.isSorted(array, c));
+
+        array = new Integer[]{1,3,2};
+        assertFalse(ArrayUtils.isSorted(array, c));
+    }
+    
+    @Test(expected = IllegalArgumentException.class)
+    public void testIsSortedNullComparator() throws Exception {
+        ArrayUtils.isSorted(null, null);
+    }
+
+    @Test
+    public void testIsSortedInt() {
+        int[] array = null;
+        assertTrue(ArrayUtils.isSorted(array));
+
+        array = new int[]{1};
+        assertTrue(ArrayUtils.isSorted(array));
+
+        array = new int[]{1,2,3};
+        assertTrue(ArrayUtils.isSorted(array));
+
+        array = new int[]{1,3,2};
+        assertFalse(ArrayUtils.isSorted(array));
+    }
+
+    @Test
+    public void testIsSortedFloat() {
+        float[] array = null;
+        assertTrue(ArrayUtils.isSorted(array));
+
+        array = new float[]{0f};
+        assertTrue(ArrayUtils.isSorted(array));
+
+        array = new float[]{-1f, 0f, 0.1f, 0.2f};
+        assertTrue(ArrayUtils.isSorted(array));
+
+        array = new float[]{-1f, 0.2f, 0.1f, 0f};
+        assertFalse(ArrayUtils.isSorted(array));
+    }
+
+    @Test
+    public void testIsSortedLong() {
+        long[] array = null;
+        assertTrue(ArrayUtils.isSorted(array));
+
+        array = new long[]{0L};
+        assertTrue(ArrayUtils.isSorted(array));
+
+        array = new long[]{-1L, 0L, 1L};
+        assertTrue(ArrayUtils.isSorted(array));
+
+        array = new long[]{-1L, 1L, 0L};
+        assertFalse(ArrayUtils.isSorted(array));
+    }
+
+    @Test
+    public void testIsSortedDouble() {
+        double[] array = null;
+        assertTrue(ArrayUtils.isSorted(array));
+
+        array = new double[]{0.0};
+        assertTrue(ArrayUtils.isSorted(array));
+
+        array = new double[]{-1.0, 0.0, 0.1, 0.2};
+        assertTrue(ArrayUtils.isSorted(array));
+
+        array = new double[]{-1.0, 0.2, 0.1, 0.0};
+        assertFalse(ArrayUtils.isSorted(array));
+    }
+
+    @Test
+    public void testIsSortedChar() {
+        char[] array = null;
+        assertTrue(ArrayUtils.isSorted(array));
+
+        array = new char[]{'a'};
+        assertTrue(ArrayUtils.isSorted(array));
+
+        array = new char[]{'a', 'b', 'c'};
+        assertTrue(ArrayUtils.isSorted(array));
+
+        array = new char[]{'a', 'c', 'b'};
+        assertFalse(ArrayUtils.isSorted(array));
+    }
+
+    @Test
+    public void testIsSortedByte() {
+        byte[] array = null;
+        assertTrue(ArrayUtils.isSorted(array));
+
+        array = new byte[]{0x10};
+        assertTrue(ArrayUtils.isSorted(array));
+
+        array = new byte[]{0x10, 0x20, 0x30};
+        assertTrue(ArrayUtils.isSorted(array));
+
+        array = new byte[]{0x10, 0x30, 0x20};
+        assertFalse(ArrayUtils.isSorted(array));
+    }
+
+    @Test
+    public void testIsSortedShort() {
+        short[] array = null;
+        assertTrue(ArrayUtils.isSorted(array));
+
+        array = new short[]{0};
+        assertTrue(ArrayUtils.isSorted(array));
+
+        array = new short[]{-1, 0, 1};
+        assertTrue(ArrayUtils.isSorted(array));
+
+        array = new short[]{-1, 1, 0};
+        assertFalse(ArrayUtils.isSorted(array));
+    }
+
+    @Test
+    public void testIsSortedBool() {
+        boolean[] array = null;
+        assertTrue(ArrayUtils.isSorted(array));
+
+        array = new boolean[]{true};
+        assertTrue(ArrayUtils.isSorted(array));
+
+        array = new boolean[]{false, true};
+        assertTrue(ArrayUtils.isSorted(array));
+
+        array = new boolean[]{true, false};
+        assertFalse(ArrayUtils.isSorted(array));
+    }
+
 }
diff --git a/src/test/java/org/apache/commons/lang3/BooleanUtilsTest.java b/src/test/java/org/apache/commons/lang3/BooleanUtilsTest.java
index f157080..d3464b7 100644
--- a/src/test/java/org/apache/commons/lang3/BooleanUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/BooleanUtilsTest.java
@@ -1006,5 +1006,13 @@
                     Boolean.TRUE })
                     .booleanValue());
     }
+
+    @Test
+    public void testCompare(){
+        assertTrue(BooleanUtils.compare(true, false) > 0);
+        assertTrue(BooleanUtils.compare(true, true) == 0);
+        assertTrue(BooleanUtils.compare(false, false) == 0);
+        assertTrue(BooleanUtils.compare(false, true) < 0);
+    }
     
 }
diff --git a/src/test/java/org/apache/commons/lang3/CharUtilsTest.java b/src/test/java/org/apache/commons/lang3/CharUtilsTest.java
index b2adcb3..94acbcd 100644
--- a/src/test/java/org/apache/commons/lang3/CharUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/CharUtilsTest.java
@@ -354,5 +354,11 @@
             }
         }
     }
-    
+
+    @Test
+    public void testCompare() {
+        assertTrue(CharUtils.compare('a', 'b') < 0);
+        assertTrue(CharUtils.compare('c', 'c') == 0);
+        assertTrue(CharUtils.compare('c', 'a') > 0);
+    }
 }
diff --git a/src/test/java/org/apache/commons/lang3/math/NumberUtilsTest.java b/src/test/java/org/apache/commons/lang3/math/NumberUtilsTest.java
index e9ec47d..e40293c 100644
--- a/src/test/java/org/apache/commons/lang3/math/NumberUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/math/NumberUtilsTest.java
@@ -1359,4 +1359,31 @@
         assertTrue(Float.isNaN(NumberUtils.max(bF)));
     }
 
+    @Test
+    public void compareInt() {
+        assertTrue(NumberUtils.compare(-3, 0) < 0);
+        assertTrue(NumberUtils.compare(113, 113)==0);
+        assertTrue(NumberUtils.compare(213, 32) > 0);
+    }
+
+    @Test
+    public void compareLong() {
+        assertTrue(NumberUtils.compare(-3L, 0L) < 0);
+        assertTrue(NumberUtils.compare(113L, 113L)==0);
+        assertTrue(NumberUtils.compare(213L, 32L) > 0);
+    }
+
+    @Test
+    public void compareShort() {
+        assertTrue(NumberUtils.compare((short)-3, (short)0) < 0);
+        assertTrue(NumberUtils.compare((short)113, (short)113)==0);
+        assertTrue(NumberUtils.compare((short)213, (short)32) > 0);
+    }
+
+    @Test
+    public void compareByte() {
+        assertTrue(NumberUtils.compare((byte)-3, (byte)0) < 0);
+        assertTrue(NumberUtils.compare((byte)113, (byte)113)==0);
+        assertTrue(NumberUtils.compare((byte)123, (byte)32) > 0);
+    }
 }