001package squidpony;
002
003import squidpony.squidmath.Coord;
004
005import java.util.Arrays;
006import java.util.Iterator;
007
008/**
009 * Static methods useful to be GWT-compatible, and also methods useful for filling gaps in Java's support for arrays.
010 * You can think of the purpose of this class as "GWT, and Compatibility". There's a replacement for a Math method that
011 * isn't available on GWT, a quick way to get the first element in an Iterable, copying, inserting, and filling methods
012 * for 2D arrays of primitive types (char, int, double, and boolean), and also a method to easily clone a Coord array.
013 * 
014 * @author smelC
015 * @author Tommy Ettinger
016 */
017public class GwtCompatibility {
018
019        /**
020     * Gets an exact copy of an array of Coord. References are shared, which should be the case for all usage of Coord
021     * since they are immutable and thus don't need multiple variants on a Coord from the pool.
022         * @param input an array of Coord to copy
023         * @return A clone of {@code input}.
024         */
025        public static Coord[] cloneCoords(Coord[] input) {
026                final Coord[] result = new Coord[input.length];
027        //System.arraycopy, despite being cumbersome, is the fastest way to copy an array on the JVM.
028        System.arraycopy(input, 0, result, 0, input.length);
029                return result;
030        }
031
032        /**
033     * A replacement for Math.IEEEremainder, just because Math.IEEEremainder isn't GWT-compatible.
034     * Gets the remainder of op / d, which can be negative if any parameter is negative.
035         * @param op the operand/dividend
036         * @param d the divisor
037         * @return The remainder of {@code op / d}, as a double; can be negative
038         */
039        /* smelC: because Math.IEEEremainder isn't GWT compatible */
040        public static double IEEEremainder(double op, double d) {
041                final double div = Math.round(op / d);
042                return op - (div * d);
043        }
044
045    /**
046     * Gets the first item in an Iterable of T, or null if it is empty. Meant for collections like LinkedHashSet, which
047     * can promise a stable first element but don't provide a way to access it. Not exactly a GWT compatibility method,
048     * but more of a Java standard library stand-in.
049     * @param collection an Iterable of T; if collection is null or empty this returns null
050     * @param <T> any object type
051     * @return the first element in collection, or null if it is empty or null itself
052     */
053        public static <T> T first(Iterable<T> collection)
054    {
055        if(collection == null)
056            return null;
057        Iterator<T> it = collection.iterator();
058        if(it.hasNext())
059            return it.next();
060        return null;
061    }
062
063        /**
064         * Gets a copy of the 2D char array, source, that has the same data but shares no references with source.
065         * @param source a 2D char array
066         * @return a copy of source, or null if source is null
067         */
068        public static char[][] copy2D(char[][] source)
069        {
070                if(source == null)
071                        return null;
072                if(source.length < 1)
073                        return new char[0][0];
074                char[][] target = new char[source.length][source[0].length];
075                for (int i = 0; i < source.length && i < target.length; i++) {
076                        System.arraycopy(source[i], 0, target[i], 0, source[i].length);
077                }
078                return target;
079        }
080
081    /**
082     * Gets a copy of the 2D double array, source, that has the same data but shares no references with source.
083     * @param source a 2D double array
084     * @return a copy of source, or null if source is null
085     */
086        public static double[][] copy2D(double[][] source)
087        {
088                if(source == null)
089                        return null;
090                if(source.length < 1)
091                        return new double[0][0];
092                double[][] target = new double[source.length][source[0].length];
093                for (int i = 0; i < source.length && i < target.length; i++) {
094                        System.arraycopy(source[i], 0, target[i], 0, source[i].length);
095                }
096                return target;
097        }
098
099    /**
100     * Gets a copy of the 2D int array, source, that has the same data but shares no references with source.
101     * @param source a 2D int array
102     * @return a copy of source, or null if source is null
103     */
104    public static int[][] copy2D(int[][] source)
105    {
106        if(source == null)
107            return null;
108        if(source.length < 1)
109            return new int[0][0];
110        int[][] target = new int[source.length][source[0].length];
111        for (int i = 0; i < source.length && i < target.length; i++) {
112            System.arraycopy(source[i], 0, target[i], 0, source[i].length);
113        }
114        return target;
115    }
116
117    /**
118     * Gets a copy of the 2D boolean array, source, that has the same data but shares no references with source.
119     * @param source a 2D boolean array
120     * @return a copy of source, or null if source is null
121     */
122    public static boolean[][] copy2D(boolean[][] source)
123    {
124        if(source == null)
125            return null;
126        if(source.length < 1)
127            return new boolean[0][0];
128        boolean[][] target = new boolean[source.length][source[0].length];
129        for (int i = 0; i < source.length && i < target.length; i++) {
130            System.arraycopy(source[i], 0, target[i], 0, source[i].length);
131        }
132        return target;
133    }
134
135    /**
136     * Inserts as much of source into target at the given x,y position as target can hold or source can supply.
137     * Modifies target in-place and also returns target for chaining.
138     * Used primarily to place a smaller array into a different position in a larger array, often freshly allocated.
139     * @param source a 2D char array that will be copied and inserted into target
140     * @param target a 2D char array that will be modified by receiving as much of source as it can hold
141     * @param x the x position in target to receive the items from the first cell in source
142     * @param y the y position in target to receive the items from the first cell in source
143     * @return a modified copy of target with source inserted into it at the given position
144     */
145    public static char[][] insert2D(char[][] source, char[][] target, int x, int y)
146    {
147        if(source == null || target == null)
148            return target;
149        if(source.length < 1 || source[0].length < 1)
150            return copy2D(target);
151        for (int i = 0; i < source.length && x + i < target.length; i++) {
152            System.arraycopy(source[i], 0, target[x + i], y, Math.min(source[i].length, target[x+i].length - y));
153        }
154        return target;
155    }
156    /**
157     * Inserts as much of source into target at the given x,y position as target can hold or source can supply.
158     * Modifies target in-place and also returns target for chaining.
159     * Used primarily to place a smaller array into a different position in a larger array, often freshly allocated.
160     * @param source a 2D double array that will be copied and inserted into target
161     * @param target a 2D double array that will be modified by receiving as much of source as it can hold
162     * @param x the x position in target to receive the items from the first cell in source
163     * @param y the y position in target to receive the items from the first cell in source
164     * @return a modified copy of target with source inserted into it at the given position
165     */
166    public static double[][] insert2D(double[][] source, double[][] target, int x, int y)
167    {
168        if(source == null || target == null)
169            return target;
170        if(source.length < 1 || source[0].length < 1)
171            return copy2D(target);
172        for (int i = 0; i < source.length && x + i < target.length; i++) {
173            System.arraycopy(source[i], 0, target[x + i], y, Math.min(source[i].length, target[x+i].length - y));
174        }
175        return target;
176    }
177    /**
178     * Inserts as much of source into target at the given x,y position as target can hold or source can supply.
179     * Modifies target in-place and also returns target for chaining.
180     * Used primarily to place a smaller array into a different position in a larger array, often freshly allocated.
181     * @param source a 2D int array that will be copied and inserted into target
182     * @param target a 2D int array that will be modified by receiving as much of source as it can hold
183     * @param x the x position in target to receive the items from the first cell in source
184     * @param y the y position in target to receive the items from the first cell in source
185     * @return a modified copy of target with source inserted into it at the given position
186     */
187    public static int[][] insert2D(int[][] source, int[][] target, int x, int y)
188    {
189        if(source == null || target == null)
190            return target;
191        if(source.length < 1 || source[0].length < 1)
192            return copy2D(target);
193        for (int i = 0; i < source.length && x + i < target.length; i++) {
194            System.arraycopy(source[i], 0, target[x + i], y, Math.min(source[i].length, target[x+i].length - y));
195        }
196        return target;
197    }
198    /**
199     * Inserts as much of source into target at the given x,y position as target can hold or source can supply.
200     * Modifies target in-place and also returns target for chaining.
201     * Used primarily to place a smaller array into a different position in a larger array, often freshly allocated.
202     * @param source a 2D boolean array that will be copied and inserted into target
203     * @param target a 2D boolean array that will be modified by receiving as much of source as it can hold
204     * @param x the x position in target to receive the items from the first cell in source
205     * @param y the y position in target to receive the items from the first cell in source
206     * @return a modified copy of target with source inserted into it at the given position
207     */
208    public static boolean[][] insert2D(boolean[][] source, boolean[][] target, int x, int y)
209    {
210        if(source == null || target == null)
211            return target;
212        if(source.length < 1 || source[0].length < 1)
213            return copy2D(target);
214        for (int i = 0; i < source.length && x + i < target.length; i++) {
215            System.arraycopy(source[i], 0, target[x + i], y, Math.min(source[i].length, target[x+i].length - y));
216        }
217        return target;
218    }
219
220    /**
221     * Creates a 2D array of the given width and height, filled with entirely with the value contents.
222     * @param contents the value to fill the array with
223     * @param width the desired width
224     * @param height the desired height
225     * @return a freshly allocated 2D array of the requested dimensions, filled entirely with contents
226     */
227    public static char[][] fill2D(char contents, int width, int height)
228    {
229        char[][] next = new char[width][height];
230        for (int x = 0; x < width; x++) {
231            Arrays.fill(next[x], contents);
232        }
233        return next;
234    }
235    /**
236     * Creates a 2D array of the given width and height, filled with entirely with the value contents.
237     * @param contents the value to fill the array with
238     * @param width the desired width
239     * @param height the desired height
240     * @return a freshly allocated 2D array of the requested dimensions, filled entirely with contents
241     */
242    public static double[][] fill2D(double contents, int width, int height)
243    {
244        double[][] next = new double[width][height];
245        for (int x = 0; x < width; x++) {
246            Arrays.fill(next[x], contents);
247        }
248        return next;
249    }
250    /**
251     * Creates a 2D array of the given width and height, filled with entirely with the value contents.
252     * @param contents the value to fill the array with
253     * @param width the desired width
254     * @param height the desired height
255     * @return a freshly allocated 2D array of the requested dimensions, filled entirely with contents
256     */
257    public static int[][] fill2D(int contents, int width, int height)
258    {
259        int[][] next = new int[width][height];
260        for (int x = 0; x < width; x++) {
261            Arrays.fill(next[x], contents);
262        }
263        return next;
264    }
265    /**
266     * Creates a 2D array of the given width and height, filled with entirely with the value contents.
267     * @param contents the value to fill the array with
268     * @param width the desired width
269     * @param height the desired height
270     * @return a freshly allocated 2D array of the requested dimensions, filled entirely with contents
271     */
272    public static boolean[][] fill2D(boolean contents, int width, int height)
273    {
274        boolean[][] next = new boolean[width][height];
275        if(contents) {
276            for (int x = 0; x < width; x++) {
277                Arrays.fill(next[x], true);
278            }
279        }
280        return next;
281    }
282}