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: package org.netbeans.core.output2;
043:
044: import java.lang.ref.WeakReference;
045: import java.util.Arrays;
046:
047: /**
048: * A synchronized LIFO map that can contain duplicate keys, and can be
049: * toggled between using weak and strong references for values. Used for
050: * mapping instances of NbIO to the names used in NbIOProvider.getIO().
051: *
052: * @author Tim Boudreau
053: */
054: class PairMap {
055: //XXX weak referencing of objects no longer used - delete?
056:
057: private String[] keys = new String[10];
058: /** package private for unit tests */
059: Object[] vals = new Object[10];
060: int last = -1;
061: private boolean weak = false;
062:
063: /** Creates a new instance of PairMap */
064: PairMap() {
065: }
066:
067: public synchronized void clear() {
068: keys = new String[10];
069: vals = new Object[10];
070: last = -1;
071: }
072:
073: public synchronized int size() {
074: if (weak) {
075: return prune();
076: } else {
077: return last + 1;
078: }
079: }
080:
081: public synchronized boolean isEmpty() {
082: return size() == 0;
083: }
084:
085: public synchronized void setWeak(boolean val) {
086: if (weak != val) {
087: weak = val;
088: for (int i = 0; i <= last; i++) {
089: if (weak) {
090: vals[i] = new WeakReference(vals[i]);
091: } else {
092: vals[i] = ((WeakReference) vals[i]).get();
093: }
094: }
095: if (!weak) {
096: prune();
097: }
098: }
099: }
100:
101: public synchronized void add(String key, NbIO value) {
102: if (last == keys.length - 1) {
103: growArrays();
104: }
105: last++;
106: keys[last] = key;
107: vals[last] = value;
108: }
109:
110: public synchronized NbIO get(String key, boolean mustBeClosed) {
111: if (last < 0) {
112: return null;
113: }
114: boolean foundNull = false;
115: for (int i = last; i >= 0; i--) {
116: if (keys[i].equals(key)) {
117: NbIO io = getValue(i);
118: foundNull |= io == null;
119: if (io != null
120: && (!mustBeClosed || (mustBeClosed && io
121: .isStreamClosed()))) {
122: return io;
123: }
124: }
125: }
126: if (foundNull) {
127: prune();
128: }
129: return null;
130: }
131:
132: public boolean containsValue(NbIO io) {
133: if (last < 0) {
134: return false;
135: }
136: for (int i = last; i >= 0; i--) {
137: if (getValue(i) == io) {
138: return true;
139: }
140: }
141: return false;
142: }
143:
144: public synchronized NbIO get(String key) {
145: return get(key, false);
146: }
147:
148: public synchronized String remove(NbIO io) {
149: int idx = indexOfVal(io);
150: if (idx == -1) {
151: return null;
152: }
153: String result = keys[idx];
154: removeIndex(idx);
155: return result;
156: }
157:
158: public synchronized NbIO remove(String key) {
159: int idx = indexOfKey(key);
160: if (idx == -1) {
161: return null;
162: }
163: NbIO result = getValue(idx);
164: removeIndex(idx);
165: return result;
166: }
167:
168: private NbIO getValue(int idx) {
169: if (idx > last) {
170: throw new ArrayIndexOutOfBoundsException(
171: "Tried to fetch item "
172: + //NOI18N
173: idx + " but map only contains "
174: + (last + 1) + " elements"); //NOI18N
175: }
176: NbIO result;
177: Object o = vals[idx];
178: if (weak) {
179: result = (NbIO) ((WeakReference) vals[idx]).get();
180: if (result == null && !pruning) {
181: removeIndex(idx);
182: }
183:
184: } else {
185: result = (NbIO) o;
186: }
187: return result;
188: }
189:
190: public void setValue(int idx, NbIO value) {
191: if (weak) {
192: vals[idx] = new WeakReference(value);
193: } else {
194: vals[idx] = value;
195: }
196: }
197:
198: private void removeIndex(int idx) {
199: if (idx < 0 || idx > last) {
200: throw new ArrayIndexOutOfBoundsException(
201: "Trying to remove "
202: + //NOI18N
203: "element " + idx
204: + " but map only contains " + (last + 1) + //NOI18N
205: " elements"); //NOI18N
206: }
207: if (idx == last) {
208: keys[idx] = null;
209: vals[idx] = null;
210: } else {
211: keys[idx] = keys[last];
212: vals[idx] = vals[last];
213: vals[last] = null;
214: keys[last] = null;
215: }
216: last--;
217: }
218:
219: private int indexOfKey(String key) {
220: for (int i = last; i >= 0; i--) {
221: if (keys[i].equals(key)) {
222: return i;
223: }
224: }
225: return -1;
226: }
227:
228: private int indexOfVal(NbIO val) {
229: for (int i = last; i >= 0; i--) {
230: if (vals[i] == val) {
231: return i;
232: }
233: }
234: return -1;
235: }
236:
237: private void growArrays() {
238: String[] newKeys = new String[keys.length * 2];
239: NbIO[] newVals = new NbIO[vals.length * 2];
240: System.arraycopy(keys, 0, newKeys, 0, last + 1);
241: System.arraycopy(vals, 0, newVals, 0, last + 1);
242: keys = newKeys;
243: vals = newVals;
244: }
245:
246: private boolean pruning = false;
247:
248: private int prune() {
249: pruning = true;
250: int oldSize = last + 1;
251: int result = oldSize;
252: int[] removes = new int[oldSize];
253: Arrays.fill(removes, -1);
254: for (int i = last; i >= 0; i--) {
255: if (getValue(i) == null) {
256: removes[i] = i;
257: result--;
258: }
259: }
260:
261: if (result != oldSize) {
262: for (int i = removes.length - 1; i >= 0; i--) {
263: if (removes[i] != -1) {
264: removeIndex(removes[i]);
265: }
266: }
267: }
268: pruning = false;
269: return result;
270: }
271:
272: }
|