KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > internal > utils > Cache


1 /*******************************************************************************
2  * Copyright (c) 2004, 2005 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.core.internal.utils;
12
13 import org.eclipse.core.runtime.Assert;
14
15 /**
16  * A cache that keeps a collection of at most maximumCapacity+threshold entries.
17  * When the number of entries exceeds that limit, least recently used entries are removed
18  * so the current size is the same as the maximum capacity.
19  */

20 public class Cache {
21     public class Entry implements KeyedHashSet.KeyedElement {
22         Object JavaDoc cached;
23         Object JavaDoc key;
24         Entry next;
25         Entry previous;
26         long timestamp;
27
28         public Entry(Object JavaDoc key, Object JavaDoc 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         /* Removes this entry from the cache */
42         public void discard() {
43             unchain();
44             cached = null;
45             entries.remove(this);
46         }
47
48         public Object JavaDoc getCached() {
49             return cached;
50         }
51
52         public Object JavaDoc 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         /* Inserts into the head of the list */
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 JavaDoc cached) {
93             this.cached = cached;
94         }
95
96         public void setTimestamp(long timestamp) {
97             this.timestamp = timestamp;
98         }
99
100         public String JavaDoc toString() {
101             return key + " -> " + cached + " [" + timestamp + ']'; //$NON-NLS-1$ //$NON-NLS-2$
102
}
103
104         /* Removes from the linked list, but not from the entries collection */
105         void unchain() {
106             // it may be in the tail
107
if (tail == this)
108                 tail = previous;
109             else
110                 next.previous = previous;
111             // it may be in the head
112
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"); //$NON-NLS-1$
131
Assert.isTrue(threshold >= 0 && threshold <= 1, "threshold should be between 0 and 1"); //$NON-NLS-1$
132
Assert.isTrue(initialCapacity > 0, "initial capacity must be greater than zero"); //$NON-NLS-1$
133
entries = new KeyedHashSet(initialCapacity);
134         this.maximumCapacity = maximumCapacity;
135         this.threshold = threshold;
136     }
137
138     public void addEntry(Object JavaDoc key, Object JavaDoc toCache) {
139         addEntry(key, toCache, 0);
140     }
141
142     public Entry addEntry(Object JavaDoc key, Object JavaDoc 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             // we have reached our limit - ensure we are under the maximum capacity
152
// by discarding older entries
153
packEntries(extraEntries);
154         return newHead;
155     }
156
157     public Entry getEntry(Object JavaDoc key) {
158         return getEntry(key, true);
159     }
160
161     public Entry getEntry(Object JavaDoc 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         // should remove in an ad-hoc way to get better performance
182
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