001/*
002 * Trident - A Multithreaded Server Alternative
003 * Copyright 2014 The TridentSDK Team
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * 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 net.tridentsdk.util;
019
020import com.google.common.base.Function;
021import com.google.common.reflect.TypeToken;
022
023import javax.annotation.concurrent.ThreadSafe;
024import java.lang.reflect.Array;
025
026/**
027 * Tools for modifying elements of an array
028 *
029 * <p>Expect this to be very slow, uses LOAD of reflection to simplify array tasks at the cost of performance</p>
030 *
031 * @param <T> the type held by the array to be converted
032 */
033@ThreadSafe
034public final class ArrayTool<T> {
035    private final T[] array;
036    private final TypeToken<T> typeToken = new TypeToken<T>() {
037    };
038
039    private ArrayTool(T[] array) {
040        this.array = array;
041    }
042
043    /**
044     * Creates a new array tool
045     *
046     * @param array the underlying array
047     * @param <T>   the type of the array
048     * @return the new array tool
049     */
050    public static <T> ArrayTool<T> using(T[] array) {
051        return new ArrayTool<>(array);
052    }
053
054    /**
055     * Converts the underlying array to an array of the type specified
056     *
057     * @param c   the classtype for the new array
058     * @param <C> the array type
059     * @return the new array converted from the underlying array
060     * @throws java.lang.ClassCastException if the type of the underlying array cannot be cast to the new type
061     */
062    public <C> C[] convertTo(Class<C> c) {
063        C[] cs = (C[]) Array.newInstance(c, array.length);
064        for (int i = 0; i < array.length; i++) {
065            cs[i] = (C) array[i];
066        }
067
068        return cs;
069    }
070
071    /**
072     * Creates a deep copy of an array, assuming that its {@link Object#clone()} method returns a deep copy
073     *
074     * @return the deep copy of the underlying array
075     */
076    public T[] cloneArray(Function<T, T> cloner) {
077        T[] ts = (T[]) Array.newInstance(typeToken.getRawType(), array.length);
078        for (int i = 0; i < array.length; i++) {
079            ts[i] = cloner.apply(array[i]);
080        }
081
082        return ts;
083    }
084
085    /**
086     * Gets the array of this tool
087     *
088     * @return the array passed in during instantiation
089     */
090    public T[] underlyingArray() {
091        return this.array;
092    }
093}