package org.sef4j.core.util; import java.lang.reflect.Array; import java.util.HashMap; import java.util.Map; import com.google.common.collect.ImmutableMap; public class CopyOnWriteUtils { // HashMap copy-on-write utilities // ------------------------------------------------------------------------ public static <K,V> HashMap<K,V> newWithPut(Map<K,V> src, K key, V value) { HashMap<K,V> res = new HashMap<K,V>(src.size() + 1); res.putAll(src); res.put(key, value); return res; } public static <K,V> HashMap<K,V> newWithRemove(Map<K,V> src, K key) { HashMap<K,V> res = new HashMap<K,V>(Math.max(0, src.size() - 1)); res.putAll(src); res.remove(key); return res; } // guava ImmutableMap copy-on-write utilities // ------------------------------------------------------------------------ public static <K,V> ImmutableMap<K,V> newWithPut(ImmutableMap<K,V> src, K key, V value) { return new ImmutableMap.Builder<K,V>() .putAll(src).put(key, value).build(); } public static <K,V> ImmutableMap<K,V> newWithRemove(ImmutableMap<K,V> src, K key) { HashMap<K,V> res = new HashMap<K,V>(Math.max(0, src.size() - 1)); res.putAll(src); res.remove(key); return ImmutableMap.copyOf(res); } // native Array copy-on-write utilities (... need extra Class "componentType" argument for handling empty array from generic class ctors!!) // ------------------------------------------------------------------------ @SuppressWarnings("unchecked") public static <T> T[] newArray(Class<T> clss, int length) { return (T[]) Array.newInstance(clss, length); } public static <T> T[] newWithAdd(Class<T> clss, T[] array, T element) { int len = array.length; T[] res = newArray(clss, len + 1); System.arraycopy(array, 0, res, 0, len); res[len] = element; return res; } public static <T> T[] newWithRemove(Class<T> clss, T[] array, T element) { int index = indexOf(array, element); if (index == -1) { return array; // no need to clone... assume immutable } return newWithRemoveAt(clss ,array, index); } public static <T> T[] newWithRemoveAt(Class<T> clss, T[] array, int index) { int length = array.length; if (index < 0 || index >= length) { throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + length); } T[] result = (T[]) newArray(clss, length - 1); System.arraycopy(array, 0, result, 0, index); if (index < length - 1) { System.arraycopy(array, index + 1, result, index, length - index - 1); } return result; } public static <T> T[] newWithMerge(Class<T> clss, T[] left, T[] right) { int len = left.length + right.length; T[] res = newArray(clss, len); System.arraycopy(left, 0, res, 0, left.length); System.arraycopy(right, 0, res, left.length, right.length); return res; } public static <T> int indexOf(T[] array, T objectToFind) { if (array == null) { return -1; } if (objectToFind == null) { for (int i = 0; i < array.length; i++) { if (array[i] == null) { return i; } } } else { for (int i = 0; i < array.length; i++) { if (objectToFind.equals(array[i])) { return i; } } } return -1; } }