1 11 package org.eclipse.core.internal.utils; 12 13 import org.eclipse.core.runtime.Assert; 14 15 20 public class Cache { 21 public class Entry implements KeyedHashSet.KeyedElement { 22 Object cached; 23 Object key; 24 Entry next; 25 Entry previous; 26 long timestamp; 27 28 public Entry(Object key, Object cached, long timestamp) { 29 this.key = key; 30 this.cached = cached; 31 this.timestamp = timestamp; 32 } 33 34 public boolean compare(KeyedHashSet.KeyedElement other) { 35 if (!(other instanceof Entry)) 36 return false; 37 Entry otherEntry = (Entry) other; 38 return key.equals(otherEntry.key); 39 } 40 41 42 public void discard() { 43 unchain(); 44 cached = null; 45 entries.remove(this); 46 } 47 48 public Object getCached() { 49 return cached; 50 } 51 52 public Object getKey() { 53 return key; 54 } 55 56 public int getKeyHashCode() { 57 return key.hashCode(); 58 } 59 60 public Entry getNext() { 61 return next; 62 } 63 64 public Entry getPrevious() { 65 return previous; 66 } 67 68 public long getTimestamp() { 69 return timestamp; 70 } 71 72 public boolean isHead() { 73 return previous == null; 74 } 75 76 public boolean isTail() { 77 return next == null; 78 } 79 80 81 void makeHead() { 82 Entry oldHead = head; 83 head = this; 84 next = oldHead; 85 previous = null; 86 if (oldHead == null) 87 tail = this; 88 else 89 oldHead.previous = this; 90 } 91 92 public void setCached(Object cached) { 93 this.cached = cached; 94 } 95 96 public void setTimestamp(long timestamp) { 97 this.timestamp = timestamp; 98 } 99 100 public String toString() { 101 return key + " -> " + cached + " [" + timestamp + ']'; } 103 104 105 void unchain() { 106 if (tail == this) 108 tail = previous; 109 else 110 next.previous = previous; 111 if (head == this) 113 head = next; 114 else 115 previous.next = next; 116 } 117 } 118 119 KeyedHashSet entries; 120 Entry head; 121 private int maximumCapacity; 122 Entry tail; 123 private double threshold; 124 125 public Cache(int maximumCapacity) { 126 this(Math.min(KeyedHashSet.MINIMUM_SIZE, maximumCapacity), maximumCapacity, 0.25); 127 } 128 129 public Cache(int initialCapacity, int maximumCapacity, double threshold) { 130 Assert.isTrue(maximumCapacity >= initialCapacity, "maximum capacity < initial capacity"); Assert.isTrue(threshold >= 0 && threshold <= 1, "threshold should be between 0 and 1"); Assert.isTrue(initialCapacity > 0, "initial capacity must be greater than zero"); entries = new KeyedHashSet(initialCapacity); 134 this.maximumCapacity = maximumCapacity; 135 this.threshold = threshold; 136 } 137 138 public void addEntry(Object key, Object toCache) { 139 addEntry(key, toCache, 0); 140 } 141 142 public Entry addEntry(Object key, Object toCache, long timestamp) { 143 Entry newHead = (Entry) entries.getByKey(key); 144 if (newHead == null) 145 entries.add(newHead = new Entry(key, toCache, timestamp)); 146 newHead.cached = toCache; 147 newHead.timestamp = timestamp; 148 newHead.makeHead(); 149 int extraEntries = entries.size() - maximumCapacity; 150 if (extraEntries > maximumCapacity * threshold) 151 packEntries(extraEntries); 154 return newHead; 155 } 156 157 public Entry getEntry(Object key) { 158 return getEntry(key, true); 159 } 160 161 public Entry getEntry(Object key, boolean update) { 162 Entry existing = (Entry) entries.getByKey(key); 163 if (existing == null) 164 return null; 165 if (!update) 166 return existing; 167 existing.unchain(); 168 existing.makeHead(); 169 return existing; 170 } 171 172 public Entry getHead() { 173 return head; 174 } 175 176 public Entry getTail() { 177 return tail; 178 } 179 180 private void packEntries(int extraEntries) { 181 Entry current = tail; 183 for (; current != null && extraEntries > 0; extraEntries--) { 184 current.discard(); 185 current = current.previous; 186 } 187 } 188 189 public long size() { 190 return entries.size(); 191 } 192 193 public void discardAll() { 194 entries.clear(); 195 } 196 197 public void dispose() { 198 discardAll(); 199 entries = null; 200 } 201 } 202 | Popular Tags |