/*
* Copyright (c) 2013-2017 Cinchapi Inc.
*
* 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 com.cinchapi.concourse.util;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import com.google.common.base.Supplier;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
/**
* Map based utility methods that are not found in the Guava
* {@link com.google.collect.Maps} utility class.
*
* @author Jeff Nelson
*/
public final class TMaps {
/**
* Return a map that has all the data in {@code map} in naturally sorted
* order.
*
* @param map
* @return the sorted map
*/
public static <K extends Comparable<K>, V> SortedMap<K, V> asSortedMap(
Map<K, V> map) {
if(map instanceof SortedMap) {
return (SortedMap<K, V>) map;
}
else {
return new TreeMap<K, V>(map);
}
}
/**
* Return a set that contains all of the keys from the {@code entrySet}.
*
* @param entrySet
* @return the keySet
*/
public static <K, V> Set<K> extractKeysFromEntrySet(
Collection<Entry<K, V>> entrySet) {
Set<K> keys = entrySet instanceof SortedSet ? new TreeSet<K>(
Comparators.<K> naturalOrArbitrary()) : Sets.<K> newHashSet();
for (Entry<K, V> entry : entrySet) {
keys.add(entry.getKey());
}
return keys;
}
/**
* Return a collection that contains all of the values from the
* {@code entrySet}/
*
* @param entrySet
* @return the values collection
*/
public static <K, V> Collection<V> extractValuesFromEntrySet(
Collection<Entry<K, V>> entrySet) {
List<V> values = Lists.newArrayList();
for (Entry<K, V> entry : entrySet) {
values.add(entry.getValue());
}
return values;
}
/**
* Return a map that contains all the entries in the {@code entrySet}.
*
* @param entrySet
* @return the populated map
*/
public static <K, V> Map<K, V> fromEntrySet(Collection<Entry<K, V>> entrySet) {
// TODO: Find a better way to do this. Perhaps use reflection to place
// the entires directly in the map...
Map<K, V> map = entrySet instanceof SortedSet ? new TreeMap<K, V>(
Comparators.<K> naturalOrArbitrary()) : Maps
.<K, V> newHashMap();
for (Entry<K, V> entry : entrySet) {
map.put(entry.getKey(), entry.getValue());
}
return map;
}
/**
* Return <em>mutable</em>, insertion-ordered {@link LinkedHashMap} instance
* with enough room to fit {@code capacity} items.
*
* <p>
* Use this method over
* {@link com.google.common.collect.Maps#newLinkedHashMap()} when the size
* of the map is known in advance and we are being careful to not oversize
* collections.
* </p>
*
* @param capacity the initial capacity
* @return a new, empty {@link LinkedHashMap}
*/
public static <K, V> Map<K, V> newLinkedHashMapWithCapacity(int capacity) {
return new LinkedHashMap<K, V>(capacity);
}
/**
* The same as
* {@link java.util.concurrent.ConcurrentMap#putIfAbsent(Object, Object))}
* but for non concurrent maps. This method is purely syntactic sugar.
*
* @param map the map to modify
* @param key the key to lookup
* @param value the value to associate with {@code key} if no other
* currently exists
* @return the value that is already associated with {@code key} if it
* exists, otherwise {@code value}
*/
public static <K, V> V putIfAbsent(Map<K, V> map, K key, V value) {
V stored = map.get(key);
if(stored == null) {
stored = value;
map.put(key, value);
}
return stored;
}
/**
* Use the {@code supplier} to provide a value to associate with the
* {@code key} in the {@code map} if there isn't currently an associated
* value.
*
* @param map the map to modify
* @param key the key to lookup and/or associate
* @param supplier the {@link Supplier} that lazily produces the value to
* associate if no other value currently exists
* @return the value that is already associated with {@code key} if it
* exists, otherwise the supplied value
*/
public static <K, V> V supplyIfAbsent(Map<K, V> map, K key,
Supplier<V> supplier) {
V stored = map.get(key);
if(stored == null) {
stored = supplier.get();
map.put(key, stored);
}
return stored;
}
private TMaps() {/* noop */}
}