/*
* Copyright 2013 Cameron Beccario
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.nullschool.collect.basic;
import net.nullschool.collect.*;
import net.nullschool.util.ObjectTools;
import java.util.*;
import static net.nullschool.collect.basic.BasicTools.*;
import static net.nullschool.util.ArrayTools.EMPTY_CLASS_ARRAY;
import static net.nullschool.util.ArrayTools.EMPTY_OBJECT_ARRAY;
/**
* 2013-06-04<p/>
*
* Utility methods for constructing the entire family of const collections that use basic arrays to store their
* elements.
*
* @see BasicConstList
* @see BasicConstSet
* @see BasicConstSortedSet
* @see BasicConstMap
* @see BasicConstSortedMap
*
* @author Cameron Beccario
*/
public final class BasicCollections {
private BasicCollections() {
throw new AssertionError();
}
// -----------------------------------------------------------------------------------------------------------------
// BasicConstList utility methods
/**
* Returns an empty ConstList.
*
* @return a persistent empty list.
*/
public static <E> ConstList<E> emptyList() {
return BasicList0.instance();
}
/**
* Returns a ConstList with a single element.
*
* @param e0 the element.
* @return a persistent list containing the specified element.
*/
public static <E> ConstList<E> listOf(E e0) {
return new BasicList1<>(e0);
}
/**
* Returns a ConstList of two elements.
*
* @param e0 the first element.
* @param e1 the second element.
* @return a persistent list containing the specified elements.
*/
public static <E> ConstList<E> listOf(E e0, E e1) {
return new BasicListN<>(new Object[] {e0, e1});
}
/**
* Returns a ConstList of three elements.
*
* @param e0 the first element.
* @param e1 the second element.
* @param e2 the third element.
* @return a persistent list containing the specified elements.
*/
public static <E> ConstList<E> listOf(E e0, E e1, E e2) {
return new BasicListN<>(new Object[] {e0, e1, e2});
}
/**
* Returns a ConstList of four elements.
*
* @return a persistent list containing the specified elements.
*/
public static <E> ConstList<E> listOf(E e0, E e1, E e2, E e3) {
return new BasicListN<>(new Object[] {e0, e1, e2, e3});
}
/**
* Returns a ConstList of five elements.
*
* @return a persistent list containing the specified elements.
*/
public static <E> ConstList<E> listOf(E e0, E e1, E e2, E e3, E e4) {
return new BasicListN<>(new Object[] {e0, e1, e2, e3, e4});
}
/**
* Returns a ConstList of many elements.
*
* @param additional all additional elements past the sixth element.
* @return a persistent list containing the specified elements in the order they appear.
*/
@SafeVarargs
public static <E> ConstList<E> listOf(E e0, E e1, E e2, E e3, E e4, E e5, E... additional) {
Object[] elements = new Object[6 + additional.length];
elements[0] = e0;
elements[1] = e1;
elements[2] = e2;
elements[3] = e3;
elements[4] = e4;
elements[5] = e5;
System.arraycopy(additional, 0, elements, 6, additional.length);
return new BasicListN<>(elements);
}
/**
* Converts the specified array of elements into a ConstList.
*
* @param elements the elements of the list.
* @return a persistent list containing the specified elements in the order they appear.
* @throws NullPointerException if {@code elements} is null.
*/
public static <E> ConstList<E> asList(E[] elements) {
return condenseToList(copy(elements));
}
/**
* Converts the specified collection into a ConstList. The list is constructed from the elements encountered while
* iterating over the collection.
*
* @param collection the collection.
* @return a persistent list containing the elements of the specified collection in the order they appear.
* @throws NullPointerException if {@code collection} is null.
*/
public static <E> ConstList<E> asList(Collection<? extends E> collection) {
if (collection instanceof BasicConstList) {
@SuppressWarnings("unchecked") BasicConstList<E> covariant = (BasicConstList<E>)collection;
return covariant; // The collection is already a ConstList.
}
return condenseToList(copy(collection));
}
/**
* Constructs a ConstList from the sequence of elements encountered while iterating with the specified iterator.
*
* @param iterator the iterator.
* @return a persistent list containing the elements of the iteration in the order they appear.
* @throws NullPointerException if {@code iterator} is null.
*/
public static <E> ConstList<E> asList(Iterator<? extends E> iterator) {
return condenseToList(copy(iterator));
}
/**
* Instantiates the appropriate AbstractBasicConstList implementation from the specified array of elements. The
* array reference <b>must be trusted</b>:
* <ol>
* <li>the array was defensively copied or is guaranteed to be invisible to external clients</li>
* <li>the component type is Object instead of a narrower type such as String or Integer</li>
* </ol>
*
* @param trustedElements the Object array of elements.
* @return a size-appropriate implementation of AbstractBasicConstList.
*/
static <E> BasicConstList<E> condenseToList(Object[] trustedElements) {
assert trustedElements.getClass() == Object[].class;
switch (trustedElements.length) {
case 0: return BasicList0.instance();
case 1: return new BasicList1<>(trustedElements[0]);
default: return new BasicListN<>(trustedElements);
}
}
// -----------------------------------------------------------------------------------------------------------------
// BasicConstSet utility methods
/**
* Returns an empty ConstSet.
*
* @return a persistent empty set.
*/
public static <E> ConstSet<E> emptySet() {
return BasicSet0.instance();
}
/**
* Returns a ConstSet with a single element.
*
* @param e0 the element.
* @return a persistent set containing the specified element.
*/
public static <E> ConstSet<E> setOf(E e0) {
return new BasicSet1<>(e0);
}
/**
* Returns a ConstSet of up to two elements. If the second argument is equal to the first, then a ConstSet
* containing just the first element is returned. {@link Object#equals} and {@link Object#hashCode} are used
* to test for uniqueness.
*
* @param e0 the first element.
* @param e1 the (potential) second element.
* @return a persistent set containing the unique elements from the provided arguments in the order they appear.
*/
public static <E> ConstSet<E> setOf(E e0, E e1) {
return Objects.equals(e1, e0) ?
new BasicSet1<E>(e0) :
new BasicSetN<E>(new Object[] {e0, e1});
}
/**
* Returns a ConstSet comprised of the unique elements from the provided arguments. {@link Object#equals} and
* {@link Object#hashCode} are used to test for uniqueness.
*
* @param e0 the first element.
* @param e1 the (potential) second element.
* @param e2 the (potential) third element.
* @return a persistent set containing the unique elements from the provided arguments in the order they appear.
*/
public static <E> ConstSet<E> setOf(E e0, E e1, E e2) {
return condenseToSet(unionInto(EMPTY_OBJECT_ARRAY, new Object[] {e0, e1, e2}));
}
/**
* Returns a ConstSet comprised of the unique elements from the provided arguments. {@link Object#equals} and
* {@link Object#hashCode} are used to test for uniqueness.
*
* @return a persistent set containing the unique elements from the provided arguments in the order they appear.
*/
public static <E> ConstSet<E> setOf(E e0, E e1, E e2, E e3) {
return condenseToSet(unionInto(EMPTY_OBJECT_ARRAY, new Object[] {e0, e1, e2, e3}));
}
/**
* Returns a ConstSet comprised of the unique elements from the provided arguments. {@link Object#equals} and
* {@link Object#hashCode} are used to test for uniqueness.
*
* @return a persistent set containing the unique elements from the provided arguments in the order they appear.
*/
public static <E> ConstSet<E> setOf(E e0, E e1, E e2, E e3, E e4) {
return condenseToSet(unionInto(EMPTY_OBJECT_ARRAY, new Object[] {e0, e1, e2, e3, e4}));
}
/**
* Returns a ConstSet comprised of the unique elements from the provided arguments. {@link Object#equals} and
* {@link Object#hashCode} are used to test for uniqueness.
*
* @param additional all additional elements past the sixth element.
* @return a persistent set containing the unique elements from the provided arguments in the order they appear.
*/
@SafeVarargs
public static <E> ConstSet<E> setOf(E e0, E e1, E e2, E e3, E e4, E e5, E... additional) {
Object[] elements = new Object[6 + additional.length];
elements[0] = e0;
elements[1] = e1;
elements[2] = e2;
elements[3] = e3;
elements[4] = e4;
elements[5] = e5;
System.arraycopy(additional, 0, elements, 6, additional.length);
return condenseToSet(unionInto(EMPTY_OBJECT_ARRAY, elements));
}
/**
* Converts the specified array of elements into a ConstSet comprised of the unique elements from the array.
* {@link Object#equals} and {@link Object#hashCode} are used to test for uniqueness.
*
* @param elements the elements from which to build the set.
* @return a persistent set containing the unique elements from the array in the order they appear.
* @throws NullPointerException if {@code elements} is null.
*/
public static <E> ConstSet<E> asSet(E[] elements) {
return condenseToSet(unionInto(EMPTY_OBJECT_ARRAY, elements));
}
/**
* Converts the specified collection into a ConstSet comprised of the unique elements encountered while iterating
* over the collection. {@link Object#equals} and {@link Object#hashCode} are used to test for uniqueness.
*
* @param collection the collection.
* @return a persistent set containing the unique elements from the collection in the order they appear.
* @throws NullPointerException if {@code collection} is null.
*/
public static <E> ConstSet<E> asSet(Collection<? extends E> collection) {
// NOTE: We do not provide overload asSet(Set<? extends E>) because the behavior of that function would
// be the same as this function. Set membership must be recomputed because Set lacks an explicit membership
// function, unlike SortedSet.
if (collection instanceof BasicConstSet && !(collection instanceof BasicConstSortedSet)) {
@SuppressWarnings("unchecked") BasicConstSet<E> covariant = (BasicConstSet<E>)collection;
return covariant; // The collection is already a non-sorted ConstSet.
}
return condenseToSet(unionInto(EMPTY_OBJECT_ARRAY, collection.toArray()));
}
/**
* Constructs a ConstSet from the unique elements encountered while iterating with the specified iterator.
* {@link Object#equals} and {@link Object#hashCode} are used to test for uniqueness.
*
* @param iterator the iterator.
* @return a persistent set containing the unique elements of the iteration in the order they appear.
* @throws NullPointerException if {@code iterator} is null.
*/
public static <E> ConstSet<E> asSet(Iterator<? extends E> iterator) {
return condenseToSet(unionInto(EMPTY_OBJECT_ARRAY, copy(iterator)));
}
/**
* Instantiates the appropriate AbstractBasicConstSet implementation from the specified array of elements. The
* array reference <b>must be trusted</b>:
* <ol>
* <li>the array was defensively copied or is guaranteed to be invisible to external clients</li>
* <li>the component type is Object instead of a narrower type such as String or Integer</li>
* <li><i>the array contains only unique elements</i></li>
* </ol>
*
* @param trustedElements the Object array of elements.
* @return a size-appropriate implementation of AbstractBasicConstSet.
*/
static <E> BasicConstSet<E> condenseToSet(Object[] trustedElements) {
assert trustedElements.getClass() == Object[].class;
switch (trustedElements.length) {
case 0: return BasicSet0.instance();
case 1: return new BasicSet1<>(trustedElements[0]);
default: return new BasicSetN<>(trustedElements);
}
}
// -----------------------------------------------------------------------------------------------------------------
// BasicConstSortedSet utility methods
/**
* Returns an empty ConstSortedSet with the ordering of the specified comparator.
*
* @param comparator the comparator, or null for {@link Comparable natural ordering}.
* @return a persistent empty sorted set.
*/
public static <E> ConstSortedSet<E> emptySortedSet(Comparator<? super E> comparator) {
return BasicSortedSet0.instance(comparator);
}
/**
* Returns a ConstSortedSet with a single element and the ordering of the specified comparator.
*
* @param comparator the comparator, or null for {@link Comparable natural ordering}.
* @param e0 the element.
* @return a persistent sorted set containing the specified element.
* @throws NullPointerException if the element is null and the comparator is null or does not permit nulls.
* @throws ClassCastException if the element is of a type not compatible for comparison.
*/
public static <E> ConstSortedSet<E> sortedSetOf(Comparator<? super E> comparator, E e0) {
return new BasicSortedSet1<>(comparator, checkType(comparator, e0));
}
/**
* Returns a ConstSortedSet comprised of the unique elements from the provided arguments, having the ordering
* of the specified comparator.
*
* @param comparator the comparator, or null for {@link Comparable natural ordering}.
* @param e0 the first element.
* @param e1 the (potential) second element.
* @return a persistent sorted set containing the unique elements from the provided arguments.
* @throws NullPointerException if any element is null and the comparator is null or does not permit nulls.
* @throws ClassCastException if any element is of a type not compatible for comparison.
*/
public static <E> ConstSortedSet<E> sortedSetOf(Comparator<? super E> comparator, E e0, E e1) {
int cmp = ObjectTools.compare(e0, e1, comparator);
return cmp == 0 ?
new BasicSortedSet1<>(comparator, e0) :
cmp < 0 ?
new BasicSortedSetN<>(comparator, new Object[] {e0, e1}) :
new BasicSortedSetN<>(comparator, new Object[] {e1, e0});
}
/**
* Returns a ConstSortedSet comprised of the unique elements from the provided arguments, having the ordering
* of the specified comparator.
*
* @param comparator the comparator, or null for {@link Comparable natural ordering}.
* @param e0 the first element.
* @param e1 the (potential) second element.
* @param e2 the (potential) third element.
* @return a persistent sorted set containing the unique elements from the provided arguments.
* @throws NullPointerException if any element is null and the comparator is null or does not permit nulls.
* @throws ClassCastException if any element is of a type not compatible for comparison.
*/
public static <E> ConstSortedSet<E> sortedSetOf(Comparator<? super E> comparator, E e0, E e1, E e2) {
return condenseToSortedSet(comparator, unionInto(EMPTY_OBJECT_ARRAY, new Object[] {e0, e1, e2}, comparator));
}
/**
* Returns a ConstSortedSet comprised of the unique elements from the provided arguments, having the ordering
* of the specified comparator.
*
* @param comparator the comparator, or null for {@link Comparable natural ordering}.
* @return a persistent sorted set containing the unique elements from the provided arguments.
* @throws NullPointerException if any element is null and the comparator is null or does not permit nulls.
* @throws ClassCastException if any element is of a type not compatible for comparison.
*/
public static <E> ConstSortedSet<E> sortedSetOf(Comparator<? super E> comparator, E e0, E e1, E e2, E e3) {
return condenseToSortedSet(
comparator,
unionInto(EMPTY_OBJECT_ARRAY, new Object[] {e0, e1, e2, e3}, comparator));
}
/**
* Returns a ConstSortedSet comprised of the unique elements from the provided arguments, having the ordering
* of the specified comparator.
*
* @param comparator the comparator, or null for {@link Comparable natural ordering}.
* @return a persistent sorted set containing the unique elements from the provided arguments.
* @throws NullPointerException if any element is null and the comparator is null or does not permit nulls.
* @throws ClassCastException if any element is of a type not compatible for comparison.
*/
public static <E> ConstSortedSet<E> sortedSetOf(
Comparator<? super E> comparator,
E e0,
E e1,
E e2,
E e3,
E e4) {
return condenseToSortedSet(
comparator,
unionInto(EMPTY_OBJECT_ARRAY, new Object[] {e0, e1, e2, e3, e4}, comparator));
}
/**
* Returns a ConstSortedSet comprised of the unique elements from the provided arguments, having the ordering
* of the specified comparator.
*
* @param comparator the comparator, or null for {@link Comparable natural ordering}.
* @param additional all additional elements past the sixth element.
* @return a persistent sorted set containing the unique elements from the provided arguments.
* @throws NullPointerException if any element is null and the comparator is null or does not permit nulls.
* @throws ClassCastException if any element is of a type not compatible for comparison.
*/
@SafeVarargs
public static <E> ConstSortedSet<E> sortedSetOf(
Comparator<? super E> comparator,
E e0,
E e1,
E e2,
E e3,
E e4,
E e5,
E... additional) {
Object[] elements = new Object[6 + additional.length];
elements[0] = e0;
elements[1] = e1;
elements[2] = e2;
elements[3] = e3;
elements[4] = e4;
elements[5] = e5;
System.arraycopy(additional, 0, elements, 6, additional.length);
return condenseToSortedSet(comparator, unionInto(EMPTY_OBJECT_ARRAY, elements, comparator));
}
/**
* Converts the specified array of elements into a ConstSortedSet comprised of the unique elements from the array,
* having the ordering of the specified comparator.
*
* @param comparator the comparator, or null for {@link Comparable natural ordering}.
* @param elements the elements from which to build the set.
* @return a persistent sorted set containing the unique elements from the array in sorted order.
* @throws NullPointerException if any element is null and the comparator is either null or does not permit nulls,
* or the {@code elements} array itself is null.
* @throws ClassCastException if any element is of a type not compatible for comparison.
*/
public static <E> ConstSortedSet<E> asSortedSet(Comparator<? super E> comparator, E[] elements) {
return condenseToSortedSet(comparator, unionInto(EMPTY_OBJECT_ARRAY, elements, comparator));
}
/**
* Converts the specified sorted set into a ConstSortedSet with the same elements and ordering.
*
* @param set the sorted set.
* @return a persistent sorted set containing the exact elements and ordering of the specified set.
*/
public static <E> ConstSortedSet<E> asSortedSet(SortedSet<E> set) {
if (set instanceof BasicConstSortedSet) {
return (BasicConstSortedSet<E>)set; // The set is already a ConstSortedSet.
}
return condenseToSortedSet(set.comparator(), set.toArray());
}
/**
* Converts the specified collection into a ConstSortedSet comprised of the unique elements from the collection,
* having the ordering of the specified comparator.
*
* @param comparator the comparator, or null for {@link Comparable natural ordering}.
* @param collection the collection.
* @return a persistent sorted set containing the unique elements from the collection in sorted order.
* @throws NullPointerException if any element is null and the comparator is either null or does not permit nulls,
* or the {@code collection} itself is null.
* @throws ClassCastException if any element is of a type not compatible for comparison.
*/
public static <E> ConstSortedSet<E> asSortedSet(
Comparator<? super E> comparator,
Collection<? extends E> collection) {
if (collection instanceof SortedSet) {
@SuppressWarnings("unchecked") SortedSet<E> covariant = (SortedSet<E>)collection;
if (Objects.equals(comparator, covariant.comparator())) {
return asSortedSet(covariant); // the set is already in the desired sorted order.
}
}
return condenseToSortedSet(comparator, unionInto(EMPTY_OBJECT_ARRAY, collection.toArray(), comparator));
}
/**
* Constructs a ConstSortedSet from the unique elements encountered while iterating with the specified iterator.
* The resulting elements are sorted with the specified comparator.
*
* @param comparator the comparator, or null for {@link Comparable natural ordering}.
* @param iterator the iterator.
* @return a persistent sorted set containing the unique elements of the iteration in sorted order.
* @throws NullPointerException if any element is null and the comparator is either null or does not permit nulls,
* or the {@code iterator} itself is null.
* @throws ClassCastException if any element is of a type not compatible for comparison.
*/
public static <E> ConstSortedSet<E> asSortedSet(
Comparator<? super E> comparator,
Iterator<? extends E> iterator) {
return condenseToSortedSet(comparator, unionInto(EMPTY_OBJECT_ARRAY, copy(iterator), comparator));
}
/**
* Instantiates the appropriate AbstractBasicConstSortedSet implementation from the specified array of elements.
* The array reference <b>must be trusted</b>:
* <ol>
* <li>the array was defensively copied or is guaranteed to be invisible to external clients</li>
* <li>the component type is Object instead of a narrower type such as String or Integer</li>
* <li><i>the array contains only unique elements</i></li>
* <li><i>the array is already sorted using the specified comparator</i></li>
* </ol>
*
* @param trustedElements the Object array of elements.
* @return a size-appropriate implementation of AbstractBasicConstSet.
*/
static <E> BasicConstSortedSet<E> condenseToSortedSet(Comparator<? super E> comparator, Object[] trustedElements) {
assert trustedElements.getClass() == Object[].class;
switch (trustedElements.length) {
case 0: return BasicSortedSet0.instance(comparator);
case 1: return new BasicSortedSet1<>(comparator, trustedElements[0]);
default: return new BasicSortedSetN<>(comparator, trustedElements);
}
}
// -----------------------------------------------------------------------------------------------------------------
// BasicConstMap utility methods
/**
* Returns an empty ConstMap.
*
* @return a persistent empty map.
*/
public static <K, V> ConstMap<K, V> emptyMap() {
return BasicMap0.instance();
}
/**
* Returns a ConstMap with a single entry.
*
* @param k0 the key.
* @param v0 the value.
* @return a persistent map containing the specified entry.
*/
public static <K, V> ConstMap<K, V> mapOf(K k0, V v0) {
return new BasicMap1<>(k0, v0);
}
/**
* Returns a ConstMap comprised of the unique entries from the provided arguments. Duplicate keys are not retained,
* but their associated values replace the values associated with existing keys, just as repeated calls to
* {@link Map#put} behaves. {@link Object#equals} and {@link Object#hashCode} are used to test for uniqueness.
*
* @param k0 the first key.
* @param v0 the first value.
* @param k1 the second key.
* @param v1 the second value.
* @return a persistent map containing the unique entries from the provided arguments in the order they appear.
*/
public static <K, V> ConstMap<K, V> mapOf(K k0, V v0, K k1, V v1) {
return Objects.equals(k1, k0) ?
new BasicMap1<K, V>(k0, v1) :
new BasicMapN<K, V>(new Object[] {k0, k1}, new Object[] {v0, v1});
}
/**
* Returns a ConstMap comprised of the unique entries from the provided arguments. Duplicate keys are not retained,
* but their associated values replace the values associated with existing keys, just as repeated calls to
* {@link Map#put} behaves. {@link Object#equals} and {@link Object#hashCode} are used to test for uniqueness.
*
* @return a persistent map containing the unique entries from the provided arguments in the order they appear.
*/
public static <K, V> ConstMap<K, V> mapOf(K k0, V v0, K k1, V v1, K k2, V v2) {
return condenseToMap(
unionInto(
EMPTY_OBJECT_ARRAY,
EMPTY_OBJECT_ARRAY,
new Object[] {k0, k1, k2},
new Object[] {v0, v1, v2}));
}
/**
* Returns a ConstMap comprised of the unique entries from the provided arguments. Duplicate keys are not retained,
* but their associated values replace the values associated with existing keys, just as repeated calls to
* {@link Map#put} behaves. {@link Object#equals} and {@link Object#hashCode} are used to test for uniqueness.
*
* @return a persistent map containing the unique entries from the provided arguments in the order they appear.
*/
public static <K, V> ConstMap<K, V> mapOf(K k0, V v0, K k1, V v1, K k2, V v2, K k3, V v3) {
return condenseToMap(
unionInto(
EMPTY_OBJECT_ARRAY,
EMPTY_OBJECT_ARRAY,
new Object[] {k0, k1, k2, k3},
new Object[] {v0, v1, v2, v3}));
}
/**
* Returns a ConstMap comprised of the unique entries from the provided arguments. Duplicate keys are not retained,
* but their associated values replace the values associated with existing keys, just as repeated calls to
* {@link Map#put} behaves. {@link Object#equals} and {@link Object#hashCode} are used to test for uniqueness.
*
* @return a persistent map containing the unique entries from the provided arguments in the order they appear.
*/
public static <K, V> ConstMap<K, V> mapOf(K k0, V v0, K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
return condenseToMap(
unionInto(
EMPTY_OBJECT_ARRAY,
EMPTY_OBJECT_ARRAY,
new Object[] {k0, k1, k2, k3, k4},
new Object[] {v0, v1, v2, v3, v4}));
}
/**
* Converts the specified arrays of keys and values into a ConstMap comprised of the unique entries represented
* by these arrays, where each index i represents the entry {@code {keys[i], values[i]}}. Duplicate keys are not
* retained, but their associated values replace the values associated with existing keys, just as repeated calls
* to {@link Map#put} behaves. Extra keys or values, when the arrays differ in length, are ignored.
* {@link Object#equals} and {@link Object#hashCode} are used to test for uniqueness.
*
* @param keys the map keys.
* @param values the map values.
* @return a persistent map containing the unique entries from the arrays in the order they appear.
* @throws NullPointerException if {@code keys} or {@code values} is null.
*/
public static <K, V> ConstMap<K, V> asMap(K[] keys, V[] values) {
return condenseToMap(unionInto(EMPTY_OBJECT_ARRAY, EMPTY_OBJECT_ARRAY, keys, values));
}
/**
* Converts the specified map into a ConstMap containing the unique entries encountered while iterating
* over the specified map. {@link Object#equals} and {@link Object#hashCode} are used to test for uniqueness.
*
* @param map the map.
* @return a persistent map containing the unique entries from the map in the order they appear.
* @throws NullPointerException if {@code map} is null.
*/
public static <K, V> ConstMap<K, V> asMap(Map<? extends K, ? extends V> map) {
if (map instanceof BasicConstMap && !(map instanceof BasicConstSortedMap)) {
@SuppressWarnings("unchecked") BasicConstMap<K, V> covariant = (BasicConstMap<K, V>)map;
return covariant; // The map is already a non-sorted ConstMap.
}
// Unfortunately, we must build the map from scratch. The provided map may have different uniqueness semantics.
MapColumns mc = copy(map);
return condenseToMap(unionInto(EMPTY_OBJECT_ARRAY, EMPTY_OBJECT_ARRAY, mc.keys, mc.values));
}
/**
* Instantiates the appropriate AbstractBasicConstMap implementation from the specified columns. The embedded
* columns <b>must be trusted</b>:
* <ol>
* <li>the arrays were defensively copied or are guaranteed to be invisible to external clients</li>
* <li>the component type is Object instead of a narrower type such as String or Integer</li>
* <li><i>the keys column contains only unique keys</i></li>
* </ol>
*
* @param trustedColumns the map columns.
* @return a size-appropriate implementation of AbstractBasicConstMap.
*/
static <K, V> BasicConstMap<K, V> condenseToMap(MapColumns trustedColumns) {
return condenseToMap(trustedColumns.keys, trustedColumns.values);
}
/**
* Instantiates the appropriate AbstractBasicConstMap implementation from the specified arrays of entries. The
* array references <b>must be trusted</b>:
* <ol>
* <li>the arrays were defensively copied or are guaranteed to be invisible to external clients</li>
* <li>the component type is Object instead of a narrower type such as String or Integer</li>
* <li><i>the keys array contains only unique keys</i></li>
* <li><i>the arrays are the same length</i></li>
* </ol>
*
* @param trustedKeys the Object array of keys.
* @param trustedValues the Object array of values.
* @return a size-appropriate implementation of AbstractBasicConstMap.
*/
static <K, V> BasicConstMap<K, V> condenseToMap(Object[] trustedKeys, Object[] trustedValues) {
assert trustedKeys.getClass() == Object[].class;
assert trustedValues.getClass() == Object[].class;
assert trustedKeys.length == trustedValues.length;
switch (trustedKeys.length) {
case 0: return BasicMap0.instance();
case 1: return new BasicMap1<>(trustedKeys[0], trustedValues[0]);
default: return new BasicMapN<>(trustedKeys, trustedValues);
}
}
// -----------------------------------------------------------------------------------------------------------------
// BasicConstSortedMap utility methods
/**
* Returns an empty ConstSortedMap with the ordering of the specified comparator.
*
* @param comparator the comparator, or null for {@link Comparable natural ordering}.
* @return a persistent empty sorted map.
*/
public static <K, V> ConstSortedMap<K, V> emptySortedMap(Comparator<? super K> comparator) {
return BasicSortedMap0.instance(comparator);
}
/**
* Returns a ConstSortedMap with a single entry and the ordering of the specified comparator.
*
* @param comparator the comparator, or null for {@link Comparable natural ordering}.
* @param k0 the key.
* @param v0 the value.
* @return a persistent sorted map containing the specified entry.
* @throws NullPointerException if the key is null and the comparator is null or does not permit nulls.
* @throws ClassCastException if the key is of a type not compatible for comparison.
*/
public static <K, V> ConstSortedMap<K, V> sortedMapOf(Comparator<? super K> comparator, K k0, V v0) {
return new BasicSortedMap1<>(comparator, checkType(comparator, k0), v0);
}
/**
* Returns a ConstSortedMap comprised of the unique entries from the provided arguments, having the ordering
* of the specified comparator. Duplicate keys are not retained, but their associated values replace the values
* associated with existing keys, just as repeated calls to {@link Map#put} behaves.
*
* @param comparator the comparator, or null for {@link Comparable natural ordering}.
* @param k0 the first key.
* @param v0 the first value.
* @param k1 the second key.
* @param v1 the second value.
* @return a persistent map containing the unique entries from the provided arguments.
* @throws NullPointerException if any key is null and the comparator is null or does not permit nulls.
* @throws ClassCastException if any key is of a type not compatible for comparison.
*/
public static <K, V> ConstSortedMap<K, V> sortedMapOf(
Comparator<? super K> comparator,
K k0, V v0,
K k1, V v1) {
int cmp = ObjectTools.compare(k0, k1, comparator);
return cmp == 0 ?
new BasicSortedMap1<K, V>(comparator, k0, v1) :
cmp < 0 ?
new BasicSortedMapN<K, V>(comparator, new Object[] {k0, k1}, new Object[] {v0, v1}) :
new BasicSortedMapN<K, V>(comparator, new Object[] {k1, k0}, new Object[] {v1, v0});
}
/**
* Returns a ConstSortedMap comprised of the unique entries from the provided arguments, having the ordering
* of the specified comparator. Duplicate keys are not retained, but their associated values replace the values
* associated with existing keys, just as repeated calls to {@link Map#put} behaves.
*
* @param comparator the comparator, or null for {@link Comparable natural ordering}.
* @return a persistent map containing the unique entries from the provided arguments.
* @throws NullPointerException if any key is null and the comparator is null or does not permit nulls.
* @throws ClassCastException if any key is of a type not compatible for comparison.
*/
public static <K, V> ConstSortedMap<K, V> sortedMapOf(
Comparator<? super K> comparator,
K k0, V v0,
K k1, V v1,
K k2, V v2) {
return condenseToSortedMap(
comparator,
unionInto(
EMPTY_OBJECT_ARRAY,
EMPTY_CLASS_ARRAY,
new Object[] {k0, k1, k2},
new Object[] {v0, v1, v2},
comparator));
}
/**
* Returns a ConstSortedMap comprised of the unique entries from the provided arguments, having the ordering
* of the specified comparator. Duplicate keys are not retained, but their associated values replace the values
* associated with existing keys, just as repeated calls to {@link Map#put} behaves.
*
* @param comparator the comparator, or null for {@link Comparable natural ordering}.
* @return a persistent map containing the unique entries from the provided arguments.
* @throws NullPointerException if any key is null and the comparator is null or does not permit nulls.
* @throws ClassCastException if any key is of a type not compatible for comparison.
*/
public static <K, V> ConstSortedMap<K, V> sortedMapOf(
Comparator<? super K> comparator,
K k0, V v0,
K k1, V v1,
K k2, V v2,
K k3, V v3) {
return condenseToSortedMap(
comparator,
unionInto(
EMPTY_OBJECT_ARRAY,
EMPTY_CLASS_ARRAY,
new Object[] {k0, k1, k2, k3},
new Object[] {v0, v1, v2, v3},
comparator));
}
/**
* Returns a ConstSortedMap comprised of the unique entries from the provided arguments, having the ordering
* of the specified comparator. Duplicate keys are not retained, but their associated values replace the values
* associated with existing keys, just as repeated calls to {@link Map#put} behaves.
*
* @param comparator the comparator, or null for {@link Comparable natural ordering}.
* @return a persistent map containing the unique entries from the provided arguments.
* @throws NullPointerException if any key is null and the comparator is null or does not permit nulls.
* @throws ClassCastException if any key is of a type not compatible for comparison.
*/
public static <K, V> ConstSortedMap<K, V> sortedMapOf(
Comparator<? super K> comparator,
K k0, V v0,
K k1, V v1,
K k2, V v2,
K k3, V v3,
K k4, V v4) {
return condenseToSortedMap(
comparator,
unionInto(
EMPTY_OBJECT_ARRAY,
EMPTY_CLASS_ARRAY,
new Object[] {k0, k1, k2, k3, k4},
new Object[] {v0, v1, v2, v3, v4},
comparator));
}
/**
* Converts the specified arrays of keys and values into a ConstSortedMap comprised of the unique entries
* represented by these arrays, where each index i represents the entry {@code {keys[i], values[i]}}, and having
* the ordering of the specified comparator. Duplicate keys are not retained, but their associated values replace
* the values associated with existing keys, just as repeated calls to {@link Map#put} behaves. Extra keys or
* values, when the arrays differ in length, are ignored.
*
* @param comparator the comparator, or null for {@link Comparable natural ordering}.
* @param keys the map keys.
* @param values the map values.
* @return a persistent sorted map containing the unique entries from the arrays.
* @throws NullPointerException if any key is null and the comparator is null or does not permit nulls, or if
* the {@code keys} or {@code values} array is null.
* @throws ClassCastException if any key is of a type not compatible for comparison.
*/
public static <K, V> ConstSortedMap<K, V> asSortedMap(Comparator<? super K> comparator, K[] keys, V[] values) {
return condenseToSortedMap(
comparator,
unionInto(EMPTY_OBJECT_ARRAY, EMPTY_OBJECT_ARRAY, keys, values, comparator));
}
/**
* Converts the specified sorted map into a ConstSortedMap with the same entries and ordering.
*
* @param map the sorted map.
* @return a persistent sorted map containing the exact entries and ordering of the specified map.
* @throws NullPointerException if {@code map} is null.
*/
public static <K, V> ConstSortedMap<K, V> asSortedMap(SortedMap<K, V> map) {
if (map instanceof BasicConstSortedMap) {
return (BasicConstSortedMap<K, V>)map; // The map is already a ConstSortedMap.
}
return condenseToSortedMap(map.comparator(), copy(map));
}
/**
* Converts the specified map into a ConstSortedMap comprised of the unique entries from the map having the
* ordering of the specified comparator.
*
* @param comparator the comparator, or null for {@link Comparable natural ordering}.
* @param map the map.
* @return a persistent sorted map containing the unique entries from the map in sorted order.
* @throws NullPointerException if any key is null and the comparator is null or does not permit nulls, or if
* the {@code map} is null.
* @throws ClassCastException if any key is of a type not compatible for comparison.
*/
public static <K, V> ConstSortedMap<K, V> asSortedMap(
Comparator<? super K> comparator,
Map<? extends K, ? extends V> map) {
if (map instanceof SortedMap) {
@SuppressWarnings("unchecked") SortedMap<K, V> covariant = (SortedMap<K, V>)map;
if (Objects.equals(comparator, covariant.comparator())) {
return asSortedMap(covariant); // the map is already in the desired sorted order.
}
}
MapColumns mc = copy(map);
return condenseToSortedMap(
comparator,
unionInto(EMPTY_OBJECT_ARRAY, EMPTY_OBJECT_ARRAY, mc.keys, mc.values, comparator));
}
/**
* Instantiates the appropriate AbstractBasicConstSortedMap implementation from the specified columns. The
* embedded columns <b>must be trusted</b>:
* <ol>
* <li>the arrays were defensively copied or are guaranteed to be invisible to external clients</li>
* <li>the component type is Object instead of a narrower type such as String or Integer</li>
* <li><i>the keys column contains only unique keys</i></li>
* <li><i>the arrays are already sorted using the specified comparator</i></li>
* </ol>
*
* @param comparator the comparator, or null for {@link Comparable natural ordering}.
* @param trustedColumns the map columns.
* @return a size-appropriate implementation of AbstractBasicConstSortedMap.
*/
static <K, V> BasicConstSortedMap<K, V> condenseToSortedMap(
Comparator<? super K> comparator,
MapColumns trustedColumns) {
return condenseToSortedMap(comparator, trustedColumns.keys, trustedColumns.values);
}
/**
* Instantiates the appropriate AbstractBasicConstSortedMap implementation from the specified arrays of entries.
* The array references <b>must be trusted</b>:
* <ol>
* <li>the arrays were defensively copied or are guaranteed to be invisible to external clients</li>
* <li>the component type is Object instead of a narrower type such as String or Integer</li>
* <li><i>the keys array contains only unique keys</i></li>
* <li><i>the arrays are already sorted using the specified comparator and are the same length</i></li>
* </ol>
*
* @param comparator the comparator, or null for {@link Comparable natural ordering}.
* @param trustedKeys the Object array of keys.
* @param trustedValues the Object array of values.
* @return a size-appropriate implementation of AbstractBasicConstSortedMap.
*/
static <K, V> BasicConstSortedMap<K, V> condenseToSortedMap(
Comparator<? super K> comparator,
Object[] trustedKeys,
Object[] trustedValues) {
assert trustedKeys.getClass() == Object[].class;
assert trustedValues.getClass() == Object[].class;
assert trustedKeys.length == trustedValues.length;
switch (trustedKeys.length) {
case 0: return BasicSortedMap0.instance(comparator);
case 1: return new BasicSortedMap1<>(comparator, trustedKeys[0], trustedValues[0]);
default: return new BasicSortedMapN<>(comparator, trustedKeys, trustedValues);
}
}
}