001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: // XXX what is wrong with org.openide.util.WeakSet??
043: package org.netbeans.editor.ext.html;
044:
045: import java.lang.ref.WeakReference;
046:
047: /** This is a special set-like (not java.util.Set-like) class.
048: * It holds a set of objects referenced only weakly, and which
049: * can be get() by an equivalent object. It can be used e.g.
050: * as a lightweight (gc()-able) intern() for String or as a temporal storage
051: * for an algorithm creating a lot of long-lasting equals() immutables.
052: *
053: * @author Petr Nejedly
054: * @version 1.0
055: */
056: public class WeakHashSet {
057:
058: Entry[] data;
059: // count of (possibly) active Entries
060: int count = 0;
061: // Number of Entries at which we rehash
062: int treshold;
063: float loadFactor;
064:
065: /** Creates new WeakHashSet */
066: public WeakHashSet(int capacity, float loadFactor) {
067: this .loadFactor = loadFactor;
068: treshold = (int) (capacity * loadFactor);
069: data = new Entry[capacity];
070: }
071:
072: /** Return the object equals to this object */
073: public Object get(Object obj) {
074: if (obj == null)
075: return null;
076:
077: Entry[] tab = data;
078: Entry prev = null;
079: int hash = obj.hashCode();
080: int index = (hash & 0x7FFFFFFF) % tab.length;
081:
082: for (Entry e = tab[index]; e != null; prev = e, e = e.next)
083: if (e.hash == hash) {
084: Object value = e.value.get();
085: if (value == null) {
086: // remove this entry from chain
087: count--;
088: if (prev == null)
089: tab[index] = e.next;
090: else
091: prev.next = e.next;
092: } else {
093: if (value.equals(obj))
094: return value;
095: }
096: }
097: return null;
098: }
099:
100: public Object put(Object obj) {
101: if (obj == null)
102: return null;
103:
104: Entry[] tab = data;
105: Entry prev = null;
106: int hash = obj.hashCode();
107: int index = (hash & 0x7FFFFFFF) % tab.length;
108:
109: for (Entry e = tab[index]; e != null; prev = e, e = e.next)
110: if (e.hash == hash) {
111: Object value = e.value.get();
112: if (value == null) {
113: count--;
114: if (prev == null)
115: tab[index] = e.next;
116: else
117: prev.next = e.next;
118: } else {
119: if (value.equals(obj))
120: return value;
121: }
122: }
123:
124: if (count >= treshold) {
125: rehash();
126: tab = data;
127: index = (hash & 0x7FFFFFFF) % tab.length;
128: }
129:
130: Entry e = new Entry(hash, obj, tab[index]);
131: tab[index] = e;
132: count++;
133:
134: return obj;
135: }
136:
137: private void rehash() {
138: int oldCapacity = data.length;
139: Entry oldMap[] = data;
140:
141: int newCapacity = oldCapacity * 2 + 1;
142: Entry newMap[] = new Entry[newCapacity];
143:
144: treshold = (int) (newCapacity * loadFactor);
145: data = newMap;
146:
147: for (int i = oldCapacity; i-- > 0;) {
148: for (Entry old = oldMap[i]; old != null;) {
149: Entry e = old;
150: old = old.next;
151:
152: int index = (e.hash & 0x7FFFFFFF) % newCapacity;
153: e.next = newMap[index];
154: newMap[index] = e;
155: }
156: }
157: }
158:
159: /**
160: * WeakHashSet collision list entry.
161: */
162: private static class Entry {
163: int hash;
164: WeakReference value;
165: Entry next;
166:
167: Entry(int hash, Object value, Entry next) {
168: this .hash = hash;
169: this .value = new WeakReference(value);
170: this.next = next;
171: }
172: }
173:
174: }
|