diff --git a/platform/util/src/com/intellij/util/containers/ByteArrayList.java b/platform/util/src/com/intellij/util/containers/ByteArrayList.java
new file mode 100644
index 000000000000..2f47c5de6fad
--- /dev/null
+++ b/platform/util/src/com/intellij/util/containers/ByteArrayList.java
@@ -0,0 +1,852 @@
+///////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2001, Eric D. Friedman All Rights Reserved.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+///////////////////////////////////////////////////////////////////////////////
+
+package com.intellij.util.containers;
+
+import gnu.trove.HashFunctions;
+import gnu.trove.TIntProcedure;
+
+import java.util.Arrays;
+import java.util.Random;
+
+/**
+ * A resizable, array-backed list of int primitives.
+ *
+ * Created: Sat Dec 29 14:21:12 2001
+ *
+ * @author Eric D. Friedman
+ * @version $Id: TIntArrayList.java,v 1.5 2004/09/24 09:11:15 cdr Exp $
+ */
+
+public class ByteArrayList implements Cloneable {
+
+ /** the data of the list */
+ protected transient byte[] _data;
+
+ /** the index after the last entry in the list */
+ protected transient int _pos;
+
+ /** the default capacity for new lists */
+ protected static final int DEFAULT_CAPACITY = 4;
+
+ /**
+ * Creates a new TIntArrayList instance with the
+ * default capacity.
+ */
+ public ByteArrayList() {
+ this(DEFAULT_CAPACITY);
+ }
+
+ /**
+ * Creates a new TIntArrayList instance with the
+ * specified capacity.
+ *
+ * @param capacity an int value
+ */
+ public ByteArrayList(int capacity) {
+ _data = new byte[capacity];
+ _pos = 0;
+ }
+
+ /**
+ * Creates a new TIntArrayList instance whose
+ * capacity is the greater of the length of values and
+ * DEFAULT_CAPACITY and whose initial contents are the specified
+ * values.
+ *
+ * @param values an int[] value
+ */
+ public ByteArrayList(byte[] values) {
+ this(Math.max(values.length, DEFAULT_CAPACITY));
+ add(values);
+ }
+
+ // sizing
+
+ /**
+ * Grow the internal array as needed to accomodate the specified
+ * number of elements. The size of the array doubles on each
+ * resize unless capacity requires more than twice the
+ * current capacity.
+ *
+ * @param capacity an int value
+ */
+ public void ensureCapacity(int capacity) {
+ byte[] data = _data;
+ if (capacity > data.length) {
+ int newCap = Math.max(data.length < 100000 ? data.length << 1 : data.length * 4 / 3, capacity);
+ byte[] tmp = new byte[newCap];
+ System.arraycopy(data, 0, tmp, 0, data.length);
+ _data = tmp;
+ }
+ }
+
+ /**
+ * Returns the number of values in the list.
+ *
+ * @return the number of values in the list.
+ */
+ public int size() {
+ return _pos;
+ }
+
+ /**
+ * Tests whether this list contains any values.
+ *
+ * @return true if the list is empty.
+ */
+ public boolean isEmpty() {
+ return _pos == 0;
+ }
+
+ /**
+ * Sheds any excess capacity above and beyond the current size of
+ * the list.
+ */
+ public void trimToSize() {
+ if (_data.length > size()) {
+ byte[] tmp = new byte[size()];
+ toNativeArray(tmp, 0, tmp.length);
+ _data = tmp;
+ }
+ }
+
+ // modifying
+
+ /**
+ * Adds val to the end of the list, growing as needed.
+ *
+ * @param val an int value
+ */
+ public void add(byte val) {
+ ensureCapacity(_pos + 1);
+ _data[_pos++] = val;
+ }
+
+ /**
+ * Adds the values in the array vals to the end of the
+ * list, in order.
+ *
+ * @param vals an int[] value
+ */
+ public void add(byte[] vals) {
+ add(vals, 0, vals.length);
+ }
+
+ /**
+ * Adds a subset of the values in the array vals to the
+ * end of the list, in order.
+ *
+ * @param vals an int[] value
+ * @param offset the offset at which to start copying
+ * @param length the number of values to copy.
+ */
+ public void add(byte[] vals, int offset, int length) {
+ ensureCapacity(_pos + length);
+ System.arraycopy(vals, offset, _data, _pos, length);
+ _pos += length;
+ }
+
+ /**
+ * Inserts value into the list at offset. All
+ * values including and to the right of offset are shifted
+ * to the right.
+ *
+ * @param offset an int value
+ * @param value an int value
+ */
+ public void insert(int offset, byte value) {
+ if (offset == _pos) {
+ add(value);
+ return;
+ }
+ ensureCapacity(_pos + 1);
+ // shift right
+ System.arraycopy(_data, offset, _data, offset + 1, _pos - offset);
+ // insert
+ _data[offset] = value;
+ _pos++;
+ }
+
+ /**
+ * Inserts the array of values into the list at
+ * offset. All values including and to the right of
+ * offset are shifted to the right.
+ *
+ * @param offset an int value
+ * @param values an int[] value
+ */
+ public void insert(int offset, byte[] values) {
+ insert(offset, values, 0, values.length);
+ }
+
+ /**
+ * Inserts a slice of the array of values into the list
+ * at offset. All values including and to the right of
+ * offset are shifted to the right.
+ *
+ * @param offset an int value
+ * @param values an int[] value
+ * @param valOffset the offset in the values array at which to
+ * start copying.
+ * @param len the number of values to copy from the values array
+ */
+ public void insert(int offset, byte[] values, int valOffset, int len) {
+ if (offset == _pos) {
+ add(values, valOffset, len);
+ return;
+ }
+
+ ensureCapacity(_pos + len);
+ // shift right
+ System.arraycopy(_data, offset, _data, offset + len, _pos - offset);
+ // insert
+ System.arraycopy(values, valOffset, _data, offset, len);
+ _pos += len;
+ }
+
+ /**
+ * Returns the value at the specified offset.
+ *
+ * @param offset an int value
+ * @return an int value
+ */
+ public byte get(int offset) {
+ if (offset >= _pos) {
+ throw new ArrayIndexOutOfBoundsException(offset);
+ }
+ return _data[offset];
+ }
+
+ /**
+ * Returns the value at the specified offset without doing any
+ * bounds checking.
+ *
+ * @param offset an int value
+ * @return an int value
+ */
+ public byte getQuick(int offset) {
+ return _data[offset];
+ }
+
+ /**
+ * Sets the value at the specified offset.
+ *
+ * @param offset an int value
+ * @param val an int value
+ */
+ public void set(int offset, byte val) {
+ if (offset < 0 || offset >= _pos) {
+ throw new ArrayIndexOutOfBoundsException(offset);
+ }
+ _data[offset] = val;
+ }
+
+ /**
+ * Sets the value at the specified offset and returns the
+ * previously stored value.
+ *
+ * @param offset an int value
+ * @param val an int value
+ * @return the value previously stored at offset.
+ */
+ public byte getSet(int offset, byte val) {
+ if (offset < 0 || offset >= _pos) {
+ throw new ArrayIndexOutOfBoundsException(offset);
+ }
+ byte old = _data[offset];
+ _data[offset] = val;
+ return old;
+ }
+
+ /**
+ * Replace the values in the list starting at offset with
+ * the contents of the values array.
+ *
+ * @param offset the first offset to replace
+ * @param values the source of the new values
+ */
+ public void set(int offset, byte[] values) {
+ set(offset, values, 0, values.length);
+ }
+
+ /**
+ * Replace the values in the list starting at offset with
+ * length values from the values array, starting
+ * at valOffset.
+ *
+ * @param offset the first offset to replace
+ * @param values the source of the new values
+ * @param valOffset the first value to copy from the values array
+ * @param length the number of values to copy
+ */
+ public void set(int offset, byte[] values, int valOffset, int length) {
+ if (offset < 0 || offset + length > _pos) {
+ throw new ArrayIndexOutOfBoundsException(offset);
+ }
+ System.arraycopy(_data, offset, values, valOffset, length);
+ }
+
+ /**
+ * Sets the value at the specified offset without doing any bounds
+ * checking.
+ *
+ * @param offset an int value
+ * @param val an int value
+ */
+ public void setQuick(int offset, byte val) {
+ _data[offset] = val;
+ }
+
+ /**
+ * Flushes the internal state of the list, resetting the capacity
+ * to the default.
+ */
+ public void clear() {
+ clear(DEFAULT_CAPACITY);
+ }
+
+ /**
+ * Flushes the internal state of the list, setting the capacity of
+ * the empty list to capacity.
+ *
+ * @param capacity an int value
+ */
+ public void clear(int capacity) {
+ _data = new byte[capacity];
+ _pos = 0;
+ }
+
+ /**
+ * Sets the size of the list to 0, but does not change its
+ * capacity. This method can be used as an alternative to the
+ * {@link #clear clear} method if you want to recyle a list without
+ * allocating new backing arrays.
+ *
+ * @see #clear
+ */
+ public void reset() {
+ _pos = 0;
+ fill((byte)0);
+ }
+
+ /**
+ * Sets the size of the list to 0, but does not change its
+ * capacity. This method can be used as an alternative to the
+ * {@link #clear clear} method if you want to recyle a list
+ * without allocating new backing arrays. This method differs
+ * from {@link #reset reset} in that it does not clear the old
+ * values in the backing array. Thus, it is possible for {@link
+ * #getQuick getQuick} to return stale data if this method is used
+ * and the caller is careless about bounds checking.
+ *
+ * @see #reset
+ * @see #clear
+ * @see #getQuick
+ */
+ public void resetQuick() {
+ _pos = 0;
+ }
+
+ /**
+ * Removes the value at offset from the list.
+ *
+ * @param offset an int value
+ * @return the value previously stored at offset.
+ */
+ public byte remove(int offset) {
+ byte old = get(offset);
+ remove(offset, 1);
+ return old;
+ }
+
+ /**
+ * Removes length values from the list, starting at
+ * offset
+ *
+ * @param offset an int value
+ * @param length an int value
+ */
+ public void remove(int offset, int length) {
+ if (offset < 0 || offset >= _pos) {
+ throw new ArrayIndexOutOfBoundsException(offset);
+ }
+
+ if (offset == 0) {
+ // data at the front
+ System.arraycopy(_data, length, _data, 0, _pos - length);
+ } else if (_pos - length == offset) {
+ // no copy to make, decrementing pos "deletes" values at
+ // the end
+ } else {
+ // data in the middle
+ System.arraycopy(_data, offset + length,
+ _data, offset, _pos - (offset + length));
+ }
+ _pos -= length;
+ // no need to clear old values beyond _pos, because this is a
+ // primitive collection and 0 takes as much room as any other
+ // value
+ }
+
+
+ /**
+ * Reverse the order of the elements in the list.
+ */
+ public void reverse() {
+ reverse(0, _pos);
+ }
+
+ /**
+ * Reverse the order of the elements in the range of the list.
+ *
+ * @param from the inclusive index at which to start reversing
+ * @param to the exclusive index at which to stop reversing
+ */
+ public void reverse(int from, int to) {
+ if (from == to) {
+ return; // nothing to do
+ }
+ if (from > to) {
+ throw new IllegalArgumentException("from cannot be greater than to");
+ }
+ for (int i = from, j = to - 1; i < j; i++, j--) {
+ swap(i, j);
+ }
+ }
+
+ /**
+ * Shuffle the elements of the list using the specified random
+ * number generator.
+ *
+ * @param rand a Random value
+ */
+ public void shuffle(Random rand) {
+ for (int i = _pos; i-- > 1;) {
+ swap(i, rand.nextInt(i));
+ }
+ }
+
+ /**
+ * Swap the values at offsets i and j.
+ *
+ * @param i an offset into the data array
+ * @param j an offset into the data array
+ */
+ private final void swap(int i, int j) {
+ byte tmp = _data[i];
+ _data[i] = _data[j];
+ _data[j] = tmp;
+ }
+
+ // copying
+
+ /**
+ * Returns a clone of this list. Since this is a primitive
+ * collection, this will be a deep clone.
+ *
+ * @return a deep clone of the list.
+ */
+ public Object clone() {
+ ByteArrayList clone = null;
+ try {
+ clone = (ByteArrayList)super.clone();
+ clone._data = (byte[])_data.clone();
+ } catch (CloneNotSupportedException e) {
+ // it's supported
+ } // end of try-catch
+ return clone;
+ }
+
+ /**
+ * Copies the contents of the list into a native array.
+ *
+ * @return an int[] value
+ */
+ public byte[] toNativeArray() {
+ return toNativeArray(0, _pos);
+ }
+
+ /**
+ * Copies a slice of the list into a native array.
+ *
+ * @param offset the offset at which to start copying
+ * @param len the number of values to copy.
+ * @return an int[] value
+ */
+ public byte[] toNativeArray(int offset, int len) {
+ byte[] rv = new byte[len];
+ toNativeArray(rv, offset, len);
+ return rv;
+ }
+
+ /**
+ * Copies a slice of the list into a native array.
+ *
+ * @param dest the array to copy into.
+ * @param offset the offset of the first value to copy
+ * @param len the number of values to copy.
+ */
+ public void toNativeArray(byte[] dest, int offset, int len) {
+ if (len == 0) {
+ return; // nothing to copy
+ }
+ if (offset < 0 || offset >= _pos) {
+ throw new ArrayIndexOutOfBoundsException(offset);
+ }
+ System.arraycopy(_data, offset, dest, 0, len);
+ }
+
+ // comparing
+
+ /**
+ * Compares this list to another list, value by value.
+ *
+ * @param other the object to compare against
+ * @return true if other is a TIntArrayList and has exactly the
+ * same values.
+ */
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ } else if (other instanceof ByteArrayList) {
+ ByteArrayList that = (ByteArrayList)other;
+ if (that.size() != this.size()) {
+ return false;
+ } else {
+ for (int i = _pos; i-- > 0;) {
+ if (this._data[i] != that._data[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+ } else {
+ return false;
+ }
+ }
+
+ public int hashCode() {
+ int h = 0;
+ for (int i = _pos; i-- > 0;) {
+ h += HashFunctions.hash(_data[i]);
+ }
+ return h;
+ }
+
+ // procedures
+
+ /**
+ * Applies the procedure to each value in the list in ascending
+ * (front to back) order.
+ *
+ * @param procedure a TIntProcedure value
+ * @return true if the procedure did not terminate prematurely.
+ */
+ public boolean forEach(TIntProcedure procedure) {
+ for (int i = 0; i < _pos; i++) {
+ if (! procedure.execute(_data[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Applies the procedure to each value in the list in descending
+ * (back to front) order.
+ *
+ * @param procedure a TIntProcedure value
+ * @return true if the procedure did not terminate prematurely.
+ */
+ public boolean forEachDescending(TIntProcedure procedure) {
+ for (int i = _pos; i-- > 0;) {
+ if (! procedure.execute(_data[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // sorting
+
+ /**
+ * Sort the values in the list (ascending) using the Sun quicksort
+ * implementation.
+ *
+ * @see java.util.Arrays#sort
+ */
+ public void sort() {
+ Arrays.sort(_data, 0, _pos);
+ }
+
+ /**
+ * Sort a slice of the list (ascending) using the Sun quicksort
+ * implementation.
+ *
+ * @param fromIndex the index at which to start sorting (inclusive)
+ * @param toIndex the index at which to stop sorting (exclusive)
+ * @see java.util.Arrays#sort
+ */
+ public void sort(int fromIndex, int toIndex) {
+ Arrays.sort(_data, fromIndex, toIndex);
+ }
+
+ // filling
+
+ /**
+ * Fills every slot in the list with the specified value.
+ *
+ * @param val the value to use when filling
+ */
+ public void fill(byte val) {
+ Arrays.fill(_data, 0, _pos, val);
+ }
+
+ /**
+ * Fills a range in the list with the specified value.
+ *
+ * @param fromIndex the offset at which to start filling (inclusive)
+ * @param toIndex the offset at which to stop filling (exclusive)
+ * @param val the value to use when filling
+ */
+ public void fill(int fromIndex, int toIndex, byte val) {
+ if (toIndex > _pos) {
+ ensureCapacity(toIndex);
+ _pos = toIndex;
+ }
+ Arrays.fill(_data, fromIndex, toIndex, val);
+ }
+
+ // searching
+
+ /**
+ * Performs a binary search for value in the entire list.
+ * Note that you must {@link #sort sort} the list before
+ * doing a search.
+ *
+ * @param value the value to search for
+ * @return the absolute offset in the list of the value, or its
+ * negative insertion point into the sorted list.
+ */
+ public int binarySearch(byte value) {
+ return binarySearch(value, 0, _pos);
+ }
+
+ /**
+ * Performs a binary search for value in the specified
+ * range. Note that you must {@link #sort sort} the list
+ * or the range before doing a search.
+ *
+ * @param value the value to search for
+ * @param fromIndex the lower boundary of the range (inclusive)
+ * @param toIndex the upper boundary of the range (exclusive)
+ * @return the absolute offset in the list of the value, or its
+ * negative insertion point into the sorted list.
+ */
+ public int binarySearch(byte value, int fromIndex, int toIndex) {
+ if (fromIndex < 0) {
+ throw new ArrayIndexOutOfBoundsException(fromIndex);
+ }
+ if (toIndex > _pos) {
+ throw new ArrayIndexOutOfBoundsException(toIndex);
+ }
+
+ int low = fromIndex;
+ int high = toIndex - 1;
+
+ while (low <= high) {
+ int mid = (low + high) >> 1;
+ byte midVal = _data[mid];
+
+ if (midVal < value) {
+ low = mid + 1;
+ } else if (midVal > value) {
+ high = mid - 1;
+ } else {
+ return mid; // value found
+ }
+ }
+ return -(low + 1); // value not found.
+ }
+
+ /**
+ * Searches the list front to back for the index of
+ * value.
+ *
+ * @param value an int value
+ * @return the first offset of the value, or -1 if it is not in
+ * the list.
+ * @see #binarySearch for faster searches on sorted lists
+ */
+ public int indexOf(byte value) {
+ return indexOf(0, value);
+ }
+
+ /**
+ * Searches the list front to back for the index of
+ * value, starting at offset.
+ *
+ * @param offset the offset at which to start the linear search
+ * (inclusive)
+ * @param value an int value
+ * @return the first offset of the value, or -1 if it is not in
+ * the list.
+ * @see #binarySearch for faster searches on sorted lists
+ */
+ public int indexOf(int offset, byte value) {
+ for (int i = offset; i < _pos; i++) {
+ if (_data[i] == value) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Searches the list back to front for the last index of
+ * value.
+ *
+ * @param value an int value
+ * @return the last offset of the value, or -1 if it is not in
+ * the list.
+ * @see #binarySearch for faster searches on sorted lists
+ */
+ public int lastIndexOf(byte value) {
+ return lastIndexOf(_pos, value);
+ }
+
+ /**
+ * Searches the list back to front for the last index of
+ * value, starting at offset.
+ *
+ * @param offset the offset at which to start the linear search
+ * (exclusive)
+ * @param value an int value
+ * @return the last offset of the value, or -1 if it is not in
+ * the list.
+ * @see #binarySearch for faster searches on sorted lists
+ */
+ public int lastIndexOf(int offset, byte value) {
+ for (int i = offset; i-- > 0;) {
+ if (_data[i] == value) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Searches the list for value
+ *
+ * @param value an int value
+ * @return true if value is in the list.
+ */
+ public boolean contains(byte value) {
+ return lastIndexOf(value) >= 0;
+ }
+
+ /**
+ * Searches the list for values satisfying condition in
+ * the manner of the *nix grep utility.
+ *
+ * @param condition a condition to apply to each element in the list
+ * @return a list of values which match the condition.
+ */
+ public ByteArrayList grep(TIntProcedure condition) {
+ ByteArrayList list = new ByteArrayList();
+ for (int i = 0; i < _pos; i++) {
+ if (condition.execute(_data[i])) {
+ list.add(_data[i]);
+ }
+ }
+ return list;
+ }
+
+ /**
+ * Searches the list for values which do not satisfy
+ * condition. This is akin to *nix grep -v.
+ *
+ * @param condition a condition to apply to each element in the list
+ * @return a list of values which do not match the condition.
+ */
+ public ByteArrayList inverseGrep(TIntProcedure condition) {
+ ByteArrayList list = new ByteArrayList();
+ for (int i = 0; i < _pos; i++) {
+ if (! condition.execute(_data[i])) {
+ list.add(_data[i]);
+ }
+ }
+ return list;
+ }
+
+ /**
+ * Finds the maximum value in the list.
+ *
+ * @return the largest value in the list.
+ * @exception IllegalStateException if the list is empty
+ */
+ public int max() {
+ if (size() == 0) {
+ throw new IllegalStateException("cannot find maximum of an empty list");
+ }
+ int max = _data[_pos - 1];
+ for (int i = _pos - 1; i-- > 0;) {
+ max = Math.max(max, _data[_pos]);
+ }
+ return max;
+ }
+
+ /**
+ * Finds the minimum value in the list.
+ *
+ * @return the smallest value in the list.
+ * @exception IllegalStateException if the list is empty
+ */
+ public int min() {
+ if (size() == 0) {
+ throw new IllegalStateException("cannot find minimum of an empty list");
+ }
+ int min = _data[_pos - 1];
+ for (int i = _pos - 1; i-- > 0;) {
+ min = Math.min(min, _data[_pos]);
+ }
+ return min;
+ }
+
+ // stringification
+
+ /**
+ * Returns a String representation of the list, front to back.
+ *
+ * @return a String value
+ */
+ public String toString() {
+ final StringBuffer buf = new StringBuffer("{");
+ forEach(new TIntProcedure() {
+ public boolean execute(int val) {
+ buf.append(val);
+ buf.append(", ");
+ return true;
+ }
+ });
+ buf.append("}");
+ return buf.toString();
+ }
+
+} // TIntArrayList
diff --git a/platform/util/src/com/intellij/util/containers/ConcurrentIntObjectMap.java b/platform/util/src/com/intellij/util/containers/ConcurrentIntObjectMap.java
new file mode 100644
index 000000000000..5b5a44f80e41
--- /dev/null
+++ b/platform/util/src/com/intellij/util/containers/ConcurrentIntObjectMap.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2000-2012 JetBrains s.r.o.
+ *
+ * Licensed 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 com.intellij.util.containers;
+
+import org.jetbrains.annotations.NotNull;
+
+/**
+ * methods adapted from java.util.concurrent.ConcurrentMap to integer keys
+ * @see java.util.concurrent.ConcurrentMap
+ */
+public interface ConcurrentIntObjectMap {
+ // concurrency related methods
+
+ /**
+ * @return written value
+ */
+ @NotNull
+ V cacheOrGet(int key, @NotNull V value);
+ boolean remove(int key, @NotNull V value);
+ boolean replace(int key, @NotNull V oldValue, @NotNull V newValue);
+
+ // regular Map methods
+ V put(int key, @NotNull V value);
+ V get(int key);
+ V remove(int key);
+ boolean containsKey(int key);
+ void clear();
+ @NotNull
+ Iterable> entries();
+}
diff --git a/platform/util/src/com/intellij/util/containers/ConcurrentRefValueIntObjectHashMap.java b/platform/util/src/com/intellij/util/containers/ConcurrentRefValueIntObjectHashMap.java
new file mode 100644
index 000000000000..2a10009a31c4
--- /dev/null
+++ b/platform/util/src/com/intellij/util/containers/ConcurrentRefValueIntObjectHashMap.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2000-2012 JetBrains s.r.o.
+ *
+ * Licensed 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 com.intellij.util.containers;
+
+
+import com.intellij.util.IncorrectOperationException;
+import org.jetbrains.annotations.NotNull;
+
+import java.lang.ref.ReferenceQueue;
+import java.util.Iterator;
+
+abstract class ConcurrentRefValueIntObjectHashMap implements ConcurrentIntObjectMap {
+ private final StripedLockIntObjectConcurrentHashMap> myMap = new StripedLockIntObjectConcurrentHashMap>();
+ private final ReferenceQueue myQueue = new ReferenceQueue();
+
+ protected abstract IntReference createReference(int key, @NotNull V value, ReferenceQueue queue);
+
+ protected interface IntReference {
+ int getKey();
+ V get();
+ }
+
+ void processQueue() {
+ while(true){
+ IntReference ref = (IntReference)myQueue.poll();
+ if (ref == null) {
+ return;
+ }
+ int key = ref.getKey();
+ myMap.remove(key);
+ }
+ }
+
+ @NotNull
+ @Override
+ public V cacheOrGet(int key, @NotNull V value) {
+ processQueue();
+ IntReference ref = myMap.putIfAbsent(key, createReference(key, value, myQueue));
+ V v = ref == null ? null : ref.get();
+ return v == null ? value : v;
+ }
+
+ @Override
+ public boolean remove(int key, @NotNull V value) {
+ processQueue();
+ return myMap.remove(key, createReference(key, value, myQueue));
+ }
+
+ @Override
+ public boolean replace(int key, @NotNull V oldValue, @NotNull V newValue) {
+ processQueue();
+ return myMap.replace(key, createReference(key, oldValue,myQueue), createReference(key, newValue,myQueue));
+ }
+
+ @Override
+ public V put(int key, @NotNull V value) {
+ processQueue();
+ IntReference ref = myMap.put(key, createReference(key, value, myQueue));
+ return ref == null ? null : ref.get();
+ }
+
+ @Override
+ public V get(int key) {
+ IntReference ref = myMap.get(key);
+ return ref == null ? null : ref.get();
+ }
+
+ @Override
+ public V remove(int key) {
+ processQueue();
+ IntReference ref = myMap.remove(key);
+ return ref == null ? null : ref.get();
+ }
+
+ @Override
+ public boolean containsKey(int key) {
+ return myMap.containsKey(key);
+ }
+
+ @Override
+ public void clear() {
+ myMap.clear();
+ processQueue();
+ }
+
+ @NotNull
+ @Override
+ public Iterable> entries() {
+ final Iterator>> entryIterator = myMap.entries().iterator();
+ return new Iterable>() {
+ @Override
+ public Iterator> iterator() {
+ return new Iterator>() {
+ StripedLockIntObjectConcurrentHashMap.IntEntry next = nextAliveEntry();
+ @Override
+ public boolean hasNext() {
+ return next != null;
+ }
+
+ @Override
+ public StripedLockIntObjectConcurrentHashMap.IntEntry next() {
+ StripedLockIntObjectConcurrentHashMap.IntEntry result = next;
+ next = nextAliveEntry();
+ return result;
+ }
+
+ private StripedLockIntObjectConcurrentHashMap.IntEntry nextAliveEntry() {
+ while (entryIterator.hasNext()) {
+ StripedLockIntObjectConcurrentHashMap.IntEntry> entry = entryIterator.next();
+ final V v = entry.getValue().get();
+ if (v == null) {
+ continue;
+ }
+ final int key = entry.getKey();
+ return new StripedLockIntObjectConcurrentHashMap.IntEntry() {
+ @Override
+ public int getKey() {
+ return key;
+ }
+
+ @NotNull
+ @Override
+ public V getValue() {
+ return v;
+ }
+ };
+ }
+ return null;
+ }
+
+ @Override
+ public void remove() {
+ throw new IncorrectOperationException("not implemented");
+ }
+ };
+ }
+ };
+ }
+}
diff --git a/platform/util/src/com/intellij/util/containers/ConcurrentSoftValueIntObjectHashMap.java b/platform/util/src/com/intellij/util/containers/ConcurrentSoftValueIntObjectHashMap.java
new file mode 100644
index 000000000000..1d2643cec415
--- /dev/null
+++ b/platform/util/src/com/intellij/util/containers/ConcurrentSoftValueIntObjectHashMap.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2000-2012 JetBrains s.r.o.
+ *
+ * Licensed 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 com.intellij.util.containers;
+
+
+import org.jetbrains.annotations.NotNull;
+
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.SoftReference;
+
+public class ConcurrentSoftValueIntObjectHashMap extends ConcurrentRefValueIntObjectHashMap {
+ private static class MyRef extends SoftReference implements IntReference {
+ private final int hash;
+ private final int key;
+
+ MyRef(int key, @NotNull V referent, ReferenceQueue queue) {
+ super(referent, queue);
+ this.key = key;
+ hash = referent.hashCode();
+ }
+
+ @Override
+ public int hashCode() {
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ V v = get();
+ return obj instanceof MyRef && ((MyRef)obj).hash == hash && v != null && v.equals(((MyRef)obj).get());
+ }
+
+ @Override
+ public int getKey() {
+ return key;
+ }
+ }
+
+ @Override
+ protected IntReference createReference(int key, @NotNull V value, ReferenceQueue queue) {
+ return new MyRef(key, value, queue);
+ }
+}
diff --git a/platform/util/src/com/intellij/util/containers/ConcurrentWeakValueIntObjectHashMap.java b/platform/util/src/com/intellij/util/containers/ConcurrentWeakValueIntObjectHashMap.java
new file mode 100644
index 000000000000..861e47ac781d
--- /dev/null
+++ b/platform/util/src/com/intellij/util/containers/ConcurrentWeakValueIntObjectHashMap.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2000-2012 JetBrains s.r.o.
+ *
+ * Licensed 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 com.intellij.util.containers;
+
+
+import org.jetbrains.annotations.NotNull;
+
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+
+public class ConcurrentWeakValueIntObjectHashMap extends ConcurrentRefValueIntObjectHashMap {
+ private static class MyRef extends WeakReference implements IntReference {
+ private final int hash;
+ private final int key;
+
+ MyRef(int key, @NotNull V referent, ReferenceQueue queue) {
+ super(referent, queue);
+ this.key = key;
+ hash = referent.hashCode();
+ }
+
+ @Override
+ public int hashCode() {
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ V v = get();
+ return obj instanceof MyRef && ((MyRef)obj).hash == hash && v != null && v.equals(((MyRef)obj).get());
+ }
+
+ @Override
+ public int getKey() {
+ return key;
+ }
+ }
+
+ @Override
+ protected IntReference createReference(int key, @NotNull V value, ReferenceQueue queue) {
+ return new MyRef(key, value, queue);
+ }
+}
diff --git a/platform/util/src/com/intellij/util/containers/IntArrayList.java b/platform/util/src/com/intellij/util/containers/IntArrayList.java
index d595a53cc008..a34ba3ebf75c 100644
--- a/platform/util/src/com/intellij/util/containers/IntArrayList.java
+++ b/platform/util/src/com/intellij/util/containers/IntArrayList.java
@@ -50,6 +50,20 @@ public class IntArrayList implements Cloneable {
System.arraycopy(oldData, 0, myData, 0, mySize);
}
}
+ public void fill(int fromIndex, int toIndex, int value) {
+ if (toIndex > mySize) {
+ ensureCapacity(toIndex);
+ mySize = toIndex;
+ }
+ Arrays.fill(myData, fromIndex, toIndex, value);
+ }
+
+ public void add(int[] values) {
+ int length = values.length;
+ ensureCapacity(mySize + length);
+ System.arraycopy(values, 0, myData, mySize, length);
+ mySize += length;
+ }
public int size() {
return mySize;
@@ -105,11 +119,19 @@ public class IntArrayList implements Cloneable {
return a;
}
+ public int[] toArray(int startIndex, int length) {
+ int[] result = new int[length];
+ System.arraycopy(myData, startIndex, result, 0, length);
+ return result;
+ }
public int get(int index) {
checkRange(index);
return myData[index];
}
+ public int getQuick(int index) {
+ return myData[index];
+ }
public int set(int index, int element) {
checkRange(index);
@@ -118,6 +140,9 @@ public class IntArrayList implements Cloneable {
myData[index] = element;
return oldValue;
}
+ public void setQuick(int index, int element) {
+ myData[index] = element;
+ }
public void add(int o) {
ensureCapacity(mySize + 1);
diff --git a/platform/util/src/com/intellij/util/containers/StripedLockIntObjectConcurrentHashMap.java b/platform/util/src/com/intellij/util/containers/StripedLockIntObjectConcurrentHashMap.java
index a862b2a8b782..f00542bc8ab1 100644
--- a/platform/util/src/com/intellij/util/containers/StripedLockIntObjectConcurrentHashMap.java
+++ b/platform/util/src/com/intellij/util/containers/StripedLockIntObjectConcurrentHashMap.java
@@ -16,21 +16,22 @@
package com.intellij.util.containers;
-import gnu.trove.THashSet;
import org.jetbrains.annotations.NotNull;
-import java.util.*;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
/** similar to java.util.ConcurrentHashMap except:
keys are ints
conserved as much memory as possible by
-- using only one Segment
-- eliminating unnecessary fields
- -- using one of 256 ReentrantLock for Segment staticly preallocated in StripedReentrantLocks
+ -- using one of 256 ReentrantLock for Segment statically pre-allocated in {@link StripedReentrantLocks}
added hashing strategy argument
made not Serializable
*/
-public class StripedLockIntObjectConcurrentHashMap {
+public class StripedLockIntObjectConcurrentHashMap implements ConcurrentIntObjectMap {
/* ---------------- Constants -------------- */
/**
@@ -145,6 +146,7 @@ public class StripedLockIntObjectConcurrentHashMap {
* @throws NullPointerException if the key or value is
* null.
*/
+ @Override
public V put(int key, @NotNull V value) {
return put(key, value, false);
}
@@ -185,19 +187,22 @@ public class StripedLockIntObjectConcurrentHashMap {
* @throws NullPointerException if the key is
* null.
*/
+ @Override
public V remove(int key) {
- return remove(key, null);
+ return doRemove(key, null);
}
+ @Override
+ public boolean remove(int key, @NotNull V value) {
+ return doRemove(key, value) != null;
+ }
-
-
-
-
-
-
-
-
+ @NotNull
+ @Override
+ public V cacheOrGet(int key, @NotNull V value) {
+ V prev = putIfAbsent(key, value);
+ return prev == null ? value : prev;
+ }
/**
* Returns an enumeration of the values in this table.
@@ -212,13 +217,11 @@ public class StripedLockIntObjectConcurrentHashMap {
/* ---------------- Iterator Support -------------- */
private class HashIterator {
- private int nextTableIndex;
- private IntHashEntry[] currentTable;
+ private int nextTableIndex = table.length - 1;
private IntHashEntry nextEntry;
private IntHashEntry lastReturned;
private HashIterator() {
- nextTableIndex = -1;
advance();
}
@@ -232,21 +235,10 @@ public class StripedLockIntObjectConcurrentHashMap {
}
while (nextTableIndex >= 0) {
- if ((nextEntry = (IntHashEntry)currentTable[nextTableIndex--]) != null) {
+ if ((nextEntry = (IntHashEntry)table[nextTableIndex--]) != null) {
return;
}
}
-
- StripedLockIntObjectConcurrentHashMap seg = StripedLockIntObjectConcurrentHashMap.this;
- if (seg.count != 0) {
- currentTable = seg.table;
- for (int j = currentTable.length - 1; j >= 0; --j) {
- if ((nextEntry = (IntHashEntry)currentTable[j]) != null) {
- nextTableIndex = j - 1;
- return;
- }
- }
- }
}
public boolean hasNext() {
@@ -289,15 +281,33 @@ public class StripedLockIntObjectConcurrentHashMap {
}
- public Collection> entries() {
- HashIterator iterator = new HashIterator();
- Set> result = new THashSet>();
- while (iterator.hasNext()) {
- IntHashEntry ie = iterator.nextEntry;
- SimpleEntry entry = new SimpleEntry(ie.key, ie.value);
- result.add(entry);
- }
- return result;
+ @Override
+ @NotNull
+ public Iterable> entries() {
+ return new Iterable>() {
+ @Override
+ public Iterator> iterator() {
+ final HashIterator hashIterator = new HashIterator();
+ return new Iterator>() {
+ @Override
+ public boolean hasNext() {
+ return hashIterator.hasNext();
+ }
+
+ @Override
+ public IntEntry next() {
+ IntHashEntry ie = hashIterator.nextEntry;
+ hashIterator.nextEntry();
+ return new SimpleEntry(ie.key, ie.value);
+ }
+
+ @Override
+ public void remove() {
+ hashIterator.remove();
+ }
+ };
+ }
+ };
}
/**
@@ -461,6 +471,7 @@ public class StripedLockIntObjectConcurrentHashMap {
/* Specialized implementations of map methods */
+ @Override
public V get(int key) {
if (count != 0) { // read-volatile
IntHashEntry e = getFirst(key);
@@ -478,6 +489,7 @@ public class StripedLockIntObjectConcurrentHashMap {
return null;
}
+ @Override
public boolean containsKey(int key) {
if (count != 0) { // read-volatile
IntHashEntry e = getFirst(key);
@@ -491,6 +503,7 @@ public class StripedLockIntObjectConcurrentHashMap {
return false;
}
+ @Override
public boolean replace(int key, @NotNull V oldValue, @NotNull V newValue) {
lock();
try {
@@ -614,7 +627,7 @@ public class StripedLockIntObjectConcurrentHashMap {
/**
* Remove; match on key only if value null, else match both.
*/
- protected V remove(int key, Object value) {
+ protected V doRemove(int key, V value) {
lock();
try {
int c = count - 1;
@@ -650,6 +663,7 @@ public class StripedLockIntObjectConcurrentHashMap {
}
}
+ @Override
public void clear() {
if (count != 0) {
lock();