001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache license, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the license for the specific language governing permissions and
015 * limitations under the license.
016 */
017
018package org.apache.logging.log4j.core.util;
019
020import java.lang.reflect.Array;
021
022/**
023 * Copied from Apache Commons Lang (including the {@code @since} tags.)
024 */
025public class ArrayUtils {
026
027    /**
028     * Checks if an array of Objects is empty or {@code null}.
029     *
030     * @param array  the array to test
031     * @return {@code true} if the array is empty or {@code null}
032     * @since 2.1
033     */
034    public static boolean isEmpty(final byte[] array) {
035        return getLength(array) == 0;
036    }
037    
038    /**
039     * <p>Returns the length of the specified array.
040     * This method can deal with {@code Object} arrays and with primitive arrays.</p>
041     *
042     * <p>If the input array is {@code null}, {@code 0} is returned.</p>
043     *
044     * <pre>
045     * ArrayUtils.getLength(null)            = 0
046     * ArrayUtils.getLength([])              = 0
047     * ArrayUtils.getLength([null])          = 1
048     * ArrayUtils.getLength([true, false])   = 2
049     * ArrayUtils.getLength([1, 2, 3])       = 3
050     * ArrayUtils.getLength(["a", "b", "c"]) = 3
051     * </pre>
052     *
053     * @param array  the array to retrieve the length from, may be null
054     * @return The length of the array, or {@code 0} if the array is {@code null}
055     * @throws IllegalArgumentException if the object argument is not an array.
056     * @since 2.1
057     */
058    public static int getLength(final Object array) {
059        if (array == null) {
060            return 0;
061        }
062        return Array.getLength(array);
063    }
064
065    /**
066     * <p>Removes the element at the specified position from the specified array.
067     * All subsequent elements are shifted to the left (subtracts one from
068     * their indices).</p>
069     *
070     * <p>This method returns a new array with the same elements of the input
071     * array except the element on the specified position. The component
072     * type of the returned array is always the same as that of the input
073     * array.</p>
074     *
075     * <p>If the input array is {@code null}, an IndexOutOfBoundsException
076     * will be thrown, because in that case no valid index can be specified.</p>
077     *
078     * @param array  the array to remove the element from, may not be {@code null}
079     * @param index  the position of the element to be removed
080     * @return A new array containing the existing elements except the element
081     *         at the specified position.
082     * @throws IndexOutOfBoundsException if the index is out of range
083     * (index &lt; 0 || index &gt;= array.length), or if the array is {@code null}.
084     * @since 2.1
085     */
086    private static Object remove(final Object array, final int index) {
087        final int length = getLength(array);
088        if (index < 0 || index >= length) {
089            throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + length);
090        }
091
092        final Object result = Array.newInstance(array.getClass().getComponentType(), length - 1);
093        System.arraycopy(array, 0, result, 0, index);
094        if (index < length - 1) {
095            System.arraycopy(array, index + 1, result, index, length - index - 1);
096        }
097
098        return result;
099    }
100
101    /**
102     * <p>Removes the element at the specified position from the specified array.
103     * All subsequent elements are shifted to the left (subtracts one from
104     * their indices).</p>
105     *
106     * <p>This method returns a new array with the same elements of the input
107     * array except the element on the specified position. The component
108     * type of the returned array is always the same as that of the input
109     * array.</p>
110     *
111     * <p>If the input array is {@code null}, an IndexOutOfBoundsException
112     * will be thrown, because in that case no valid index can be specified.</p>
113     *
114     * <pre>
115     * ArrayUtils.remove(["a"], 0)           = []
116     * ArrayUtils.remove(["a", "b"], 0)      = ["b"]
117     * ArrayUtils.remove(["a", "b"], 1)      = ["a"]
118     * ArrayUtils.remove(["a", "b", "c"], 1) = ["a", "c"]
119     * </pre>
120     *
121     * @param <T> the component type of the array
122     * @param array  the array to remove the element from, may not be {@code null}
123     * @param index  the position of the element to be removed
124     * @return A new array containing the existing elements except the element
125     *         at the specified position.
126     * @throws IndexOutOfBoundsException if the index is out of range
127     * (index &lt; 0 || index &gt;= array.length), or if the array is {@code null}.
128     * @since 2.1
129     */
130    @SuppressWarnings("unchecked") // remove() always creates an array of the same type as its input
131    public static <T> T[] remove(final T[] array, final int index) {
132        return (T[]) remove((Object) array, index);
133    }
134
135}