package com.github.czyzby.kiwi.util.gdx.collection;
import com.badlogic.gdx.utils.ArrayMap;
import com.badlogic.gdx.utils.Disposable;
import com.badlogic.gdx.utils.IdentityMap;
import com.badlogic.gdx.utils.ObjectMap;
import com.badlogic.gdx.utils.OrderedMap;
import com.github.czyzby.kiwi.util.gdx.asset.lazy.provider.ObjectProvider;
import com.github.czyzby.kiwi.util.gdx.collection.disposable.DisposableObjectMap;
import com.github.czyzby.kiwi.util.gdx.collection.immutable.ImmutableObjectMap;
import com.github.czyzby.kiwi.util.gdx.collection.lazy.LazyObjectMap;
/** Common LibGDX maps utilities, somewhat inspired by Guava.
*
* @author MJ */
public class GdxMaps {
private GdxMaps() {
}
/** @return an empty, new object map. */
public static <Key, Value> ObjectMap<Key, Value> newObjectMap() {
return new ObjectMap<Key, Value>();
}
/** @return a new object map with the passed values. */
public static <Key, Value> ObjectMap<Key, Value> newObjectMap(final ObjectMap<? extends Key, ? extends Value> map) {
return new ObjectMap<Key, Value>(map);
}
/** @param keyAndValues pairs of keys and values. Each value has to be proceeded by a key.
* @return a new object map with the given values. Not fail-fast - be careful when passing arguments, or it might
* result in unexpected map values. */
@SuppressWarnings("unchecked")
public static <Key, Value> ObjectMap<Key, Value> newObjectMap(final Object... keyAndValues) {
if (keyAndValues.length % 2 != 0) {
throw new IllegalArgumentException("Total number of keys and values has to be even.");
}
final ObjectMap<Key, Value> map = new ObjectMap<Key, Value>();
for (int pairIndex = 0; pairIndex < keyAndValues.length; pairIndex++) {
map.put((Key) keyAndValues[pairIndex], (Value) keyAndValues[++pairIndex]);
}
return map;
}
/** @return an empty, new ordered map. */
public static <Key, Value> OrderedMap<Key, Value> newOrderedMap() {
return new OrderedMap<Key, Value>();
}
/** @return a new ordered map with the passed values. */
public static <Key, Value> OrderedMap<Key, Value> newOrderedMap(
final ObjectMap<? extends Key, ? extends Value> map) {
return new OrderedMap<Key, Value>(map);
}
/** @param keyAndValues pairs of keys and values. Each value has to be proceeded by a key.
* @return a new ordered map with the given values. Not fail-fast - be careful when passing arguments, or it might
* result in unexpected map values. */
@SuppressWarnings("unchecked")
public static <Key, Value> OrderedMap<Key, Value> newOrderedMap(final Object... keyAndValues) {
if (keyAndValues.length % 2 != 0) {
throw new IllegalArgumentException("Total number of keys and values has to be even.");
}
final OrderedMap<Key, Value> map = new OrderedMap<Key, Value>();
for (int pairIndex = 0; pairIndex < keyAndValues.length; pairIndex++) {
map.put((Key) keyAndValues[pairIndex], (Value) keyAndValues[++pairIndex]);
}
return map;
}
/** @return an empty, new identity map. */
public static <Key, Value> IdentityMap<Key, Value> newIdentityMap() {
return new IdentityMap<Key, Value>();
}
/** @return a new identity map with the passed values. */
public static <Key, Value> IdentityMap<Key, Value> newIdentityMap(
final IdentityMap<? extends Key, ? extends Value> map) {
return new IdentityMap<Key, Value>(map);
}
/** @param keyAndValues pairs of keys and values. Each value has to be proceeded by a key.
* @return a new identity map with the given values. Not fail-fast - be careful when passing arguments, or it might
* result in unexpected map values. */
@SuppressWarnings("unchecked")
public static <Key, Value> IdentityMap<Key, Value> newIdentityMap(final Object... keyAndValues) {
if (keyAndValues.length % 2 != 0) {
throw new IllegalArgumentException("Total number of keys and values has to be even.");
}
final IdentityMap<Key, Value> map = new IdentityMap<Key, Value>();
for (int pairIndex = 0; pairIndex < keyAndValues.length; pairIndex++) {
map.put((Key) keyAndValues[pairIndex], (Value) keyAndValues[++pairIndex]);
}
return map;
}
/** @return an empty, new array map. */
public static <Key, Value> ArrayMap<Key, Value> newArrayMap() {
return new ArrayMap<Key, Value>();
}
/** @return a new array map with the passed values. */
public static <Key, Value> ArrayMap<Key, Value> newArrayMap(final ArrayMap<? extends Key, ? extends Value> map) {
return new ArrayMap<Key, Value>(map);
}
/** @return an empty, new array map. */
public static <Key, Value> ArrayMap<Key, Value> newArrayMap(final boolean ordered) {
return new ArrayMap<Key, Value>(ordered, 16); // default capacity
}
/** @return an empty, new typed array map. */
public static <Key, Value> ArrayMap<Key, Value> newArrayMap(final Class<Key> keyType,
final Class<Value> valueType) {
return new ArrayMap<Key, Value>(keyType, valueType);
}
/** @param keyAndValues pairs of keys and values. Each value has to be proceeded by a key.
* @return a new array map with the given values. Not fail-fast - be careful when passing arguments, or it might
* result in unexpected map values. */
@SuppressWarnings("unchecked")
public static <Key, Value> ArrayMap<Key, Value> newArrayMap(final Object... keyAndValues) {
if (keyAndValues.length % 2 != 0) {
throw new IllegalArgumentException("Total number of keys and values has to be even.");
}
final ArrayMap<Key, Value> map = new ArrayMap<Key, Value>();
for (int pairIndex = 0; pairIndex < keyAndValues.length; pairIndex++) {
map.put((Key) keyAndValues[pairIndex], (Value) keyAndValues[++pairIndex]);
}
return map;
}
/** @param keyAndValues pairs of keys and values. Each value has to be proceeded by a key.
* @return a new typed array map with the given values. Not fail-fast - be careful when passing arguments, or it
* might result in unexpected map values. */
@SuppressWarnings("unchecked")
public static <Key, Value> ArrayMap<Key, Value> newArrayMap(final Class<Key> keyType, final Class<Value> valueType,
final Object... keyAndValues) {
if (keyAndValues.length % 2 != 0) {
throw new IllegalArgumentException("Total number of keys and values has to be even.");
}
final ArrayMap<Key, Value> map = new ArrayMap<Key, Value>(keyType, valueType);
for (int pairIndex = 0; pairIndex < keyAndValues.length; pairIndex++) {
map.put((Key) keyAndValues[pairIndex], (Value) keyAndValues[++pairIndex]);
}
return map;
}
/** @return a new disposable object map with the passed values. */
public static <Key, Value extends Disposable> DisposableObjectMap<Key, Value> toDisposable(
final ObjectMap<? extends Key, ? extends Value> map) {
return new DisposableObjectMap<Key, Value>(map);
}
/** @return a new immutable map with the passed values. */
public static <Key, Value> ImmutableObjectMap<Key, Value> toImmutable(
final ObjectMap<? extends Key, ? extends Value> map) {
return new ImmutableObjectMap<Key, Value>(map);
}
/** @return a new ordered map with the passed values. */
public static <Key, Value> OrderedMap<Key, Value> toOrdered(final ObjectMap<? extends Key, ? extends Value> map) {
return new OrderedMap<Key, Value>(map);
}
/** @param provider creates new object on get(key) calls if the key is not present in the map.
* @return a new ordered map with the passed values. */
public static <Key, Value> LazyObjectMap<Key, Value> toLazy(final ObjectMap<? extends Key, ? extends Value> map,
final ObjectProvider<? extends Value> provider) {
return new LazyObjectMap<Key, Value>(provider, map);
}
/** @return true if map is null or has no elements. */
public static boolean isEmpty(final ObjectMap<?, ?> map) {
return map == null || map.size == 0;
}
/** @return true if map is not null and has at least one element. */
public static boolean isNotEmpty(final ObjectMap<?, ?> map) {
return map != null && map.size > 0;
}
/** Puts a value with the given key in the passed map, provided that the passed key isn't already present in the
* map.
*
* @param map may contain a value associated with the key.
* @param key map key.
* @param value map value to add.
* @return value associated with the key in the map (recently added or the previous one). */
public static <Key, Value> Value putIfAbsent(final ObjectMap<Key, Value> map, final Key key, final Value value) {
if (!map.containsKey(key)) {
map.put(key, value);
return value;
}
return map.get(key);
}
/** @param maps will all be cleared, with an additional null-check before the clearing. */
public static void clearAll(final ObjectMap<?, ?>... maps) {
for (final ObjectMap<?, ?> map : maps) {
if (map != null) {
map.clear();
}
}
}
/** @param maps all contained maps will all be cleared, with an additional null-check before the clearing. */
public static void clearAll(final Iterable<ObjectMap<?, ?>> maps) {
for (final ObjectMap<?, ?> map : maps) {
if (map != null) {
map.clear();
}
}
}
/** Static utility for accessing {@link ObjectMap#size} variable (which is kind of ugly, since it allows to easily
* modify and damage internal collection data). Performs null check.
*
* @param map its size will be checked. Can be null.
* @return current size of the passed map. 0 if map is empty or null. */
public static int sizeOf(final ObjectMap<?, ?> map) {
if (map == null) {
return 0;
}
return map.size;
}
}