001/*-------------------------------------------------------------------------+ 002| | 003| Copyright 2005-2011 The ConQAT Project | 004| | 005| Licensed under the Apache License, Version 2.0 (the "License"); | 006| you may not use this file except in compliance with the License. | 007| You may obtain a copy of the License at | 008| | 009| http://www.apache.org/licenses/LICENSE-2.0 | 010| | 011| Unless required by applicable law or agreed to in writing, software | 012| distributed under the License is distributed on an "AS IS" BASIS, | 013| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 014| See the License for the specific language governing permissions and | 015| limitations under the License. | 016+-------------------------------------------------------------------------*/ 017package org.conqat.lib.commons.collections; 018 019import java.util.Collection; 020import java.util.Map; 021import java.util.Set; 022 023import org.conqat.lib.commons.assertion.CCSMAssert; 024 025/** 026 * A hybrid map is a map which starts with one map implementation, but switches 027 * to another one after a certain size is reached. 028 */ 029public abstract class HybridMapBase<K, V> implements Map<K, V> { 030 031 /** The inner map. */ 032 private Map<K, V> map; 033 034 /** Constructor. */ 035 protected HybridMapBase(Map<K, V> initialMap) { 036 CCSMAssert.isNotNull(initialMap); 037 map = initialMap; 038 } 039 040 /** 041 * Template method for deciding that a switch of map implementation should 042 * be performed before the next insertion. This will be called right before 043 * each put operation. If this returns true, the new map implementation is 044 * obtained via {@link #obtainNewMap()} and all values are copied. 045 * 046 * @param map 047 * the currently used map. 048 */ 049 protected abstract boolean shouldSwitch(Map<K, V> map); 050 051 /** 052 * Template method for obtaining a new map implementation after 053 * {@link #shouldSwitch(Map)} returned true. 054 */ 055 protected abstract Map<K, V> obtainNewMap(); 056 057 /** {@inheritDoc} */ 058 @Override 059 public void clear() { 060 map.clear(); 061 } 062 063 /** {@inheritDoc} */ 064 @Override 065 public boolean containsKey(Object key) { 066 return map.containsKey(key); 067 } 068 069 /** {@inheritDoc} */ 070 @Override 071 public boolean containsValue(Object value) { 072 return map.containsValue(value); 073 } 074 075 /** {@inheritDoc} */ 076 @Override 077 public Set<java.util.Map.Entry<K, V>> entrySet() { 078 return map.entrySet(); 079 } 080 081 /** {@inheritDoc} */ 082 @Override 083 public V get(Object key) { 084 return map.get(key); 085 } 086 087 /** {@inheritDoc} */ 088 @Override 089 public boolean isEmpty() { 090 return map.isEmpty(); 091 } 092 093 /** {@inheritDoc} */ 094 @Override 095 public Set<K> keySet() { 096 return map.keySet(); 097 } 098 099 /** {@inheritDoc} */ 100 @Override 101 public V put(K key, V value) { 102 if (shouldSwitch(map)) { 103 Map<K, V> oldMap = map; 104 map = obtainNewMap(); 105 map.putAll(oldMap); 106 } 107 108 return map.put(key, value); 109 } 110 111 /** {@inheritDoc} */ 112 @Override 113 public void putAll(Map<? extends K, ? extends V> m) { 114 // must use explicit loop instead of putAll, as otherwise switching of 115 // the map implementation will not happen 116 for (java.util.Map.Entry<? extends K, ? extends V> entry : m.entrySet()) { 117 put(entry.getKey(), entry.getValue()); 118 } 119 } 120 121 /** {@inheritDoc} */ 122 @Override 123 public V remove(Object key) { 124 return map.remove(key); 125 } 126 127 /** {@inheritDoc} */ 128 @Override 129 public int size() { 130 return map.size(); 131 } 132 133 /** {@inheritDoc} */ 134 @Override 135 public Collection<V> values() { 136 return map.values(); 137 } 138 139 /** {@inheritDoc} */ 140 @Override 141 public String toString() { 142 return map.toString(); 143 } 144}