001package squidpony;
002
003import squidpony.squidmath.*;
004
005import java.util.*;
006
007/**
008 * Utility methods for more easily constructing data structures, particularly those in Java's standard library.
009 * All static methods and inner classes; meant to be imported with {@code import static squidpony.Maker.*}.
010 * Created by Tommy Ettinger on 5/19/2016.
011 */
012public class Maker {
013
014    /**
015     * Stores any information relating to non-fatal issues, such as caught and handled Exceptions that still change the
016     * behavior of methods. Typically shouldn't be cleared while debugging, since it could be useful later on, and
017     * hopefully won't need to be written to in a release build.
018     */
019    public static final StringBuilder issueLog = new StringBuilder(1024);
020    /**
021     * Makes a LinkedHashMap (LHM) with key and value types inferred from the types of k0 and v0, and considers all
022     * parameters key-value pairs, casting the Objects at positions 0, 2, 4... etc. to K and the objects at positions
023     * 1, 3, 5... etc. to V. If rest has an odd-number length, then it discards the last item. If any pair of items in
024     * rest cannot be cast to the correct type of K or V, then this inserts nothing for that pair and logs information
025     * on the problematic pair to the static Maker.issueLog field.
026     * @param k0 the first key; used to infer the types of other keys if generic parameters aren't specified.
027     * @param v0 the first value; used to infer the types of other values if generic parameters aren't specified.
028     * @param rest an array or vararg of keys and values in pairs; should contain alternating K, V, K, V... elements
029     * @param <K> the type of keys in the returned LinkedHashMap; if not specified, will be inferred from k0
030     * @param <V> the type of values in the returned LinkedHashMap; if not specified, will be inferred from v0
031     * @return a freshly-made LinkedHashMap with K keys and V values, using k0, v0, and the contents of rest to fill it
032     */
033    @SuppressWarnings("unchecked")
034    public static <K, V> LinkedHashMap<K, V> makeLHM(K k0, V v0, Object... rest)
035    {
036        if(rest == null || rest.length == 0)
037        {
038            LinkedHashMap<K, V> lhm = new LinkedHashMap<>(2);
039            lhm.put(k0, v0);
040            return lhm;
041        }
042        LinkedHashMap<K, V> lhm = new LinkedHashMap<>(1 + (rest.length / 2));
043        lhm.put(k0, v0);
044
045        for (int i = 0; i < rest.length - 1; i+=2) {
046            try {
047                lhm.put((K) rest[i], (V) rest[i + 1]);
048            }catch (ClassCastException cce) {
049                issueLog.append("makeLHM call had a casting problem with pair at rest[")
050                        .append(i)
051                        .append("] and/or rest[")
052                        .append(i + 1)
053                        .append("], with contents: ")
054                        .append(rest[i])
055                        .append(", ")
056                        .append(rest[i + 1])
057                        .append(".\n\nException messages:\n")
058                        .append(cce);
059                String msg = cce.getMessage();
060                if (msg != null) {
061                    issueLog.append('\n').append(msg);
062                }
063                issueLog.append('\n');
064            }
065        }
066        return lhm;
067    }
068
069    /**
070     * Makes an empty LinkedHashMap (LHM); needs key and value types to be specified in order to work. For an empty
071     * LinkedHashMap with String keys and Coord values, you could use {@code Maker.<String, Coord>makeLHM();}. Using
072     * the new keyword is probably just as easy in this case; this method is provided for completeness relative to
073     * makeLHM() with 2 or more parameters.
074     * @param <K> the type of keys in the returned LinkedHashMap; cannot be inferred and must be specified
075     * @param <V> the type of values in the returned LinkedHashMap; cannot be inferred and must be specified
076     * @return an empty LinkedHashMap with the given key and value types.
077     */
078    public static <K, V> LinkedHashMap<K, V> makeLHM()
079    {
080        return new LinkedHashMap<>();
081    }
082    /**
083     * Makes a HashMap (HM) with key and value types inferred from the types of k0 and v0, and considers all
084     * parameters key-value pairs, casting the Objects at positions 0, 2, 4... etc. to K and the objects at positions
085     * 1, 3, 5... etc. to V. If rest has an odd-number length, then it discards the last item. If any pair of items in
086     * rest cannot be cast to the correct type of K or V, then this inserts nothing for that pair and logs information
087     * on the problematic pair to the static Maker.issueLog field.
088     * @param k0 the first key; used to infer the types of other keys if generic parameters aren't specified.
089     * @param v0 the first value; used to infer the types of other values if generic parameters aren't specified.
090     * @param rest an array or vararg of keys and values in pairs; should contain alternating K, V, K, V... elements
091     * @param <K> the type of keys in the returned HashMap; if not specified, will be inferred from k0
092     * @param <V> the type of values in the returned HashMap; if not specified, will be inferred from v0
093     * @return a freshly-made HashMap with K keys and V values, using k0, v0, and the contents of rest to fill it
094     */
095    @SuppressWarnings("unchecked")
096    public static <K, V> HashMap<K, V> makeHM(K k0, V v0, Object... rest)
097    {
098        if(rest == null || rest.length == 0)
099        {
100            HashMap<K, V> hm = new HashMap<>(2);
101            hm.put(k0, v0);
102            return hm;
103        }
104        HashMap<K, V> hm = new HashMap<>(1 + (rest.length / 2));
105        hm.put(k0, v0);
106
107        for (int i = 0; i < rest.length - 1; i+=2) {
108            try {
109                hm.put((K) rest[i], (V) rest[i + 1]);
110            }catch (ClassCastException cce) {
111                issueLog.append("makeHM call had a casting problem with pair at rest[")
112                        .append(i).append("] and/or rest[")
113                        .append(i + 1).append("], with contents: ")
114                        .append(rest[i]).append(", ")
115                        .append(rest[i + 1]).append(".\n\nException messages:\n")
116                        .append(cce);
117                String msg = cce.getMessage();
118                if (msg != null) {
119                    issueLog.append('\n').append(msg);
120                }
121                issueLog.append('\n');
122            }
123        }
124        return hm;
125    }
126
127    /**
128     * Makes an empty HashMap (HM); needs key and value types to be specified in order to work. For an empty
129     * HashMap with String keys and Coord values, you could use {@code Maker.<String, Coord>makeHM();}. Using
130     * the new keyword is probably just as easy in this case; this method is provided for completeness relative to
131     * makeHM() with 2 or more parameters.
132     * @param <K> the type of keys in the returned HashMap; cannot be inferred and must be specified
133     * @param <V> the type of values in the returned HashMap; cannot be inferred and must be specified
134     * @return an empty HashMap with the given key and value types.
135     */
136    public static <K, V> HashMap<K, V> makeHM()
137    {
138        return new HashMap<>();
139    }
140
141    /**
142     * Makes an ArrayList of T given an array or vararg of T elements.
143     * @param elements an array or vararg of T
144     * @param <T> just about any non-primitive type
145     * @return a newly-allocated ArrayList containing all of elements, in order
146     */
147    @SuppressWarnings("unchecked")
148    public static <T> ArrayList<T> makeList(T... elements) {
149        if(elements == null) return null;
150        ArrayList<T> list = new ArrayList<>(elements.length);
151        Collections.addAll(list, elements);
152        return list;
153    }
154
155    /**
156     * Makes an ArrayList of T given a single T element; avoids creating an array for varargs as
157     * {@link #makeList(Object[])} would do, but only allows one item.
158     * @param element an array or vararg of T
159     * @param <T> just about any non-primitive, non-array type (arrays would cause confusion with the vararg method)
160     * @return a newly-allocated ArrayList containing only element
161     */
162    public static <T> ArrayList<T> makeList(T element) {
163        ArrayList<T> list = new ArrayList<>(1);
164        list.add(element);
165        return list;
166    }
167
168    /**
169     * Makes a LinkedHashSet (LHS) of T given an array or vararg of T elements. Duplicate items in elements will have
170     * all but one item discarded, using the later item in elements.
171     * @param elements an array or vararg of T
172     * @param <T> just about any non-primitive type
173     * @return a newly-allocated LinkedHashSet containing all of the non-duplicate items in elements, in order
174     */
175    @SuppressWarnings("unchecked")
176    public static <T> LinkedHashSet<T> makeLHS(T... elements) {
177        if(elements == null) return null;
178        LinkedHashSet<T> set = new LinkedHashSet<>(elements.length);
179        Collections.addAll(set, elements);
180        return set;
181    }
182
183    /**
184     * Makes a LinkedHashSet (LHS) of T given a single T element.
185     * @param element a single T
186     * @param <T> just about any non-primitive type
187     * @return a newly-allocated LinkedHashSet containing only {@code element}
188     */
189    public static <T> LinkedHashSet<T> makeLHS(T element) {
190        LinkedHashSet<T> set = new LinkedHashSet<T>(1);
191        set.add(element);
192        return set;
193    }
194
195    /**
196     * Makes a HashSet (HS) of T given an array or vararg of T elements. Duplicate items in elements will have
197     * all but one item discarded, using the later item in elements.
198     * @param elements an array or vararg of T
199     * @param <T> just about any non-primitive type
200     * @return a newly-allocated HashSet containing all of the non-duplicate items in elements, in order
201     */
202    @SuppressWarnings("unchecked")
203    public static <T> HashSet<T> makeHS(T... elements) {
204        if(elements == null) return null;
205        HashSet<T> set = new HashSet<>(elements.length);
206        Collections.addAll(set, elements);
207        return set;
208    }
209
210    /**
211     * Makes a HashSet (HS) of T given a single T element.
212     * @param element a single T
213     * @param <T> just about any non-primitive type
214     * @return a newly-allocated HashSet containing only {@code element}
215     */
216    public static <T> HashSet<T> makeHS(T element) {
217        HashSet<T> set = new HashSet<T>(1);
218        set.add(element);
219        return set;
220    }
221
222    /**
223     * Makes an OrderedMap (OM) with key and value types inferred from the types of k0 and v0, and considers all
224     * parameters key-value pairs, casting the Objects at positions 0, 2, 4... etc. to K and the objects at positions
225     * 1, 3, 5... etc. to V. If rest has an odd-number length, then it discards the last item. If any pair of items in
226     * rest cannot be cast to the correct type of K or V, then this inserts nothing for that pair and logs information
227     * on the problematic pair to the static Maker.issueLog field.
228     * @param k0 the first key; used to infer the types of other keys if generic parameters aren't specified.
229     * @param v0 the first value; used to infer the types of other values if generic parameters aren't specified.
230     * @param rest an array or vararg of keys and values in pairs; should contain alternating K, V, K, V... elements
231     * @param <K> the type of keys in the returned OrderedMap; if not specified, will be inferred from k0
232     * @param <V> the type of values in the returned OrderedMap; if not specified, will be inferred from v0
233     * @return a freshly-made OrderedMap with K keys and V values, using k0, v0, and the contents of rest to fill it
234     */
235    public static <K, V> OrderedMap<K, V> makeOM(K k0, V v0, Object... rest)
236    {
237        return makeOM(0.625f, k0, v0, rest);
238    }
239    /**
240     * Makes an OrderedMap (OM) with the given load factor (which should be between 0.1 and 0.9), key and value types
241     * inferred from the types of k0 and v0, and considers all remaining parameters key-value pairs, casting the Objects
242     * at positions 0, 2, 4... etc. to K and the objects at positions 1, 3, 5... etc. to V. If rest has an odd-number
243     * length, then it discards the last item. If any pair of items in rest cannot be cast to the correct type of K or
244     * V, then this inserts nothing for that pair and logs information on the problematic pair to the static
245     * Maker.issueLog field.
246     * @param factor the load factor; should be between 0.1 and 0.9, and 0.75f is a safe choice
247     * @param k0 the first key; used to infer the types of other keys if generic parameters aren't specified.
248     * @param v0 the first value; used to infer the types of other values if generic parameters aren't specified.
249     * @param rest an array or vararg of keys and values in pairs; should contain alternating K, V, K, V... elements
250     * @param <K> the type of keys in the returned OrderedMap; if not specified, will be inferred from k0
251     * @param <V> the type of values in the returned OrderedMap; if not specified, will be inferred from v0
252     * @return a freshly-made OrderedMap with K keys and V values, using k0, v0, and the contents of rest to fill it
253     */
254    @SuppressWarnings("unchecked")
255    public static <K, V> OrderedMap<K, V> makeOM(float factor, K k0, V v0, Object... rest)
256    {
257        if(rest == null || rest.length == 0)
258        {
259            OrderedMap<K, V> om = new OrderedMap<>(2, factor);
260            om.put(k0, v0);
261            return om;
262        }
263        OrderedMap<K, V> om = new OrderedMap<>(1 + (rest.length / 2), factor);
264        om.put(k0, v0);
265
266        for (int i = 0; i < rest.length - 1; i+=2) {
267            try {
268                om.put((K) rest[i], (V) rest[i + 1]);
269            }catch (ClassCastException cce) {
270                issueLog.append("makeOM call had a casting problem with pair at rest[")
271                          .append(i)
272                          .append("] and/or rest[")
273                          .append(i + 1)
274                          .append("], with contents: ")
275                          .append(rest[i])
276                          .append(", ")
277                          .append(rest[i+1])
278                          .append(".\n\nException messages:\n")
279                          .append(cce);
280                String msg = cce.getMessage();
281                if (msg != null) {
282                    issueLog.append('\n').append(msg);
283                }
284                issueLog.append('\n');
285            }
286        }
287        return om;
288    }
289
290    /**
291     * Makes an empty OrderedMap (OM); needs key and value types to be specified in order to work. For an empty
292     * OrderedMap with String keys and Coord values, you could use {@code Maker.<String, Coord>makeOM()}. Using
293     * the new keyword is probably just as easy in this case; this method is provided for completeness relative to
294     * makeOM() with 2 or more parameters.
295     * @param <K> the type of keys in the returned OrderedMap; cannot be inferred and must be specified
296     * @param <V> the type of values in the returned OrderedMap; cannot be inferred and must be specified
297     * @return an empty OrderedMap with the given key and value types.
298     */
299    public static <K, V> OrderedMap<K, V> makeOM()
300    {
301        return new OrderedMap<>();
302    }
303
304    /**
305     * Makes an OrderedSet (OS) of T given an array or vararg of T elements. Duplicate items in elements will have
306     * all but one item discarded, using the later item in elements.
307     * @param elements an array or vararg of T
308     * @param <T> just about any non-primitive type
309     * @return a newly-allocated OrderedSet containing all of the non-duplicate items in elements, in order
310     */
311    @SuppressWarnings("unchecked")
312    public static <T> OrderedSet<T> makeOS(T... elements) {
313        if(elements == null) return null;
314        return new OrderedSet<>(elements);
315    }
316
317    /**
318     * Makes an OrderedSet of T given a single T element; avoids creating an array for varargs as
319     * {@link #makeOS(Object[])} would do, but only allows one item.
320     * @param element an array or vararg of T
321     * @param <T> just about any non-primitive, non-array type (arrays would cause confusion with the vararg method)
322     * @return a newly-allocated OrderedSet containing only element
323     */
324    public static <T> OrderedSet<T> makeOS(T element) {
325        OrderedSet<T> set = new OrderedSet<>(1);
326        set.add(element);
327        return set;
328    }
329    
330    /**
331     * Makes an UnorderedSet (UOS) of T given an array or vararg of T elements. Duplicate items in elements will have
332     * all but one item discarded, using the later item in elements; order will not be kept.
333     * @param elements an array or vararg of T
334     * @param <T> just about any non-primitive type
335     * @return a newly-allocated UnorderedSet containing all of the non-duplicate items in elements, in order
336     */
337    @SuppressWarnings("unchecked")
338    public static <T> UnorderedSet<T> makeUOS(T... elements) {
339        if(elements == null) return null;
340        return new UnorderedSet<>(elements);
341    }
342
343    /**
344     * Makes an UnorderedSet of T given a single T element; avoids creating an array for varargs as
345     * {@link #makeOS(Object[])} would do, but only allows one item.
346     * @param element an array or vararg of T
347     * @param <T> just about any non-primitive, non-array type (arrays would cause confusion with the vararg method)
348     * @return a newly-allocated UnorderedSet containing only element
349     */
350    public static <T> UnorderedSet<T> makeUOS(T element) {
351        UnorderedSet<T> set = new UnorderedSet<>(1);
352        set.add(element);
353        return set;
354    }
355
356    /**
357     * Makes a EnumOrderedSet (OS) of the enum type T given at least one T element followed by an array or vararg of any
358     * number of additional T elements. Duplicate items in elements will have all but one item discarded, using the
359     * later item in elements. The order given here will be kept in the result, like in OrderedSet, and
360     * you can use {@link EnumOrderedSet#getAt(int)} to get a T value at a given index, like you would with a List.
361     * @param initial the first item to insert into the EnumOrderedSet; if initial is null, the method returns null
362     * @param elements an array or vararg of T; allowed to be empty
363     * @param <T> an enum type
364     * @return a newly-allocated OrderedSet containing all of the non-duplicate items in elements, in order
365     */
366    @SuppressWarnings("unchecked")
367    public static <T extends Enum<?>> EnumOrderedSet<T> makeEOS(T initial, T... elements)
368    {
369        if(initial == null) return null;
370        EnumOrderedSet<T> eos = new EnumOrderedSet<>(initial);
371        eos.add(initial);
372        if(elements != null)
373            eos.addAll(elements);
374        return eos;
375    }
376
377    /**
378     * Makes an empty EnumOrderedSet (EOS); needs item type to be specified in order to work. For an empty
379     * EnumOrderedSet with Radius items, you could use {@code Maker.<Radius>makeEOS()}. Using the new keyword is
380     * probably just as easy in this case; this method is provided for completeness relative to makeEOS() with 1 or more
381     * parameters.
382     * @param <T> the type of Enum keys in the returned EnumOrderedSet; cannot be inferred and must be specified
383     * @return an empty EnumOrderedSet with the given item type
384     */
385    public static <T extends Enum<T>> EnumOrderedSet<T> makeEOS() { return new EnumOrderedSet<>(); }
386
387    /**
388     * Makes a Arrangement (Arrange) of T given an array or vararg of T elements. Duplicate items in elements will have
389     * all but one item discarded, using the later item in elements. As is always the case with Arrangement, each item
390     * will be mapped bi-directionally to its index in the iteration order, and an item can be retrieved with
391     * {@link Arrangement#keyAt(int)} if you only know its index, or the int index for an item can be retrieved with
392     * {@link Arrangement#getInt(Object)} if you only have an item.
393     * @param elements an array or vararg of T
394     * @param <T> just about any non-primitive type
395     * @return a newly-allocated Arrangement containing all of the non-duplicate items in elements, in order
396     */
397    @SuppressWarnings("unchecked")
398    public static <T> Arrangement<T> makeArrange(T... elements) {
399        if(elements == null) return null;
400        return new Arrangement<>(elements);
401    }
402    /**
403     * Makes a K2 (two-key set/bimap) with A and B key types inferred from the types of a0 and b0, and considers all
404     * parameters A-B pairs, casting the Objects at positions 0, 2, 4... etc. to A and the objects at positions
405     * 1, 3, 5... etc. to B. If rest has an odd-number length, then it discards the last item. If any pair of items in
406     * rest cannot be cast to the correct type of A or B, then this inserts nothing for that pair and logs information
407     * on the problematic pair to the static Maker.issueLog field.
408     * @param a0 the first A key; used to infer the types of other keys if generic parameters aren't specified.
409     * @param b0 the first B key; used to infer the types of other values if generic parameters aren't specified.
410     * @param rest an array or vararg of keys and values in pairs; should contain alternating A, B, A, B... elements
411     * @param <A> a type of keys in the returned K2; if not specified, will be inferred from a0
412     * @param <B> a type of keys in the returned K2; if not specified, will be inferred from b0
413     * @return a freshly-made K2 with A and B keys, using a0, b0, and the contents of rest to fill it
414     */
415    public static <A, B> K2<A, B> makeK2(A a0, B b0, Object... rest)
416    {
417        return makeK2(0.625f, a0, b0, rest);
418    }
419    /**
420     * Makes a K2 (two-key set/bimap) with the given load factor (which should be between 0.1 and 0.9), A and B key
421     * types inferred from the types of a0 and b0, and considers all parameters A-B pairs, casting the Objects at
422     * positions 0, 2, 4... etc. to A and the objects at positions 1, 3, 5... etc. to B. If rest has an odd-number
423     * length, then it discards the last item. If any pair of items in rest cannot be cast to the correct type of A or
424     * B, then this inserts nothing for that pair and logs information on the problematic pair to the static
425     * Maker.issueLog field.
426     * @param factor the load factor; should be between 0.1 and 0.9, and 0.75f is a safe choice
427     * @param a0 the first A key; used to infer the types of other keys if generic parameters aren't specified.
428     * @param b0 the first B key; used to infer the types of other values if generic parameters aren't specified.
429     * @param rest an array or vararg of keys and values in pairs; should contain alternating A, B, A, B... elements
430     * @param <A> a type of keys in the returned K2; if not specified, will be inferred from a0
431     * @param <B> a type of keys in the returned K2; if not specified, will be inferred from b0
432     * @return a freshly-made K2 with A and B keys, using a0, b0, and the contents of rest to fill it
433     */
434    @SuppressWarnings("unchecked")
435    public static <A, B> K2<A, B> makeK2(float factor, A a0, B b0, Object... rest)
436    {
437        if(rest == null || rest.length == 0)
438        {
439            K2<A, B> k2 = new K2<>(2, factor);
440            k2.put(a0, b0);
441            return k2;
442        }
443        K2<A, B> k2 = new K2<>(1 + (rest.length >> 1), factor);
444        k2.put(a0, b0);
445
446        for (int i = 0; i < rest.length - 1; i+=2) {
447            try {
448                k2.put((A) rest[i], (B) rest[i + 1]);
449            }catch (ClassCastException cce) {
450                issueLog.append("makeK2 call had a casting problem with pair at rest[")
451                          .append(i)
452                          .append("] and/or rest[")
453                          .append(i + 1)
454                          .append("], with contents: ")
455                          .append(rest[i])
456                          .append(", ")
457                          .append(rest[i+1])
458                          .append(".\n\nException messages:\n")
459                          .append(cce);
460                String msg = cce.getMessage();
461                if (msg != null) {
462                    issueLog.append('\n').append(msg);
463                }
464                issueLog.append('\n');
465            }
466        }
467        return k2;
468    }
469
470    /**
471     * Makes an empty K2 (two-key set/bimap); needs A and B key types to be specified in order to work. For an empty
472     * K2 with String A keys Coord B keys, you could use {@code Maker.<String, Coord>makeK2();}. Using
473     * the new keyword is probably just as easy in this case; this method is provided for completeness relative to
474     * makeK2() with 2 or more parameters.
475     * @param <A> the type of "A" keys in the returned K2; cannot be inferred and must be specified
476     * @param <B> the type of "B" keys in the returned K2; cannot be inferred and must be specified
477     * @return an empty K2 with the given key and value types.
478     */
479    public static <A, B> K2<A, B> makeK2()
480    {
481        return new K2<>();
482    }
483    /**
484     * Makes an EnumOrderedMap (EOM) with key and value types inferred from the types of k0 and v0, and considers all
485     * remaining parameters key-value pairs, casting the Objects at positions 0, 2, 4... etc. to K and the objects at
486     * positions 1, 3, 5... etc. to V. If rest has an odd-number length, then it discards the last item. If any pair of
487     * items in rest cannot be cast to the correct type of K or V, then this inserts nothing for that pair and logs
488     * information on the problematic pair to the static Maker.issueLog field. The order given here will be kept in the
489     * result, unlike in the JDK's EnumMap class, and you can use {@link EnumOrderedMap#keyAt(int)} or
490     * {@link EnumOrderedMap#getAt(int)} to get a key or value at a given index, like you would with a List.
491     *
492     * @param k0 the first key, which must be an Enum; used to infer the types of other keys if generic parameters aren't specified.
493     * @param v0 the first value; used to infer the types of other values if generic parameters aren't specified.
494     * @param rest an array or vararg of keys and values in pairs; should contain alternating K, V, K, V... elements
495     * @param <K> the type of Enum keys in the returned EnumOrderedMap; if not specified, will be inferred from k0
496     * @param <V> the type of values in the returned EnumOrderedMap; if not specified, will be inferred from v0
497     * @return a freshly-made EnumOrderedMap with K keys and V values, using k0, v0, and the contents of rest to fill it
498     */
499    @SuppressWarnings("unchecked")
500    public static <K extends Enum<?>, V> EnumOrderedMap<K, V> makeEOM(K k0, V v0, Object... rest)
501    {
502        if(rest == null || rest.length == 0)
503        {
504            EnumOrderedMap<K, V> eom = new EnumOrderedMap<>();
505            eom.put(k0, v0);
506            return eom;
507        }
508        EnumOrderedMap<K, V> eom = new EnumOrderedMap<>(k0);
509        eom.put(k0, v0);
510
511        for (int i = 0; i < rest.length - 1; i+=2) {
512            try {
513                eom.put((K) rest[i], (V) rest[i + 1]);
514            }catch (ClassCastException cce) {
515                issueLog.append("makeEOM call had a casting problem with pair at rest[")
516                          .append(i)
517                          .append("] and/or rest[")
518                          .append(i + 1)
519                          .append("], with contents: ")
520                          .append(rest[i])
521                          .append(", ")
522                          .append(rest[i+1])
523                          .append(".\n\nException messages:\n")
524                          .append(cce);
525                String msg = cce.getMessage();
526                if (msg != null) {
527                    issueLog.append('\n').append(msg);
528                }
529                issueLog.append('\n');
530            }
531        }
532        return eom;
533    }
534
535    /**
536     * Makes an empty EnumOrderedMap (EOM); needs key and value types to be specified in order to work. For an empty
537     * EnumOrderedMap with Radius keys and Coord values, you could use {@code Maker.<Radius, Coord>makeEOM()}. Using
538     * the new keyword is probably just as easy in this case; this method is provided for completeness relative to
539     * makeEOM() with 2 or more parameters.
540     * @param <K> the type of Enum keys in the returned EnumOrderedMap; cannot be inferred and must be specified
541     * @param <V> the type of values in the returned EnumOrderedMap; cannot be inferred and must be specified
542     * @return an empty EnumOrderedMap with the given key and value types.
543     */
544    public static <K extends Enum<K>, V> EnumOrderedMap<K, V> makeEOM() { return new EnumOrderedMap<>(); }
545
546}