1 11 package org.eclipse.core.internal.expressions.util; 12 13 import java.util.Enumeration ; 14 import java.util.Hashtable ; 15 16 20 public class LRUCache implements Cloneable { 21 22 30 protected static class LRUCacheEntry { 31 32 35 public Object _fKey; 36 37 40 public Object _fValue; 41 42 45 public int _fTimestamp; 46 47 50 public int _fSpace; 51 52 55 public LRUCacheEntry _fPrevious; 56 57 60 public LRUCacheEntry _fNext; 61 62 69 public LRUCacheEntry (Object key, Object value, int space) { 70 _fKey = key; 71 _fValue = value; 72 _fSpace = space; 73 } 74 75 79 public String toString() { 80 81 return "LRUCacheEntry [" + _fKey + "-->" + _fValue + "]"; } 83 } 84 85 88 protected int fCurrentSpace; 89 90 93 protected int fSpaceLimit; 94 95 98 protected int fTimestampCounter; 99 100 103 protected Hashtable fEntryTable; 104 105 108 protected LRUCacheEntry fEntryQueue; 109 110 113 protected LRUCacheEntry fEntryQueueTail; 114 115 118 protected static final int DEFAULT_SPACELIMIT = 100; 119 123 public LRUCache() { 124 125 this(DEFAULT_SPACELIMIT); 126 } 127 131 public LRUCache(int size) { 132 133 fTimestampCounter = fCurrentSpace = 0; 134 fEntryQueue = fEntryQueueTail = null; 135 fEntryTable = new Hashtable (size); 136 fSpaceLimit = size; 137 } 138 143 public Object clone() { 144 145 LRUCache newCache = newInstance(fSpaceLimit); 146 LRUCacheEntry qEntry; 147 148 149 qEntry = this.fEntryQueueTail; 150 while (qEntry != null) { 151 newCache.privateAdd (qEntry._fKey, qEntry._fValue, qEntry._fSpace); 152 qEntry = qEntry._fPrevious; 153 } 154 return newCache; 155 } 156 public double fillingRatio() { 157 return (fCurrentSpace) * 100.0 / fSpaceLimit; 158 } 159 162 public void flush() { 163 164 fCurrentSpace = 0; 165 LRUCacheEntry entry = fEntryQueueTail; fEntryTable = new Hashtable (); fEntryQueue = fEntryQueueTail = null; 168 while (entry != null) { privateNotifyDeletionFromCache(entry); 170 entry = entry._fPrevious; 171 } 172 } 173 179 public void flush (Object key) { 180 181 LRUCacheEntry entry; 182 183 entry = (LRUCacheEntry) fEntryTable.get(key); 184 185 186 if (entry == null) return; 187 188 this.privateRemoveEntry (entry, false); 189 } 190 197 public Object get(Object key) { 198 199 LRUCacheEntry entry = (LRUCacheEntry) fEntryTable.get(key); 200 if (entry == null) { 201 return null; 202 } 203 204 this.updateTimestamp (entry); 205 return entry._fValue; 206 } 207 211 public int getCurrentSpace() { 212 return fCurrentSpace; 213 } 214 218 public int getSpaceLimit() { 219 return fSpaceLimit; 220 } 221 225 public Enumeration keys() { 226 return fEntryTable.keys(); 227 } 228 236 protected boolean makeSpace (int space) { 237 238 int limit; 239 240 limit = this.getSpaceLimit(); 241 242 243 if (fCurrentSpace + space <= limit) { 244 return true; 245 } 246 247 248 if (space > limit) { 249 return false; 250 } 251 252 253 while (fCurrentSpace + space > limit && fEntryQueueTail != null) { 254 this.privateRemoveEntry (fEntryQueueTail, false); 255 } 256 return true; 257 } 258 263 protected LRUCache newInstance(int size) { 264 return new LRUCache(size); 265 } 266 274 public Object peek(Object key) { 275 276 LRUCacheEntry entry = (LRUCacheEntry) fEntryTable.get(key); 277 if (entry == null) { 278 return null; 279 } 280 return entry._fValue; 281 } 282 288 protected void privateAdd (Object key, Object value, int space) { 289 290 LRUCacheEntry entry; 291 292 entry = new LRUCacheEntry(key, value, space); 293 this.privateAddEntry (entry, false); 294 } 295 301 protected void privateAddEntry (LRUCacheEntry entry, boolean shuffle) { 302 303 if (!shuffle) { 304 fEntryTable.put (entry._fKey, entry); 305 fCurrentSpace += entry._fSpace; 306 } 307 308 entry._fTimestamp = fTimestampCounter++; 309 entry._fNext = this.fEntryQueue; 310 entry._fPrevious = null; 311 312 if (fEntryQueue == null) { 313 314 fEntryQueueTail = entry; 315 } else { 316 fEntryQueue._fPrevious = entry; 317 } 318 319 fEntryQueue = entry; 320 } 321 327 protected void privateNotifyDeletionFromCache(LRUCacheEntry entry) { 328 } 330 336 protected void privateRemoveEntry (LRUCacheEntry entry, boolean shuffle) { 337 338 LRUCacheEntry previous, next; 339 340 previous = entry._fPrevious; 341 next = entry._fNext; 342 343 if (!shuffle) { 344 fEntryTable.remove(entry._fKey); 345 fCurrentSpace -= entry._fSpace; 346 privateNotifyDeletionFromCache(entry); 347 } 348 349 350 if (previous == null) { 351 fEntryQueue = next; 352 } else { 353 previous._fNext = next; 354 } 355 356 357 if (next == null) { 358 fEntryQueueTail = previous; 359 } else { 360 next._fPrevious = previous; 361 } 362 } 363 370 public Object put(Object key, Object value) { 371 372 int newSpace, oldSpace, newTotal; 373 LRUCacheEntry entry; 374 375 376 newSpace = spaceFor(value); 377 entry = (LRUCacheEntry) fEntryTable.get (key); 378 379 if (entry != null) { 380 381 386 oldSpace = entry._fSpace; 387 newTotal = getCurrentSpace() - oldSpace + newSpace; 388 if (newTotal <= getSpaceLimit()) { 389 updateTimestamp (entry); 390 entry._fValue = value; 391 entry._fSpace = newSpace; 392 this.fCurrentSpace = newTotal; 393 return value; 394 } else { 395 privateRemoveEntry (entry, false); 396 } 397 } 398 if (makeSpace(newSpace)) { 399 privateAdd (key, value, newSpace); 400 } 401 return value; 402 } 403 410 public Object removeKey (Object key) { 411 412 LRUCacheEntry entry = (LRUCacheEntry) fEntryTable.get(key); 413 if (entry == null) { 414 return null; 415 } 416 Object value = entry._fValue; 417 this.privateRemoveEntry (entry, false); 418 return value; 419 } 420 425 public void setSpaceLimit(int limit) { 426 if (limit < fSpaceLimit) { 427 makeSpace(fSpaceLimit - limit); 428 } 429 fSpaceLimit = limit; 430 } 431 436 protected int spaceFor (Object value) { 437 return 1; 438 } 439 440 445 public String toString() { 446 return 447 toStringFillingRation("LRUCache") + toStringContents(); 449 } 450 451 456 protected String toStringContents() { 457 StringBuffer result = new StringBuffer (); 458 int length = fEntryTable.size(); 459 Object [] unsortedKeys = new Object [length]; 460 String [] unsortedToStrings = new String [length]; 461 Enumeration e = this.keys(); 462 for (int i = 0; i < length; i++) { 463 Object key = e.nextElement(); 464 unsortedKeys[i] = key; 465 unsortedToStrings[i] = key.toString(); 466 } 467 ToStringSorter sorter = new ToStringSorter(); 468 sorter.sort(unsortedKeys, unsortedToStrings); 469 for (int i = 0; i < length; i++) { 470 String toString = sorter.sortedStrings[i]; 471 Object value = this.get(sorter.sortedObjects[i]); 472 result.append(toString); 473 result.append(" -> "); result.append(value); 475 result.append("\n"); } 477 return result.toString(); 478 } 479 480 public String toStringFillingRation(String cacheName) { 481 StringBuffer buffer = new StringBuffer (cacheName); 482 buffer.append('['); 483 buffer.append(getSpaceLimit()); 484 buffer.append("]: "); buffer.append(fillingRatio()); 486 buffer.append("% full"); return buffer.toString(); 488 } 489 490 495 protected void updateTimestamp (LRUCacheEntry entry) { 496 497 entry._fTimestamp = fTimestampCounter++; 498 if (fEntryQueue != entry) { 499 this.privateRemoveEntry (entry, true); 500 this.privateAddEntry (entry, true); 501 } 502 return; 503 } 504 } 505 | Popular Tags |