org.apache.commons.lang3.ExtendedArrayUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.commons.lang3.ExtendedArrayUtils.java

Source

/*
 * Copyright 2013 Lyor Goldstein
 * 
 * Licensed 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.commons.lang3;

import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.apache.commons.collections15.ExtendedCollectionUtils;
import org.apache.commons.collections15.ExtendedComparatorUtils;
import org.apache.commons.lang3.math.ExtendedNumberUtils;

/**
 * @author lgoldstein
 */
public class ExtendedArrayUtils extends ArrayUtils {
    public ExtendedArrayUtils() {
        super();
    }

    /**
     * A "safe" version of {@link Arrays#asList(Object...)}
     * @param arr The elements array - if {@code null}/empty then {@link Collections#emptyList()}
     * is returned
     * @return A {@link List} encapsulating the array (never {@code null})
     */
    @SafeVarargs
    public static final <T> List<T> asList(T... arr) {
        if (length(arr) <= 0) {
            return Collections.emptyList();
        } else {
            return Arrays.asList(arr);
        }
    }

    public static final int hashCode(Object... arr) {
        return ExtendedCollectionUtils.hashCode(asList(arr));
    }

    public static final int deepHash(Object... arr) {
        return ExtendedCollectionUtils.deepHash(asList(arr));
    }

    public static final <T> int length(T[] array) {
        return getLength(array);
    }

    public static final int length(int... array) {
        return getLength(array);
    }

    public static final int length(long... array) {
        return getLength(array);
    }

    public static final int length(short... array) {
        return getLength(array);
    }

    public static final int length(double... array) {
        return getLength(array);
    }

    public static final int length(float... array) {
        return getLength(array);
    }

    public static final int length(byte... array) {
        return getLength(array);
    }

    public static final int length(char... array) {
        return getLength(array);
    }

    public static final int length(boolean... array) {
        return getLength(array);
    }

    public static final int hashCode(byte[] buf, int offset, int length) {
        int hashValue = 0;
        for (int index = offset, l = 0; l < length; index++, l++) {
            hashValue += 31 * hashValue + buf[index];
        }

        return hashValue;
    }

    public static final int hashCode(short[] buf, int offset, int length) {
        int hashValue = 0;
        for (int index = offset, l = 0; l < length; index++, l++) {
            hashValue += 31 * hashValue + buf[index];
        }

        return hashValue;
    }

    public static final int hashCode(int[] buf, int offset, int length) {
        int hashValue = 0;
        for (int index = offset, l = 0; l < length; index++, l++) {
            hashValue += 31 * hashValue + buf[index];
        }

        return hashValue;
    }

    public static final int hashCode(long[] buf, int offset, int length) {
        int hashValue = 0;
        for (int index = offset, l = 0; l < length; index++, l++) {
            hashValue += 31 * hashValue + ExtendedNumberUtils.hashCode(buf[index]);
        }

        return hashValue;
    }

    public static final int hashCode(float[] buf, int offset, int length) {
        int hashValue = 0;
        for (int index = offset, l = 0; l < length; index++, l++) {
            hashValue += 31 * hashValue + ExtendedNumberUtils.hashCode(buf[index]);
        }

        return hashValue;
    }

    public static final int hashCode(double[] buf, int offset, int length) {
        int hashValue = 0;
        for (int index = offset, l = 0; l < length; index++, l++) {
            hashValue += 31 * hashValue + ExtendedNumberUtils.hashCode(buf[index]);
        }

        return hashValue;
    }

    public static final int hashCode(char[] buf, int offset, int length) {
        int hashValue = 0;
        for (int index = offset, l = 0; l < length; index++, l++) {
            hashValue += 31 * hashValue + buf[index];
        }

        return hashValue;
    }

    public static final int hashCode(boolean[] buf, int offset, int length) {
        int hashValue = 0;
        for (int index = offset, l = 0; l < length; index++, l++) {
            if (buf[index]) {
                hashValue += 31 * hashValue + index;
            }
        }

        return hashValue;
    }

    public static final int hashCode(Object[] buf, int offset, int length) {
        int hashValue = 0;
        for (int index = offset, l = 0; l < length; index++, l++) {
            hashValue += 31 * hashCode(buf[index]);
        }

        return hashValue;
    }

    /**
     * A {@link Comparator} that compares 2 boolean arrays using {@link #findFirstNonMatchingIndex(boolean[], boolean[])}.
     * If the non-matching index is below the &quot;common&quot; length, then
     * the matching values in the arrays are compared. Otherwise, the shorter
     * array is deemed to come 1st
     */
    public static final Comparator<boolean[]> BOOLEAN_ARRAYS_COMPARATOR = new Comparator<boolean[]>() {
        @Override
        public int compare(boolean[] a1, boolean[] a2) {
            int l1 = length(a1), l2 = length(a2), cmnLen = Math.min(l1, l2);
            int index = findFirstNonMatchingIndex(a1, a2);
            if (index < 0) {
                return 0;
            }

            if (index < cmnLen) {
                return Boolean.valueOf(a1[index]).compareTo(Boolean.valueOf(a2[index]));
            } else {
                return ExtendedNumberUtils.signOf(l1 - l2);
            }
        }
    };

    /**
     * Scans 2 given byte arrays for the 1st non-matching value
     * @param a1 The 1st array (may be {@code null}/empty)
     * @param a2 The 2nd array (may be {@code null}/empty)
     * @return The index of the 1st non-matching value - negative if both
     * arrays of same length and have same values. <B>Note:</B> if arrays are
     * of different length but one is a &quot;prefix&quot; of the other
     * then returns the length of the shorter one as the non-matching index
     */
    public static final int findFirstNonMatchingIndex(boolean[] a1, boolean[] a2) {
        if (a1 == a2) { // take care of the obvious
            return (-1);
        }

        int l1 = length(a1), l2 = length(a2), cmpLen = Math.min(l1, l2);
        for (int index = 0; index < cmpLen; index++) {
            if (a1[index] != a2[index]) {
                return index;
            }
        }

        if (l1 != l2) {
            return cmpLen;
        } else {
            return (-1);
        }
    }

    /**
     * A {@link Comparator} that compares 2 byte arrays using {@link #findFirstNonMatchingIndex(byte[], byte[])}.
     * If the non-matching index is below the &quot;common&quot; length, then
     * the matching values in the arrays are compared. Otherwise, the shorter
     * array is deemed to come 1st
     */
    public static final Comparator<byte[]> BYTE_ARRAYS_COMPARATOR = new Comparator<byte[]>() {
        @Override
        public int compare(byte[] a1, byte[] a2) {
            int l1 = length(a1), l2 = length(a2), cmnLen = Math.min(l1, l2);
            int index = findFirstNonMatchingIndex(a1, a2);
            if (index < 0) {
                return 0;
            }

            if (index < cmnLen) {
                return ExtendedNumberUtils.signOf(a1[index] - a2[index]);
            } else {
                return ExtendedNumberUtils.signOf(l1 - l2);
            }
        }
    };

    /**
     * Scans 2 given byte arrays for the 1st non-matching value
     * @param a1 The 1st array (may be {@code null}/empty)
     * @param a2 The 2nd array (may be {@code null}/empty)
     * @return The index of the 1st non-matching value - negative if both
     * arrays of same length and have same values. <B>Note:</B> if arrays are
     * of different length but one is a &quot;prefix&quot; of the other
     * then returns the length of the shorter one as the non-matching index
     */
    public static final int findFirstNonMatchingIndex(byte[] a1, byte[] a2) {
        if (a1 == a2) { // take care of the obvious
            return (-1);
        }

        int l1 = length(a1), l2 = length(a2), cmpLen = Math.min(l1, l2);
        for (int index = 0; index < cmpLen; index++) {
            if (a1[index] != a2[index]) {
                return index;
            }
        }

        if (l1 != l2) {
            return cmpLen;
        } else {
            return (-1);
        }
    }

    /**
     * A {@link Comparator} that compares 2 {@code short} arrays using
     * {@link #findFirstNonMatchingIndex(short[], short[])}. If the
     * non-matching index is below the &quot;common&quot; length, then the
     * matching values in the arrays are compared. Otherwise, the shorter
     * array is deemed to come 1st
     */
    public static final Comparator<short[]> SHORT_ARRAYS_COMPARATOR = new Comparator<short[]>() {
        @Override
        public int compare(short[] a1, short[] a2) {
            int l1 = length(a1), l2 = length(a2), cmnLen = Math.min(l1, l2);
            int index = findFirstNonMatchingIndex(a1, a2);
            if (index < 0) {
                return 0;
            }

            if (index < cmnLen) {
                return ExtendedNumberUtils.signOf(a1[index] - a2[index]);
            } else {
                return ExtendedNumberUtils.signOf(l1 - l2);
            }
        }
    };

    /**
     * Scans 2 given {@code short} arrays for the 1st non-matching value
     * @param a1 The 1st array (may be {@code null}/empty)
     * @param a2 The 2nd array (may be {@code null}/empty)
     * @return The index of the 1st non-matching value - negative if both
     * arrays of same length and have same values. <B>Note:</B> if arrays are
     * of different length but one is a &quot;prefix&quot; of the other
     * then returns the length of the shorter one as the non-matching index
     */
    public static final int findFirstNonMatchingIndex(short[] a1, short[] a2) {
        if (a1 == a2) { // take care of the obvious
            return (-1);
        }

        int l1 = length(a1), l2 = length(a2), cmpLen = Math.min(l1, l2);
        for (int index = 0; index < cmpLen; index++) {
            if (a1[index] != a2[index]) {
                return index;
            }
        }

        if (l1 != l2) {
            return cmpLen;
        } else {
            return (-1);
        }
    }

    /**
     * A {@link Comparator} that compares 2 {@code int} arrays using
     * {@link #findFirstNonMatchingIndex(int[], int[])}. If the
     * non-matching index is below the &quot;common&quot; length, then the
     * matching values in the arrays are compared. Otherwise, the shorter
     * array is deemed to come 1st
     */
    public static final Comparator<int[]> INT_ARRAYS_COMPARATOR = new Comparator<int[]>() {
        @Override
        public int compare(int[] a1, int[] a2) {
            int l1 = length(a1), l2 = length(a2), cmnLen = Math.min(l1, l2);
            int index = findFirstNonMatchingIndex(a1, a2);
            if (index < 0) {
                return 0;
            }

            if (index < cmnLen) {
                return ExtendedNumberUtils.signOf(a1[index] - a2[index]);
            } else {
                return ExtendedNumberUtils.signOf(l1 - l2);
            }
        }
    };

    /**
     * Scans 2 given {@code int} arrays for the 1st non-matching value
     * @param a1 The 1st array (may be {@code null}/empty)
     * @param a2 The 2nd array (may be {@code null}/empty)
     * @return The index of the 1st non-matching value - negative if both
     * arrays of same length and have same values. <B>Note:</B> if arrays are
     * of different length but one is a &quot;prefix&quot; of the other
     * then returns the length of the shorter one as the non-matching index
     */
    public static final int findFirstNonMatchingIndex(int[] a1, int[] a2) {
        if (a1 == a2) { // take care of the obvious
            return (-1);
        }

        int l1 = length(a1), l2 = length(a2), cmpLen = Math.min(l1, l2);
        for (int index = 0; index < cmpLen; index++) {
            if (a1[index] != a2[index]) {
                return index;
            }
        }

        if (l1 != l2) {
            return cmpLen;
        } else {
            return (-1);
        }
    }

    /**
     * A {@link Comparator} that compares 2 {@code long} arrays using
     * {@link #findFirstNonMatchingIndex(long[], long[])}. If the
     * non-matching index is below the &quot;common&quot; length, then the
     * matching values in the arrays are compared. Otherwise, the shorter
     * array is deemed to come 1st
     */
    public static final Comparator<long[]> LONG_ARRAYS_COMPARATOR = new Comparator<long[]>() {
        @Override
        public int compare(long[] a1, long[] a2) {
            int l1 = length(a1), l2 = length(a2), cmnLen = Math.min(l1, l2);
            int index = findFirstNonMatchingIndex(a1, a2);
            if (index < 0) {
                return 0;
            }

            if (index < cmnLen) {
                return ExtendedNumberUtils.signOf(a1[index] - a2[index]);
            } else {
                return ExtendedNumberUtils.signOf(l1 - l2);
            }
        }
    };

    /**
     * Scans 2 given {@code long} arrays for the 1st non-matching value
     * @param a1 The 1st array (may be {@code null}/empty)
     * @param a2 The 2nd array (may be {@code null}/empty)
     * @return The index of the 1st non-matching value - negative if both
     * arrays of same length and have same values. <B>Note:</B> if arrays are
     * of different length but one is a &quot;prefix&quot; of the other
     * then returns the length of the shorter one as the non-matching index
     */
    public static final int findFirstNonMatchingIndex(long[] a1, long[] a2) {
        if (a1 == a2) { // take care of the obvious
            return (-1);
        }

        int l1 = length(a1), l2 = length(a2), cmpLen = Math.min(l1, l2);
        for (int index = 0; index < cmpLen; index++) {
            if (a1[index] != a2[index]) {
                return index;
            }
        }

        if (l1 != l2) {
            return cmpLen;
        } else {
            return (-1);
        }
    }

    /**
     * A {@link Comparator} that compares 2 {@code float} arrays using
     * {@link #findFirstNonMatchingIndex(float[], float[])}. If the
     * non-matching index is below the &quot;common&quot; length, then the
     * matching values in the arrays are compared. Otherwise, the shorter
     * array is deemed to come 1st
     */
    public static final Comparator<float[]> FLOAT_ARRAYS_COMPARATOR = new Comparator<float[]>() {
        @Override
        public int compare(float[] a1, float[] a2) {
            int l1 = length(a1), l2 = length(a2), cmnLen = Math.min(l1, l2);
            int index = findFirstNonMatchingIndex(a1, a2);
            if (index < 0) {
                return 0;
            }

            if (index < cmnLen) {
                return Float.compare(a1[index], a2[index]);
            } else {
                return ExtendedNumberUtils.signOf(l1 - l2);
            }
        }
    };

    /**
     * Scans 2 given {@code float} arrays for the 1st non-matching value.
     * <B>Note:</B> uses {@link ExtendedNumberUtils#compare(float, float)}
     * in order to handle {@code NaN}s correctly
     * @param a1 The 1st array (may be {@code null}/empty)
     * @param a2 The 2nd array (may be {@code null}/empty)
     * @return The index of the 1st non-matching value - negative if both
     * arrays of same length and have same values. <B>Note:</B> if arrays are
     * of different length but one is a &quot;prefix&quot; of the other
     * then returns the length of the shorter one as the non-matching index
     */
    public static final int findFirstNonMatchingIndex(float[] a1, float[] a2) {
        if (a1 == a2) { // take care of the obvious
            return (-1);
        }

        int l1 = length(a1), l2 = length(a2), cmpLen = Math.min(l1, l2);
        for (int index = 0; index < cmpLen; index++) {
            if (ExtendedNumberUtils.compare(a1[index], a2[index]) != 0) {
                return index;
            }
        }

        if (l1 != l2) {
            return cmpLen;
        } else {
            return (-1);
        }
    }

    /**
     * A {@link Comparator} that compares 2 {@code double} arrays using
     * {@link #findFirstNonMatchingIndex(double[], double[])}. If the
     * non-matching index is below the &quot;common&quot; length, then the
     * matching values in the arrays are compared. Otherwise, the shorter
     * array is deemed to come 1st
     */
    public static final Comparator<double[]> DOUBLE_ARRAYS_COMPARATOR = new Comparator<double[]>() {
        @Override
        public int compare(double[] a1, double[] a2) {
            int l1 = length(a1), l2 = length(a2), cmnLen = Math.min(l1, l2);
            int index = findFirstNonMatchingIndex(a1, a2);
            if (index < 0) {
                return 0;
            }

            if (index < cmnLen) {
                return Double.compare(a1[index], a2[index]);
            } else {
                return ExtendedNumberUtils.signOf(l1 - l2);
            }
        }
    };

    /**
     * Scans 2 given {@code double} arrays for the 1st non-matching value.
     * <B>Note:</B> uses {@link ExtendedNumberUtils#compare(double, double)}
     * in order to handle {@code NaN}s correctly
     * @param a1 The 1st array (may be {@code null}/empty)
     * @param a2 The 2nd array (may be {@code null}/empty)
     * @return The index of the 1st non-matching value - negative if both
     * arrays of same length and have same values. <B>Note:</B> if arrays are
     * of different length but one is a &quot;prefix&quot; of the other
     * then returns the length of the shorter one as the non-matching index
     */
    public static final int findFirstNonMatchingIndex(double[] a1, double[] a2) {
        if (a1 == a2) { // take care of the obvious
            return (-1);
        }

        int l1 = length(a1), l2 = length(a2), cmpLen = Math.min(l1, l2);
        for (int index = 0; index < cmpLen; index++) {
            if (ExtendedNumberUtils.compare(a1[index], a2[index]) != 0) {
                return index;
            }
        }

        if (l1 != l2) {
            return cmpLen;
        } else {
            return (-1);
        }
    }

    /**
     * <p>Finds the index of the given value in the array starting at the given index
     * and checking up to specified number of elements.</p>
     *
     * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
     *
     * <p>A negative startIndex is treated as zero. A startIndex larger than the array
     * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).</p>
     *
     * @param array  the array to search through for the object, may be {@code null}
     * @param valueToFind  the value to find
     * @param startIndex  the index to start searching at
     * @param len the number of elements to search from the start index
     * @return the index of the value within the array,
     *  {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
     *  or non-positive number of elements
     */
    public static final int indexOf(byte[] array, byte valueToFind, int startIndex, int len) {
        if (array == null) {
            return INDEX_NOT_FOUND;
        }

        for (int i = Math.max(startIndex, 0), l = 0; l < len; i++, l++) {
            if (valueToFind == array[i]) {
                return i;
            }
        }

        return INDEX_NOT_FOUND;
    }

    /**
     * <p>Finds the index of the given value in the array starting at the given index
     * and checking up to specified number of elements.</p>
     *
     * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
     *
     * <p>A negative startIndex is treated as zero. A startIndex larger than the array
     * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).</p>
     *
     * @param array  the array to search through for the object, may be {@code null}
     * @param valueToFind  the value to find
     * @param startIndex  the index to start searching at
     * @param len the number of elements to search from the start index
     * @return the index of the value within the array,
     *  {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
     *  or non-positive number of elements
     */
    public static final int indexOf(short[] array, short valueToFind, int startIndex, int len) {
        if (array == null) {
            return INDEX_NOT_FOUND;
        }

        for (int i = Math.max(startIndex, 0), l = 0; l < len; i++, l++) {
            if (valueToFind == array[i]) {
                return i;
            }
        }

        return INDEX_NOT_FOUND;
    }

    /**
     * <p>Finds the index of the given value in the array starting at the given index
     * and checking up to specified number of elements.</p>
     *
     * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
     *
     * <p>A negative startIndex is treated as zero. A startIndex larger than the array
     * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).</p>
     *
     * @param array  the array to search through for the object, may be {@code null}
     * @param valueToFind  the value to find
     * @param startIndex  the index to start searching at
     * @param len the number of elements to search from the start index
     * @return the index of the value within the array,
     *  {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
     *  or non-positive number of elements
     */
    public static final int indexOf(int[] array, int valueToFind, int startIndex, int len) {
        if (array == null) {
            return INDEX_NOT_FOUND;
        }

        for (int i = Math.max(startIndex, 0), l = 0; l < len; i++, l++) {
            if (valueToFind == array[i]) {
                return i;
            }
        }

        return INDEX_NOT_FOUND;
    }

    /**
     * <p>Finds the index of the given value in the array starting at the given index
     * and checking up to specified number of elements.</p>
     *
     * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
     *
     * <p>A negative startIndex is treated as zero. A startIndex larger than the array
     * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).</p>
     *
     * @param array  the array to search through for the object, may be {@code null}
     * @param valueToFind  the value to find
     * @param startIndex  the index to start searching at
     * @param len the number of elements to search from the start index
     * @return the index of the value within the array,
     *  {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
     *  or non-positive number of elements
     */
    public static final int indexOf(long[] array, long valueToFind, int startIndex, int len) {
        if (array == null) {
            return INDEX_NOT_FOUND;
        }

        for (int i = Math.max(startIndex, 0), l = 0; l < len; i++, l++) {
            if (valueToFind == array[i]) {
                return i;
            }
        }

        return INDEX_NOT_FOUND;
    }

    /**
     * <p>Finds the index of the given value in the array starting at the given index
     * and checking up to specified number of elements.</p>
     *
     * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
     *
     * <p>A negative startIndex is treated as zero. A startIndex larger than the array
     * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).</p>
     *
     * @param array  the array to search through for the object, may be {@code null}
     * @param valueToFind  the value to find
     * @param startIndex  the index to start searching at
     * @param len the number of elements to search from the start index
     * @return the index of the value within the array,
     *  {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
     *  or non-positive number of elements
     */
    public static final int indexOf(float[] array, float valueToFind, int startIndex, int len) {
        if (array == null) {
            return INDEX_NOT_FOUND;
        }

        for (int i = Math.max(startIndex, 0), l = 0; l < len; i++, l++) {
            if (ExtendedNumberUtils.compare(valueToFind, array[i]) == 0) {
                return i;
            }
        }

        return INDEX_NOT_FOUND;
    }

    /**
     * <p>Finds the index of the given value in the array starting at the given index
     * and checking up to specified number of elements.</p>
     *
     * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
     *
     * <p>A negative startIndex is treated as zero. A startIndex larger than the array
     * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).</p>
     *
     * @param array  the array to search through for the object, may be {@code null}
     * @param valueToFind  the value to find
     * @param startIndex  the index to start searching at
     * @param len the number of elements to search from the start index
     * @return the index of the value within the array,
     *  {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
     *  or non-positive number of elements
     */
    public static final int indexOf(double[] array, double valueToFind, int startIndex, int len) {
        if (array == null) {
            return INDEX_NOT_FOUND;
        }

        for (int i = Math.max(startIndex, 0), l = 0; l < len; i++, l++) {
            if (ExtendedNumberUtils.compare(valueToFind, array[i]) == 0) {
                return i;
            }
        }

        return INDEX_NOT_FOUND;
    }

    /**
     * <p>Finds the index of the given value in the array starting at the given index
     * and checking up to specified number of elements.</p>
     *
     * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
     *
     * <p>A negative startIndex is treated as zero. A startIndex larger than the array
     * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).</p>
     *
     * @param array  the array to search through for the object, may be {@code null}
     * @param valueToFind  the value to find
     * @param startIndex  the index to start searching at
     * @param len the number of elements to search from the start index
     * @return the index of the value within the array,
     *  {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
     *  or non-positive number of elements
     */
    public static final int indexOf(boolean[] array, boolean valueToFind, int startIndex, int len) {
        if (array == null) {
            return INDEX_NOT_FOUND;
        }

        for (int i = Math.max(startIndex, 0), l = 0; l < len; i++, l++) {
            if (valueToFind == array[i]) {
                return i;
            }
        }

        return INDEX_NOT_FOUND;
    }

    /**
     * <p>Finds the index of the given value in the array starting at the given index
     * and checking up to specified number of elements.</p>
     *
     * <p>This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.</p>
     *
     * <p>A negative startIndex is treated as zero. A startIndex larger than the array
     * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).</p>
     *
     * @param array  the array to search through for the object, may be {@code null}
     * @param valueToFind  the value to find
     * @param startIndex  the index to start searching at
     * @param len the number of elements to search from the start index
     * @return the index of the value within the array,
     *  {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
     *  or non-positive number of elements
     */
    public static final int indexOf(char[] array, char valueToFind, int startIndex, int len) {
        if (array == null) {
            return INDEX_NOT_FOUND;
        }

        for (int i = Math.max(startIndex, 0), l = 0; l < len; i++, l++) {
            if (valueToFind == array[i]) {
                return i;
            }
        }

        return INDEX_NOT_FOUND;
    }

    /**
     * @param buf1 First buffer data
     * @param offs1 First buffer offset
     * @param buf2 Second buffer data
     * @param offs2 Second buffer offset
     * @param length Number of elements to compare
     * @return The zero-based offset of the 1st different element - negative
     * if all compared elements are equal
     */
    public static final int diffOffset(byte[] buf1, int offs1, byte[] buf2, int offs2, int length) {
        for (int i1 = offs1, i2 = offs2, l = 0; l < length; i1++, i2++, l++) {
            byte b1 = buf1[i1], b2 = buf2[i2];
            if (b1 != b2) {
                return l;
            }
        }

        return INDEX_NOT_FOUND;
    }

    /**
     * @param buf1 First buffer data
     * @param offs1 First buffer offset
     * @param buf2 Second buffer data
     * @param offs2 Second buffer offset
     * @param length Number of elements to compare
     * @return The zero-based offset of the 1st different element - negative
     * if all compared elements are equal
     */
    public static final int diffOffset(short[] buf1, int offs1, short[] buf2, int offs2, int length) {
        for (int i1 = offs1, i2 = offs2, l = 0; l < length; i1++, i2++, l++) {
            short b1 = buf1[i1], b2 = buf2[i2];
            if (b1 != b2) {
                return l;
            }
        }

        return INDEX_NOT_FOUND;
    }

    /**
     * @param buf1 First buffer data
     * @param offs1 First buffer offset
     * @param buf2 Second buffer data
     * @param offs2 Second buffer offset
     * @param length Number of elements to compare
     * @return The zero-based offset of the 1st different element - negative
     * if all compared elements are equal
     */
    public static final int diffOffset(int[] buf1, int offs1, int[] buf2, int offs2, int length) {
        for (int i1 = offs1, i2 = offs2, l = 0; l < length; i1++, i2++, l++) {
            int b1 = buf1[i1], b2 = buf2[i2];
            if (b1 != b2) {
                return l;
            }
        }

        return INDEX_NOT_FOUND;
    }

    /**
     * @param buf1 First buffer data
     * @param offs1 First buffer offset
     * @param buf2 Second buffer data
     * @param offs2 Second buffer offset
     * @param length Number of elements to compare
     * @return The zero-based offset of the 1st different element - negative
     * if all compared elements are equal
     */
    public static final int diffOffset(long[] buf1, int offs1, long[] buf2, int offs2, int length) {
        for (int i1 = offs1, i2 = offs2, l = 0; l < length; i1++, i2++, l++) {
            long b1 = buf1[i1], b2 = buf2[i2];
            if (b1 != b2) {
                return l;
            }
        }

        return INDEX_NOT_FOUND;
    }

    /**
     * @param buf1 First buffer data
     * @param offs1 First buffer offset
     * @param buf2 Second buffer data
     * @param offs2 Second buffer offset
     * @param length Number of elements to compare
     * @return The zero-based offset of the 1st different element - negative
     * if all compared elements are equal
     */
    public static final int diffOffset(float[] buf1, int offs1, float[] buf2, int offs2, int length) {
        for (int i1 = offs1, i2 = offs2, l = 0; l < length; i1++, i2++, l++) {
            float b1 = buf1[i1], b2 = buf2[i2];
            if (Float.compare(b1, b2) != 0) {
                return l;
            }
        }

        return INDEX_NOT_FOUND;
    }

    /**
     * @param buf1 First buffer data
     * @param offs1 First buffer offset
     * @param buf2 Second buffer data
     * @param offs2 Second buffer offset
     * @param length Number of elements to compare
     * @return The zero-based offset of the 1st different element - negative
     * if all compared elements are equal
     */
    public static final int diffOffset(double[] buf1, int offs1, double[] buf2, int offs2, int length) {
        for (int i1 = offs1, i2 = offs2, l = 0; l < length; i1++, i2++, l++) {
            double b1 = buf1[i1], b2 = buf2[i2];
            if (Double.compare(b1, b2) != 0) {
                return l;
            }
        }

        return INDEX_NOT_FOUND;
    }

    /**
     * @param buf1 First buffer data
     * @param offs1 First buffer offset
     * @param buf2 Second buffer data
     * @param offs2 Second buffer offset
     * @param length Number of elements to compare
     * @return The zero-based offset of the 1st different element - negative
     * if all compared elements are equal
     */
    public static final int diffOffset(char[] buf1, int offs1, char[] buf2, int offs2, int length) {
        for (int i1 = offs1, i2 = offs2, l = 0; l < length; i1++, i2++, l++) {
            char b1 = buf1[i1], b2 = buf2[i2];
            if (b1 != b2) {
                return l;
            }
        }

        return INDEX_NOT_FOUND;
    }

    /**
     * @param buf1 First buffer data
     * @param offs1 First buffer offset
     * @param buf2 Second buffer data
     * @param offs2 Second buffer offset
     * @param length Number of elements to compare
     * @return The zero-based offset of the 1st different element - negative
     * if all compared elements are equal
     */
    public static final int diffOffset(boolean[] buf1, int offs1, boolean[] buf2, int offs2, int length) {
        for (int i1 = offs1, i2 = offs2, l = 0; l < length; i1++, i2++, l++) {
            boolean b1 = buf1[i1], b2 = buf2[i2];
            if (b1 != b2) {
                return l;
            }
        }

        return INDEX_NOT_FOUND;
    }

    /**
     * @param buf1 First array of objects
     * @param offs1 First array offset
     * @param buf2 Second array of objects
     * @param offs2 Second array offset
     * @param length Number of elements to compare
     * @return The zero-based offset of the 1st different element - negative
     * if all compared elements are equal
     * @see #diffOffset(Object[], int, Object[], int, Comparator, int)
     */
    public static final <T> int diffOffset(T[] buf1, int offs1, T[] buf2, int offs2, int length) {
        return diffOffset(buf1, offs1, buf2, offs2, null, length);
    }

    /**
     * @param buf1 First array of objects
     * @param offs1 First array offset
     * @param buf2 Second array of objects
     * @param offs2 Second array offset
     * @param length Number of elements to compare using {@link Comparable#compareTo(Object)}
     * @return The zero-based offset of the 1st different element - negative
     * if all compared elements are equal
     * @see #diffOffset(Object[], int, Object[], int, Comparator, int)
     */
    public static final <T extends Comparable<T>> int diffComparableOffset(T[] buf1, int offs1, T[] buf2, int offs2,
            int length) {
        return diffOffset(buf1, offs1, buf2, offs2, ExtendedComparatorUtils.<T>comparableComparator(), length);
    }

    /**
     * @param buf1 First array of objects
     * @param offs1 First array offset
     * @param buf2 Second array of objects
     * @param offs2 Second array offset
     * @param c A {@link Comparator} to use to check for equality - if
     * {@code null} then {@link ObjectUtils#equals(Object, Object)} is
     * used
     * @param length Number of elements to compare
     * @return The zero-based offset of the 1st different element - negative
     * if all compared elements are equal
     */
    public static final <T> int diffOffset(T[] buf1, int offs1, T[] buf2, int offs2, Comparator<? super T> c,
            int length) {
        for (int i1 = offs1, i2 = offs2, l = 0; l < length; i1++, i2++, l++) {
            T v1 = buf1[i1], v2 = buf2[i2];
            if (c == null) {
                if (!ObjectUtils.equals(v1, v2)) {
                    return l;
                }
            } else {
                if (c.compare(v1, v2) != 0) {
                    return l;
                }
            }
        }

        return INDEX_NOT_FOUND;
    }

    public static final List<String> toStringList(Object... objs) {
        if (length(objs) <= 0) {
            return Collections.emptyList();
        } else {
            return ExtendedStringUtils.toStringList(Arrays.asList(objs));
        }
    }

    public static final String toString(CharSequence separator, byte... data) {
        return toString(separator, data, 0, length(data));
    }

    public static final String toString(CharSequence separator, byte[] data, int offset, int length) {
        if (length <= 0) {
            return "";
        }

        try {
            return append(new StringBuilder(length * (3 + ExtendedCharSequenceUtils.getSafeLength(separator))),
                    separator, data, offset, length).toString();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static final <A extends Appendable> A append(A sb, CharSequence separator, byte... data)
            throws IOException {
        return append(sb, separator, data, 0, length(data));
    }

    public static final <A extends Appendable> A append(A sb, CharSequence separator, byte[] data, int offset,
            int length) throws IOException {
        if (length <= 0) {
            return sb;
        }

        for (int index = 0, pos = offset; index < length; index++, pos++) {
            if ((index > 0) && (ExtendedCharSequenceUtils.getSafeLength(separator) > 0)) {
                sb.append(separator);
            }

            sb.append(String.valueOf(data[pos]));
        }

        return sb;
    }
}