1   /*
2    *  SimpleMapImpl.java
3    *
4    *  Copyright (c) 2001, The University of Sheffield.
5    *
6    *  This file is part of GATE (see http://gate.ac.uk/), and is free
7    *  software, licenced under the GNU Library General Public License,
8    *  Version 2, June 1991 (in the distribution as file licence.html,
9    *  and also available at http://gate.ac.uk/gate/licence.html).
10   *
11   *  D.Ognyanoff, 5/Nov/2001
12   *
13   *  $Id: SimpleMapImpl.java,v 1.5 2001/11/20 12:25:51 kalina Exp $
14   */
15  
16  package gate.util;
17  
18  import java.util.*;
19  
20  /**
21   * Implements Map interface in using less memory. Very simple but usefull
22   * for small number of items on it.
23   */
24  
25  class SimpleMapImpl implements Map, java.lang.Cloneable, java.io.Serializable {
26  
27    /**
28     * The capacity of the map
29     */
30    int m_capacity=3;
31  
32    /**
33     * The current number of elements of the map
34     */
35    int m_size=0;
36  
37    /**
38     * Array keeping the keys of the entries in the map. It is "synchrnized"
39     * with the m_values array - the Nth position in both arrays correspond
40     * to one and the same entry
41     */
42    Object m_keys[];
43    /**
44     * Array keeping the values of the entries in the map. It is "synchrnized"
45     * with the m_keys array - the Nth position in both arrays correspond
46     * to one and the same entry
47     */
48    Object m_values[];
49  
50    public SimpleMapImpl() {
51      m_keys = new Object[m_capacity];
52      m_values = new Object[m_capacity];
53    }
54  
55    public int size() {
56      return m_size;
57    }
58  
59    public boolean isEmpty() {
60      return (m_size == 0);
61    }
62  
63    public Collection values()
64    {
65      throw new UnsupportedOperationException(
66        "SimpleMapImpl.values() not implemented!");
67    }
68  
69    public Set keySet()
70    {
71      HashSet s = new HashSet(size());
72      Object k;
73      for (int i=0; i<m_size; i++) {
74        k = m_keys[i];
75        if (k == nullKey)
76             s.add(null);
77          else
78             s.add(k);
79      } //for
80      return s;
81    } // keySet
82  
83    public void clear()
84    {
85      for (int i=0; i<m_size; i++) {
86        m_keys[i] = null;
87        m_values[i] = null;
88      } // for
89      m_size =0;
90    } // clear
91  
92    public  boolean containsKey(Object key) {
93      return (getPostionByKey(key) != -1);
94    }// containsKey
95  
96    public boolean containsValue(Object value) {
97      return (getPostionByValue(value) != -1);
98    }
99  
100   public Object get(Object key) {
101     int pos = getPostionByKey(key);
102     return (pos == -1) ? null : m_values[pos];
103   } // get
104 
105   public Object put(Object key, Object value)
106   {
107     int pos = getPostionByKey(key);
108     if (pos >= 0) {
109       Object oldVal = m_values[pos];
110       m_values[pos] = value;
111       return oldVal;
112     }
113 
114     if (m_size == m_capacity)
115       increaseCapacity();
116 
117     if (g_akey == null)
118         theKeysHere.put(key, key);
119     else
120         key = g_akey;
121     m_keys[m_size] = key;
122     m_values[m_size] = value;
123     m_size++;
124     return null;
125   } // put
126 
127   public Object remove(Object key)
128   {
129     int pos = getSubsumeKey((key==null)?nullKey:key);//getPostionByKey(key);
130     if (pos == -1)
131         return null;
132 
133     Object oldVal = m_values[pos];
134     m_size--;
135     if (m_size != 0)
136     {
137         m_keys[pos] = m_keys[m_size];
138         m_values[pos] = m_values[m_size];
139     }
140     m_keys[m_size] = null;
141     m_values[m_size] = null;
142 
143     return oldVal;
144   } // remove
145 
146   public void putAll(Map t)
147   {
148     if (t == null) {
149       throw new UnsupportedOperationException(
150       "SimpleMapImpl.putAll argument is null");
151     }
152 
153     if (t instanceof SimpleMapImpl) {
154       SimpleMapImpl sfm = (SimpleMapImpl)t;
155       Object key;
156       for (int i=0; i<sfm.m_size; i++) {
157           key = sfm.m_keys[i];
158           put(key, sfm.m_values[i]);
159       } //for
160     } else {
161       Iterator entries = t.entrySet().iterator();
162       Map.Entry e;
163       while (entries.hasNext()) {
164         e = (Map.Entry)entries.next();
165         put(e.getKey(), e.getValue());
166       } // while
167     } // if
168   } // putAll
169 
170 transient Object g_akey = null;
171   private int getPostionByKey(Object key) {
172     if (key == null)
173         key = nullKey;
174     g_akey = theKeysHere.get(key);
175     if (g_akey == null)
176         return -1;
177 
178     for (int i=0; i<m_size; i++) {
179       if (g_akey.equals(m_keys[i]))
180           return i;
181     } // for
182     return -1;
183   } // getPostionByKey
184 
185   protected int getSubsumeKey(Object key) {
186     for (int i=0; i<m_size; i++) {
187       if (key == m_keys[i])
188           return i;
189     } // for
190     return -1;
191   } // getPostionByKey
192 
193   private int getPostionByValue(Object value) {
194     Object av;
195     for (int i=0; i<m_size; i++) {
196       av = m_values[i];
197       if (value == null) {
198         if (av == null)
199           return i;
200       }
201       else
202         if (value.equals(av))
203             return i;
204     } // for
205 
206     return -1;
207   } // getPostionByValue
208 
209   // Modification Operations
210   private void increaseCapacity()
211   {
212     int m_oldCapacity = m_capacity;
213     m_capacity *= 2;
214     Object m_oldKeys[] = m_keys;
215     m_keys = new Object[m_capacity];
216 
217     Object m_oldValues[] = m_values;
218     m_values = new Object[m_capacity];
219 
220     System.arraycopy(m_oldKeys, 0, m_keys, 0, m_oldCapacity);
221     System.arraycopy(m_oldValues, 0, m_values, 0, m_oldCapacity);
222   } // increaseCapacity
223 
224   /**
225    * Auxiliary classes needed for the support of entrySet() method
226    */
227   private static class Entry implements Map.Entry {
228     int hash;
229     Object key;
230     Object value;
231 
232     Entry(int hash, Object key, Object value) {
233       this.hash = hash;
234       this.key = key;
235       this.value = value;
236     }
237 
238     protected Object clone() {
239       return new Entry(hash, key, value);
240     }
241 
242     public Object getKey() {
243       return key;
244     }
245 
246     public Object getValue() {
247       return value;
248     }
249 
250     public Object setValue(Object value) {
251       Object oldValue = this.value;
252       this.value = value;
253       return oldValue;
254     }
255 
256     public boolean equals(Object o) {
257         if (!(o instanceof Map.Entry))
258             return false;
259         Map.Entry e = (Map.Entry)o;
260 
261         return (key==null ? e.getKey()==null : key.equals(e.getKey())) &&
262             (value==null ? e.getValue()==null : value.equals(e.getValue()));
263     }
264 
265     public int hashCode() {
266         return hash ^ (key==null ? 0 : key.hashCode());
267     }
268 
269     public String toString() {
270         return key+"="+value;
271     }
272   } // Entry
273 
274 
275   public Set entrySet() {
276     HashSet s = new HashSet(size());
277     Object v, k;
278     for (int i=0; i<m_size; i++) {
279       k = m_keys[i];
280       s.add(new Entry(k.hashCode(), ((k==nullKey)?null:k), m_values[i]));
281     } //for
282     return s;
283   } // entrySet
284 
285   // Comparison and hashing
286 
287   public boolean equals(Object o) {
288     if (!(o instanceof Map)) {
289       return false;
290     }
291 
292     Map m = (Map)o;
293     if (m.size() != m_size) {
294       return false;
295     }
296 
297     Object v, k;
298     for (int i=0; i<m_size; i++) {
299       k = m_keys[i];
300       v = m.get(k);
301       if (v==null) {
302         if (m_values[i]!=null)
303           return false;
304       }
305       else if (!v.equals(m_values[i])){
306         return false;
307       }
308     } // for
309 
310     return true;
311   } // equals
312 
313   /*
314   public int hashCode() {
315     int hash=0;
316     Object key;
317     for (int i=0; i<m_capacity; i++) {
318       key = m_keys[i];
319       if (key == null)
320       continue;
321       HashMap hm;
322       hash += m_keys[i].hashCode();
323       hash += m_values[i].hashCode();
324     } // for
325 
326     return hash;
327   } // hashCode
328 */
329 
330   public int hashCode() {
331     int h = 0;
332     Iterator i = entrySet().iterator();
333     while (i.hasNext())
334       h += i.next().hashCode();
335     return h;
336   }
337 
338 
339   public Object clone() {
340     SimpleMapImpl newMap;
341     try {
342       newMap = (SimpleMapImpl)super.clone();
343     } catch (CloneNotSupportedException e) {
344       throw(new InternalError(e.toString()));
345     }
346 
347     newMap.m_size = m_size;
348     newMap.m_keys = new Object[m_capacity];
349     System.arraycopy(m_keys, 0, newMap.m_keys, 0, m_capacity);
350 
351     newMap.m_values = new Object[m_capacity];
352     System.arraycopy(m_values, 0, newMap.m_values, 0, m_capacity);
353 
354     return newMap;
355   } // clone
356 
357   public String toString() {
358     int max = size() - 1;
359     StringBuffer buf = new StringBuffer();
360     Iterator i = entrySet().iterator();
361 
362     buf.append("{");
363     for (int j = 0; j <= max; j++) {
364         Entry e = (Entry) (i.next());
365         buf.append(e.getKey() + "=" + e.getValue());
366         if (j < max)
367       buf.append(", ");
368     }
369     buf.append("}");
370     return buf.toString();
371   }
372 
373 
374  /** Freeze the serialization UID. */
375   static final long serialVersionUID = -6747241616127229116L;
376 
377  /** the Object instance that will represent the NULL keys in the map */
378   transient static Object nullKey = new Object();
379   transient public static HashMap theKeysHere = new HashMap();
380   static {
381     theKeysHere.put(nullKey, nullKey);
382   }
383 
384   /** the static keys colleaction */
385 } //SimpleMapImpl
386