001: /*
002: * Copyright 2003 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package velosurf.util;
018:
019: import java.util.ArrayList;
020: import java.util.HashMap;
021: import java.util.Iterator;
022: import java.util.List;
023: import java.util.Map;
024: import java.util.Set;
025:
026: /**
027: * A MultiMap is a Map allowing multiple occurrences of keys.
028: *
029: * @author Mark Richters
030: * @see java.util.Map
031: */
032:
033: public class HashMultiMap implements MultiMap {
034: /** inner map.
035: */
036: private Map map; // (Object key -> List values)
037: /** total number of values.
038: */
039: private transient int sizeAll;
040:
041: /** build a new HashMultiMap.
042: */
043: public HashMultiMap() {
044: map = new HashMap();
045: }
046:
047: // Query Operations
048:
049: /**
050: * Returns the number of values in this multimap.
051: *
052: * @return totla number of values
053: */
054: public int size() {
055: return sizeAll;
056: }
057:
058: /**
059: * Returns <tt>true</tt> if this multimap contains no mappings.
060: *
061: * @return empty status
062: */
063: public boolean isEmpty() {
064: return sizeAll == 0;
065: }
066:
067: /**
068: * Returns <tt>true</tt> if this multimap contains a mapping for
069: * the specified key.
070: *
071: * @param key
072: */
073: public boolean containsKey(Object key) {
074: return map.containsKey(key);
075: }
076:
077: /**
078: * Returns <tt>true</tt> if this multimap maps one or more keys to
079: * the specified value.
080: */
081: public boolean containsValue(Object value) {
082: Iterator it = map.values().iterator();
083: while (it.hasNext()) {
084: List l = (List) it.next();
085: if (l.contains(value))
086: return true;
087: }
088: return false;
089: }
090:
091: /**
092: * Returns a list of values to which this multimap maps the specified
093: * key.
094: *
095: * @return the list of values to which this map maps the specified key, the
096: * list may be empty if the multimap contains no mapping for this key.
097: */
098: public List get(Object key) {
099: List l = (List) map.get(key);
100: if (l == null)
101: l = new ArrayList();
102: return l;
103: }
104:
105: // Modification Operations
106:
107: /**
108: * Adds the specified value with the specified key to this multimap.
109: * @param key
110: * @param value
111: */
112: public void put(Object key, Object value) {
113: List l = (List) map.get(key);
114: if (l == null) {
115: l = new ArrayList();
116: map.put(key, l);
117: }
118: l.add(value);
119: sizeAll++;
120: }
121:
122: /**
123: * Copies all entries from the specified multimap to this
124: * multimap.
125: * @param t source multimap
126: */
127: public void putAll(MultiMap t) {
128:
129: Iterator it = t.keySet().iterator();
130: while (it.hasNext()) {
131: Object key = it.next();
132: List tl = (List) t.get(key);
133:
134: List l = (List) map.get(key);
135: if (l == null) {
136: l = new ArrayList();
137: map.put(key, l);
138: }
139: l.addAll(tl);
140: sizeAll += tl.size();
141: }
142: }
143:
144: /**
145: * Removes all mappings for this key from this multimap if present.
146: * @param key
147: */
148: public void remove(Object key) {
149: List l = (List) map.get(key);
150: if (l != null)
151: sizeAll -= l.size();
152: map.remove(key);
153: }
154:
155: /**
156: * Removes the specified key/value mapping from this multimap if present.
157: * @param key
158: * @param value
159: */
160: public void remove(Object key, Object value) {
161: List l = (List) map.get(key);
162: if (l != null)
163: if (l.remove(value))
164: sizeAll--;
165: }
166:
167: // Bulk Operations
168:
169: /**
170: * Removes all mappings from this map (optional operation).
171: */
172: public void clear() {
173: map.clear();
174: sizeAll = 0;
175: }
176:
177: // Views
178:
179: /**
180: * Returns a set view of the keys contained in this multimap.
181: */
182: public Set keySet() {
183: return map.keySet();
184: }
185:
186: // Comparison and hashing
187:
188: /**
189: * Compares the specified object with this multimap for equality.
190: * @param o
191: */
192: public boolean equals(Object o) {
193: if (o == this )
194: return true;
195:
196: // FIXME: use MultiMap interface only
197: if (!(o instanceof HashMultiMap))
198: return false;
199: HashMultiMap c = (HashMultiMap) o;
200: if (c.size() != size())
201: return false;
202:
203: return map.equals(c.map);
204: }
205:
206: /**
207: * Returns the hash code value for this multimap.
208: */
209: public int hashCode() {
210: int h = 0;
211: Iterator it = map.entrySet().iterator();
212: while (it.hasNext()) {
213: Object obj = it.next();
214: h += obj.hashCode();
215: }
216: return h;
217: }
218: }
|