1 /*
2 * Copyright (c) 2003, Henri Yandell
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or
6 * without modification, are permitted provided that the
7 * following conditions are met:
8 *
9 * + Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 *
12 * + Redistributions in binary form must reproduce the above copyright notice,
13 * this list of conditions and the following disclaimer in the documentation
14 * and/or other materials provided with the distribution.
15 *
16 * + Neither the name of Genjava-Core nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32 package com.generationjava.collections;
33
34 import java.util.Collection;
35 import java.util.HashMap;
36 import java.util.Iterator;
37 import java.util.LinkedList;
38 import java.util.Map;
39 import java.util.Set;
40 import java.util.HashSet;
41
42 import com.generationjava.patterns.Null;
43
44 /***
45 * A Map in which multiple keys are used, ie) an Object array
46 * of keys.
47 *
48 * @author bayard@generationjava.com
49 * @date 2001-12-19
50 */
51 /// Pass in: { "key1", "key2", "key3" } and a value.
52 public class MultiKeyedMap implements Map {
53
54 // this is not lazy instantiation. One MUST be
55 // constructed in a constructor.
56 private Map myMap = null;
57
58 public MultiKeyedMap(Map m) {
59 myMap = m;
60 }
61
62 public MultiKeyedMap() {
63 this(new HashMap());
64 }
65
66 /* map interface */
67
68 // Removes all mappings from this map (optional operation) {.
69 public void clear() {
70 myMap.clear();
71 }
72
73 // Returns true if this map contains a mapping for the specified key.
74 public boolean containsKey(Object key) {
75 return get(key) != null;
76 }
77
78 // Returns true if this map maps one or more keys to the specified value.
79 public boolean containsValue(Object value) {
80 return this.containsValue(this.myMap, value);
81 }
82
83 private boolean containsValue(Map map, Object value) {
84 Iterator values = map.values().iterator();
85 while(values.hasNext()) {
86 Object obj = values.next();
87 if(obj instanceof Map) {
88 if(containsValue((Map)obj, value) ) {
89 return true;
90 }
91 }
92 if(value == obj) {
93 return true;
94 }
95 if(value.equals(obj)) {
96 return true;
97 }
98 }
99
100 return false;
101 }
102
103 // Returns a set view of the mappings contained in this map.
104 public Set entrySet() {
105 // FIX : Make this actually work.
106 return myMap.entrySet();
107 }
108
109 // Compares the specified object with this map for equality.
110 public boolean equals(Object o) {
111 return myMap.equals(o);
112 }
113
114 // Returns the value to which this map maps the specified key.
115 public Object get(Object key) {
116 if(key instanceof Object[]) {
117 Object[] keys = (Object[])key;
118 Map map = this.myMap;
119 int szLessOne = keys.length - 1;
120 for(int i=0; i<szLessOne; i++) {
121 Object value = map.get(keys[i]);
122 if(value instanceof Map) {
123 map = (Map)value;
124 } else {
125 return null;
126 }
127 }
128 return map.get(keys[szLessOne]);
129 } else {
130 return this.myMap.get(key);
131 }
132 }
133
134 // Returns the hash code value for this map.
135 public int hashCode() {
136 return myMap.hashCode();
137 }
138
139 // Returns true if this map contains no key-value mappings.
140 public boolean isEmpty() {
141 return myMap.isEmpty();
142 }
143
144 // Returns a set view of the keys contained in this map.
145 /// NOTE: If fred:foo is added, it will return that key as
146 /// the array [fred]. Arrays are the correct way to talk
147 /// to this class.
148 public Set keySet() {
149 Set set = new HashSet();
150 keySetRecurse(this.myMap, set, new LinkedList());
151 return set;
152 }
153
154 // SLOW :(
155 private void keySetRecurse(Map map, Set set, LinkedList head) {
156 Iterator keys = map.keySet().iterator();
157 while(keys.hasNext()) {
158 Object key = keys.next();
159 head.add(key);
160 Object value = map.get(key);
161 if(value instanceof Map) {
162 keySetRecurse((Map)value, set, head);
163 } else {
164 set.add(head.toArray());
165 }
166 head.removeLast();
167 }
168 }
169
170 // Put a value into the specified map (optional operation)
171 public Object put(Object key, Object value) {
172 if(key instanceof Object[]) {
173 Object[] keys = (Object[])key;
174 int szLessOne = keys.length-1;
175 Map map = this.myMap;
176 for(int i=0; i<szLessOne; i++) {
177 Object obj = map.get(keys[i]);
178 if(obj instanceof Map) {
179 map = (Map)obj;
180 } else {
181 Map oldmap = map;
182 map = CollectionsW.cloneNewEmptyMap(map);
183 oldmap.put(keys[i], map);
184 }
185 }
186 return map.put(keys[szLessOne], value);
187 } else {
188 return this.myMap.put(key, value);
189 }
190 }
191
192 // Copies all of the mappings from the specified map to this map (optional operation)
193 public void putAll(Map t) {
194 if(t != null) {
195 Set set = t.keySet();
196 if(set != null) {
197 Iterator iterator = set.iterator();
198 while(iterator.hasNext()) {
199 Object key = iterator.next();
200 put(key,t.get(key));
201 }
202 }
203 }
204 }
205
206 // Removes the mapping for this key from this map if present (optional operation)
207 public Object remove(Object key) {
208 if(key instanceof Object[]) {
209 Object[] keys = (Object[])key;
210 int szLessOne = keys.length-1;
211 Map map = this.myMap;
212 for(int i=0; i<szLessOne; i++) {
213 Object obj = map.get(keys[i]);
214 if(obj instanceof Map) {
215 map = (Map)obj;
216 } else {
217 return null;
218 }
219 }
220 return map.remove(keys[szLessOne]);
221 } else {
222 return this.myMap.remove(key);
223 }
224 }
225
226 // Returns the number of key-value mappings in this map.
227 public int size() {
228 // QUERY: This is okay I think. Should it return size of flattened???
229 return values().size();
230 }
231
232 // Returns a collection view of the values contained in this map.
233 public Collection values() {
234 Collection list = new LinkedList();
235 valuesRecurse( this.myMap, list );
236 return list;
237 }
238
239 private void valuesRecurse(Map map, Collection list) {
240 Iterator iterator = map.keySet().iterator();
241 while(iterator.hasNext()) {
242 Object key = iterator.next();
243 Object value = map.get(key);
244 if(value instanceof Map) {
245 valuesRecurse((Map)value, list);
246 } else {
247 list.add(value);
248 }
249 }
250 }
251
252 public String toString() {
253 return myMap.toString();
254 }
255
256 }
This page was automatically generated by Maven