001package squidpony.squidmath;
002
003import squidpony.ArrayTools;
004
005import java.util.ArrayList;
006import java.util.Collection;
007import java.util.Iterator;
008import java.util.SortedSet;
009
010/**
011 * An ordered bidirectional map-like data structure, with "bundles" of unique E (for Element) keys and unique S (for
012 * Single) keys updated together like a map that can be queried by E key bundles, S keys, or int indices, as well as
013 * like a multimap that can be queried by lone E keys. A bundle can be specified as a Collection of E values, an array
014 * of E values, or in two parts as either of the above given to a BundleBiMap method along with an int array that can
015 * represent variations on E keys (e.g. some quantity for an E value that permits different amounts to be passed with
016 * the unique E values to getS and have it yield a different S for a, say, 1 Foo and 1 Bar vs. 2 Foo and 3 Bar). This
017 * allows an intended purpose for this class as a way to describe crafting recipes that may need various amounts of an
018 * item to be mixed in, and since the quantities are optional, it can still be used to group multiple E keys with S
019 * keys. The multimap property allows you to use an E element key to get all of the S keys that are associated with a
020 * bundle that contains that E key (you can also get the ordering indices for those S keys, which you can use to get the
021 * full bundle if you want).
022 * <br>
023 * Does not implement any interfaces that you would expect for a data structure, because almost every method it has
024 * needs to specify whether it applies to E or S items, or otherwise doesn't fit a normal Collection-like interface's
025 * requirements.
026 * <br>
027 * Closely related to Arrangement, K2, and K2V1 in implementation.
028 * <br>
029 * Created by Tommy Ettinger on 4/26/2017.
030 */
031public class BundleBiMap<E, S>
032{
033    private Arrangement<E> elements;
034    private K2<int[][], S> bm;
035    private ArrayList<IntVLA> mm;
036
037    /**
038     * Constructs an empty BundleBiMap.
039     */
040    public BundleBiMap()
041    {
042        this(Arrangement.DEFAULT_INITIAL_SIZE, Arrangement.DEFAULT_LOAD_FACTOR);
043    }
044
045    /**
046     * Constructs a BundleBiMap with the expected number of indices to hold (the number of bundles and number of S items
047     * is always the same, and this will be more efficient if expected is greater than that number).
048     * @param expected how many bundle-to-single pairings this is expected to hold
049     */
050    public BundleBiMap(int expected)
051    {
052        this(expected, Arrangement.DEFAULT_LOAD_FACTOR);
053    }
054
055    /**
056     * Constructs a BundleBiMap with the expected number of indices to hold (the number of bundles and number of S items
057     * is always the same, and this will be more efficient if expected is greater than that number) and the load factor
058     * to use, between 0.1f and 0.8f usually (using load factors higher than 0.8f can cause problems).
059     * @param expected the amount of indices (the count of bundles is the same as the count of S items) this should hold
060     * @param f the load factor, probably between 0.1f and 0.8f
061     */
062    public BundleBiMap(int expected, float f)
063    {
064        elements = new Arrangement<>(expected, f);
065        bm = new K2<>(expected, f, CrossHash.int2DHasher, CrossHash.defaultHasher);
066        mm = new ArrayList<>(expected * 4);
067    }
068
069
070    /**
071     * Constructs a BundleBiMap using another BundleBiMap to copy.
072     * @param other the other BundleBiMap to copy
073     */
074    public BundleBiMap(BundleBiMap<E, S> other)
075    {
076        if(other == null)
077        {
078            elements = new Arrangement<>(64, 0.75f);
079            bm = new K2<>(16, 0.75f, CrossHash.int2DHasher, CrossHash.defaultHasher);
080            mm = new ArrayList<>(64);
081        }
082        else
083        {
084            elements = new Arrangement<>(other.elements);
085            bm = new K2<>(other.bm);
086            mm = new ArrayList<>(other.mm);
087        }
088    }
089
090    /**
091     * Returns true if this contains the E, element, in any of its bundles of E keys.
092     * @param element the E to check the presence of in all bundles
093     * @return true if element is present in this; false otherwise
094     */
095    public boolean containsElement(E element) { return elements.containsKey(element); }
096    /**
097     * Returns true if this contains the S, single, in its collection of S items.
098     * @param single the S to check the presence of
099     * @return true if single is present in this; false otherwise
100     */
101    public boolean containsSingle(S single) { return bm.containsB(single); }
102
103    /**
104     * Returns true if index is between 0 (inclusive) and {@link #size()} (exclusive), or false otherwise.
105     * @param index the index to check
106     * @return true if index is a valid index in the ordering of this BundleBiMap
107     */
108    public boolean containsIndex(int index) { return index >= 0 && index < bm.size(); }
109
110    /**
111     * Given an int index, finds the associated S key (using index as a point in the ordering).
112     * @param index an int index into this BundleBiMap
113     * @return the S object with index for its position in the ordering, or null if index was invalid
114     */
115    public S getSingleAt(int index)
116    {
117        return bm.getBAt(index);
118    }
119
120    /**
121     * Gets a random E from this BundleBiMap's individual elements using the given IRNG.
122     * @param random generates a random index to get an E with
123     * @return a randomly chosen E, or null if this is empty
124     */
125    public E randomElement(IRNG random)
126    {
127        return elements.randomKey(random);
128    }
129
130    /**
131     * Gets a random S from this BundleBiMap using the given IRNG.
132     * @param random generates a random index to get a S with
133     * @return a randomly chosen S, or null if this is empty
134     */
135    public S randomSingle(IRNG random)
136    {
137        return bm.randomB(random);
138    }
139
140    /**
141     * Changes an existing S key, {@code past}, to another S key, {@code future}, if past exists in this BundleBiMap
142     * and future does not yet exist in this BundleBiMap. This will retain past's point in the ordering for future, so
143     * the associated other key(s) will still be associated in the same way.
144     * @param past a S key, that must exist in this BundleBiMap's S keys, and will be changed
145     * @param future a S key, that cannot currently exist in this BundleBiMap's S keys, but will if this succeeds
146     * @return this for chaining
147     */
148    public BundleBiMap<E, S> alterB(S past, S future)
149    {
150        bm.alterB(past, future);
151        return this;
152    }
153
154
155
156    /**
157     * Changes the S key at {@code index} to another S key, {@code future}, if index is valid and future does not
158     * yet exist in this K2. The position in the ordering for future will be the same as index, and the same
159     * as the key this replaced, if this succeeds, so the other key(s) at that position will still be associated in
160     * the same way.
161     * @param index a position in the ordering to change; must be at least 0 and less than {@link #size()}
162     * @param future a S key, that cannot currently exist in this BundleBiMap's S keys, but will if this succeeds
163     * @return this for chaining
164     */
165    public BundleBiMap<E, S> alterSingleAt(int index, S future)
166    {
167        bm.alterBAt(index, future);
168        return this;
169    }
170    /**
171     * Adds a bundle of E keys and a S key at the same point in the ordering (the end) to this BundleBiMap. Neither
172     * parameter can be present in this collection before this is called.
173     * @param e an array of E keys to add; the array cannot already be present, nor can it be null
174     * @param s e S key to add; cannot already be present
175     * @return true if this collection changed as e result of this call
176     */
177    public boolean put(E[] e, S s)
178    {
179        if(e == null) return false;
180        int len = elements.size;
181        elements.putAll(e);
182        for (int i = len; i < elements.size; i++) {
183            mm.add(new IntVLA(e.length));
184        }
185
186        elements.putAll(e);
187        int[][] bundle = new int[][]{elements.getArray(e)};
188        if(!bm.put(bundle, s))
189            return false;
190        for (int i = 0; i < e.length; i++) {
191            mm.get(bundle[0][i]).add(bm.size()-1);
192        }
193        return true;
194    }
195    /**
196     * Adds a bundle of E keys, mixed with an int array of variations, and a S key at the same point in the ordering
197     * (the end) to this BundleBiMap. Neither the S key nor the bundle (effectively, the pair of e and variation) can be
198     * present in this collection before this is called.
199     * @param e an array of E keys to add; the array cannot already have been inserted with an equivalent variation, nor can it be null
200     * @param variation an int array that can be used to make a different version of e, i.e. the same things at different quantities; cannot be null
201     * @param s e S key to add; cannot already be present
202     * @return true if this collection changed as e result of this call
203     */
204    public boolean put(E[] e, int[] variation, S s)
205    {
206        if(e == null || variation == null) return false;
207        int len = elements.size;
208        elements.putAll(e);
209        for (int i = len; i < elements.size; i++) {
210            mm.add(new IntVLA(e.length));
211        }
212
213        int[][] bundle = new int[][]{elements.getArray(e), variation};
214        if(!bm.put(bundle, s))
215            return false;
216        for (int i = 0; i < e.length; i++) {
217            mm.get(bundle[0][i]).add(bm.size()-1);
218        }
219        return true;
220    }
221    /**
222     * Adds a bundle of E keys and a S key at the same point in the ordering (the end) to this BundleBiMap. Neither
223     * parameter can be present in this collection before this is called.
224     * @param e an array of E keys to add; the array cannot already be present, nor can it be null
225     * @param s e S key to add; cannot already be present
226     * @return true if this collection changed as e result of this call
227     */
228    public boolean put(Collection<? extends E> e, S s)
229    {
230        if(e == null) return false;
231        int len = elements.size;
232        elements.putAll(e);
233        for (int i = len; i < elements.size; i++) {
234            mm.add(new IntVLA(e.size()));
235        }
236        int[][] bundle = new int[][]{elements.getArray(e)};
237        if(!bm.put(bundle, s))
238            return false;
239        len = bundle[0].length;
240        for (int i = 0; i < len; i++) {
241            mm.get(bundle[0][i]).add(bm.size()-1);
242        }
243        return true;
244    }
245    /**
246     * Adds a bundle of E keys, mixed with an int array of variations, and a S key at the same point in the ordering
247     * (the end) to this BundleBiMap. Neither the S key nor the bundle (effectively, the pair of e and variation) can be
248     * present in this collection before this is called.
249     * @param e an array of E keys to add; the array cannot already have been inserted with an equivalent variation, nor can it be null
250     * @param variation an int array that can be used to make a different version of e, i.e. the same things at different quantities; cannot be null
251     * @param s e S key to add; cannot already be present
252     * @return true if this collection changed as e result of this call
253     */
254    public boolean put(Collection<? extends E> e, int[] variation, S s)
255    {
256        if(e == null || variation == null) return false;
257        int len = elements.size;
258        elements.putAll(e);
259        for (int i = len; i < elements.size; i++) {
260            mm.add(new IntVLA(e.size()));
261        }
262        int[][] bundle = new int[][]{elements.getArray(e), variation};
263        if(!bm.put(bundle, s))
264            return false;
265        len = bundle[0].length;
266        for (int i = 0; i < len; i++) {
267            mm.get(bundle[0][i]).add(bm.size()-1);
268        }
269        return true;
270    }
271
272    /**
273     * Puts all unique E and S keys in {@code aKeys} and {@code bKeys} into this K2 at the end. If an E in aKeys or a S
274     * in bKeys is already present when this would add one, this will not put the E and S keys at that point in the
275     * iteration order, and will place the next unique E and S it finds in the arguments at that position instead.
276     * @param aKeys an Iterable or Collection of E keys to add; should all be unique (like a Set)
277     * @param bKeys an Iterable or Collection of S keys to add; should all be unique (like a Set)
278     * @return true if this collection changed as a result of this call
279     */
280    public boolean putAll(Iterable<? extends Collection<? extends E>> aKeys, Iterable<? extends S> bKeys)
281    {
282        if(aKeys == null || bKeys == null) return false;
283        Iterator<? extends Collection<? extends E>> aIt = aKeys.iterator();
284        Iterator<? extends S> bIt = bKeys.iterator();
285        boolean changed = false;
286        while (aIt.hasNext() && bIt.hasNext())
287        {
288            changed = put(aIt.next(), bIt.next()) || changed;
289        }
290        return changed;
291    }
292    /**
293     * Puts all unique E and S keys in {@code other} into this K2, respecting other's ordering. If an E or a S in other
294     * is already present when this would add one, this will not put the E and S keys at that point in the iteration
295     * order, and will place the next unique E and S it finds in the arguments at that position instead.
296     * @param other another K2 collection with the same E and S types
297     * @return true if this collection changed as a result of this call
298     */
299    public boolean putAll(BundleBiMap<? extends E, ? extends S> other)
300    {
301        if(other == null) return false;
302        boolean changed = false;
303        int sz = other.size();
304        for (int i = 0; i < sz; i++) {
305            int[][] bundle = other.bm.getAAt(i);
306            if(bundle == null || bundle.length == 0) continue;
307            if(bundle.length == 1)
308                changed |= put(elements.keysAt(bundle[0]), other.bm.getBAt(i));
309            else
310                changed |= put(elements.keysAt(bundle[0]), bundle[1], other.bm.getBAt(i));
311        }
312        return changed;
313    }
314
315    /**
316     * Given an S key to look up, gets a 2D int array representing the key's matching bundle. The bundle is likely to
317     * use a representation for the first sub-array that will be meaningless without internal information from this
318     * BundleBiMap, but the second sub-array, if present, should match the variation supplied with that bundle
319     * to {@link #put(Object[], int[], Object)} or {@link #put(Collection, int[], Object)}.
320     * <br>
321     * This method copies the 2D int array it returns, so modifying it won't affect the original BundleBiMap.
322     * @param single a S key to look up
323     * @return a copied 2D int array that represents a bundle, or null if single is not present in this
324     */
325    public int[][] getCode(S single)
326    {
327        if(single == null) return null;
328        return ArrayTools.copy(bm.getAFromB(single));
329    }
330    /**
331     * Given an index to look up, gets a 2D int array representing the bundle at that index. The bundle is likely to
332     * use a representation for the first sub-array that will be meaningless without internal information from this
333     * BundleBiMap, but the second sub-array, if present, should match the variation supplied with that bundle
334     * to {@link #put(Object[], int[], Object)} or {@link #put(Collection, int[], Object)}.
335     * <br>
336     * This method copies the 2D int array it returns, so modifying it won't affect the original BundleBiMap.
337     * @param index an int index to look up
338     * @return a 2D int array that represents a bundle, or null if index is out of bounds
339     */
340    public int[][] getCodeAt(int index)
341    {
342        return ArrayTools.copy(bm.getAAt(index));
343    }
344    /**
345     * Given an index to look up, gets the S key present at that position in the ordering.
346     * @param index an int index to look up
347     * @return a 2D int array that represents a bundle, or null if index is out of bounds
348     */
349    public S singleAt(int index)
350    {
351        return bm.getBAt(index);
352    }
353
354    /**
355     * Given a bundle of E keys as an array with no variation, gets the matching S key for that bundle, or null if there
356     * is none.
357     * @param e an array of E
358     * @return the S key that corresponds to the given bundle, e
359     */
360    public S getSingle(E[] e)
361    {
362        if(e == null) return null;
363        return bm.getBFromA(new int[][]{elements.getArray(e)});
364    }
365
366    /**
367     * Given a bundle of E keys as an array with an int array variation, gets the matching S key for that bundle, or
368     * null if there is none.
369     * @param e an array of E element keys
370     * @param variations an int array that should match an int array used as a variation parameter to put
371     * @return the S key that corresponds to the given bundle, e combined with variations
372     */
373    public S getSingle(E[] e, int[] variations)
374    {
375        if(e == null || variations == null) return null;
376        return bm.getBFromA(new int[][]{elements.getArray(e), variations});
377    }
378
379    /**
380     * Given a bundle of E keys as a Collection with no variation, gets the matching S key for that bundle, or
381     * null if there is none.
382     * @param e a Collection of E element keys (each key can be an E or an instance of any subclass of E)
383     * @return the S key that corresponds to the given bundle, e
384     */
385    public S getSingle(Collection<? extends E> e)
386    {
387        if(e == null) return null;
388        return bm.getBFromA(new int[][]{elements.getArray(e)});
389    }
390
391    /**
392     * Given a bundle of E keys as a Collection with an int array variation, gets the matching S key for that bundle, or
393     * null if there is none.
394     * @param e a Collection of E element keys (each key can be an E or an instance of any subclass of E)
395     * @param variations an int array that should match an int array used as a variation parameter to put
396     * @return the S key that corresponds to the given bundle, e combined with variations
397     */
398    public S getSingle(Collection<? extends E> e, int[] variations)
399    {
400        if(e == null || variations == null) return null;
401        return bm.getBFromA(new int[][]{elements.getArray(e), variations});
402    }
403    /**
404     * Given a bundle as a coded 2D int array, gets the matching S key for that bundle, or null if there is none.
405     * The code parameter should be obtained from one of the methods that specifically returns that kind of 2D array,
406     * since the code uses internal information to efficiently represent a bundle.
407     * @param code a 2D int array representing a bundle that should have been obtained directly from this object
408     * @return the S key that corresponds to the given coded bundle
409     */
410    public S getSingleCoded(int[][] code)
411    {
412        if(code == null) return null;
413        return bm.getBFromA(code);
414    }
415
416    /**
417     * Gets (in near-constant time) the index of the given S single key in the ordering.
418     * @param single a S single key to look up
419     * @return the position in the ordering of single
420     */
421    public int indexOfSingle(S single)
422    {
423        return bm.indexOfB(single);
424    }
425
426    /**
427     * Given a coded bundle as produced by some methods in this class, decodes the elements part of the bundle and
428     * returns it as a newly-allocated OrderedSet of E element keys.
429     * @param bundle a coded bundle as a 2D int array
430     * @return an OrderedSet of E element keys corresponding to the data coded into bundle
431     */
432    public OrderedSet<E> elementsFromCode(int[][] bundle)
433    {
434        if(bundle == null || bundle.length < 1 || bundle[0] == null) return null;
435        return elements.keysAt(bundle[0]);
436    }
437
438    /**
439     * Given a coded bundle as produced by some methods in this class, decodes the variation part of the bundle, if
440     * present, and returns it as a newly-allocated 1D int array. If there is no variation in the given coded bundle,
441     * this returns null.
442     * @param bundle a coded bundle as a 2D int array
443     * @return an OrderedSet of E element keys corresponding to the data coded into bundle
444     */
445    public int[] variationFromCode(int[][] bundle)
446    {
447        if(bundle == null || bundle.length < 2 || bundle[1] == null) return null;
448        int[] ret = new int[bundle[1].length];
449        System.arraycopy(bundle[1], 0, ret, 0, ret.length);
450        return ret;
451    }
452
453    /**
454     * Given an S key to look up, gets a (newly-allocated) OrderedSet of E element keys corresponding to that S key.
455     * If a variation is part of the bundle, it will not be present in this, but a copy can be retrieved with
456     * {@link #getBundleVariation(Object)}.
457     * @param single a S key to look up
458     * @return an OrderedSet of the E elements used in the bundle that corresponds to single, or null if invalid
459     */
460    public OrderedSet<E> getBundleElements(S single)
461    {
462        int[][] bundle;
463        if(single == null || (bundle = bm.getAFromB(single)) == null || bundle.length < 1 || bundle[0] == null) return null;
464        return elements.keysAt(bundle[0]);
465    }
466
467    /**
468     * Given an S key to look up, gets a (newly-allocated) int array that is equivalent to the variation part of the
469     * bundle corresponding to single. If there is no variation in the corresponding bundle, then this returns null.
470     * To get the E elements that are the main part of a bundle, you can use {@link #getBundleElements(Object)}.
471     * @param single a S key to look up
472     * @return an int array copied from the variation part of the bundle that corresponds to single, or null if invalid
473     */
474    public int[] getBundleVariation(S single)
475    {
476        int[][] bundle;
477        if(single == null || (bundle = bm.getAFromB(single)) == null || bundle.length < 2 || bundle[1] == null) return null;
478        int[] ret = new int[bundle[1].length];
479        System.arraycopy(bundle[1], 0, ret, 0, ret.length);
480        return ret;
481    }
482
483    /**
484     * Given an index to look up, gets a (newly-allocated) OrderedSet of E element keys in the bundle at that index.
485     * If a variation is part of the bundle, it will not be present in this, but a copy can be retrieved with
486     * {@link #getBundleVariationAt(int)}.
487     * @param index an int position in the ordering to look up
488     * @return an OrderedSet of the E elements used in the bundle present at index, or null if invalid
489     */
490    public OrderedSet<E> getBundleElementsAt(int index)
491    {
492        int[][] bundle;
493        if((bundle = bm.getAAt(index)) == null || bundle.length < 1) return null;
494        return elements.keysAt(bundle[0]);
495    }
496    /**
497     * Given an index to look up, gets a (newly-allocated) int array that is equivalent to the variation part of the
498     * bundle present at that index. If there is no variation in the corresponding bundle, then this returns null.
499     * To get the E elements that are the main part of a bundle, you can use {@link #getBundleElementsAt(int)}.
500     * @param index an int position in the ordering to look up
501     * @return an int array copied from the variation part of the bundle present at index, or null if invalid
502     */
503    public int[] getBundleVariationAt(int index)
504    {
505        int[][] bundle;
506        if((bundle = bm.getAAt(index)) == null || bundle.length < 2 || bundle[1] == null) return null;
507        int[] ret = new int[bundle[1].length];
508        System.arraycopy(bundle[1], 0, ret, 0, ret.length);
509        return ret;
510    }
511
512    /**
513     * Given an E element key that could be used in one or more bundles this uses, finds all S single keys corresponding
514     * to bundles that contain the given element. Thus, if E was String and this BundleBiMap contained ["Copper", "Tin"]
515     * mapped to "Bronze" and ["Zinc", "Copper"] mapped to "Brass", then calling this method with "Copper" would get an
516     * OrderedSet that contains ["Bronze", "Brass"].
517     * @param element an E element key to look up (probably a component of one or more bundles)
518     * @return an OrderedSet of all S keys where the given element is part of the bundle corresponding to that S key, or null if E does not match anything
519     */
520    public OrderedSet<S> getManySingles(E element)
521    {
522        if(element == null) return null;
523        int pos;
524        if((pos = elements.getInt(element)) < 0) return null;
525        return bm.keysB.keysAt(mm.get(pos));
526    }
527    /**
528     * Given an E element key that could be used in one or more bundles this uses, gets all bundles in this object that
529     * contain the given element, as coded 2D int arrays. These coded bundles can be given to
530     * {@link #elementsFromCode(int[][])} and {@link #variationFromCode(int[][])} to get usable information from them.
531     * @param element an E element key to look up (probably a component of one or more bundles)
532     * @return an OrderedSet of all coded 2D int array bundles that contain the given element, or null if E is not in any bundles
533     */
534    public OrderedSet<int[][]> getManyCoded(E element)
535    {
536        if(element == null) return null;
537        int pos;
538        if((pos = elements.getInt(element)) < 0) return null;
539        return bm.keysA.keysAt(mm.get(pos));
540    }
541
542    /**
543     * Given an E element key that could be used in one or more bundles this uses, gets all indices in the ordering
544     * that contain a bundle with that element.  From such an index, you can use {@link #getSingleAt(int)} to get the
545     * S key at that position, {@link #getBundleElementsAt(int)} to get the E element keys at that position,
546     * {@link #getBundleVariationAt(int)} to get the possible variation at that position, or {@link #getCodeAt(int)} to
547     * get the coded bundle at that position.
548     * @return an OrderedSet of all coded 2D int array bundles that contain the given element, or null if E is not in any bundles
549     */
550    public int[] getManyIndices(E element)
551    {
552        if(element == null) return null;
553        int pos;
554        if((pos = elements.getInt(element)) < 0) return null;
555        return mm.get(pos).toArray();
556    }
557
558    /**
559     * Reorders this BundleBiMap using {@code ordering}, which has the same length as this object's {@link #size()}
560     * and can be generated with {@link ArrayTools#range(int)} (which, if applied, would produce no
561     * change to the current ordering), {@link IRNG#randomOrdering(int)} (which gives a random ordering, and if
562     * applied immediately would be the same as calling {@link #shuffle(IRNG)}), or made in some other way. If you
563     * already have an ordering and want to make a different ordering that can undo the change, you can use
564     * {@link ArrayTools#invertOrdering(int[])} called on the original ordering. The effects of this method, if called
565     * with an ordering that has repeat occurrences of an int or contains ints that are larger than its size should
566     * permit, are undefined other than the vague definition of "probably bad, unless you like crashes."
567     * @param ordering an int array or vararg that must contain each int from 0 to {@link #size()}
568     * @return this for chaining
569     */
570    public BundleBiMap<E, S> reorder(int... ordering)
571    {
572        if(ordering == null || ordering.length != bm.size()) return this;
573        bm.reorder(ordering);
574        int len = mm.size();
575        for (int i = 0; i < len; i++) {
576            IntVLA iv = mm.get(i);
577            for (int j = 0; j < iv.size; j++) {
578                iv.set(i, ordering[iv.get(i)]);
579            }
580        }
581        return this;
582    }
583
584    /**
585     * Generates a random ordering with rng and applies the same ordering to all kinds of keys this has; they will
586     * maintain their current association to other keys but their ordering/indices will change.
587     * @param rng an IRNG to produce the random ordering this will use
588     * @return this for chaining
589     */
590    public BundleBiMap<E, S> shuffle(IRNG rng)
591    {
592        return reorder(rng.randomOrdering(bm.size()));
593    }
594
595    /**
596     * Creates a new iterator over the individual E element keys this holds, with a larger total count the iterator may
597     * yield than {@link #size()} in most cases (it should be equal to {@link #elementSize()}), and in no particular
598     * order (though the order should be stable across versions and platforms, no special means are provided to further
599     * control the order). The E keys are individual, not bundled, and duplicate keys should never be encountered even
600     * if an E key appears in many bundles.
601     * @return a newly-created iterator over this BundleBiMap's individual (non-bundled) E keys
602     */
603    public Iterator<E> iteratorElements()
604    {
605        return elements.iterator();
606    }
607    /**
608     * Creates a new iterator over the S single keys this holds. The total number of items this yields should be equal
609     * to {@link #size()}. This method can be problematic for garbage collection if called very frequently; it may be
610     * better to access items by index (which also lets you access other keys associated with that index) using
611     * {@link #getSingleAt(int)} in a for(int i=0...) loop.
612     * @return a newly-created iterator over this BundleBiMap's S keys
613     */
614    public Iterator<S> iteratorSingles()
615    {
616        return bm.iteratorB();
617    }
618
619    /**
620     * Gets and caches the individual E keys as a Collection that implements SortedSet (and so also implements Set).
621     * @return the E keys as a SortedSet
622     */
623    public SortedSet<E> getElementSet() {
624        return elements.keySet();
625    }
626
627    /**
628     * Gets and caches the S single keys as a Collection that implements SortedSet (and so also implements Set).
629     * @return the S keys as a SortedSet
630     */
631    public SortedSet<S> getSingleSet() {
632        return bm.getSetB();
633    }
634
635    /**
636     * To be called sparingly, since this allocates a new OrderedSet instead of reusing one.
637     * @return the E keys as an OrderedSet
638     */
639    public OrderedSet<E> getElementOrderedSet() {
640        return elements.keysAsOrderedSet();
641    }
642
643    /**
644     * To be called sparingly, since this allocates a new OrderedSet instead of reusing one.
645     * @return the S keys as an OrderedSet
646     */
647    public OrderedSet<S> getSingleOrderedSet() {
648        return bm.getOrderedSetB();
649    }
650
651    /**
652     * Gets the total number of bundle-to-single pairs in this BundleBiMap.
653     * @return the total number of bundle keys (equivalently, the number of single keys) in this object
654     */
655    public int size() {
656        return bm.size();
657    }
658
659    /**
660     * Gets the total number of unique E element keys across all bundles in this BundleBiMap. Usually not the same as
661     * {@link #size()}, and ordinarily a fair amount larger, though this can also be smaller.
662     * @return the total number of unique E element keys in all bundles this contains
663     */
664    public int elementSize() {
665        return elements.size();
666    }
667
668    public boolean isEmpty()
669    {
670        return bm.isEmpty();
671    }
672
673}