|
SimpleMapImpl |
|
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.8 2002/01/14 13:42:01 nasso Exp $ 14 */ 15 16 package gate.util; 17 18 import java.util.*; 19 import java.io.*; 20 21 /** 22 * Implements Map interface in using less memory. Very simple but usefull 23 * for small number of items on it. 24 */ 25 26 class SimpleMapImpl implements Map, java.lang.Cloneable, java.io.Serializable { 27 28 /** 29 * The capacity of the map 30 */ 31 int capacity = 3; 32 33 /** 34 * The current number of elements of the map 35 */ 36 int count = 0; 37 38 /** 39 * Array keeping the keys of the entries in the map. It is "synchrnized" 40 * with the values array - the Nth position in both arrays correspond 41 * to one and the same entry 42 */ 43 Object theKeys[]; 44 45 /** 46 * Array keeping the values of the entries in the map. It is "synchrnized" 47 * with the keys array - the Nth position in both arrays correspond 48 * to one and the same entry 49 */ 50 Object theValues[]; 51 52 /** Freeze the serialization UID. */ 53 static final long serialVersionUID = -6747241616127229116L; 54 55 /** the Object instance that will represent the NULL keys in the map */ 56 transient static Object nullKey = new Object(); 57 58 /** the static 'all keys' collection */ 59 transient public static HashMap theKeysHere = new HashMap(); 60 61 /** additional static members initialization */ 62 static { 63 theKeysHere.put(nullKey, nullKey); 64 } // static code 65 66 /** 67 * Constructor 68 */ 69 public SimpleMapImpl() { 70 theKeys = new Object[capacity]; 71 theValues = new Object[capacity]; 72 } // SimpleMapImpl() 73 74 /** 75 * return the number of elements in the map 76 */ 77 public int size() { 78 return count; 79 } // size() 80 81 /** 82 * return true if there are no elements in the map 83 */ 84 public boolean isEmpty() { 85 return (count == 0); 86 } // isEmpty() 87 88 /** 89 * Not supported. This method is here only to conform the Map interface 90 */ 91 public Collection values() { 92 throw new UnsupportedOperationException( 93 "SimpleMapImpl.values() not implemented!"); 94 } // values() 95 96 /** 97 * return the set of the keys in the map. The changes in the set DO NOT 98 * affect the map. 99 */ 100 public Set keySet() 101 { 102 HashSet s = new HashSet(size()); 103 Object k; 104 for (int i = 0; i < count; i++) { 105 k = theKeys[i]; 106 if (k == nullKey) 107 s.add(null); 108 else 109 s.add(k); 110 } //for 111 return s; 112 } // keySet() 113 114 /** 115 * clear the map 116 */ 117 public void clear() 118 { 119 for (int i = 0; i < count; i++) { 120 theKeys[i] = null; 121 theValues[i] = null; 122 } // for 123 count = 0; 124 } // clear 125 126 /** 127 * return true if the key is in the map 128 */ 129 public boolean containsKey(Object key) { 130 return (getPostionByKey(key) != -1); 131 }// containsKey 132 133 /** 134 * return true if the map contains that value 135 */ 136 public boolean containsValue(Object value) { 137 return (getPostionByValue(value) != -1); 138 }// containsValue 139 140 /** 141 * return the value associated with the key. If the key is 142 * not in the map returns null. 143 */ 144 public Object get(Object key) { 145 int pos = getPostionByKey(key); 146 return (pos == -1) ? null : theValues[pos]; 147 } // get 148 149 /** 150 * put a value in the map using the given key. If the key exist in the map 151 * the value is replaced and the old one is returned. 152 */ 153 public Object put(Object key, Object value) { 154 Object gKey; 155 if (key == null) { 156 key = nullKey; 157 gKey = nullKey; 158 } else 159 gKey = theKeysHere.get(key); 160 // if the key is already in the 'all keys' map - try to find it in that instance 161 // comparing by reference 162 if (gKey != null) { 163 for (int i = 0; i < count; i++) { 164 if (gKey == theKeys[i]) { 165 // we found the reference - return the value 166 Object oldVal = theValues[i]; 167 theValues[i] = value; 168 return oldVal; 169 } 170 } // for 171 } else {// if(gKey != null) 172 // no, the key is not in the 'all keys' map - put it there 173 theKeysHere.put(key, key); 174 gKey = key; 175 } 176 // enlarge the containers if necessary 177 if (count == capacity) 178 increaseCapacity(); 179 180 // put the key and value to the map 181 theKeys[count] = gKey; 182 theValues[count] = value; 183 count++; 184 return null; 185 } // put 186 187 /** 188 * remove value from the map using it's key. 189 */ 190 public Object remove(Object key) { 191 int pos = getPostionByKey(key); 192 if (pos == -1) 193 return null; 194 195 // save the value to return it at the end 196 Object oldVal = theValues[pos]; 197 count--; 198 // move the last element key and value removing the element 199 if (count != 0) { 200 theKeys[pos] = theKeys[count]; 201 theValues[pos] = theValues[count]; 202 } 203 // clear the last position 204 theKeys[count] = null; 205 theValues[count] = null; 206 207 // return the value 208 return oldVal; 209 } // remove 210 211 /** 212 * put all the elements from a map 213 */ 214 public void putAll(Map t) 215 { 216 if (t == null) { 217 throw new UnsupportedOperationException( 218 "SimpleMapImpl.putAll argument is null"); 219 } // if (t == null) 220 221 if (t instanceof SimpleMapImpl) { 222 SimpleMapImpl sfm = (SimpleMapImpl)t; 223 Object key; 224 for (int i = 0; i < sfm.count; i++) { 225 key = sfm.theKeys[i]; 226 put(key, sfm.theValues[i]); 227 } //for 228 } else { // if (t instanceof SimpleMapImpl) 229 Iterator entries = t.entrySet().iterator(); 230 Map.Entry e; 231 while (entries.hasNext()) { 232 e = (Map.Entry)entries.next(); 233 put(e.getKey(), e.getValue()); 234 } // while 235 } // if(t instanceof SimpleMapImpl) 236 } // putAll 237 238 /** 239 * return positive value as index of the key in the map. 240 * Negative value means that the key is not present in the map 241 */ 242 private int getPostionByKey(Object key) { 243 if (key == null) 244 key = nullKey; 245 // check the 'all keys' map for the very first key occurence 246 key = theKeysHere.get(key); 247 if (key == null) 248 return -1; 249 250 for (int i = 0; i < count; i++) { 251 if (key == theKeys[i]) 252 return i; 253 } // for 254 return -1; 255 } // getPostionByKey 256 257 /** 258 * return the index of the key in the map comparing them by reference only. 259 * This method is used in subsume check to speed it up. 260 */ 261 protected int getSubsumeKey(Object key) { 262 for (int i = 0; i < count; i++) { 263 if (key == theKeys[i]) 264 return i; 265 } // for 266 return -1; 267 } // getPostionByKey 268 269 /** 270 * return positive value as index of the value in the map. 271 */ 272 private int getPostionByValue(Object value) { 273 Object av; 274 for (int i = 0; i < count; i++) { 275 av = theValues[i]; 276 if (value == null) { 277 if (av == null) 278 return i; 279 } else {//if (value == null) 280 if (value.equals(av)) 281 return i; 282 } //if (value == null) 283 } // for 284 285 return -1; 286 } // getPostionByValue 287 288 // Modification Operations 289 private void increaseCapacity() { 290 int oldCapacity = capacity; 291 capacity *= 2; 292 Object oldKeys[] = theKeys; 293 theKeys = new Object[capacity]; 294 295 Object oldValues[] = theValues; 296 theValues = new Object[capacity]; 297 298 System.arraycopy(oldKeys, 0, theKeys, 0, oldCapacity); 299 System.arraycopy(oldValues, 0, theValues, 0, oldCapacity); 300 } // increaseCapacity 301 302 /** 303 * Auxiliary classes needed for the support of entrySet() method 304 */ 305 private static class Entry implements Map.Entry { 306 int hash; 307 Object key; 308 Object value; 309 310 Entry(int hash, Object key, Object value) { 311 this.hash = hash; 312 this.key = key; 313 this.value = value; 314 } 315 316 protected Object clone() { 317 return new Entry(hash, key, value); 318 } 319 320 public Object getKey() { 321 return key; 322 } 323 324 public Object getValue() { 325 return value; 326 } 327 328 public Object setValue(Object value) { 329 Object oldValue = this.value; 330 this.value = value; 331 return oldValue; 332 } 333 334 public boolean equals(Object o) { 335 if (!(o instanceof Map.Entry)) 336 return false; 337 Map.Entry e = (Map.Entry)o; 338 339 return (key==null ? e.getKey()==null : key.equals(e.getKey())) && 340 (value==null ? e.getValue()==null : value.equals(e.getValue())); 341 } 342 343 public int hashCode() { 344 return hash ^ (key==null ? 0 : key.hashCode()); 345 } 346 347 public String toString() { 348 return key+"="+value; 349 } 350 } // Entry 351 352 353 public Set entrySet() { 354 HashSet s = new HashSet(size()); 355 Object v, k; 356 for (int i = 0; i < count; i++) { 357 k = theKeys[i]; 358 s.add(new Entry(k.hashCode(), ((k==nullKey)?null:k), theValues[i])); 359 } //for 360 return s; 361 } // entrySet 362 363 // Comparison and hashing 364 public boolean equals(Object o) { 365 if (!(o instanceof Map)) { 366 return false; 367 } 368 369 Map m = (Map)o; 370 if (m.size() != count) { 371 return false; 372 } 373 374 Object v, k; 375 for (int i = 0; i < count; i++) { 376 k = theKeys[i]; 377 v = m.get(k); 378 if (v==null) { 379 if (theValues[i]!=null) 380 return false; 381 } 382 else if (!v.equals(theValues[i])){ 383 return false; 384 } 385 } // for 386 387 return true; 388 } // equals 389 390 /** 391 * return the hashCode for the map 392 */ 393 public int hashCode() { 394 int h = 0; 395 Iterator i = entrySet().iterator(); 396 while (i.hasNext()) 397 h += i.next().hashCode(); 398 return h; 399 } // hashCode 400 401 /** 402 * Create a copy of the map including the data. 403 */ 404 public Object clone() { 405 SimpleMapImpl newMap; 406 try { 407 newMap = (SimpleMapImpl)super.clone(); 408 } catch (CloneNotSupportedException e) { 409 throw(new InternalError(e.toString())); 410 } 411 412 newMap.count = count; 413 newMap.theKeys = new Object[capacity]; 414 System.arraycopy(theKeys, 0, newMap.theKeys, 0, capacity); 415 416 newMap.theValues = new Object[capacity]; 417 System.arraycopy(theValues, 0, newMap.theValues, 0, capacity); 418 419 return newMap; 420 } // clone 421 422 public String toString() { 423 int max = size() - 1; 424 StringBuffer buf = new StringBuffer(); 425 Iterator i = entrySet().iterator(); 426 427 buf.append("{"); 428 for (int j = 0; j <= max; j++) { 429 Entry e = (Entry) (i.next()); 430 buf.append(e.getKey() + "=" + e.getValue()); 431 if (j < max) 432 buf.append(", "); 433 } 434 buf.append("}"); 435 return buf.toString(); 436 } // toString 437 438 /** 439 * readObject - calls the default readObject() and then initialises the 440 * transient data 441 * 442 * @serialData Read serializable fields. No optional data read. 443 */ 444 private void readObject(ObjectInputStream s) 445 throws IOException, ClassNotFoundException { 446 s.defaultReadObject(); 447 if (theKeysHere == null) { 448 theKeysHere = new HashMap(); 449 theKeysHere.put(nullKey, nullKey); 450 } 451 for (int i = 0; i < theKeys.length; i++) { 452 // if the key is in the 'all keys' map 453 Object o = theKeysHere.get(theKeys[i]); 454 if (o != null) // yes - so reuse the reference 455 theKeys[i] = o; 456 else // no - put it in the 'all keys' map 457 theKeysHere.put(theKeys[i], theKeys[i]); 458 }//for 459 }//readObject 460 } //SimpleMapImpl 461
|
SimpleMapImpl |
|