/** * Copyright (c) 2015 The original author or authors * * 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 org.reveno.atp.utils; import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import java.io.Serializable; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Supplier; @SuppressWarnings({ "unchecked", "rawtypes" }) public abstract class MapUtils { public static Map<String, Object> map(Object... objs) { if (objs.length % 2 != 0) { throw new IllegalArgumentException("Input map should contain even count of arguments."); } Map<String, Object> map = new LinkedHashMap<>(); for (int i = 0; i < objs.length; i += 2) { map.put((String) objs[i], objs[i + 1]); } return map; } public static SimpleMap<Class<?>, Long2ObjectLinkedOpenHashMap<Object>> linkedFastRepo() { return new SimpleMap<Class<?>, Long2ObjectLinkedOpenHashMap<Object>>((Supplier & Serializable)Long2ObjectLinkedOpenHashMap::new); } public static SimpleMap<Class<?>, Long2ObjectOpenHashMap<Object>> fastRepo() { return new SimpleMap<Class<?>, Long2ObjectOpenHashMap<Object>>((Supplier & Serializable)Long2ObjectOpenHashMap::new); } public static SimpleMap<Class<?>, Long2ObjectOpenHashMap<Object>> fastRepo(int capacity, float loadFactor) { return new SimpleMap<Class<?>, Long2ObjectOpenHashMap<Object>>(capacity, loadFactor, (Supplier & Serializable)() -> new Long2ObjectOpenHashMap<>(capacity, loadFactor)); } public static <T> ConcurrentMapOfMap<Class<?>, Long, T> concurrentRepositoryMap() { return new ConcurrentMapOfMap<>(); } public static <T> ConcurrentMapOfMap<Class<?>, Long, T> concurrentRepositoryMap(int capacity, float loadFactor) { return new ConcurrentMapOfMap<>(capacity, loadFactor); } public static <T> MapOfMap<Class<?>, Long, T> repositoryMap() { return new MapOfMap<>(); } public static <T> MapOfList<Class<?>, T> repositoryList() { return new MapOfList<>(); } public static <T> MapOfSet<Class<?>, T> repositorySet() { return new MapOfSet<>(); } public static SimpleMap<Class<?>, LongOpenHashSet> fastSetRepo() { return new SimpleMap<>(LongOpenHashSet::new); } public static <T> MapOfSet<Class<?>, Long> repositoryLinkedSet() { return new MapOfSet<>(LongLinkedOpenHashSet::new, new LinkedHashMap<>()); } public static class SimpleMap<K, V> extends HashMap<K, V> implements Map<K, V> { private static final long serialVersionUID = 1L; private final Supplier<V> supplier; public SimpleMap(int capacity, float loadFactor, Supplier<V> supplier) { super(capacity, loadFactor); this.supplier = supplier; } public SimpleMap(Supplier<V> supplier) { this.supplier = supplier; } @Override public V get(Object key) { return safeGet((K) key); } public V safeGet(K key) { V result = super.get(key); if (result == null) this.put(key, (result = supplier.get())); return result; } } public static class MapOfMap<T, U, M> extends HashMap<T, Map<U, M>> implements Map<T, Map<U, M>> { private static final long serialVersionUID = 8689714774124849342L; @Override public Map<U, M> get(Object key) { return safeGet((T) key); } public Map<U, M> safeGet(T key) { Map<U, M> result = super.get(key); if (result == null) this.put(key, (result = new HashMap<>())); return result; } } public static class ConcurrentMapOfMap<T, U, M> extends ConcurrentHashMap<T, Map<U, M>> implements Map<T, Map<U, M>> { private static final long serialVersionUID = 8689714774124849342L; public ConcurrentMapOfMap() { } public ConcurrentMapOfMap(int capacity, float loadFactor) { super(capacity, loadFactor); } @Override public Map<U, M> get(Object key) { return safeGet((T) key); } public Map<U, M> safeGet(T key) { return super.computeIfAbsent(key, k -> new ConcurrentHashMap<>()); } } public static class MapOfList<T, U> extends HashMap<T, List<U>> implements Map<T, List<U>> { private static final long serialVersionUID = -5096309465438907445L; @Override public List<U> get(Object key) { return safeGet((T) key); } public List<U> safeGet(T key) { List<U> result = super.get(key); if (result == null) this.put(key, (result = new ArrayList<>())); return result; } } public static class MapOfSet<T, U> implements Map<T, Set<U>> { protected final Supplier<Set<U>> setCreator; protected final Map<T, Set<U>> underlying; @Override public Set<U> get(Object key) { return safeGet((T) key); } public Set<U> safeGet(T key) { Set<U> result = underlying.get(key); if (result == null) this.put(key, (result = setCreator.get())); return result; } public MapOfSet() { this.setCreator = HashSet::new; this.underlying = new HashMap<>(); } public MapOfSet(Supplier<Set<U>> setCreator, Map<T, Set<U>> underlying) { this.setCreator = setCreator; this.underlying = underlying; } @Override public int size() { return underlying.size(); } @Override public boolean isEmpty() { return underlying.isEmpty(); } @Override public boolean containsKey(Object key) { return underlying.containsKey(key); } @Override public boolean containsValue(Object value) { return underlying.containsValue(value); } @Override public Set<U> put(T key, Set<U> value) { return underlying.put(key, value); } @Override public Set<U> remove(Object key) { return underlying.remove(key); } @Override public void putAll(Map<? extends T, ? extends Set<U>> m) { this.putAll(m); } @Override public void clear() { underlying.clear(); } @Override public Set<T> keySet() { return underlying.keySet(); } @Override public Collection<Set<U>> values() { return underlying.values(); } @Override public Set<java.util.Map.Entry<T, Set<U>>> entrySet() { return underlying.entrySet(); } } }