Java tutorial
/* * Copyright (c) 2002-2008 "Neo Technology," * Network Engine for Objects in Lund AB [http://neotechnology.com] * * This file is part of Neo4j. * * Neo4j is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; public class ArrayMap<K, V> { private ArrayEntry<K, V>[] arrayEntries; private volatile int arrayCount = 0; private int toMapThreshold = 5; private Map<K, V> propertyMap = null; private final boolean useThreadSafeMap; private boolean switchBackToArray = false; public ArrayMap() { useThreadSafeMap = false; arrayEntries = new ArrayEntry[toMapThreshold]; } public ArrayMap(int mapThreshold, boolean threadSafe, boolean shrinkToArray) { this.toMapThreshold = mapThreshold; this.useThreadSafeMap = threadSafe; this.switchBackToArray = shrinkToArray; arrayEntries = new ArrayEntry[toMapThreshold]; } public void put(K key, V value) { if (useThreadSafeMap) { synchronizedPut(key, value); return; } for (int i = 0; i < arrayCount; i++) { if (arrayEntries[i].getKey().equals(key)) { arrayEntries[i].setNewValue(value); return; } } if (arrayCount != -1) { if (arrayCount < arrayEntries.length) { arrayEntries[arrayCount++] = new ArrayEntry<K, V>(key, value); } else { propertyMap = new HashMap<K, V>(); for (int i = 0; i < arrayCount; i++) { propertyMap.put(arrayEntries[i].getKey(), arrayEntries[i].getValue()); } arrayCount = -1; propertyMap.put(key, value); } } else { propertyMap.put(key, value); } } private synchronized void synchronizedPut(K key, V value) { for (int i = 0; i < arrayCount; i++) { if (arrayEntries[i].getKey().equals(key)) { arrayEntries[i].setNewValue(value); return; } } if (arrayCount != -1) { if (arrayCount < arrayEntries.length) { arrayEntries[arrayCount++] = new ArrayEntry<K, V>(key, value); } else { propertyMap = new ConcurrentHashMap<K, V>(); for (int i = 0; i < arrayCount; i++) { propertyMap.put(arrayEntries[i].getKey(), arrayEntries[i].getValue()); } arrayEntries = null; arrayCount = -1; propertyMap.put(key, value); } } else { propertyMap.put(key, value); } } public V get(K key) { if (key == null) { return null; } if (useThreadSafeMap) { return synchronizedGet(key); } int count = arrayCount; for (int i = 0; i < count; i++) { if (key.equals(arrayEntries[i].getKey())) { return arrayEntries[i].getValue(); } } if (arrayCount == -1) { return propertyMap.get(key); } return null; } private synchronized V synchronizedGet(K key) { for (int i = 0; i < arrayCount; i++) { if (key.equals(arrayEntries[i].getKey())) { return arrayEntries[i].getValue(); } } if (arrayCount == -1) { return propertyMap.get(key); } return null; } private synchronized V synchronizedRemove(K key) { for (int i = 0; i < arrayCount; i++) { if (arrayEntries[i].getKey().equals(key)) { V removedProperty = arrayEntries[i].getValue(); arrayCount--; System.arraycopy(arrayEntries, i + 1, arrayEntries, i, arrayCount - i); return removedProperty; } } if (arrayCount == -1) { V value = propertyMap.remove(key); if (switchBackToArray && propertyMap.size() < toMapThreshold) { arrayEntries = new ArrayEntry[toMapThreshold]; int tmpCount = 0; for (Entry<K, V> entry : propertyMap.entrySet()) { arrayEntries[tmpCount++] = new ArrayEntry<K, V>(entry.getKey(), entry.getValue()); } arrayCount = tmpCount; } return value; } return null; } public V remove(K key) { if (useThreadSafeMap) { return synchronizedRemove(key); } for (int i = 0; i < arrayCount; i++) { if (arrayEntries[i].getKey().equals(key)) { V removedProperty = arrayEntries[i].getValue(); arrayCount--; System.arraycopy(arrayEntries, i + 1, arrayEntries, i, arrayCount - i); return removedProperty; } } if (arrayCount == -1) { V value = propertyMap.remove(key); if (switchBackToArray && propertyMap.size() < toMapThreshold) { arrayEntries = new ArrayEntry[toMapThreshold]; int tmpCount = 0; for (Entry<K, V> entry : propertyMap.entrySet()) { arrayEntries[tmpCount++] = new ArrayEntry<K, V>(entry.getKey(), entry.getValue()); } arrayCount = tmpCount; } return value; } return null; } static class ArrayEntry<K, V> implements Entry<K, V> { private K key; private V value; ArrayEntry(K key, V value) { this.key = key; this.value = value; } public K getKey() { return key; } public V getValue() { return value; } void setNewValue(V value) { this.value = value; } public V setValue(V value) { V oldValue = value; this.value = value; return oldValue; } } public Iterable<K> keySet() { if (arrayCount == -1) { return propertyMap.keySet(); } List<K> keys = new LinkedList<K>(); for (int i = 0; i < arrayCount; i++) { keys.add(arrayEntries[i].getKey()); } return keys; } public Iterable<V> values() { if (arrayCount == -1) { return propertyMap.values(); } List<V> values = new LinkedList<V>(); for (int i = 0; i < arrayCount; i++) { values.add(arrayEntries[i].getValue()); } return values; } public Set<Entry<K, V>> entrySet() { if (arrayCount == -1) { return propertyMap.entrySet(); } Set<Entry<K, V>> entries = new HashSet<Entry<K, V>>(); for (int i = 0; i < arrayCount; i++) { entries.add(arrayEntries[i]); } return entries; } public int size() { if (arrayCount != -1) { return arrayCount; } return propertyMap.size(); } public void clear() { if (arrayCount != -1) { arrayCount = 0; } else { propertyMap.clear(); } } }