blob: c27a5d41a03913576d575a3f019ff5db7a26fa8d [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.core.output2;
import java.lang.ref.WeakReference;
import java.util.Arrays;
import org.openide.util.Parameters;
/**
* A synchronized LIFO map that can contain duplicate keys, and can be
* toggled between using weak and strong references for values. Used for
* mapping instances of NbIO to the names used in NbIOProvider.getIO().
*
* @author Tim Boudreau
*/
class PairMap {
//XXX weak referencing of objects no longer used - delete?
private String [] keys = new String[10];
/** package private for unit tests */
Object [] vals = new Object[10];
int last = -1;
private boolean weak = false;
/** Creates a new instance of PairMap */
PairMap() {
}
public synchronized void clear() {
keys = new String[10];
vals = new Object[10];
last = -1;
}
public synchronized int size() {
if (weak) {
return prune();
} else {
return last+1;
}
}
public synchronized boolean isEmpty() {
return size() == 0;
}
public synchronized void setWeak(boolean val) {
if (weak != val) {
weak = val;
for (int i=0; i <= last; i++) {
if (weak) {
vals[i] = new WeakReference<Object>(vals[i]);
} else {
vals[i] = ((WeakReference<?>) vals[i]).get();
}
}
if (!weak) {
prune();
}
}
}
public synchronized void add (String key, NbIO value) {
Parameters.notNull("key", key);
if (last == keys.length -1) {
growArrays();
}
last++;
keys[last] = key;
vals[last] = value;
}
public synchronized NbIO get (String key, boolean mustBeClosed) {
if (last < 0) {
return null;
}
boolean foundNull = false;
for (int i=last; i >= 0; i--) {
if (keys[i].equals(key)) {
NbIO io = getValue(i);
foundNull |= io == null;
if (io != null && (!mustBeClosed || (mustBeClosed && io.isStreamClosed()))) {
return io;
}
}
}
if (foundNull) {
prune();
}
return null;
}
public boolean containsValue(NbIO io) {
if (last < 0) {
return false;
}
for (int i=last; i >= 0; i--) {
if (getValue(i) == io) {
return true;
}
}
return false;
}
public synchronized NbIO get (String key) {
return get(key, false);
}
public synchronized String remove (NbIO io) {
int idx = indexOfVal (io);
if (idx == -1) {
return null;
}
String result = keys[idx];
removeIndex(idx);
return result;
}
public synchronized NbIO remove (String key) {
int idx = indexOfKey(key);
if (idx == -1) {
return null;
}
NbIO result = getValue(idx);
removeIndex(idx);
return result;
}
private NbIO getValue(int idx) {
if (idx > last) {
throw new ArrayIndexOutOfBoundsException ("Tried to fetch item " + //NOI18N
idx + " but map only contains " + (last + 1) + " elements"); //NOI18N
}
NbIO result;
Object o = vals[idx];
if (weak) {
result = (NbIO) ((WeakReference) vals[idx]).get();
if (result == null && !pruning) {
removeIndex(idx);
}
} else {
result = (NbIO) o;
}
return result;
}
public void setValue (int idx, NbIO value) {
if (weak) {
vals[idx] = new WeakReference<Object>(value);
} else {
vals[idx] = value;
}
}
private void removeIndex (int idx) {
if (idx < 0 || idx > last) {
throw new ArrayIndexOutOfBoundsException ("Trying to remove " + //NOI18N
"element " + idx + " but map only contains " + (last+1) + //NOI18N
" elements"); //NOI18N
}
if (idx == last) {
keys[idx] = null;
vals[idx] = null;
} else {
keys[idx] = keys[last];
vals[idx] = vals[last];
vals[last] = null;
keys[last] = null;
}
last--;
}
private int indexOfKey (String key) {
for (int i=last; i >= 0; i--) {
if (keys[i].equals(key)) {
return i;
}
}
return -1;
}
private int indexOfVal (NbIO val) {
for (int i=last; i >= 0; i--) {
if (vals[i] == val) {
return i;
}
}
return -1;
}
private void growArrays() {
String[] newKeys = new String[keys.length * 2];
NbIO[] newVals = new NbIO[vals.length * 2];
System.arraycopy (keys, 0, newKeys, 0, last+1);
System.arraycopy (vals, 0, newVals, 0, last+1);
keys = newKeys;
vals = newVals;
}
private boolean pruning = false;
private int prune() {
pruning = true;
int oldSize = last + 1;
int result = oldSize;
int[] removes = new int[oldSize];
Arrays.fill (removes, -1);
for (int i=last; i >= 0; i--) {
if (getValue(i) == null) {
removes[i] = i;
result--;
}
}
if (result != oldSize) {
for (int i=removes.length-1; i >= 0; i--) {
if (removes[i] != -1) {
removeIndex(removes[i]);
}
}
}
pruning = false;
return result;
}
}