2 * Copyright 2000-2014 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.util.indexing.containers;
18 import com.intellij.util.indexing.ValueContainer;
19 import gnu.trove.TIntProcedure;
22 * Created by Maxim.Mossienko on 5/27/2014.
24 public class SortedIdSet implements Cloneable, RandomAccessIntContainer {
26 private int mySetLength;
29 public SortedIdSet(final int initialCapacity) {
30 assert initialCapacity < Short.MAX_VALUE;
31 mySet = new int[initialCapacity]; // todo slightly increase size
34 public SortedIdSet(final int[] array, int size) {
36 mySetLength = mySize = size;
39 public boolean isEmpty() {
47 public boolean add(int value) {
51 if (mySetLength == 0 || (mySetLength > 0 && Math.abs(mySet[mySetLength -1]) < value)) {
52 pos = -mySetLength-1; // most of the time during bulk indexing we add near the end
55 pos = binarySearch(mySet, 0, mySetLength, value);
58 if (mySet[pos] > 0) return false;
59 pos = -pos - 1; // found removed
61 if (mySetLength == mySet.length) {
62 int nextArraySize = mySet.length < 1024 ? mySet.length << 1 : mySet.length + mySet.length / 5;
63 int[] newSet = new int[nextArraySize];
64 System.arraycopy(mySet, 0, newSet, 0, mySet.length);
69 boolean lengthIsIncreased = pos == mySetLength; // insert at end
70 if (!lengthIsIncreased && Math.abs(mySet[pos]) != value) { // todo we can shift until first removed
71 System.arraycopy(mySet, pos, mySet, pos + 1, mySetLength - pos);
72 lengthIsIncreased = true;
76 if (lengthIsIncreased) ++mySetLength;
80 public boolean remove(int value) {
82 int pos = binarySearch(mySet, 0, mySetLength, value);
83 if (pos < 0 || mySet[pos] < 0) return false;
85 //if (pos != mySetLength - 1) System.arraycopy(mySet, pos + 1, mySet, pos, mySetLength - pos - 1);
92 public ValueContainer.IntIterator intIterator() {
93 return new Iterator();
97 public ValueContainer.IntPredicate intPredicate() {
98 return new ValueContainer.IntPredicate() {
101 public boolean contains(int id) {
102 return SortedIdSet.this.contains(id);
107 private class Iterator implements ValueContainer.IntIterator {
108 private int myCursor;
111 myCursor = findNext(0);
115 public boolean hasNext() {
116 return myCursor != -1;
121 int result = get(myCursor);
122 myCursor = findNext(myCursor + 1);
128 return SortedIdSet.this.size();
132 public boolean hasAscendingOrder() {
137 public ValueContainer.IntIterator createCopyInInitialState() {
138 return new Iterator();
142 private static int binarySearch(int[] set, int off, int length, int key) {
144 int high = length - 1;
146 while (low <= high) {
147 int mid = (low + high) >>> 1;
148 int midVal = Math.abs(set[mid]);
152 else if (midVal > key)
155 return mid; // key found
157 return -(low + 1); // key not found.
160 public void forEach(TIntProcedure procedure) {
161 for(int i = 0; i < mySetLength; ++i) {
162 int value = mySet[i];
163 if (value > 0 && !procedure.execute(value)) break;
167 public boolean contains(int value) {
168 if(value <= 0) return false;
169 int pos = binarySearch(mySet, 0, mySetLength, value);
170 return pos >= 0 && mySet[pos] > 0;
174 public Object clone() {
176 SortedIdSet set = (SortedIdSet)super.clone();
177 set.mySet = mySet.clone();
180 catch (CloneNotSupportedException e) {
181 throw new RuntimeException(e);
185 public void compact() {
186 if(2 * mySize < mySetLength && mySetLength > 5) {
187 int positivePosition = -1;
188 for(int i = 0; i < mySetLength; ++i) {
190 while(i < mySetLength && mySet[i] < 0) ++i;
192 if (i == mySetLength) {
195 mySet[++positivePosition] = mySet[i];
199 if (i != positivePosition) mySet[positivePosition] = mySet[i];
202 // todo slightly decrease size
203 mySetLength = (short)(positivePosition + 1);
207 public RandomAccessIntContainer ensureContainerCapacity(int count) {
208 int newSize = mySetLength + count;
209 if (newSize < mySet.length) return this;
210 if (newSize > ChangeBufferingList.MAX_FILES) {
211 return new IdBitSet(this, count);
214 newSize = ChangeBufferingList.calcNextArraySize(mySet.length, newSize);
215 assert newSize < Short.MAX_VALUE;
217 int[] newSet = new int[newSize]; // todo slightly increase size and compact
218 System.arraycopy(mySet, 0, newSet, 0, mySetLength);
224 public int findNext(int i) {
225 while(i < mySetLength) {
226 if (mySet[i] > 0) return i;
232 public int get(int cursor) {
233 assert cursor < mySetLength;
234 int value = mySet[cursor];